Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Aug 2016 21:14:23 +0000 (14:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Aug 2016 21:14:23 +0000 (14:14 -0700)
Pull ARM SoC fixes from Arnd Bergmann:
 "A couple of bug fixes have come in for v4.8 so far.  Since the first
  few were originally meant to go into -rc1 (but didn't get sent in time
  for travel reasons), the branch is unfortunately based on top of a
  commit in the middle of the merge window rather than -rc1.

  Content-wise we have:

   - a fix for the last remaining broken build in kernelci, getting
     mach-shmobile to build again with SMP disabled

   - a fix for a realview regression that broke real hardware but not
     the qemu model that everyone uses in practice (needed for v4.7 as
     well)

   - a merge conflict fix for Tegra that also broke v4.7

   - two Kconfig fixes for arm64 build regressions

   - a couple of arm32 build warning fixes (all harmless)

   - fix the RTC on Exynos7 Espresso (which apparently never worked
     right)"

* tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc:
  Merge tag 'pxa-fixes-v4.8' of https://github.com/rjarzmik/linux into randconfig-4.8
  arm64: Kconfig: select HISILICON_IRQ_MBIGEN only if PCI is selected
  arm64: Kconfig: select ALPINE_MSI only if PCI is selected
  ARM: dts: realview: Fix PBX-A9 cache description
  ARM: tegra: fix erroneous address in dts
  ARM: dts: add syscon compatible string for AP syscon
  ARM: dts: add syscon compatible string for CP syscon
  ARM: oxnas: select reset controller framework
  ARM: hide mach-*/ include for ARM_SINGLE_ARMV7M
  ARM: don't include removed directories
  Revert "ARM: aspeed: adapt defconfigs for new CONFIG_PRINTK_TIME"
  ARM: shmobile: don't call platform_can_secondary_boot on UP
  MAINTAINER: alpine: add a mailing list
  ARM: do away with final ARCH_REQUIRE_GPIOLIB
  arm64: dts: Fix RTC by providing rtc_src clock

2073 files changed:
.cocciconfig [new file with mode: 0644]
.gitignore
.mailmap
Documentation/ABI/testing/sysfs-class-pwm
Documentation/DMA-API.txt
Documentation/DMA-attributes.txt
Documentation/DocBook/Makefile
Documentation/DocBook/media/.gitignore [deleted file]
Documentation/DocBook/media/Makefile [deleted file]
Documentation/DocBook/media/bayer.png.b64 [deleted file]
Documentation/DocBook/media/constraints.png.b64 [deleted file]
Documentation/DocBook/media/crop.gif.b64 [deleted file]
Documentation/DocBook/media/dvb/.gitignore [deleted file]
Documentation/DocBook/media/dvb/audio.xml [deleted file]
Documentation/DocBook/media/dvb/ca.xml [deleted file]
Documentation/DocBook/media/dvb/demux.xml [deleted file]
Documentation/DocBook/media/dvb/dvbapi.xml [deleted file]
Documentation/DocBook/media/dvb/dvbproperty.xml [deleted file]
Documentation/DocBook/media/dvb/dvbstb.pdf [deleted file]
Documentation/DocBook/media/dvb/examples.xml [deleted file]
Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml [deleted file]
Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml [deleted file]
Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml [deleted file]
Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml [deleted file]
Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml [deleted file]
Documentation/DocBook/media/dvb/fe-get-info.xml [deleted file]
Documentation/DocBook/media/dvb/fe-get-property.xml [deleted file]
Documentation/DocBook/media/dvb/fe-read-status.xml [deleted file]
Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml [deleted file]
Documentation/DocBook/media/dvb/fe-set-tone.xml [deleted file]
Documentation/DocBook/media/dvb/fe-set-voltage.xml [deleted file]
Documentation/DocBook/media/dvb/frontend.xml [deleted file]
Documentation/DocBook/media/dvb/frontend_legacy_api.xml [deleted file]
Documentation/DocBook/media/dvb/intro.xml [deleted file]
Documentation/DocBook/media/dvb/net.xml [deleted file]
Documentation/DocBook/media/dvb/video.xml [deleted file]
Documentation/DocBook/media/dvbstb.png.b64 [deleted file]
Documentation/DocBook/media/fieldseq_bt.gif.b64 [deleted file]
Documentation/DocBook/media/fieldseq_tb.gif.b64 [deleted file]
Documentation/DocBook/media/nv12mt.gif.b64 [deleted file]
Documentation/DocBook/media/nv12mt_example.gif.b64 [deleted file]
Documentation/DocBook/media/pipeline.png.b64 [deleted file]
Documentation/DocBook/media/selection.png.b64 [deleted file]
Documentation/DocBook/media/typical_media_device.svg [deleted file]
Documentation/DocBook/media/v4l/.gitignore [deleted file]
Documentation/DocBook/media/v4l/biblio.xml [deleted file]
Documentation/DocBook/media/v4l/capture.c.xml [deleted file]
Documentation/DocBook/media/v4l/cec-api.xml [deleted file]
Documentation/DocBook/media/v4l/cec-func-close.xml [deleted file]
Documentation/DocBook/media/v4l/cec-func-ioctl.xml [deleted file]
Documentation/DocBook/media/v4l/cec-func-open.xml [deleted file]
Documentation/DocBook/media/v4l/cec-func-poll.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml [deleted file]
Documentation/DocBook/media/v4l/cec-ioc-receive.xml [deleted file]
Documentation/DocBook/media/v4l/common.xml [deleted file]
Documentation/DocBook/media/v4l/compat.xml [deleted file]
Documentation/DocBook/media/v4l/controls.xml [deleted file]
Documentation/DocBook/media/v4l/crop.pdf [deleted file]
Documentation/DocBook/media/v4l/dev-capture.xml [deleted file]
Documentation/DocBook/media/v4l/dev-codec.xml [deleted file]
Documentation/DocBook/media/v4l/dev-effect.xml [deleted file]
Documentation/DocBook/media/v4l/dev-event.xml [deleted file]
Documentation/DocBook/media/v4l/dev-osd.xml [deleted file]
Documentation/DocBook/media/v4l/dev-output.xml [deleted file]
Documentation/DocBook/media/v4l/dev-overlay.xml [deleted file]
Documentation/DocBook/media/v4l/dev-radio.xml [deleted file]
Documentation/DocBook/media/v4l/dev-raw-vbi.xml [deleted file]
Documentation/DocBook/media/v4l/dev-rds.xml [deleted file]
Documentation/DocBook/media/v4l/dev-sdr.xml [deleted file]
Documentation/DocBook/media/v4l/dev-sliced-vbi.xml [deleted file]
Documentation/DocBook/media/v4l/dev-subdev.xml [deleted file]
Documentation/DocBook/media/v4l/dev-teletext.xml [deleted file]
Documentation/DocBook/media/v4l/driver.xml [deleted file]
Documentation/DocBook/media/v4l/fdl-appendix.xml [deleted file]
Documentation/DocBook/media/v4l/fieldseq_bt.pdf [deleted file]
Documentation/DocBook/media/v4l/fieldseq_tb.pdf [deleted file]
Documentation/DocBook/media/v4l/func-close.xml [deleted file]
Documentation/DocBook/media/v4l/func-ioctl.xml [deleted file]
Documentation/DocBook/media/v4l/func-mmap.xml [deleted file]
Documentation/DocBook/media/v4l/func-munmap.xml [deleted file]
Documentation/DocBook/media/v4l/func-open.xml [deleted file]
Documentation/DocBook/media/v4l/func-poll.xml [deleted file]
Documentation/DocBook/media/v4l/func-read.xml [deleted file]
Documentation/DocBook/media/v4l/func-select.xml [deleted file]
Documentation/DocBook/media/v4l/func-write.xml [deleted file]
Documentation/DocBook/media/v4l/gen-errors.xml [deleted file]
Documentation/DocBook/media/v4l/io.xml [deleted file]
Documentation/DocBook/media/v4l/keytable.c.xml [deleted file]
Documentation/DocBook/media/v4l/libv4l.xml [deleted file]
Documentation/DocBook/media/v4l/lirc_device_interface.xml [deleted file]
Documentation/DocBook/media/v4l/media-controller.xml [deleted file]
Documentation/DocBook/media/v4l/media-func-close.xml [deleted file]
Documentation/DocBook/media/v4l/media-func-ioctl.xml [deleted file]
Documentation/DocBook/media/v4l/media-func-open.xml [deleted file]
Documentation/DocBook/media/v4l/media-ioc-device-info.xml [deleted file]
Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml [deleted file]
Documentation/DocBook/media/v4l/media-ioc-enum-links.xml [deleted file]
Documentation/DocBook/media/v4l/media-ioc-g-topology.xml [deleted file]
Documentation/DocBook/media/v4l/media-ioc-setup-link.xml [deleted file]
Documentation/DocBook/media/v4l/media-types.xml [deleted file]
Documentation/DocBook/media/v4l/pipeline.pdf [deleted file]
Documentation/DocBook/media/v4l/pixfmt-grey.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-m420.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv12.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv12m.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv16.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv16m.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-nv24.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb10.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb12.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-srggb8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-uv8.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-uyvy.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-vyuy.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y10.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y10b.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y12.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y12i.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y16-be.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y16.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y41p.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-y8i.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv410.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv420.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv422m.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuv444m.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yuyv.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-yvyu.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt-z16.xml [deleted file]
Documentation/DocBook/media/v4l/pixfmt.xml [deleted file]
Documentation/DocBook/media/v4l/planar-apis.xml [deleted file]
Documentation/DocBook/media/v4l/remote_controllers.xml [deleted file]
Documentation/DocBook/media/v4l/selection-api.xml [deleted file]
Documentation/DocBook/media/v4l/selections-common.xml [deleted file]
Documentation/DocBook/media/v4l/subdev-formats.xml [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-full.dia [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-full.svg [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia [deleted file]
Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg [deleted file]
Documentation/DocBook/media/v4l/v4l2.xml [deleted file]
Documentation/DocBook/media/v4l/v4l2grab.c.xml [deleted file]
Documentation/DocBook/media/v4l/vbi_525.pdf [deleted file]
Documentation/DocBook/media/v4l/vbi_625.pdf [deleted file]
Documentation/DocBook/media/v4l/vbi_hsync.pdf [deleted file]
Documentation/DocBook/media/v4l/vidioc-create-bufs.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-cropcap.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-dqevent.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enumaudio.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enuminput.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enumoutput.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-enumstd.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-expbuf.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-audio.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-audioout.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-crop.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-edid.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-fmt.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-frequency.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-input.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-modulator.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-output.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-parm.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-priority.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-selection.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-std.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-log-status.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-overlay.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-qbuf.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-querybuf.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-querycap.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-querystd.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-reqbufs.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-streamon.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml [deleted file]
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml [deleted file]
Documentation/DocBook/media/vbi_525.gif.b64 [deleted file]
Documentation/DocBook/media/vbi_625.gif.b64 [deleted file]
Documentation/DocBook/media/vbi_hsync.gif.b64 [deleted file]
Documentation/DocBook/media_api.tmpl [deleted file]
Documentation/Makefile.sphinx
Documentation/PCI/MSI-HOWTO.txt
Documentation/binfmt_misc.txt
Documentation/block/biodoc.txt
Documentation/cgroup-v1/cgroups.txt
Documentation/cgroup-v1/cpusets.txt
Documentation/cgroup-v1/memcg_test.txt
Documentation/coccinelle.txt
Documentation/device-mapper/dm-flakey.txt
Documentation/devicetree/bindings/input/rotary-encoder.txt
Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
Documentation/devicetree/bindings/misc/ramoops.txt [deleted file]
Documentation/devicetree/bindings/mtd/atmel-quadspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/brcm,brcmnand.txt
Documentation/devicetree/bindings/mtd/cadence-quadspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Documentation/devicetree/bindings/mtd/hisilicon,fmc-spi-nor.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtk-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/sunxi-nand.txt
Documentation/devicetree/bindings/pci/aardvark-pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/brcm,iproc-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
Documentation/devicetree/bindings/pwm/st,stmpe-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/pwm-regulator.txt
Documentation/devicetree/bindings/reserved-memory/ramoops.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/dontdiff
Documentation/filesystems/Locking
Documentation/filesystems/nilfs2.txt
Documentation/filesystems/orangefs.txt
Documentation/filesystems/porting
Documentation/filesystems/tmpfs.txt
Documentation/filesystems/vfs.txt
Documentation/gcc-plugins.txt [new file with mode: 0644]
Documentation/gpu/kms-properties.csv
Documentation/ioctl/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/kernel-per-CPU-kthreads.txt
Documentation/module-signing.txt
Documentation/ramoops.txt
Documentation/rapidio/mport_cdev.txt
Documentation/rapidio/rio_cm.txt [new file with mode: 0644]
Documentation/rapidio/tsi721.txt
Documentation/scheduler/sched-deadline.txt
Documentation/scheduler/sched-design-CFS.txt
Documentation/scheduler/sched-rt-group.txt
Documentation/sysctl/kernel.txt
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/devices/arm-vgic.txt
Documentation/virtual/kvm/devices/vm.txt
Documentation/virtual/kvm/locking.txt
Documentation/vm/numa
Documentation/vm/numa_memory_policy.txt
Documentation/vm/page_migration
Documentation/vm/unevictable-lru.txt
Documentation/x86/x86_64/fake-numa-for-cpusets
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/boot/Makefile
arch/alpha/include/asm/dma-mapping.h
arch/alpha/include/asm/rtc.h [deleted file]
arch/alpha/include/asm/thread_info.h
arch/alpha/kernel/core_marvel.c
arch/alpha/kernel/machvec_impl.h
arch/alpha/kernel/pci-noop.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/rtc.c
arch/arc/mm/dma.c
arch/arc/mm/init.c
arch/arm/Kconfig
arch/arm/common/dmabounce.c
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/kexec.h
arch/arm/include/asm/kvm_asm.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/kvm_hyp.h
arch/arm/include/asm/kvm_mmu.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/uaccess.h
arch/arm/include/asm/virt.h
arch/arm/include/asm/xen/page-coherent.h
arch/arm/kernel/bios32.c
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/setup.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/kvm/Kconfig
arch/arm/kvm/Makefile
arch/arm/kvm/arm.c
arch/arm/kvm/emulate.c
arch/arm/kvm/guest.c
arch/arm/kvm/init.S
arch/arm/kvm/irq.h [new file with mode: 0644]
arch/arm/kvm/mmu.c
arch/arm/kvm/reset.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-integrator/impd1.c
arch/arm/mach-mv78xx0/common.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mm/dma-mapping.c
arch/arm/xen/mm.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/marvell/armada-3720-db.dts
arch/arm64/boot/dts/marvell/armada-37xx.dtsi
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/virt.h
arch/arm64/include/uapi/asm/auxvec.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/head.S
arch/arm64/kernel/pci.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/Kconfig
arch/arm64/kvm/Makefile
arch/arm64/kvm/guest.c
arch/arm64/kvm/hyp-init.S
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/inject_fault.c
arch/arm64/kvm/irq.h [new file with mode: 0644]
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/mmu.c
arch/avr32/mm/dma-coherent.c
arch/blackfin/kernel/dma-mapping.c
arch/blackfin/mm/init.c
arch/c6x/include/asm/dma-mapping.h
arch/c6x/kernel/dma.c
arch/c6x/mm/dma-coherent.c
arch/cris/arch-v10/drivers/axisflashmap.c
arch/cris/arch-v32/drivers/axisflashmap.c
arch/cris/arch-v32/drivers/pci/dma.c
arch/frv/include/asm/mc146818rtc.h [deleted file]
arch/frv/mb93090-mb00/pci-dma-nommu.c
arch/frv/mb93090-mb00/pci-dma.c
arch/h8300/include/asm/mc146818rtc.h [deleted file]
arch/h8300/kernel/dma.c
arch/hexagon/include/asm/dma-mapping.h
arch/hexagon/kernel/dma.c
arch/hexagon/mm/init.c
arch/ia64/Kconfig
arch/ia64/hp/common/sba_iommu.c
arch/ia64/include/asm/machvec.h
arch/ia64/include/asm/mc146818rtc.h [deleted file]
arch/ia64/include/asm/thread_info.h
arch/ia64/include/asm/uaccess.h
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/pci-swiotlb.c
arch/ia64/sn/pci/pci_dma.c
arch/m68k/amiga/config.c
arch/m68k/apollo/config.c
arch/m68k/bvme6000/config.c
arch/m68k/hp300/config.c
arch/m68k/include/asm/flat.h
arch/m68k/include/asm/processor.h
arch/m68k/include/asm/rtc.h [deleted file]
arch/m68k/kernel/dma.c
arch/m68k/kernel/time.c
arch/m68k/mac/config.c
arch/m68k/mac/misc.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/q40/config.c
arch/m68k/sun3/config.c
arch/m68k/sun3/intersil.c
arch/m68k/sun3x/time.c
arch/metag/include/asm/cmpxchg_lnkget.h
arch/metag/include/asm/metag_mem.h
arch/metag/include/asm/metag_regs.h
arch/metag/kernel/cachepart.c
arch/metag/kernel/dma.c
arch/metag/lib/divsi3.S
arch/metag/mm/fault.c
arch/metag/mm/init.c
arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/kernel/dma.c
arch/microblaze/mm/init.c
arch/microblaze/mm/pgtable.c
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/ath79/setup.c
arch/mips/bmips/setup.c
arch/mips/boot/compressed/decompress.c
arch/mips/boot/compressed/head.S
arch/mips/boot/dts/cavium-octeon/dlink_dsr-1000n.dts
arch/mips/boot/dts/cavium-octeon/octeon_3xxx.dts
arch/mips/boot/tools/relocs_64.c
arch/mips/cavium-octeon/dma-octeon.c
arch/mips/cavium-octeon/executive/cvmx-bootmem.c
arch/mips/cavium-octeon/executive/cvmx-helper-board.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/cobalt/setup.c
arch/mips/configs/ath25_defconfig [new file with mode: 0644]
arch/mips/configs/cavium_octeon_defconfig
arch/mips/include/asm/addrspace.h
arch/mips/include/asm/bootinfo.h
arch/mips/include/asm/dsemul.h [new file with mode: 0644]
arch/mips/include/asm/elf.h
arch/mips/include/asm/fpu_emulator.h
arch/mips/include/asm/kvm_host.h
arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
arch/mips/include/asm/mach-cavium-octeon/irq.h
arch/mips/include/asm/mach-cavium-octeon/mangle-port.h
arch/mips/include/asm/mips-cm.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/mmu.h
arch/mips/include/asm/mmu_context.h
arch/mips/include/asm/msa.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pci.h
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/seccomp.h
arch/mips/include/asm/setup.h
arch/mips/include/asm/signal.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/syscall.h
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/uasm.h
arch/mips/include/uapi/asm/auxvec.h
arch/mips/include/uapi/asm/inst.h
arch/mips/jz4740/setup.c
arch/mips/kernel/Makefile
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/branch.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/csrc-r4k.c
arch/mips/kernel/elf.c
arch/mips/kernel/head.S
arch/mips/kernel/mips-cm.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/pm-cps.c
arch/mips/kernel/process.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/segment.c
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/signal_o32.c [new file with mode: 0644]
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/kernel/vdso.c
arch/mips/kvm/Kconfig
arch/mips/kvm/Makefile
arch/mips/kvm/commpage.c
arch/mips/kvm/dyntrans.c
arch/mips/kvm/emulate.c
arch/mips/kvm/entry.c [new file with mode: 0644]
arch/mips/kvm/fpu.S
arch/mips/kvm/interrupt.c
arch/mips/kvm/interrupt.h
arch/mips/kvm/locore.S [deleted file]
arch/mips/kvm/mips.c
arch/mips/kvm/mmu.c [new file with mode: 0644]
arch/mips/kvm/stats.c
arch/mips/kvm/tlb.c
arch/mips/kvm/trace.h
arch/mips/kvm/trap_emul.c
arch/mips/lantiq/irq.c
arch/mips/lantiq/prom.c
arch/mips/loongson64/common/dma-swiotlb.c
arch/mips/loongson64/loongson-3/hpet.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/dsemul.c
arch/mips/mm/c-r4k.c
arch/mips/mm/dma-default.c
arch/mips/mm/init.c
arch/mips/mm/sc-debugfs.c
arch/mips/mm/sc-rm7k.c
arch/mips/mm/tlbex.c
arch/mips/mm/uasm-micromips.c
arch/mips/mm/uasm-mips.c
arch/mips/mm/uasm.c
arch/mips/mti-malta/malta-dtshim.c
arch/mips/mti-malta/malta-memory.c
arch/mips/mti-malta/malta-setup.c
arch/mips/net/bpf_jit.c
arch/mips/netlogic/common/nlm-dma.c
arch/mips/pci/pci.c
arch/mips/pic32/pic32mzda/init.c
arch/mips/pistachio/init.c
arch/mips/ralink/mt7620.c
arch/mips/sgi-ip22/ip22-reset.c
arch/mips/sni/time.c
arch/mips/txx9/generic/pci.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/rtc-regs.h
arch/mn10300/include/asm/rtc.h
arch/mn10300/kernel/rtc.c
arch/mn10300/mm/dma-alloc.c
arch/mn10300/proc-mn103e010/proc-init.c
arch/mn10300/proc-mn2ws0050/proc-init.c
arch/nios2/mm/dma-mapping.c
arch/nios2/mm/init.c
arch/openrisc/kernel/dma.c
arch/openrisc/mm/ioremap.c
arch/parisc/Kconfig
arch/parisc/include/asm/hash.h [new file with mode: 0644]
arch/parisc/include/asm/mc146818rtc.h [deleted file]
arch/parisc/include/asm/rtc.h [deleted file]
arch/parisc/kernel/firmware.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/time.c
arch/parisc/lib/iomap.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/boot/Makefile
arch/powerpc/include/asm/book3s/64/hugetlb-radix.h
arch/powerpc/include/asm/book3s/64/mmu-hash.h
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/tlbflush-hash.h
arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
arch/powerpc/include/asm/book3s/64/tlbflush.h
arch/powerpc/include/asm/cacheflush.h
arch/powerpc/include/asm/cpu_has_feature.h [new file with mode: 0644]
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/cputime.h
arch/powerpc/include/asm/dbell.h
arch/powerpc/include/asm/dcr-native.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/hmi.h [new file with mode: 0644]
arch/powerpc/include/asm/hugetlb.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/jump_label.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mman.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/rtc.h [deleted file]
arch/powerpc/include/asm/switch_to.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/time.h
arch/powerpc/include/asm/tlb.h
arch/powerpc/include/asm/tlbflush.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/include/asm/xor.h
arch/powerpc/include/uapi/asm/elf.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/align.c
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/hmi.c [new file with mode: 0644]
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/idle_book3s.S
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_ras.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/emulate.c
arch/powerpc/kvm/mpic.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/lib/alloc.c
arch/powerpc/lib/feature-fixups.c
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage-radix.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/pgtable-book3s64.c
arch/powerpc/mm/pgtable-radix.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/tlb-radix.c
arch/powerpc/mm/tlb_hash32.c
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/perf/power9-events-list.h
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/pervasive.c
arch/powerpc/platforms/pasemi/iommu.c
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/powernv/npu-dma.c
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/platforms/ps3/device-init.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/ps3/time.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/sysdev/dart_iommu.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/msi_bitmap.c
arch/powerpc/xmon/ppc-dis.c
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/hypfs/hypfs_diag.c
arch/s390/include/asm/cpacf.h
arch/s390/include/asm/diag.h
arch/s390/include/asm/dma-mapping.h
arch/s390/include/asm/gmap.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/sclp.h
arch/s390/include/uapi/asm/kvm.h
arch/s390/include/uapi/asm/sie.h
arch/s390/kernel/diag.c
arch/s390/kvm/Makefile
arch/s390/kvm/diag.c
arch/s390/kvm/gaccess.c
arch/s390/kvm/gaccess.h
arch/s390/kvm/guestdbg.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/s390/kvm/sthyi.c [new file with mode: 0644]
arch/s390/kvm/trace.h
arch/s390/kvm/vsie.c [new file with mode: 0644]
arch/s390/lib/uaccess.c
arch/s390/mm/fault.c
arch/s390/mm/gmap.c
arch/s390/mm/pgalloc.c
arch/s390/mm/pgtable.c
arch/s390/pci/pci_dma.c
arch/score/mm/init.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/board-secureedge5410.c
arch/sh/boards/of-generic.c
arch/sh/boot/dts/Makefile [new file with mode: 0644]
arch/sh/boot/dts/j2_mimas_v2.dts [new file with mode: 0755]
arch/sh/configs/j2_defconfig [new file with mode: 0644]
arch/sh/drivers/heartbeat.c
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/atomic.h
arch/sh/include/asm/barrier.h
arch/sh/include/asm/bitops-cas.h [new file with mode: 0644]
arch/sh/include/asm/bitops.h
arch/sh/include/asm/cmpxchg-cas.h [new file with mode: 0644]
arch/sh/include/asm/cmpxchg-xchg.h
arch/sh/include/asm/cmpxchg.h
arch/sh/include/asm/dma-mapping.h
arch/sh/include/asm/futex-cas.h [new file with mode: 0644]
arch/sh/include/asm/futex-irq.h
arch/sh/include/asm/futex-llsc.h [new file with mode: 0644]
arch/sh/include/asm/futex.h
arch/sh/include/asm/mc146818rtc.h [deleted file]
arch/sh/include/asm/processor.h
arch/sh/include/asm/rtc.h
arch/sh/include/asm/spinlock-cas.h [new file with mode: 0644]
arch/sh/include/asm/spinlock-llsc.h [new file with mode: 0644]
arch/sh/include/asm/spinlock.h
arch/sh/include/asm/thread_info.h
arch/sh/include/uapi/asm/cpu-features.h
arch/sh/include/uapi/asm/sigcontext.h
arch/sh/include/uapi/asm/unistd_32.h
arch/sh/include/uapi/asm/unistd_64.h
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/proc.c
arch/sh/kernel/cpu/sh2/Makefile
arch/sh/kernel/cpu/sh2/entry.S
arch/sh/kernel/cpu/sh2/probe.c
arch/sh/kernel/cpu/sh2/smp-j2.c [new file with mode: 0644]
arch/sh/kernel/dma-nommu.c
arch/sh/kernel/dwarf.c
arch/sh/kernel/head_32.S
arch/sh/kernel/setup.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/time.c
arch/sh/mm/Makefile
arch/sh/mm/asids-debugfs.c
arch/sh/mm/cache-j2.c [new file with mode: 0644]
arch/sh/mm/cache.c
arch/sh/mm/consistent.c
arch/sh/mm/ioremap.c
arch/sparc/Kconfig
arch/sparc/include/asm/io_32.h
arch/sparc/include/asm/pci_64.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/uaccess_32.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/vmlinux.lds.S
arch/tile/include/asm/thread_info.h
arch/tile/kernel/pci-dma.c
arch/tile/kernel/vmlinux.lds.S
arch/um/Kconfig.common
arch/um/Makefile
arch/um/include/asm/irqflags.h
arch/um/kernel/Makefile
arch/um/kernel/initrd.c
arch/um/kernel/um_arch.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/signal.c
arch/unicore32/kernel/pci.c
arch/unicore32/mm/dma-swiotlb.c
arch/x86/Kconfig
arch/x86/boot/Makefile
arch/x86/entry/common.c
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/vdso/Makefile
arch/x86/entry/vdso/vclock_gettime.c
arch/x86/entry/vdso/vdso2c.h
arch/x86/events/core.c
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/elf.h
arch/x86/include/asm/fpu/internal.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mc146818rtc.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/rtc.h [deleted file]
arch/x86/include/asm/svm.h
arch/x86/include/asm/swiotlb.h
arch/x86/include/asm/syscall.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/virtext.h
arch/x86/include/asm/xen/page-coherent.h
arch/x86/kernel/amd_gart_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/fpu/signal.c
arch/x86/kernel/hpet.c
arch/x86/kernel/nmi.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-nommu.c
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/rtc.c
arch/x86/kernel/signal.c
arch/x86/kvm/Kconfig
arch/x86/kvm/i8254.c
arch/x86/kvm/iommu.c
arch/x86/kvm/irq.h
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu.h
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/pmu_intel.c
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/hweight.S
arch/x86/mm/init.c
arch/x86/pci/common.c
arch/x86/pci/sta2x11-fixup.c
arch/x86/pci/vmd.c
arch/x86/platform/efi/early_printk.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/intel-mid/intel_mid_vrtc.c
arch/x86/power/hibernate_64.c
arch/x86/power/hibernate_asm_64.S
arch/x86/purgatory/Makefile
arch/x86/realmode/rm/Makefile
arch/x86/um/vdso/Makefile
arch/x86/xen/enlighten.c
arch/xtensa/kernel/pci-dma.c
block/Kconfig
block/bio-integrity.c
block/bio.c
block/blk-core.c
block/blk-merge.c
block/blk-mq-sysfs.c
block/blk-mq.c
block/blk-throttle.c
block/cfq-iosched.c
block/genhd.c
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_cmos_rtc.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/osl.c
drivers/acpi/pci_mcfg.c [new file with mode: 0644]
drivers/acpi/pci_root.c
drivers/base/firmware_class.c
drivers/base/node.c
drivers/base/power/opp/core.c
drivers/base/power/trace.c
drivers/base/power/wakeup.c
drivers/block/brd.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/pktcdvd.c
drivers/block/rbd.c
drivers/block/umem.c
drivers/block/virtio_blk.c
drivers/block/zram/zram_drv.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/genrtc.c [deleted file]
drivers/clk/clkdev.c
drivers/cpufreq/Kconfig
drivers/cpufreq/intel_pstate.c
drivers/firmware/broadcom/bcm47xx_sprom.c
drivers/fpga/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_blend.c [new file with mode: 0644]
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_internal.h
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/mediatek/mtk_drm_gem.c
drivers/gpu/drm/mediatek/mtk_drm_gem.h
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rcar-du/rcar_du_plane.h
drivers/gpu/drm/rcar-du/rcar_du_vsp.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.h
drivers/gpu/drm/sti/sti_cursor.c
drivers/gpu/drm/sti/sti_gdp.c
drivers/gpu/drm/sti/sti_hqvdp.c
drivers/gpu/drm/sti/sti_mixer.c
drivers/gpu/drm/sti/sti_plane.c
drivers/gpu/drm/sti/sti_plane.h
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/infiniband/Kconfig
drivers/infiniband/core/cma.c
drivers/infiniband/core/device.c
drivers/infiniband/core/iwcm.c
drivers/infiniband/core/iwcm.h
drivers/infiniband/core/iwpm_util.c
drivers/infiniband/core/multicast.c
drivers/infiniband/core/netlink.c
drivers/infiniband/core/rw.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/umem.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/hfi1/Kconfig
drivers/infiniband/hw/hfi1/Makefile
drivers/infiniband/hw/hfi1/affinity.c
drivers/infiniband/hw/hfi1/affinity.h
drivers/infiniband/hw/hfi1/chip.c
drivers/infiniband/hw/hfi1/chip.h
drivers/infiniband/hw/hfi1/chip_registers.h
drivers/infiniband/hw/hfi1/driver.c
drivers/infiniband/hw/hfi1/file_ops.c
drivers/infiniband/hw/hfi1/firmware.c
drivers/infiniband/hw/hfi1/hfi.h
drivers/infiniband/hw/hfi1/init.c
drivers/infiniband/hw/hfi1/mad.c
drivers/infiniband/hw/hfi1/mad.h
drivers/infiniband/hw/hfi1/mmu_rb.c
drivers/infiniband/hw/hfi1/mmu_rb.h
drivers/infiniband/hw/hfi1/pcie.c
drivers/infiniband/hw/hfi1/pio.c
drivers/infiniband/hw/hfi1/platform.c
drivers/infiniband/hw/hfi1/qp.c
drivers/infiniband/hw/hfi1/qp.h
drivers/infiniband/hw/hfi1/qsfp.c
drivers/infiniband/hw/hfi1/qsfp.h
drivers/infiniband/hw/hfi1/rc.c
drivers/infiniband/hw/hfi1/ruc.c
drivers/infiniband/hw/hfi1/sysfs.c
drivers/infiniband/hw/hfi1/trace.h
drivers/infiniband/hw/hfi1/trace_ctxts.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_dbg.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_ibhdrs.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_misc.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_rc.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_rx.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/trace_tx.h [new file with mode: 0644]
drivers/infiniband/hw/hfi1/twsi.c [deleted file]
drivers/infiniband/hw/hfi1/twsi.h [deleted file]
drivers/infiniband/hw/hfi1/uc.c
drivers/infiniband/hw/hfi1/ud.c
drivers/infiniband/hw/hfi1/user_exp_rcv.c
drivers/infiniband/hw/hfi1/user_pages.c
drivers/infiniband/hw/hfi1/user_sdma.c
drivers/infiniband/hw/hfi1/user_sdma.h
drivers/infiniband/hw/hfi1/verbs.c
drivers/infiniband/hw/hfi1/verbs.h
drivers/infiniband/hw/hfi1/verbs_txreq.h
drivers/infiniband/hw/i40iw/i40iw_cm.c
drivers/infiniband/hw/i40iw/i40iw_d.h
drivers/infiniband/hw/i40iw/i40iw_puda.c
drivers/infiniband/hw/i40iw/i40iw_type.h
drivers/infiniband/hw/i40iw/i40iw_uk.c
drivers/infiniband/hw/i40iw/i40iw_user.h
drivers/infiniband/hw/i40iw/i40iw_verbs.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/gsi.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mlx5/srq.c
drivers/infiniband/hw/mlx5/user.h
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_reset.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/qib/qib_qp.c
drivers/infiniband/hw/qib/qib_ud.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/hw/qib/qib_verbs.h
drivers/infiniband/hw/usnic/usnic_ib_main.c
drivers/infiniband/hw/usnic/usnic_ib_sysfs.c
drivers/infiniband/sw/Makefile
drivers/infiniband/sw/rdmavt/Kconfig
drivers/infiniband/sw/rdmavt/cq.c
drivers/infiniband/sw/rdmavt/mr.c
drivers/infiniband/sw/rdmavt/mr.h
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/rdmavt/vt.c
drivers/infiniband/sw/rxe/Kconfig [new file with mode: 0644]
drivers/infiniband/sw/rxe/Makefile [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_av.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_comp.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_cq.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_dma.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_hdr.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_icrc.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_loc.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_mcast.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_mmap.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_mr.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_net.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_net.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_opcode.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_opcode.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_param.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_pool.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_pool.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_qp.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_queue.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_queue.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_recv.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_req.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_resp.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_srq.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_sysfs.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_task.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_task.h [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_verbs.c [new file with mode: 0644]
drivers/infiniband/sw/rxe/rxe_verbs.h [new file with mode: 0644]
drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/infiniband/ulp/srpt/ib_srpt.h
drivers/input/joystick/xpad.c
drivers/input/keyboard/cros_ec_keyb.c
drivers/input/misc/rotary_encoder.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elantech.c
drivers/input/rmi4/rmi_bus.c
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ili210x.c
drivers/input/touchscreen/silead.c [new file with mode: 0644]
drivers/input/touchscreen/sis_i2c.c [new file with mode: 0644]
drivers/iommu/amd_iommu.c
drivers/iommu/dma-iommu.c
drivers/iommu/intel-iommu.c
drivers/irqchip/Kconfig
drivers/irqchip/irq-mips-gic.c
drivers/md/bcache/request.c
drivers/md/bcache/super.c
drivers/md/bcache/writeback.h
drivers/md/dm-cache-target.c
drivers/md/dm-crypt.c
drivers/md/dm-era-target.c
drivers/md/dm-flakey.c
drivers/md/dm-io.c
drivers/md/dm-log-writes.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-region-hash.c
drivers/md/dm-rq.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-thin.c
drivers/md/dm-zero.c
drivers/md/dm.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5-cache.c
drivers/md/raid5.c
drivers/media/dvb-frontends/cxd2841er.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7511.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
drivers/media/platform/sti/bdisp/bdisp-hw.c
drivers/media/platform/vim2m.c
drivers/media/platform/vivid/vivid-cec.c
drivers/media/v4l2-core/videobuf2-dma-contig.c
drivers/media/v4l2-core/videobuf2-dma-sg.c
drivers/media/v4l2-core/videobuf2-vmalloc.c
drivers/memory/Kconfig
drivers/memory/fsl_ifc.c
drivers/memstick/core/ms_block.c
drivers/misc/Makefile
drivers/misc/genwqe/card_base.c
drivers/misc/lkdtm_usercopy.c
drivers/misc/mic/Kconfig
drivers/misc/mic/host/mic_boot.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/m25p80.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pmcmsp-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/jz4780_bch.c
drivers/mtd/nand/jz4780_nand.c
drivers/mtd/nand/mtk_ecc.c [new file with mode: 0644]
drivers/mtd/nand/mtk_ecc.h [new file with mode: 0644]
drivers/mtd/nand/mtk_nand.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/nand/xway_nand.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/Makefile
drivers/mtd/spi-nor/atmel-quadspi.c [new file with mode: 0644]
drivers/mtd/spi-nor/cadence-quadspi.c [new file with mode: 0644]
drivers/mtd/spi-nor/fsl-quadspi.c
drivers/mtd/spi-nor/hisi-sfc.c [new file with mode: 0644]
drivers/mtd/spi-nor/mtk-quadspi.c
drivers/mtd/spi-nor/nxp-spifi.c
drivers/mtd/spi-nor/spi-nor.c
drivers/mtd/ssfdc.c
drivers/mtd/tests/nandbiterrs.c
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/wl.c
drivers/net/caif/Kconfig
drivers/net/caif/caif_spi.c
drivers/net/dsa/b53/b53_mmap.c
drivers/net/dsa/bcm_sf2.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/aurora/nb8800.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/brocade/bna/bnad_debugfs.c
drivers/net/ethernet/cavium/octeon/octeon_mgmt.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/dec/tulip/de4x5.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/fm10k/fm10k_pci.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx5/core/srq.c
drivers/net/ethernet/mellanox/mlx5/core/transobj.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_sriov.c
drivers/net/ethernet/qlogic/qed/qed_vf.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/macsec.c
drivers/net/phy/mdio-xgene.c
drivers/net/phy/micrel.c
drivers/net/wan/fsl_ucc_hdlc.c
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/common-spectral.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/dfs_pattern_detector.c
drivers/net/wireless/ath/regd.c
drivers/ntb/hw/intel/ntb_hw_intel.c
drivers/ntb/ntb_transport.c
drivers/ntb/test/ntb_perf.c
drivers/ntb/test/ntb_pingpong.c
drivers/ntb/test/ntb_tool.c
drivers/nvdimm/btt.c
drivers/nvdimm/pmem.c
drivers/nvme/host/pci.c
drivers/of/platform.c
drivers/parisc/ccio-dma.c
drivers/parisc/sba_iommu.c
drivers/pci/Kconfig
drivers/pci/bus.c
drivers/pci/ecam.c
drivers/pci/ecam.h [deleted file]
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-aardvark.c [new file with mode: 0644]
drivers/pci/host/pci-dra7xx.c
drivers/pci/host/pci-host-common.c
drivers/pci/host/pci-host-generic.c
drivers/pci/host/pci-hyperv.c
drivers/pci/host/pci-keystone.c
drivers/pci/host/pci-layerscape.c
drivers/pci/host/pci-mvebu.c
drivers/pci/host/pci-rcar-gen2.c
drivers/pci/host/pci-tegra.c
drivers/pci/host/pci-thunder-ecam.c
drivers/pci/host/pci-thunder-pem.c
drivers/pci/host/pci-versatile.c
drivers/pci/host/pci-xgene.c
drivers/pci/host/pcie-altera.c
drivers/pci/host/pcie-armada8k.c
drivers/pci/host/pcie-artpec6.c [new file with mode: 0644]
drivers/pci/host/pcie-designware-plat.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-hisi.c
drivers/pci/host/pcie-iproc.c
drivers/pci/host/pcie-rcar.c
drivers/pci/host/pcie-xilinx-nwl.c
drivers/pci/host/pcie-xilinx.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aspm.c
drivers/pci/pcie/pcie-dpc.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/setup-bus.c
drivers/pci/xen-pcifront.c
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/x86/dell-wmi.c
drivers/pnp/pnpbios/core.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-atmel.c
drivers/pwm/pwm-bcm-iproc.c [new file with mode: 0644]
drivers/pwm/pwm-cros-ec.c [new file with mode: 0644]
drivers/pwm/pwm-lpc32xx.c
drivers/pwm/pwm-lpss-pci.c
drivers/pwm/pwm-lpss.c
drivers/pwm/pwm-rockchip.c
drivers/pwm/pwm-stmpe.c [new file with mode: 0644]
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tipwmss.c
drivers/pwm/pwm-tipwmss.h [deleted file]
drivers/pwm/sysfs.c
drivers/rapidio/Kconfig
drivers/rapidio/Makefile
drivers/rapidio/devices/rio_mport_cdev.c
drivers/rapidio/devices/tsi721.c
drivers/rapidio/devices/tsi721.h
drivers/rapidio/devices/tsi721_dma.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio.c
drivers/rapidio/rio.h
drivers/rapidio/rio_cm.c [new file with mode: 0644]
drivers/rapidio/switches/Kconfig
drivers/rapidio/switches/Makefile
drivers/rapidio/switches/idt_gen2.c
drivers/rapidio/switches/idt_gen3.c [new file with mode: 0644]
drivers/rapidio/switches/tsi57x.c
drivers/regulator/pwm-regulator.c
drivers/remoteproc/qcom_q6v5_pil.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/interface.c
drivers/rtc/rtc-abx80x.c
drivers/rtc/rtc-asm9260.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-da9055.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1343.c
drivers/rtc/rtc-ds1685.c
drivers/rtc/rtc-ds2404.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-efi.c
drivers/rtc/rtc-generic.c
drivers/rtc/rtc-hym8563.c
drivers/rtc/rtc-isl12057.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-max6916.c [new file with mode: 0644]
drivers/rtc/rtc-mc146818-lib.c [new file with mode: 0644]
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf85063.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-rc5t583.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-rv8803.c
drivers/rtc/rtc-rx8010.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-tegra.c
drivers/rtc/rtc-v3020.c
drivers/s390/char/sclp_early.c
drivers/s390/char/sclp_ocf.c
drivers/s390/virtio/Makefile
drivers/s390/virtio/kvm_virtio.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/cxlflash/main.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe.h
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/viosrp.h [deleted file]
drivers/scsi/ibmvscsi_tgt/Makefile [new file with mode: 0644]
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c [new file with mode: 0644]
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h [new file with mode: 0644]
drivers/scsi/ibmvscsi_tgt/libsrp.c [new file with mode: 0644]
drivers/scsi/ibmvscsi_tgt/libsrp.h [new file with mode: 0644]
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/ssb/driver_gpio.c
drivers/staging/emxx_udc/Kconfig
drivers/staging/emxx_udc/emxx_udc.c
drivers/staging/lustre/lustre/llite/dcache.c
drivers/staging/lustre/lustre/llite/statahead.c
drivers/staging/media/Kconfig
drivers/staging/media/cec/cec-adap.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_sess.c
drivers/tty/serial/ar933x_uart.c
drivers/usb/host/xhci-pci.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/generic.c
drivers/usb/serial/option.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/ti_usb_3410_5052.h [deleted file]
drivers/vhost/Kconfig
drivers/vhost/Kconfig.vringh [new file with mode: 0644]
drivers/vhost/Makefile
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/vhost/vsock.c [new file with mode: 0644]
drivers/video/fbdev/bfin_adv7393fb.c
drivers/video/fbdev/bfin_adv7393fb.h
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/omap2/omapfb/omapfb.h
drivers/video/logo/logo.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/w1/masters/omap_hdq.c
drivers/w1/slaves/w1_ds2406.c
drivers/w1/slaves/w1_ds2408.c
drivers/w1/slaves/w1_ds2413.c
drivers/w1/slaves/w1_ds2423.c
drivers/w1/slaves/w1_ds2431.c
drivers/w1/slaves/w1_ds2433.c
drivers/w1/slaves/w1_ds2760.c
drivers/w1/slaves/w1_ds2780.c
drivers/w1/slaves/w1_ds2781.c
drivers/w1/slaves/w1_ds28e04.c
drivers/w1/w1_family.h
drivers/xen/swiotlb-xen.c
fs/9p/fid.c
fs/9p/fid.h
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/xattr.c
fs/Kconfig
fs/Kconfig.binfmt
fs/adfs/dir.c
fs/affs/amigaffs.c
fs/affs/namei.c
fs/autofs4/root.c
fs/autofs4/waitq.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_em86.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
fs/btrfs/backref.c
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/dedupe.h [new file with mode: 0644]
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-tree.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/props.c
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/tests/btrfs-tests.h
fs/btrfs/tests/extent-buffer-tests.c
fs/btrfs/tests/free-space-tests.c
fs/btrfs/tests/free-space-tree-tests.c
fs/btrfs/tests/inode-tests.c
fs/btrfs/tests/qgroup-tests.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/cachefiles/namei.c
fs/ceph/addr.c
fs/ceph/cache.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/dir.c
fs/dcache.c
fs/efivarfs/super.c
fs/exec.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fs-writeback.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/inode.c
fs/hfs/catalog.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfs/string.c
fs/hfs/trans.c
fs/hfsplus/catalog.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/unicode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/dentry.c
fs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/isofs/namei.c
fs/jfs/namei.c
fs/logfs/dir.c
fs/mpage.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/proc.c
fs/nfs/unlink.c
fs/nfsd/Kconfig
fs/nfsd/Makefile
fs/nfsd/blocklayout.c
fs/nfsd/blocklayoutxdr.c
fs/nfsd/export.c
fs/nfsd/export.h
fs/nfsd/flexfilelayout.c [new file with mode: 0644]
fs/nfsd/flexfilelayoutxdr.c [new file with mode: 0644]
fs/nfsd/flexfilelayoutxdr.h [new file with mode: 0644]
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfsxdr.c
fs/nfsd/pnfs.h
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr4.h
fs/nilfs2/alloc.c
fs/nilfs2/bmap.c
fs/nilfs2/bmap.h
fs/nilfs2/btnode.c
fs/nilfs2/btree.c
fs/nilfs2/btree.h
fs/nilfs2/cpfile.c
fs/nilfs2/cpfile.h
fs/nilfs2/dat.c
fs/nilfs2/dat.h
fs/nilfs2/dir.c
fs/nilfs2/direct.c
fs/nilfs2/direct.h
fs/nilfs2/gcinode.c
fs/nilfs2/ifile.c
fs/nilfs2/ifile.h
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/mdt.c
fs/nilfs2/namei.c
fs/nilfs2/nilfs.h
fs/nilfs2/page.c
fs/nilfs2/recovery.c
fs/nilfs2/segbuf.c
fs/nilfs2/segment.c
fs/nilfs2/segment.h
fs/nilfs2/sufile.c
fs/nilfs2/sufile.h
fs/nilfs2/super.c
fs/nilfs2/sysfs.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlm/dlmthread.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/dlmfs/userdlm.c
fs/ocfs2/dlmfs/userdlm.h
fs/ocfs2/stack_user.c
fs/ocfs2/suballoc.c
fs/open.c
fs/orangefs/dcache.c
fs/orangefs/inode.c
fs/orangefs/namei.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/orangefs-mod.c
fs/orangefs/orangefs-sysfs.c
fs/orangefs/orangefs-utils.c
fs/orangefs/protocol.h
fs/pipe.c
fs/proc/Makefile
fs/proc/base.c
fs/proc/proc_sysctl.c
fs/proc/stat.c
fs/pstore/ram.c
fs/reiserfs/ibalance.c
fs/ubifs/gc.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/utimes.c
fs/xfs/Makefile
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_alloc_btree.c
fs/xfs/libxfs/xfs_attr.c
fs/xfs/libxfs/xfs_attr_leaf.c
fs/xfs/libxfs/xfs_attr_remote.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap.h
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_da_btree.c
fs/xfs/libxfs/xfs_da_btree.h
fs/xfs/libxfs/xfs_da_format.h
fs/xfs/libxfs/xfs_defer.c [new file with mode: 0644]
fs/xfs/libxfs/xfs_defer.h [new file with mode: 0644]
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_fs.h
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_ialloc.h
fs/xfs/libxfs/xfs_ialloc_btree.c
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_rmap.c [new file with mode: 0644]
fs/xfs/libxfs/xfs_rmap.h [new file with mode: 0644]
fs/xfs/libxfs/xfs_rmap_btree.c [new file with mode: 0644]
fs/xfs/libxfs/xfs_rmap_btree.h [new file with mode: 0644]
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_shared.h
fs/xfs/libxfs/xfs_trans_resv.c
fs/xfs/libxfs/xfs_trans_resv.h
fs/xfs/libxfs/xfs_types.h
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_bmap_util.h
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_error.h
fs/xfs/xfs_export.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_extfree_item.h
fs/xfs/xfs_filestream.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_ondisk.h
fs/xfs/xfs_pnfs.h
fs/xfs/xfs_rmap_item.c [new file with mode: 0644]
fs/xfs/xfs_rmap_item.h [new file with mode: 0644]
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_stats.c
fs/xfs/xfs_stats.h
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_trace.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_extfree.c
fs/xfs/xfs_trans_rmap.c [new file with mode: 0644]
include/acpi/acpi_io.h
include/asm-generic/rtc.h [deleted file]
include/asm-generic/vmlinux.lds.h
include/drm/drm_crtc.h
include/drm/drm_dp_helper.h
include/drm/ttm/ttm_bo_driver.h
include/kvm/arm_vgic.h
include/kvm/vgic/vgic.h [deleted file]
include/linux/backing-dev-defs.h
include/linux/backing-dev.h
include/linux/binfmts.h
include/linux/bio.h
include/linux/bitmap.h
include/linux/blk-cgroup.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/capability.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/decode.h
include/linux/ceph/libceph.h
include/linux/ceph/mon_client.h
include/linux/ceph/msgpool.h
include/linux/ceph/osd_client.h
include/linux/ceph/osdmap.h
include/linux/ceph/string_table.h [new file with mode: 0644]
include/linux/context_tracking.h
include/linux/cpumask.h
include/linux/dcache.h
include/linux/dma-attrs.h [deleted file]
include/linux/dma-iommu.h
include/linux/dma-mapping.h
include/linux/ds1286.h [deleted file]
include/linux/ds17287rtc.h [deleted file]
include/linux/dynamic_debug.h
include/linux/export.h
include/linux/extable.h [new file with mode: 0644]
include/linux/fence.h
include/linux/firmware.h
include/linux/fs.h
include/linux/i8042.h
include/linux/init.h
include/linux/ipc_namespace.h
include/linux/irqchip/arm-gic-v3.h
include/linux/jump_label.h
include/linux/kasan.h
include/linux/kconfig.h
include/linux/kernel.h
include/linux/kexec.h
include/linux/kvm_host.h
include/linux/lsm_hooks.h
include/linux/m48t86.h [deleted file]
include/linux/mc146818rtc.h
include/linux/mfd/cros_ec.h
include/linux/mfd/cros_ec_commands.h
include/linux/mlx4/device.h
include/linux/mlx5/cq.h
include/linux/mlx5/driver.h
include/linux/mlx5/qp.h
include/linux/mlx5/srq.h
include/linux/mman.h
include/linux/mmzone.h
include/linux/module.h
include/linux/mtd/nand.h
include/linux/mtd/spi-nor.h
include/linux/nfs4.h
include/linux/nfs_xdr.h
include/linux/nilfs2_fs.h [deleted file]
include/linux/page_ref.h
include/linux/pagemap.h
include/linux/pci-acpi.h
include/linux/pci-ecam.h [new file with mode: 0644]
include/linux/pci.h
include/linux/platform_data/rtc-ds2404.h [new file with mode: 0644]
include/linux/platform_data/rtc-m48t86.h [new file with mode: 0644]
include/linux/platform_data/rtc-v3020.h [new file with mode: 0644]
include/linux/printk.h
include/linux/pwm.h
include/linux/radix-tree.h
include/linux/ratelimit.h
include/linux/rio.h
include/linux/rio_ids.h
include/linux/rio_regs.h
include/linux/rtc-ds2404.h [deleted file]
include/linux/rtc-v3020.h [deleted file]
include/linux/rtc/ds1286.h [new file with mode: 0644]
include/linux/sched.h
include/linux/security.h
include/linux/serio.h
include/linux/slab.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/swiotlb.h
include/linux/sysctl.h
include/linux/thread_info.h
include/linux/uaccess.h
include/linux/virtio_config.h
include/linux/virtio_vsock.h [new file with mode: 0644]
include/linux/ww_mutex.h
include/media/videobuf2-core.h
include/media/videobuf2-dma-contig.h
include/net/af_vsock.h
include/net/net_namespace.h
include/net/sctp/constants.h
include/rdma/ib_sa.h
include/rdma/ib_verbs.h
include/rdma/opa_port_info.h
include/rdma/rdma_cm.h
include/rdma/rdma_vt.h
include/rdma/rdmavt_mr.h
include/rdma/rdmavt_qp.h
include/scsi/viosrp.h [new file with mode: 0644]
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/bcache.h
include/trace/events/block.h
include/trace/events/btrfs.h
include/trace/events/kvm.h
include/trace/events/sunrpc.h
include/trace/events/timer.h
include/trace/events/vsock_virtio_transport_common.h [new file with mode: 0644]
include/uapi/linux/Kbuild
include/uapi/linux/btrfs.h
include/uapi/linux/capability.h
include/uapi/linux/elf.h
include/uapi/linux/kvm.h
include/uapi/linux/nilfs2_api.h [new file with mode: 0644]
include/uapi/linux/nilfs2_ondisk.h [new file with mode: 0644]
include/uapi/linux/rio_cm_cdev.h [new file with mode: 0644]
include/uapi/linux/sysctl.h
include/uapi/linux/vhost.h
include/uapi/linux/virtio_config.h
include/uapi/linux/virtio_ids.h
include/uapi/linux/virtio_vsock.h [new file with mode: 0644]
include/uapi/rdma/Kbuild
include/uapi/rdma/hfi/hfi1_user.h
include/uapi/rdma/ib_user_verbs.h
include/uapi/rdma/rdma_user_cm.h
include/uapi/rdma/rdma_user_rxe.h [new file with mode: 0644]
include/xen/swiotlb-xen.h
init/Kconfig
init/main.c
ipc/msg.c
ipc/msgutil.c
ipc/namespace.c
ipc/sem.c
kernel/configs/android-base.config [new file with mode: 0644]
kernel/configs/android-recommended.config [new file with mode: 0644]
kernel/events/core.c
kernel/exit.c
kernel/jump_label.c
kernel/kexec.c
kernel/kexec_core.c
kernel/ksysfs.c
kernel/livepatch/core.c
kernel/module.c
kernel/panic.c
kernel/printk/printk.c
kernel/ptrace.c
kernel/relay.c
kernel/seccomp.c
kernel/sysctl.c
kernel/task_work.c
kernel/trace/Makefile
kernel/trace/blktrace.c
kernel/trace/trace_events_hist.c
lib/Kconfig.debug
lib/crc32.c
lib/dma-noop.c
lib/dynamic_debug.c
lib/iommu-helper.c
lib/radix-tree.c
lib/ratelimit.c
lib/strncpy_from_user.c
lib/strnlen_user.c
lib/swiotlb.c
lib/ubsan.c
mm/Kconfig
mm/Makefile
mm/backing-dev.c
mm/filemap.c
mm/gup.c
mm/hugetlb.c
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/quarantine.c
mm/kasan/report.c
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/mmap.c
mm/page_alloc.c
mm/page_io.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slub.c
mm/sparse-vmemmap.c
mm/sparse.c
mm/usercopy.c [new file with mode: 0644]
mm/vmscan.c
net/9p/trans_virtio.c
net/ceph/Makefile
net/ceph/ceph_common.c
net/ceph/ceph_fs.c
net/ceph/debugfs.c
net/ceph/mon_client.c
net/ceph/msgpool.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/ceph/string_table.c [new file with mode: 0644]
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/sctp/output.c
net/sctp/socket.c
net/sctp/ulpqueue.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/tipc/monitor.c
net/vmw_vsock/Kconfig
net/vmw_vsock/Makefile
net/vmw_vsock/af_vsock.c
net/vmw_vsock/virtio_transport.c [new file with mode: 0644]
net/vmw_vsock/virtio_transport_common.c [new file with mode: 0644]
net/vmw_vsock/vmci_transport.c
net/wireless/chan.c
samples/kprobes/jprobe_example.c
samples/kprobes/kprobe_example.c
samples/kprobes/kretprobe_example.c
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.clean
scripts/Makefile.gcc-plugins [new file with mode: 0644]
scripts/Makefile.host
scripts/Makefile.lib
scripts/basic/bin2c.c
scripts/checkpatch.pl
scripts/coccicheck
scripts/coccinelle/free/devm_free.cocci
scripts/coccinelle/free/ifnullfree.cocci
scripts/coccinelle/free/kfree.cocci
scripts/coccinelle/free/kfreeaddr.cocci
scripts/coccinelle/iterators/device_node_continue.cocci
scripts/coccinelle/misc/noderef.cocci
scripts/gcc-plugin.sh [new file with mode: 0755]
scripts/gcc-plugins/Makefile [new file with mode: 0644]
scripts/gcc-plugins/cyc_complexity_plugin.c [new file with mode: 0644]
scripts/gcc-plugins/gcc-common.h [new file with mode: 0644]
scripts/gcc-plugins/gcc-generate-gimple-pass.h [new file with mode: 0644]
scripts/gcc-plugins/gcc-generate-ipa-pass.h [new file with mode: 0644]
scripts/gcc-plugins/gcc-generate-rtl-pass.h [new file with mode: 0644]
scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h [new file with mode: 0644]
scripts/gcc-plugins/sancov_plugin.c [new file with mode: 0644]
scripts/get_maintainer.pl
scripts/link-vmlinux.sh
scripts/package/builddeb
scripts/recordmcount.c
scripts/setlocalversion
security/Kconfig
security/security.c
security/selinux/hooks.c
sound/arm/Kconfig
sound/hda/array.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
tools/include/linux/bitmap.h
tools/lib/bitmap.c
tools/lib/traceevent/.gitignore
tools/perf/Documentation/perf-record.txt
tools/perf/Makefile.config [new file with mode: 0644]
tools/perf/Makefile.perf
tools/perf/builtin-record.c
tools/perf/builtin-top.c
tools/perf/config/Makefile [deleted file]
tools/perf/perf.h
tools/perf/scripts/perl/Perf-Trace-Util/Build
tools/perf/tests/Build
tools/perf/tests/bitmap.c [new file with mode: 0644]
tools/perf/tests/bpf-script-example.c
tools/perf/tests/builtin-test.c
tools/perf/tests/code-reading.c
tools/perf/tests/tests.h
tools/perf/ui/browsers/annotate.c
tools/perf/ui/gtk/annotate.c
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/target.c
tools/testing/radix-tree/linux/gfp.h
tools/testing/selftests/ntb/ntb_test.sh [new file with mode: 0755]
tools/testing/selftests/timers/rtctest.c
virt/kvm/Kconfig
virt/kvm/arm/hyp/vgic-v2-sr.c
virt/kvm/arm/vgic-v2-emul.c [deleted file]
virt/kvm/arm/vgic-v2.c [deleted file]
virt/kvm/arm/vgic-v3-emul.c [deleted file]
virt/kvm/arm/vgic-v3.c [deleted file]
virt/kvm/arm/vgic.c [deleted file]
virt/kvm/arm/vgic.h [deleted file]
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-irqfd.c
virt/kvm/arm/vgic/vgic-its.c [new file with mode: 0644]
virt/kvm/arm/vgic/vgic-kvm-device.c
virt/kvm/arm/vgic/vgic-mmio-v2.c
virt/kvm/arm/vgic/vgic-mmio-v3.c
virt/kvm/arm/vgic/vgic-mmio.c
virt/kvm/arm/vgic/vgic-mmio.h
virt/kvm/arm/vgic/vgic-v2.c
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.c
virt/kvm/arm/vgic/vgic.h
virt/kvm/irqchip.c
virt/kvm/kvm_main.c

diff --git a/.cocciconfig b/.cocciconfig
new file mode 100644 (file)
index 0000000..43967c6
--- /dev/null
@@ -0,0 +1,3 @@
+[spatch]
+       options = --timeout 200
+       options = --use-gitgrep
index 0c320bf..c2ed4ec 100644 (file)
@@ -37,6 +37,7 @@ modules.builtin
 Module.symvers
 *.dwo
 *.su
+*.c.[012]*.*
 
 #
 # Top-level generic files
@@ -66,6 +67,7 @@ Module.symvers
 #
 !.gitignore
 !.mailmap
+!.cocciconfig
 
 #
 # Generated include files
index d2acafb..2a91c14 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -92,9 +92,17 @@ Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski.k@gmail.com>
 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Linas Vepstas <linas@austin.ibm.com>
+Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
+Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
 Mark Brown <broonie@sirena.org.uk>
 Matthieu CASTET <castet.matthieu@free.fr>
-Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com> <mchehab@infradead.org> <mchehab@redhat.com> <m.chehab@samsung.com> <mchehab@osg.samsung.com> <mchehab@s-opensource.com>
+Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@brturbo.com.br>
+Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com>
+Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@infradead.org>
+Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@redhat.com>
+Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com>
+Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@osg.samsung.com>
+Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com>
 Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com>
 Matt Ranostay <mranostay@gmail.com> <matt.ranostay@intel.com>
 Mayuresh Janorkar <mayur@ti.com>
@@ -130,7 +138,10 @@ Santosh Shilimkar <santosh.shilimkar@oracle.org>
 Sascha Hauer <s.hauer@pengutronix.de>
 S.Çağlar Onur <caglar@pardus.org.tr>
 Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
-Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com> <shuah.khan@hp.com> <shuahkh@osg.samsung.com> <shuah.kh@samsung.com>
+Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com>
+Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
+Shuah Khan <shuah@kernel.org> <shuahkh@osg.samsung.com>
+Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
 Simon Kelley <simon@thekelleys.org.uk>
 Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
 Stephen Hemminger <shemminger@osdl.org>
index c479d77..c20e613 100644 (file)
@@ -77,3 +77,12 @@ Description:
                Enable/disable the PWM signal.
                0 is disabled
                1 is enabled
+
+What:          /sys/class/pwm/pwmchipN/pwmX/capture
+Date:          June 2016
+KernelVersion: 4.8
+Contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Capture information about a PWM signal. The output format is a
+               pair unsigned integers (period and duty cycle), separated by a
+               single space.
index 45ef3f2..1d26eeb 100644 (file)
@@ -369,35 +369,32 @@ See also dma_map_single().
 dma_addr_t
 dma_map_single_attrs(struct device *dev, void *cpu_addr, size_t size,
                     enum dma_data_direction dir,
-                    struct dma_attrs *attrs)
+                    unsigned long attrs)
 
 void
 dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
                       size_t size, enum dma_data_direction dir,
-                      struct dma_attrs *attrs)
+                      unsigned long attrs)
 
 int
 dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
                 int nents, enum dma_data_direction dir,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 
 void
 dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
                   int nents, enum dma_data_direction dir,
-                  struct dma_attrs *attrs)
+                  unsigned long attrs)
 
 The four functions above are just like the counterpart functions
 without the _attrs suffixes, except that they pass an optional
-struct dma_attrs*.
-
-struct dma_attrs encapsulates a set of "DMA attributes". For the
-definition of struct dma_attrs see linux/dma-attrs.h.
+dma_attrs.
 
 The interpretation of DMA attributes is architecture-specific, and
 each attribute should be documented in Documentation/DMA-attributes.txt.
 
-If struct dma_attrs* is NULL, the semantics of each of these
-functions is identical to those of the corresponding function
+If dma_attrs are 0, the semantics of each of these functions
+is identical to those of the corresponding function
 without the _attrs suffix. As a result dma_map_single_attrs()
 can generally replace dma_map_single(), etc.
 
@@ -405,15 +402,15 @@ As an example of the use of the *_attrs functions, here's how
 you could pass an attribute DMA_ATTR_FOO when mapping memory
 for DMA:
 
-#include <linux/dma-attrs.h>
-/* DMA_ATTR_FOO should be defined in linux/dma-attrs.h and
+#include <linux/dma-mapping.h>
+/* DMA_ATTR_FOO should be defined in linux/dma-mapping.h and
  * documented in Documentation/DMA-attributes.txt */
 ...
 
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_FOO, &attrs);
+       unsigned long attr;
+       attr |= DMA_ATTR_FOO;
        ....
-       n = dma_map_sg_attrs(dev, sg, nents, DMA_TO_DEVICE, &attr);
+       n = dma_map_sg_attrs(dev, sg, nents, DMA_TO_DEVICE, attr);
        ....
 
 Architectures that care about DMA_ATTR_FOO would check for its
@@ -422,12 +419,10 @@ routines, e.g.:
 
 void whizco_dma_map_sg_attrs(struct device *dev, dma_addr_t dma_addr,
                             size_t size, enum dma_data_direction dir,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        ....
-       int foo =  dma_get_attr(DMA_ATTR_FOO, attrs);
-       ....
-       if (foo)
+       if (attrs & DMA_ATTR_FOO)
                /* twizzle the frobnozzle */
        ....
 
index e8cf9cf..2d455a5 100644 (file)
@@ -2,7 +2,7 @@
                        ==============
 
 This document describes the semantics of the DMA attributes that are
-defined in linux/dma-attrs.h.
+defined in linux/dma-mapping.h.
 
 DMA_ATTR_WRITE_BARRIER
 ----------------------
index 8e6dd4b..64460a8 100644 (file)
@@ -6,8 +6,6 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-ifeq ($(IGNORE_DOCBOOKS),)
-
 DOCBOOKS := z8530book.xml device-drivers.xml \
            kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
            writing_usb_driver.xml networking.xml \
@@ -16,10 +14,16 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml media_api.xml w1.xml \
+           tracepoint.xml w1.xml \
            writing_musb_glue_layer.xml crypto-API.xml iio.xml
 
-include Documentation/DocBook/media/Makefile
+ifeq ($(DOCBOOKS),)
+
+# Skip DocBook build if the user explicitly requested no DOCBOOKS.
+.DEFAULT:
+       @echo "  SKIP    DocBook $@ target (DOCBOOKS=\"\" specified)."
+
+else
 
 ###
 # The build process is as follows (targets):
@@ -49,7 +53,6 @@ pdfdocs: $(PDF)
 HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
 htmldocs: $(HTML)
        $(call cmd,build_main_index)
-       $(call install_media_images)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
@@ -217,19 +220,7 @@ silent_gen_xml = :
               -e "s/>/\\&gt;/g";     \
           echo "</programlisting>")  > $@
 
-else
-
-# Needed, due to cleanmediadocs
-include Documentation/DocBook/media/Makefile
-
-htmldocs:
-pdfdocs:
-psdocs:
-xmldocs:
-installmandocs:
-
-endif # IGNORE_DOCBOOKS
-
+endif # DOCBOOKS=""
 
 ###
 # Help targets as used by the top-level makefile
@@ -246,7 +237,7 @@ dochelp:
        @echo  '  make DOCBOOKS="s1.xml s2.xml" [target] Generate only docs s1.xml s2.xml'
        @echo  '  valid values for DOCBOOKS are: $(DOCBOOKS)'
        @echo
-       @echo  "  make IGNORE_DOCBOOKS=1 [target] Don't generate docs from Docbook"
+       @echo  "  make DOCBOOKS=\"\" [target] Don't generate docs from Docbook"
        @echo  '     This is useful to generate only the ReST docs (Sphinx)'
 
 
@@ -269,7 +260,7 @@ clean-files := $(DOCBOOKS) \
 
 clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
 
-cleandocs: cleanmediadocs
+cleandocs:
        $(Q)rm -f $(call objectify, $(clean-files))
        $(Q)rm -rf $(call objectify, $(clean-dirs))
 
diff --git a/Documentation/DocBook/media/.gitignore b/Documentation/DocBook/media/.gitignore
deleted file mode 100644 (file)
index e461c58..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!*.svg
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
deleted file mode 100644 (file)
index fdc1386..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-###
-# Media build rules - Auto-generates media contents/indexes and *.h xml's
-#
-
-SHELL=/bin/bash
-
-MEDIA_OBJ_DIR=$(objtree)/Documentation/DocBook/
-MEDIA_SRC_DIR=$(srctree)/Documentation/DocBook/media
-
-MEDIA_TEMP =  media-entities.tmpl \
-             media-indices.tmpl \
-             videodev2.h.xml \
-             v4l2.xml \
-             audio.h.xml \
-             ca.h.xml \
-             dmx.h.xml \
-             frontend.h.xml \
-             net.h.xml \
-             video.h.xml \
-
-IMGFILES := $(patsubst %.b64,%, $(notdir $(shell ls $(MEDIA_SRC_DIR)/*.b64)))
-OBJIMGFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(IMGFILES))
-GENFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(MEDIA_TEMP))
-
-PHONY += cleanmediadocs
-
-cleanmediadocs:
-       -@rm -f `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null
-
-$(obj)/media_api.xml: $(GENFILES) FORCE
-
-#$(MEDIA_OBJ_DIR)/media_api.html: $(MEDIA_OBJ_DIR)/media_api.xml
-#$(MEDIA_OBJ_DIR)/media_api.pdf: $(MEDIA_OBJ_DIR)/media_api.xml
-#$(MEDIA_OBJ_DIR)/media_api.ps: $(MEDIA_OBJ_DIR)/media_api.xml
-
-V4L_SGMLS = \
-       $(shell ls $(MEDIA_SRC_DIR)/v4l/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)') \
-       capture.c.xml \
-       keytable.c.xml \
-       v4l2grab.c.xml
-
-DVB_SGMLS = \
-       $(shell ls $(MEDIA_SRC_DIR)/dvb/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)')
-
-MEDIA_SGMLS =  $(addprefix ./,$(V4L_SGMLS)) $(addprefix ./,$(DVB_SGMLS)) $(addprefix ./,$(MEDIA_TEMP))
-
-FUNCS = \
-       close \
-       ioctl \
-       mmap \
-       munmap \
-       open \
-       poll \
-       read \
-       select \
-       write \
-
-IOCTLS = \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/videodev2.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/audio.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/ca.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/dmx.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/frontend.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/cec.h) \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
-
-DEFINES = \
-       $(shell perl -ne 'print "$$1 " if /\#define\s+(DTV_[^\s]+)\s+/' $(srctree)/include/uapi/linux/dvb/frontend.h) \
-
-TYPES = \
-       $(shell perl -ne 'print "$$1 " if /^typedef\s+.*\s+(\S+)\;/' $(srctree)/include/uapi/linux/videodev2.h) \
-       $(shell perl -ne 'print "$$1 " if /^typedef\s+.*\s+(\S+)\;/' $(srctree)/include/uapi/linux/dvb/frontend.h)
-
-ENUMS = \
-       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' \
-               $(srctree)/include/uapi/linux/videodev2.h \
-               $(srctree)/include/uapi/linux/dvb/audio.h \
-               $(srctree)/include/uapi/linux/dvb/ca.h \
-               $(srctree)/include/uapi/linux/dvb/dmx.h \
-               $(srctree)/include/uapi/linux/dvb/frontend.h \
-               $(srctree)/include/uapi/linux/dvb/net.h \
-               $(srctree)/include/uapi/linux/dvb/video.h \
-               $(srctree)/include/uapi/linux/media.h \
-               $(srctree)/include/uapi/linux/v4l2-mediabus.h \
-               $(srctree)/include/uapi/linux/v4l2-subdev.h)
-
-ENUM_DEFS = \
-       $(shell perl -e 'open IN,"cat @ARGV| cpp -fpreprocessed |"; while (<IN>) { if ($$enum) {print "$$1\n" if (/\s*([A-Z]\S+)\b/); } $$enum = 0 if ($$enum && /^\}/); $$enum = 1 if(/^\s*enum\s/); }; close IN;' \
-               $(srctree)/include/uapi/linux/dvb/dmx.h \
-               $(srctree)/include/uapi/linux/dvb/frontend.h)
-
-STRUCTS = \
-       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/videodev2.h) \
-       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s\{]+)\s*/)' $(srctree)/include/uapi/linux/dvb/audio.h) \
-       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/ca.h) \
-       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/dmx.h) \
-       $(shell perl -ne 'print "$$1 " if (!/dtv\_cmds\_h/ && /^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/frontend.h) \
-       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \
-       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \
-       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \
-       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/cec.h) \
-       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
-       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h)
-
-ERRORS = \
-       E2BIG \
-       EACCES \
-       EAGAIN \
-       EBADF \
-       EBADFD \
-       EBADR \
-       EBADRQC \
-       EBUSY \
-       ECHILD \
-       ECONNRESET \
-       EDEADLK \
-       EDOM \
-       EEXIST \
-       EFAULT \
-       EFBIG \
-       EILSEQ \
-       EINIT \
-       EINPROGRESS \
-       EINTR \
-       EINVAL \
-       EIO \
-       EMFILE \
-       ENFILE \
-       ENOBUFS \
-       ENODATA \
-       ENODEV \
-       ENOENT \
-       ENOIOCTLCMD \
-       ENOMEM \
-       ENOSPC \
-       ENOSR \
-       ENOSYS \
-       ENOTSUP \
-       ENOTSUPP \
-       ENOTTY \
-       ENXIO \
-       EOPNOTSUPP \
-       EOVERFLOW \
-       EPERM \
-       EPIPE \
-       EPROTO \
-       ERANGE \
-       EREMOTE \
-       EREMOTEIO \
-       ERESTART \
-       ERESTARTSYS \
-       ESHUTDOWN \
-       ESPIPE \
-       ETIME \
-       ETIMEDOUT \
-       EUSERS \
-       EWOULDBLOCK \
-       EXDEV \
-
-ESCAPE = \
-       -e "s/&/\\&amp;/g" \
-       -e "s/</\\&lt;/g" \
-       -e "s/>/\\&gt;/g"
-
-FILENAME = \
-       -e s,"^[^\/]*/",, \
-       -e s/"\\.xml"// \
-       -e s/"\\.tmpl"// \
-       -e s/\\\./-/g \
-       -e s/"^func-"// \
-       -e s/"^pixfmt-"// \
-       -e s/"^vidioc-"//
-
-# Generate references to these structs in videodev2.h.xml.
-DOCUMENTED = \
-       -e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1<link linkend=\"\2\">v4l2_mpeg_cx2341x_video_\2<\/link>/g" \
-       -e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1<link linkend=\"\3\">\3<\/link>/g" \
-       -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\)\(\s\+v4l2_fourcc\)/<link linkend=\"\1\">\1<\/link>\2/g" \
-       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
-       -e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
-
-DVB_DOCUMENTED = \
-       -e "s,\(struct\s\+\)\([a-z0-9_]\+\)\(\s\+{\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-       -e "s,\(}\s\+\)\([a-z0-9_]\+_t\+\),\1\<link linkend=\"\2\">\2\<\/link\>,g" \
-       -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+[0-9]\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-       -e "s,<link\s\+linkend=\".*\">\(DTV_IOCTL_MAX_MSGS\|dtv_cmds_h\|__.*_old\)<\/link>,\1,g" \
-       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
-       -e "s,\(audio-mixer\|audio-karaoke\|audio-status\|ca-slot-info\|ca-descr-info\|ca-caps\|ca-msg\|ca-descr\|ca-pid\|dmx-filter\|dmx-caps\|video-system\|video-highlight\|video-spu\|video-spu-palette\|video-navi-pack\)-t,\1,g" \
-       -e "s,DTV-ISDBT-LAYER[A-C],DTV-ISDBT-LAYER,g" \
-       -e "s,\(define\s\+\)\([A-Z0-9_]\+\)\(\s\+_IO\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-       -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
-       -e "s,<link\s\+linkend=\".*\">\(__.*_OLD\)<\/link>,\1,g" \
-       -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \
-       -e "s,<link\s\+linkend=\".*\">\(DTV_ISDBS_TS_ID_LEGACY\|DTV_MAX_COMMAND\|DTV_IOCTL_MAX_MSGS\)<\/link>,\1,g" \
-
-#
-# Media targets and dependencies
-#
-
-install_media_images = \
-       $(Q)if [ "x$(findstring media_api.xml,$(DOCBOOKS))" != "x" ]; then \
-               mkdir -p $(MEDIA_OBJ_DIR)/media_api; \
-               cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api; \
-       fi
-
-$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
-       $(Q)base64 -d $< >$@
-
-$(MEDIA_OBJ_DIR)/v4l2.xml: $(OBJIMGFILES)
-       @$($(quiet)gen_xml)
-       @(ln -sf `cd $(MEDIA_SRC_DIR) && /bin/pwd`/v4l/*xml $(MEDIA_OBJ_DIR)/)
-       @(ln -sf `cd $(MEDIA_SRC_DIR) && /bin/pwd`/dvb/*xml $(MEDIA_OBJ_DIR)/)
-
-$(MEDIA_OBJ_DIR)/videodev2.h.xml: $(srctree)/include/uapi/linux/videodev2.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DOCUMENTED) |         \
-         sed 's/i\.e\./&ie;/') >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/audio.h.xml: $(srctree)/include/uapi/linux/dvb/audio.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/') >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/ca.h.xml: $(srctree)/include/uapi/linux/dvb/ca.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/') >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/dmx.h.xml: $(srctree)/include/uapi/linux/dvb/dmx.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       for ident in $(ENUM_DEFS) ; do          \
-         entity=`echo $$ident | tr _ -` ;      \
-         r="$$r s/([^\w\-])$$ident([^\w\-])/\1\&$$entity\;\2/g;";\
-       done;                                   \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/' |                \
-         perl -ne "$$r print $$_;") >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/frontend.h.xml: $(srctree)/include/uapi/linux/dvb/frontend.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       for ident in $(ENUM_DEFS) ; do          \
-         entity=`echo $$ident | tr _ -` ;      \
-         r="$$r s/([^\w\-])$$ident([^\w\-])/\1\&$$entity\;\2/g;";\
-       done;                                   \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/' |                \
-         perl -ne "$$r print $$_;") >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/net.h.xml: $(srctree)/include/uapi/linux/dvb/net.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/') >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/video.h.xml: $(srctree)/include/uapi/linux/dvb/video.h $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                      \
-       echo "<programlisting>") > $@
-       @(                                      \
-       expand --tabs=8 < $< |                  \
-         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
-         sed 's/i\.e\./&ie;/') >> $@
-       @(                                      \
-       echo "</programlisting>") >> $@
-
-$(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                                              \
-       echo "<!-- Generated file! Do not edit. -->") >$@
-       @(                                                              \
-       echo -e "\n<!-- Functions -->") >>$@
-       @(                                                              \
-       for ident in $(FUNCS) ; do                                      \
-         entity=`echo $$ident | tr _ -` ;                              \
-         echo "<!ENTITY func-$$entity \"<link"                         \
-           "linkend='func-$$entity'><function>$$ident()</function></link>\">" \
-         >>$@ ;                                                        \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Ioctls -->") >>$@
-       @(                                                              \
-       for ident in `echo $(IOCTLS) | sed -e "s,VIDIOC_RESERVED,,"`; do\
-         entity=`echo $$ident | tr _ -` ;                              \
-         id=`grep -e "<refname>$$ident" -e "<section id=\"$$ident\"" $$(find $(MEDIA_SRC_DIR) -name *.xml -type f)| sed -r s,"^.*/(.*).xml.*","\1",` ; \
-         if [ "$$id" != "" ]; then echo "<!ENTITY $$entity \"<link"    \
-           "linkend='$$id'><constant>$$ident</constant></link>\">"     \
-         >>$@ ; else                                                   \
-               echo "Warning: undocumented ioctl: $$ident. Please document it at the media DocBook!" >&2;      \
-         fi;                                                           \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Defines -->") >>$@
-       @(                                                              \
-       for ident in $(DEFINES) ; do                                    \
-         entity=`echo $$ident | tr _ -` ;                              \
-         echo "<!ENTITY $$entity \"<link"                              \
-           "linkend='$$entity'><constant>$$ident</constant></link>\">" \
-         >>$@ ;                                                        \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Types -->") >>$@
-       @(                                                              \
-       for ident in $(TYPES) ; do                                      \
-         entity=`echo $$ident | tr _ -` ;                              \
-         echo "<!ENTITY $$entity \"<link"                              \
-           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Enums -->") >>$@
-       @(                                                              \
-       for ident in $(ENUMS) ; do                                      \
-         entity=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -` ; \
-         echo "<!ENTITY $$entity \"enum&nbsp;<link"                    \
-           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Enum definitions -->") >>$@
-       @(                                                              \
-       for ident in $(ENUM_DEFS) ; do                                  \
-         entity=`echo $$ident | tr _ -` ;                              \
-         echo "<!ENTITY $$entity \"<link"                              \
-           "linkend='$$entity'><constant>$$ident</constant></link>\">" \
-         >>$@ ;                                                        \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Structures -->") >>$@
-       @(                                                              \
-       for ident in $(STRUCTS) ; do                                    \
-         entity=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
-         echo "<!ENTITY $$entity \"struct&nbsp;<link"                  \
-           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Error Codes -->") >>$@
-       @(                                                              \
-       for ident in $(ERRORS) ; do                                     \
-         echo "<!ENTITY $$ident \"<errorcode>$$ident</errorcode>"      \
-           "error code\">" >>$@ ;                                      \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Subsections -->") >>$@
-       @(                                                              \
-       for file in $(MEDIA_SGMLS) ; do                                 \
-         entity=`echo "$$file" | sed $(FILENAME) -e s/"^([^-]*)"/sub\1/` ; \
-         if ! echo "$$file" |                                          \
-           grep -q -E -e '^(func|vidioc|pixfmt)-' ; then               \
-           echo "<!ENTITY sub-$$entity SYSTEM \"$$file\">" >>$@ ;      \
-         fi ;                                                          \
-       done)
-       @(                                                              \
-       echo -e "\n<!-- Function Reference -->") >>$@
-       @(                                                              \
-       for file in $(MEDIA_SGMLS) ; do                                 \
-         if echo "$$file" |                                            \
-           grep -q -E -e '(func|vidioc|pixfmt)-' ; then                \
-           entity=`echo "$$file" |sed $(FILENAME)` ;                   \
-           echo "<!ENTITY $$entity SYSTEM \"$$file\">" >>$@ ;  \
-         fi ;                                                          \
-       done)
-
-# Jade can auto-generate a list-of-tables, which includes all structs,
-# but we only want data types, all types, and sorted please.
-$(MEDIA_OBJ_DIR)/media-indices.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
-       @$($(quiet)gen_xml)
-       @(                                                              \
-       echo "<!-- Generated file! Do not edit. -->") >$@
-       @(                                                              \
-       echo -e "\n<index><title>List of Types</title>") >>$@
-       @(                                                              \
-       for ident in $(TYPES) ; do                                      \
-         id=`echo $$ident | tr _ -` ;                                  \
-         echo "<indexentry><primaryie><link"                           \
-           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
-       done)
-       @(                                                              \
-       for ident in $(ENUMS) ; do                                      \
-         id=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -`; \
-         echo "<indexentry><primaryie>enum&nbsp;<link"                 \
-           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
-       done)
-       @(                                                              \
-       for ident in $(STRUCTS) ; do                                    \
-         id=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
-         echo "<indexentry><primaryie>struct&nbsp;<link"               \
-           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
-       done)
-       @(                                                              \
-       echo "</index>") >>$@
-
diff --git a/Documentation/DocBook/media/bayer.png.b64 b/Documentation/DocBook/media/bayer.png.b64
deleted file mode 100644 (file)
index ccdf2bc..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-iVBORw0KGgoAAAANSUhEUgAAAlgAAACqCAMAAABGfcHVAAAAAXNSR0IArs4c6QAAAwBQTFRFAAIA
-CAICAAQVEQEBAgsAJgECAAogAwsTAQopHQYBNAEAAAxNARQAERIQAhoDABwAABZEHRQKGRYKQw0F
-ACMBACUAERwpHR4cVRAFBR5rZhADACR2JiIhBDAGAiWGgQ4AcxQABDYACSeQMSYlJykmESxYlQ4A
-PSYZIS05OSsJHS5JOC8kAEMDUC8SADXLNDUzADbEAEsAADX/2RABCFIAAD/qxB0AAD//BFgAK0Vp
-WT4r3hwA3RsTRERAAEf/5CIA2iYCCUv+WUgz7iIAOk5g3CgVSU5SiD8uB2sABm8AE1X/U1RQOFyL
-4jkfIlz/RV98M1j+G2H/fVk23jtD4T0pXl9ieFtGcV894UIiYWJfAIwA50gOV2p+4kssO2j+dGZx
-bG1qVmj/OHH/aHJzfnBX5lQ7B50AZnahdXd0AKUG5V1ARnz/6mErCqgAAKsAent46GBIW4GhAK0A
-AK8B42FtALIOin9/ALUAiIOBALkAVIf/6WxWg4eBi4SKJrEAmoVtdY2geoP/rYVXhoyOqYVuJbUh
-IrgWX5D/jo6J7nszP7gAsI9S63xnN70zZqO/fZzCOb4+cZr+64dy8otYnJ6b7ImDRcM56IqcWMEo
-oJb/N8ZoTMRL7Y9/QchcsaOTo6eohaj/7ZqKXspXj6v9xal+oK+7d7vTUM+Afco5r7CumLTVStKV
-bs9ukbb/9qx/9q9l8queoLv/e9R66beG7rDImNRhi9aDwsPAs8bWzcK2cd67jtqP5MWUodyB8b+1
-tMr/z8L/j9+kbOXWnN2ZstD7yc7Rzs7Ly9xb183UwdD/+si/qeOmvuKIx9fj4tPCtuWiqOrL+tS2
-y9v++NPK2dvZt+m0ueq80+Wo3OeSwuy/yezG+d7f/eS/z/DS3uf/6Ono4PC71O39xPb02vPZ/+nR
-+Ori6e399+vt+PGz+ur65fL55/Xb4vbh7ffX/PPY8vP9+vLy6Pf36fjr/PfM8vjr//f+/vn48P36
-9vv+/vzf+fv4/fvu//z7+v7//P/7/v/8//QpxAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY8AABWW
-AQ2TT8cAAAAHdElNRQfaCRQXGSltwbPRAAAgAElEQVR42u2dDXwU1bXAZwEJtEaNH1nbh68fpoWK
-iE1ao2Bgo9RqIrEg+BIFmqLYLOlMcHHlU6DiQmrJM2jKo0QIBHgUjD5ETcQIlKq0gKDmA+UjiRAT
-BCOBkGzC5re/++6987Ezszszdzc7s9jfPa2wO+zMPefc/5575t67Z5hB/0Ek/W668xckcmVmQZ5S
-CvLmgshl4QCiZu+8ntCOgWlzVfrl5ZZFrl6T/VYSv9x5K3Pj9wnkh9fFFxQE6VcVqXY+8PjgH5K0
-+/0bBxDaYcsN0i+vLlTbzH9kjEknkEF3zptjLPPmXL2VwGC/nxysm+YRyc+/S2bHNYUgmtJkf5RI
-vScH3HEvifz05mhqB8G68d6xJO3ecSWhHXYfYdvM99LHGEv6mEF3zmFJ5Gr49e9qVUh7O/wP/w/9
-gf4EXnKwbpjNGQs779bvktlxzULg7TCQzvDAItBvzqMD7hjrMJaxPx0Cv3OdBvqFBRZJs46xCCwi
-O+xNwNfSclom6F2L4j1A/UsG1hgI1jyWUzLEKf/gX0CwevIzsvSlJoyh8IY5LmPhEFhEhsCI9b7L
-oy/uI2GBRaDfPATWaGO596dDADhioJ+7PKyI5SBoF4NFZAcEa6ZjvL7MOg9MAWtPxv4aHdlfM315
-TMHy7Gg4pifN5cUxBMsPisub9dRrqHc1xBCsC7vHH6jVlQOO3eGBhccc9B+rGIWkP/ALBNYEA3uX
-xxasooMGbVaWxhSs0kr9Njs8zbEE60C2UbOTTAOrR6/ZHjB/ZWzBet+gzR0xBmuHfpttsQbLIEP2
-ZpsGVrsBWMspWBQsGrEoWFEAK1UUDbBkQEkJu+Ko+WDxDRmApWmH+WCF0u/bCFYIMyIHK30CL1kZ
-Y1J17wo51snhW1/4d9BdoZlgcZx7mcezzM1yemBp22E2WBzL66fsExVYjmxBxsNed1gHVra8XX2w
-WBc2A/4dDbCSp4v/2PrGb1L1hkKnZ8sRNFH39cel6K1lQyFbvLcZXf3YrmWsNlg6dpgMFltc3dAN
-j3+zazWrCVbKBun8ltcfS3FYBpb0D721L+uCxXoqxO5VfEMiBmsa6BL/+UxWqhZYMFytPSVd5yMU
-qKxJ3jlub7f4D5f+xmqDpW2HuWCxr0r69b7N6oAV6JsTj6VYBpaciP9L0QaLVXQv13ewUqeBdjyS
-ZM0/Cf6uBRbkak03uLSraBHnWfsJAJ/LEi2TIxZs7bPyZS6XZwu0XEaWCiwdO0wFi3sXgC/K4QDi
-qfhEoV8QWNtT8FLK+L90gddHWwjWjNGw1dG/mgW7/jFNsFjYvd/sKnK73Kh7P4oSWHw3JOcDkJGq
-BVbxBfD5IidKqpzOV/3gb05rwGJfRXEAfYM41nMKfMXpgaVhh5lgsVsAeJvj9YOMXVrE6YAlvHwa
-XJSFLJPBOg8m8W2lpLwFQ5YjNFgc6t45OFCx0OVgNRu1iIVEByznu+ArIUixnPMfKGRZARaCSRpf
-ENx/4wwiVgg7TASLc52CA4f4BiobCFmaYDlSusBUC8GaGgC6VgssFnavS3QtC7uXiyJYMP09o5m8
-O2GfOsW8il1TudoisF4FX8hGvy3lc1yGYAXZYSZYa+RBitvy9hyXIVij744RWP+jDRb8ygaCFLdm
-x7KoJO/tyWj2Jz3/JPhjssY8lnNL91cvsNL8KOtk1fNY5iTv3D/AP2UJMaubvGvZYSJY8Jv+T04+
-8eAyBCsFdvBXVg6F2UK7k85oDoUs7N5FsiwjSsk7v5cKkqHsD3nEcm4BnznxHINTENaaCVJpcBGn
-zXQilpYdZoL1iThSB+kXBNbu8VOhzFhwAICXrUzeF2RPnTpp6qy/nAG9YzWSd5gpfqZhRl/AkpjY
-P0HrrtBZDQ468ZuKHVgqXdYk793Ag4zkllXyDZfq5FhadpgJVjMoxZ3g3sHrV84ZzmMB8LpjdCym
-G3r/oDXdwFaD97EZHG9FxQ53VHKsadOh5K8/q51jYbDwC/FSiywFixX7/Sirk2Np2GEmWA2gHOvn
-Efe3aCfvXiTA27J9lpVLOl7cLvyH2g2PaU6QSmCx4mXcXDTASkaSmpxxEvw1VXsofBLPt79/9AgU
-2DJr5VDIFh2rh9IM6vXA0rDDgqGQW4b1awAN+neFvzoDvpTPjlqVvD8Nw+ToFG2wxKGQO3gUmnEk
-GmAlS/M/Y5KXg5pkLbD45F3IsdhgsExO3vHS5JMV2mDp2GFJ8o71KzYCK+VhSJYjxXKw4A0DeF0P
-LDF5xxOVXLQiltg384PAktaanxSmG+D9AkrtEFhWLEKzr4Jv+FsUNOizO/QjloYd5k439C6SVIID
-doPRPNbTXeA96yPW6JS3AFCkWMrpBg/qXmmYcEcbLO2IxTrfBRdfcAqYOZ1WDYVozvGf0s2vkxAs
-6yIWGqs/l9ZsnWtBsxFYKHa8bOEitDiPBQfhc49prhWyqHuliWhX1HIsvI1JL8eCMJ0CF1ezeBxk
-iz+xLMdCSyYfzRZugbd0gCO6OVZoO0xd0lnTDT57QdiktqYDtBnOvMPYcc7CRWhpghSmWW9qgoVW
-EC6u5uMGh7s3KmBNQzJ9+UnQpTnzzjmLTwHwRUVxcemWBnjnusuqRWi0ctX5cXlR8dq9HQB8s1pv
-SUfDDlMjFkxPQO/H5auKy/e2of0XhmuFKQ93gTctHwpHO1ColA+GqkVovntXFQndG5WZd0m6fqe9
-bYZzej6RPvjZ6qAJUtP2vLNrpP0c53bNYXVm3rXsMHnbzFrJL727XtCbIA0srYA/pVg33SAu6dx9
-BpyQ3Teot80oujc6E6TtWBpr1mfobPRDUrzlSEfH10d3FcEbBws3+rnX7m3o6Pjm43K9jX46dpi8
-0Y9zFe891tHZ/HHFMo5zEawV/uo4+HKsVWCdli1C+2F2p7nRj+OK+O7dUeRio7vnPdVoazIr3/Ru
-4dZkce2bI9vznmr51mRh2wd72e95T9HdmhzKDEt+paP4MQX9+Rf9lU60wKI//6JgUbAoWJczWMRF
-QehQSMEyJWJNM7B3eYwj1re8KEhnjMGaZNSsaUVB0tcrZaPqbVaMyxiVVlcqRP22KLZljEqLlApV
-q97uiG0ZowOOVzboyitmlTECK6fly2V6fr7qfXtMwTpaVKyUUtX74uYYggVAs1o9lX5F1SCGYDWB
-l2bMVMos5dsZL4HwwTIQFwYrmmICWNEUM8CKnpgDFpmEAVZQM263+shsl1ZxWz/6H/oD/ukPC6x5
-s42L6s4mrEFqClgkRX8hWPeONRYzwBpN0i4Ci8iOkGB5Q7xjbP2CZGDwoX62K29Qy/U33RB8bEDS
-SLUkpfUlYjE3EMmVIewIJTZ7sH4FfQHrqhuuV8tNQUduuJrpTyQ228hg/UoiByuXsN3+A64OtiPE
-kauYEP0bslw4c9MD9xPIA9d/5wc/JJH+uWUlaunL6Di3P1GzPxhMaMfV920N0q8qcvVO27/34/80
-lh9/b8D9D5DIz+3B7ivZFzlYv73+AaKG7x9AaEd8YbB+IUdH5hdkddR/9H2iOuX3XrE1ujnW3O+Q
-tXsdqR3PRnko/GUGQXX5jNsYjki9B5JIWvWSg3UrmVtY5jYSO9J/SV7n/efzOJKsDYI1mkSugOGp
-7ai+HAsLrLEE2afj3uvI7JhzEwTrgJGEA9ZtRPXlbx/wJMlNCA/WfgNpB/4wwCJyy5PM7UQ56u0w
-x2o7YtC/bSaB1eZx6xcqd9XHFKyXpLpnGuLYQBwTog+WF7wmlo3TkIzp7SB2YJ027F63p80csOoX
-dXR3aksHKC2PKVjZG8BpPQEvzYgpWPkrhd1koaWnJqMmhmCdqXd3dOpJd4e73hywjngM7C2viClY
-M7YbtPnKrFiDpSutWY0xBcuoe4HHNLC6KVgmgtUYa7AM8ncfBYuCRcGiYH3rwRJ+UKYLVookVoLl
-0Gw3FFgh7TAZrNRkQVKNwVKXCLIIrNBuUYKlZUZfwOJYd3FpeemqZawOWI4VCwSZ6bAyYk0V2501
-VVnzIBgsDTvMBSt1+vL5WPKVtZNCgMW6iqB6pcs41lKwtNyiACt1gmjGNHWZ/IjBYj17+T0jX+9a
-xGqCNT5wlZbXrQMrJUBEb+0f5D9NDwJLyw5zwUreLx4/80Z6qg5YrGvLMeykznplPXiTwZLc8o3K
-LQqwkqX9cl5VdbGIwWLXXIDGNjc0dwBwSfFLRWXEAoB/NN3xLgBetw6sDeC00C5UT/5LXjVYmnaY
-DNYe0IoeydgIe75GBywO/SC0t62hARXpV5S7NhcsdouWW9RgdfFm+EGXskx+hGCxW/yoTjnHch6o
-wsUXdMDi053Rk94CQFFewmSwtgsp1oIz4M2xmmBp22E6WCtxapK+shv8MVUTLM8p0LurCFVRXauq
-B28qWKj2hcwti3TAqklORRlWvrpMfoRgeU6Cz4VfvqLyDB+x2mA5UCV62OV3v6V8xoHpYOHC+6ic
-9CUZ0CqwtO0wHaz1yWPSUfb7GngjWQss9l0UL4QSVKgevEVgofrtvFtw9Y1drA5YqenIjuT5UqGx
-voCFCnzPFltzvgo+l1XADwZL6Oy/SHUIrAFLfH0azNACS8cOK8DCr1aCPVpgscXdgSjFek71yoqH
-mAkWrt+u4ZbgiKWuYNcXsIrlNe9dntJlLpcxWG8pC+JYBdbDivroSrB07LAALFw9acwH2kMh7ODP
-ZflN6arZ1kQsPbeEAAvbsTIaQyG79pQ8HXEpCnyHzrFSUHGJP8Ugx4Ij8InHNHIsPTtMB2vjmIyM
-jKzpe5QdohwK/6GsB29R8q7rliCwxmRBM6at7z7zm2iABb7RLPCtBmsFlld2A/CplXeFtQtwuxvO
-AHmxFDVY2naYDpbU+2O0wTolPPmBcwbVgzcVLB23aEw3gK7fJfd9uoEtB8f4Osw7ULnc+vpjHlYL
-rIDjP1UW/jUZrIC8PFoTLB07LAML7E/XBMsnlBUv4tU7uoO1BKwK0S2VQrsezhAs0Pi71KiB5XaK
-v6srZnXnsbygd/tMVWFnk8FqOYAnsb58KVt75l3PDvNzrFS0E3nCym7FWKgEqxsUadSrNxUsyS1t
-wW4JcVcIBT2VrysKEWut/yIfossr0SMJOsEqVjfHelo9O2pRjvUW+FJZ9Fc9FGrbYdFdYWry/G4g
-G0XUQyFOojkPUq/iiKxIr7lDodotRazBXWFqctZJ8NfkKCTvwnQsXw65Qw8sNI/FFwxPsRYs9BzH
-46D3MZ2IpWOHVdMNY1JrwHwNsHTq1ZsJFgfd8oLCLYZgwZfrFfNxkc5jfSKfS2QNwBIKhv/J4oiF
-XkxCFTS1F6F17LAMrGRtsFhUDz6g7A6LwFK5hbMQLG4NWl/gxJKMHXo5Ft+vdx9XFQy3BCx+ENZe
-hNaxwyqwUtNPakcszyk0A87x6jmrZWXFzQULAh1wC8z0VhmClZr6RjTAQlN34O1l+HET7jUNQIa0
-BlgpDwNFOWmrJkhhqOzVWYTWtsOatcLk5DGvgTOy/Q2qJZ21F8AXq92ouoq7aK8ffMxatFao7ZZg
-sPj9WMv9QHFbGCFYnAs23ftxZcWOgx3oOezGM+9BT8+waOYdDoafai9Ca9thOlh7lq+Esr4GKJJe
-1SI03nzxBVSvGpW9/uwFa5Z0VG659LbOPFYjNmPlHgD+nhyV/VicVEi996NlrM5+LLG3YQ9flG+6
-Mxms3YFnGsufIBm0H0vLDqv2YwGwUXc/VvFe8XNflLo4y/ZjabpFcx5rf3qUdpCyruLqg0cOVpe7
-We2Nfo7aA9Ja4YLa2plWgbXi+EvSIvT22t1jdXaQathhMljra/BPlfe8sVK5jSloBynLeir2HqlH
-5eBZ6/ZjSW6pVLtFCVa+YMaejdNTo73nnTXY8x76tfl73h2ybfcke97Z2Ox5Tybd887FZs87S7bn
-PWjTu9m/0nE4ZC8dlu15d2i1e9n8SkeonfFt/5VOuoYd9Odf9OdffQKL/q6QgkXBomBRsPoKlo+C
-9e8MllGzZoFV7+4EPm3pBqWxBSt7A/DqyWVQxqirpwv+H/6BRfybF9AY4zJGHt3u9YFOs8BqVlfi
-KlIXXjsYU7BWOCYpC61NUr6f5NhArJ4ZYK1Pn6astKZ6mzWtNYZgnf7aYyjNPFizSeowQ7DGkgiq
-QdpWf0QhR5Vv64+CcMAiaheBRWZHqFKRu1UCog7WbQOcROWucanID5RSs3+PUlrDKhVJ5BYnQ2iH
-vQl8repetdTj/ZXMreyTBML+6EbHHSRyRYmv6fQZlYDI5ZnvELU7+joyO5w3PXO+6YJKuiNXr8l+
-+5hfGkv67cyjThI3329vamrqVYu61TCK2/6IzC2PwohFYAeMWB8Gd29IdZgBVwbJVVcFHxtgG0wk
-tiH2IBnZB7BKCNu9NpQdwYeuZOKD1IvP7QNYSf0GBsmg4EP9mBC6XB3iWLB69viIn3ngA8+GajeU
-MKR2BOtnD13nPbNuH4HUjcwl+ty+pMLgz9X1BayRZPpl9sGOPujXNKSs7kNjqSuzV5HoV1eYFOJo
-U+Rg5RK6pcreBztCTgIwhF/XtKVkn0siqfPeRe6bQsLHWuROJrRjIYimNNnJqKyznyf63NakaGrn
-Azk5ZJ/sIraDpM67VwCrcf1GXVnfDjtkLgANldX6gsAqA2C//vXWv0acJPBgvW/QbmUbADkQrI0b
-CewoAJ1GZlSHAxYcB+r1L1gJ7773oWfQbDd4HNsBASwD7SobwgLLf3yDgWzn7TDqXtGOAxsM7fBi
-sHqmTcifriP5WfkYrA6P+nlsKnFVYLBqMqZN15X0jWFFrGqXfrPFniIfAmtlhq4Zgh3PglJ3qbEd
-YYBVb6Sfqx53yAbHzBm64qiFYPlAhUtfvyJPWzhgeWdkz9JtdqZjA7TjX4bdy9txoXb8jBmGdmCw
-2rMMJtzemIDBanYbGFRZjMHak2VgbziP7oVgVRg98PSYuwOBZTRjzdvxLPAYPmG1OCywqosMPlRU
-jcFascDgc9m7MVhGj+7tcDeEA9bp8bUGH1uwAoH1tbuDxI4LB7KBsR08WBP2AP6Rb/5QAjtkGg+W
-0SNj0bOUk/hnQoe8EN9GTwRg6Q/sxzydAlh+YzuejfIzoavA+0ZgreLBemmBfgrgJQQrnGdCQ7DO
-Zx8wSIh4sNoMA+EqASyyZ0IjsPYbfNPDBSuKT7EnilgSWAR2ULAoWBQsChYFi4JFwaJgfVvBajcA
-azkFi4JFIxYFi4JFwaJgUbAoWBQsChZN3ilYNGJRsChYFCwKVphg5RCCVUAG1pCS6A6Fc0eSgNUB
-cu4jBKsgumDFE4IVTwZWmT3KYGWC00RgxROCFU8MViEZWLklZGDlVEU3YpXlkkWswgIysKAdUQUr
-s44IrLpMMrCqMkFUwVo4lzBiZf7raxKw6jK7ScECRGChaxGBBSWqYEEhAgsKCVjQDm80wUJCAhYS
-ErCQRA8sLERg4e5tI7Jjd1TBQjuiiMDygegOhfCCZGD1kEUsnzeqEQvZSwSWjxAsX5TB8hGC5SME
-yxdtsC77iOUnAwsKjViXU8QKC6xoRiwKFgWLRiwKFgWLgkXBomBRsChYFCwKFgWL3hVSsChYNGJR
-sChYFCwKFgWLgkXBomBhsGoIwTIoR1IpgmWg4PIwk/dygw80IMUgWOsJwTKsNhNlsIolsPRlkgBW
-pf7HOsIFy6jazIoVRN0r2LHbsNrMJBGsjNcaa3SkcT1fl6jBVd/coCNtFXz5nz0ZNcrrqa7emB8m
-WMVtDbrtHnR1oC9e/nxdMyQ7PJUG16soDku/ao+uWxqaPTwpK2Ycr9WV8TxYxeW6+jUfcTWEo97p
-8dv12z0+cwXfvUeI7Ng9vraWwA4IFliZkaWQaRMUbydk8KHAV+7WL+8t1G9vn66+nvJtFnEBfGGk
-W2RQVhwXSvNDoLN0RbSj0uUhsoNUDOvaCxGmdrxKpirfOma04M/VG+jnLveFpd8Kh7Kd7Gy1IgeI
-ulewo2WG6nrjs0PZwaCa4Y2tja2tjY3wL/g3fo3+j9/gF9LorpQO1Xt+jPaDdnxuo3AJ8bKyNkjr
-lIuxv81AhM81tirsaNWyo43wepHqp37fKeQyLcdb9OT4eSEHazO4XpjqAf1moVZ8uz4jt3TyZpw3
-uh62gyFSzQ8uf/H/m9jxbyIMdQEVChYVChYVChYVKhQsKhQsKhQsKlQoWFQoWFQoWCD0g0V8fvUL
-2SdDbKDwmqqu1xtQQd1SqCNBp/WYrKDkpR5/kEt9BKf5zFscUDTfE/zSq+llXwTdq4hYWwvmIlla
-8o786M6SwmeXbj6ruOjhrYVzl5YdEo41FSycK5z5odnfhJadJagZ6XG7hULLSBm0ZFNXoDgiSi86
-benmdtO/qYGGsGuqeJfOXbi0rJVfUtonOHnp5h6VlxeqvRxlrsokXTa3KjpzHWq6Sd408vKzopel
-M5eWHIpsKExjBIkfd1LEc93wBHxo2JRuiebD9wyxoWOJ4w7hz9QxktinmNp3LYtvxi3HD1si+EFs
-2JY4hf9yyHXhu9ILehcPF0/zmxey4IV7BXfFDVvSjRvKlanzIj5SKB0Y9g7Q8rIpYKUxoZremZYg
-eOuk6JqAlzerzhTACBesTGZkDpTJsKlbeANbHoH43Dc5J3M4w9wiXvP5BCYOHUuzMQO3ocel1jHx
-OVgyYf89ZOJ37vBQ6JP7YDsJjO0hXsN4JlNs+SkcIhi7qAsDj3Sh074cJZ3G3GVaz6H9C7Ahu+Cu
-u86iYwVMkqBOAtNvG3JNCX9kMjww6JD8tEzey2dN857QvTk5sH8HviN00xM2Ji5tMvZfIj7mlbyc
-hrzs589ME8Eg9Z8KrBL+xbqh/V7EcX0iE7fkEPrWt6yTrvmcjZnyYQ+Ol6OYQTU4YsVLEaV/3Aem
-9dyXI5jEzdjxdYttzO9xOLIzTfwQ9Hx/rEsVIz7bvOURW2KNeNqSJv60BHiaecPgKNjQId4PCcyD
-PFjis5EPj7Jh1kqYTOHACPgRv+RlIHj5Qb95YJWIugy1Pci/eo6JEzpz3XAhdEB3DdvcJHr5KcWZ
-6wbzYIQNlvjA9CeY3yKbN6GQJMh7gxkcGE8k2J4Sj50bxUzhwRLzu97/Mq/n4LWlqAnxjsOv7cw+
-4V+HM1sxWElisnnpZ7YXkRXPMbdIucEm4bToC24oUcpON/W3HVKABb66FkeoEiYNKojo2cQMA7yX
-A6dBL79jHliFUjPMNThlec8WJ4FyYiizJNjLiScVSCIwIgfLDxZiPHqHMjI+JyIdusAjzDi/6Enw
-pu2hs3Kw/HJPRrvjDg+OCzj93IjEDySwvH6o2HDbZgVYXYI9h69gtgXgHJG4zaxtWS3XMbJrTxy4
-TeUO/jvAg4XzdeYWrNJ1zIuB9GFi3IsWgNXL2M6jUW8UzFykf3+OeQpqj73slcYI6OUAWH6QRxo3
-QkescyP6ob54b8A1rYF/PXcIJiz+iz/jUwW+oUsfnvdaFrH+zPwk0AG9hw95gWwohN91/EWTR6x7
-bEuE0wLSiawwR95kftKtcpccrBPX9jskHwrBRD4rhNHjrPo08yPWoPNYpUEBiADsTOyuu4CkQm8n
-9LIsYn05ot8HEYGVu68KyrpRcLSDt3+/tj0l3HBCEW6Ot18x7JR0DM+6+GU5Vi/MsfaY1XG/Zv4X
-KNThc6wSrPPihMRtQJFj9T5iG/gBPu2/g08zI3VXNCT0TagcKw0rvPUe20N4UgJ62a/2sgU5Fmpz
-Q/9xFwKdqeVldGYeD8bQuCWE92YqsEQZ181rsjTohHXMfUGXhmAVYMk19a5wKBNiGiU+XtSZn26o
-YobMRark5eK7Qi867R1ggfjguLI56GgBM5JXJwfeSgt3haLGiYcwj6G8bBJYabwu8IZ0IJ4oeoZ5
-POj7EexlnwqMSMCyJyEZYkP5G5q+4BH3jeQlTYjkXlxCPAkfS6rDYEkTHQ+1muYaO1OHo03VEL7l
-PB6sJEFnfGsMwZJ0ieMjwRCmisdfUDgH+MzpuJH47gGAJqGhTHisIDB3lMinEBAsXuEEG8zZ/TIv
-JwW8bBJY4pyfeLeQJ8bTNEFlH/DFq7xcgM+UgxF5jtWybiiDponE75JPpAb75T4erCTh4D4MVi6U
-oTbhZtskuVn4LolzoJkibcJEBx6Jqhg7VCUnIT5xyVnxtHeEWMZLmllgpQkRS5wvTsJgjczLzc0c
-HD9MnPUXcyzv4XuYRMXXV+ZlsyIWdE1mf2bcZiHuSBFLRA7mqwlBXg4Moi3rbmYe8kcOFkzuEq75
-AA23S7AGvq1QqgqZIfD17sHj+ByrCh3cahfAQkc+HYxaNW+x60Zh9G/C6uSIYO0Tb/ZtP+mRcqxN
-trglqtSMPy3XLLACORbvLogUBiuXny5KFO9MA3eFJ0b0ezHotELIo6k5Vu9E5hYxY39ezLFwZ5bF
-I7DUXs5RpP0QjJo+gNUDhjNl6DZHfldYh8E68bNB2xTD077AXeGmBHT3ahpZf2YelC2eFirAQvdT
-TL/zgbvC51CGhXVR3hVuNQss3JDM9io5WLA3+21TgyVMCilvJveZCVYh8si5UWjePYBJICXGEes5
-6OUumZdz5Gm/X5gtjBSsLhif4fmXZPNYfvAhAgvNYz0kW65UgAWet9leNAsrPzjcP64m8G6pGqxe
-xtYjm26YaBO6Ep4mZu9ePygzD6xzV0jzWLChrXKwwLkRaNxTgCVOcp2TzbMhL5sLFpozGMrccoEP
-sqOYpwJN92CwdvZPVHhZAVaXlEhGOBQKcUk+lQzvB6/FlPfv91RgkeVaOVj+XvhlOGkWWTiIB67+
-hHoofNP23XYZWOew+/zq0xabB5Ziih+6Sw4WzhOE5F1U4NJE2+9BsJeHmD6Ptckm8iRfWgGH8awp
-dNddSi+LYHl5MPZHApYAZssjDB58YSOJwlrhzidsaAUCyNYKfXWLb7bZ6gJgecGJwba7zNs+EFjF
-atl5j42ZrJggPTwUeyswQWjMGXEAAAJqSURBVPpef366gV8rPCuddp9pYPGLkry7HrEx4+RgoTUo
-YbohU5zzs/FBLMjLfpPBgtFcXISeKK4Vnt+3OMEWh159qvTy44oJ0ntIJxxUYKUVoNu7nOEMjs5e
-YXcDOmJjmHHC1/F5G9rdkItWv6EKfsXM+3MMs80srsR1d3hnAxWMm9LKg5WTh3TOTGDUM++PMGgM
-9PrA4VH8adiKKa3m6Ye2UUjuwhMvAbBganNLK45YSdjJuXg/hh97+Z4QXjYTLDgY3iXQ/QQT6Mxx
-7wS8PFn08ln+fhI7OedmJo5wUjD0fixmmLRss244nhey2ccJW3jwfqwEfr/OyCU9wv21CNalEcwg
-8wZDaacQY59yiE/NmcBWITznt5Wxi2DBACJsQhH3Y/GnmSi968SGkLu8aD9WjrSM0h9veAjsx7Lz
-82z8Nq74wGlmgZXGzBW/AZsYKbkS92PF4xiBs4qWxUPkXvaFBCMcsEpy87Aod1ruLJlbwG/HlO0w
-hMcKln4oZDdNuXmBT+dONm8XKcqYdhbCljdLq2sFvMoFS/mOBHU5c6UAsi53ssiR+jTzBDaUt7Ss
-SbwJzSmTdH8+93GYX1TlCE4uUygDvZyn9nKUwSrJqZLePZO7tNsrtHUYdTDuTG9IL/tkYBAvORnu
-eff6Zb0qSo/OcADM3Pfu1VHWq3fAr2djlNlXudQXdCTYjV4L6uCodfEG97RwSL7nXa2zPwKwqFCJ
-mlCwqFCwqFCwqFCwqFChYFGhYFGhYFGhQsGiQsGiQsGiQoWCRYWCRYWCRYUKBYsKBYsKBYsKFQoW
-FQoWFQoWFSoULCqXq/w/gbudjI6bMwYAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/constraints.png.b64 b/Documentation/DocBook/media/constraints.png.b64
deleted file mode 100644 (file)
index 125b4a9..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-iVBORw0KGgoAAAANSUhEUgAAAlQAAAFYCAYAAACVsmLPAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
-/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBIAKVtZsMAAAAxxSURBVHja
-7d3ZbqvIAkDRLsv//8v0QytXvpYZap7Wko56OAnE2AXbBSbhOI7jHwAAkr1sAgAAQQUAIKgAAAQV
-AICgAgBAUAEACCoAAEEFACCoAAAQVAAAzb2jvyMEWw0AmFvh37xnhgoAQFABAPT1zvruwtNlAADV
-VLxsyQwVAICgAgAQVAAAggoAQFABACCoYEohuFkugKACsmLq178DIKiAyJgSVQCCCigQU6IKQFAB
-BWJKVAEIKqBgKIkqAEEFFAgkUQUgqIACYSSqAAQViKkwxjIAEFSwbUyJKgBBBWJq8GUCIKhgm5gS
-VQCCCsSUqAIQVMBYoSOqAAQVLOk41lwXAIIKhoqqJyFUYhkACCpYMqpiQqjEMgAQVLBUVKWEUIll
-ACCoYImoygmhEssAQFDBElHVexkACCoAAEEFACCoAAAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQA
-AIIKAABBBQAgqAAABBUAgKACAOA/b5sAGjsO2wBgMWaoAAAEFQCAoAIAEFQAADtzUXohIQQbAYDi
-Dh9kmYIZKgAAQQUAIKgAAAQVAICgAgAgmU/5VeSTGQDE8InxeZmhAgAQVAAAggoAQFABAAgqAAAE
-FQCAoAIAEFQAAHtyY0/o4O7efe4JCzAXM1QAAIIKAEBQAQAIKgAAQQUAgKACABBUAACCCgBAUAEA
-IKgAAAQVAICgAgAQVAAACCoAAEEFACCoAAAEFVBICGMsAwBBBVPHVE4QlVgGAIIKpo6ps/9utQwA
-BBUsEVMpQVRiGQAIKlgqpmKCqMQyABBUsGRMzbouAAQVNHMca64LAEEFy0WVmAIQVCCqxBSAoAL6
-hI+YAhBUIKrEFICgAvqEkJgCEFQgqo4+3wuAoILto0pMAQgqICOQxBSAoAIyQklMAQgqICOYxBSA
-oAIyokpMAQgqICOqxBTAvN42AYwTVQDMyQwVAICgAgAQVAAAggoAQFABAJDMp/y4FIJtwJx8ehJo
-yQwVAICgAgDoyyk/HnMKhdE5RQ30YoYKAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQV
-AICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIKAEBQAQAIKgAA
-BBUAgKACABBUAACCCgAAQQUAIKgAAAQVAICgAgBAUAEACCoAAEEFACCoAAAQVAAAggoAQFABAAgq
-AACGCKoQPAs2JQAIquwCUAI2JQAIqowCOPtvbEoAEFQRBaAEbEoAEFQFCkAJ2JQAIKgKFIASsClh
-szEKrDGoXkNuiOPwwim4iezYoc9+39iDfQbVq+mGEFOiCjZ7E23swR6D6tV8Q4gpUQWb7PeNPdhn
-UL26bAgxJapgk/2+sQd7DKr3EDE1y96mUPT1fqgh6Ffosbsz9mDdQfXquiEY/rUKlBtLYgoqDJZB
-Dmjlg8qRWlSBMSSmYLOoKhtUjtCiCowdMQUbRtXLswUgpkBU5XkXf9CmPJZ9nQJrft6Gife9XmC/
-t0mHg9tr3FcJYgrmjilgn8Fa55SfI7WYAvtnYKNBW+8+VLGn/zY6wtd4qDY1iCngx+BtdNCre1G6
-W3gPt7MXUwAwW1CJKjEFCzB2wODtH1SiSkyB/TKw+KB9DfnARJWYAvtnYKLB+m7+AJ+UgL2WTQmT
-jz1jEJVf0ASD7jXck2/vY1PCQscwE+6wfkz1CaqrB6wAbEoQVcBkMdUvqH49cAVgU4KoAiaMqb5B
-9bkBFIBNCaIKmDSm+geVArApYaOxZ4zCuoPq5VkDqL//F1Ow9qASVACV9/9iCtYfVIIKoOL+X0zB
-HoNKUAFU2v+LKdhnUAkqgAZvqoG1B5WgAgAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQAAIIKAABB
-BQAgqAAABBUAgKACAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQVAICgAgAY3NsmIEYI
-//3zONK/7u/v/nx+zdPl/1rO0++LWd6vZZ59Xe7jSfnZSq3z6jnJ2ValX09PHj9AD2aoiPJ34Lo6
-wJWKiJQD7N2BN/WAzbNtZTsCuzJDRZeD8XHkH3zPZo5CSJudeTKbdrX+lkE7QkzFbq8VHj/AGTNU
-dDkY1ziw1jjY7nAA/wzKqxnIu5gSPICggoTIuDroXh1YRz3ohuCUlcgESOOUH81iZdR1fJ9+zL1Q
-use1Y6nrvLsearR46rHNAQQVw6l14HtyOurJz5USVqs9LynXt8V+ShBAUMHHQfdzFuMsQGqHSW5M
-PQmrVtdsjRCkOwY5gKBiGne3Okg5WJaMqbuw2uX5+P6aX4H8/f922F4AgorlgyD3hp47z3ycPfZf
-p/FSb00BIKjg4kD8/cm4mFNjKfd/OpsJyb2GJ+V+UzEXSK9wAfuvqGr9s7ooHRiV2yYgDCe8xUOp
-gHny2GNjVdwAOzJDRbUYSfnep8srfdCOWV6tr225ztzt3PpxiTRgdGaoAAAEFQBAX075sbS7C6dH
-OJU0w8/ocQEIKjY2w0F71bAQTMBOnPIDABBUAAB9OeXHY36tCAD8ZoYKAEBQAQD05ZQfl3xSCwDu
-maECABBUAACCCgBAUAEACCqgiRDczwtAUAFZMfXr3wEQVEBkTIkqAEEFFIgpUQUgqIACMSWqAAQV
-UDCURBWAoAIKBJKoAhBUQIEwElUAggrEVBhjGQAIKtg2pkQVgKACMTX4MgEQVLBNTIkqAEEFYkpU
-AQgqYKzQEVUAggqWdBxrrgsAQQVDRdWTECqxDAAEFSwZVTEhVGIZAAgqWCqqUkKoxDIAEFSwRFTl
-hFCJZQAgqGCJqOq9DAAEFQCAoAIAEFQAAAgqAABBBQAwibdNAECqcPKLJo8fH1cNN7+U8up7jpOP
-v6as//PvPr+/xPpTlsEazFABUDSmnsRTie/pvX74ZIYKgKz4+J55+fu7EMLPWZmU2auY9YsjejBD
-BUDRmDk7pdZq/Vf/P2bZT7/2OI7/rU/ICSoAiHIVLS2uFyq5Dtc3kcspPwCairmQvHUghhBOT1U+
-eQx/fyfQBBUALBNrtcPmc/l/QYagAoDqYi9ib/2zPZ2l+hVw7Ms1VAAkKXXbgpIXkH9eIF7r8T15
-bEJLUAHA4wD6FQ5PPoVXc/0ll3/3db/+sCen/ABIio7PU3U5YfIdY0++78n6RzPqxfiUYYYKqh94
-rv/AzFGV8nelouLue3JC5e5XzTx57E777SUcsa+4zxeIo8HlOw/vOgBwLBlqA1drGDNUAACCCgBA
-UAEATM2n/CpyQSIA7MEMFQCAoAIAEFQAAIIKAGBnLkovxI3XAGBfZqgAAAQVAEBfTvlBbXf3I3O6
-GGB6ZqgAAAQVAICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIK
-AEBQAQAIKiBFCGMsAwBBBVPHVE4QlVgGAM29bQIoGFOf/30c7ZcBrV/zd6/Rq6/7fs1/fs3T5Z+9
-AckZO2dvaL6XeffGJ/XxpPxspdZ59ZzkbKve278BM1RQOqaeDvbSy4CW/g5WV6/RUhHRcuwYc2W2
-VY3tP/hzY4YKar5bfLIDeLIMM1WsOnaOI/9AeTZzETt2YmbTrtbfMmhH2PfFbq/Syxxk/2iGCmrF
-1Kzrgplez78OpjUOsDu8qfkMyqsZyLvwSdleNZYpqGASLQe3GSpGHgNXB92r1+6or+sQvInptV+a
-eF/nlB/kDv7aO14xxUpahErqOr7Hc+yF9y3Hbul13l27NPJ+aJBTgYIKRo4qMcXK46b2wTVlHb9m
-3VpcXD/i85Kyb4v9lGCvZQoq2CiqxBQzvfY/ZzHOAqR2mOTG1JOwanXN1ghBunucR3INFYw4qMUU
-K/sLsO9rlXKuXSoZU99jcfXxmPpp5LP7f5W+B9Ukz4GggtGiSkxBn5ja/UL0v3D5/nO1jyq1zWos
-szGn/KDGTinnoliY9TV/FzZnr++U+z+dfcIw93qblPtNxVwUvcIF7N/7uZJRlbLMQS5KN0MFtQ4w
-YgrWGberjs+Y21vExmqN/eDAz0M4jsifrtZ5alh5ZyWmAMbaJxfe75qhgl7veMUUwDIEFfSMKjEF
-sAQXpUOrqJrk5nSwpLvT7yOMxxl+Ro9LUMFQUSWmoP348zN6XIIK7FgAWDWo/DZuAAAXpQMACCoA
-gM7iT/m5BgQA4P+YoQIAEFQAAIIKAEBQAQAIKgAABBUAgKACABBUAAB7+hfHbDX87cMFJQAAAABJ
-RU5ErkJggg==
diff --git a/Documentation/DocBook/media/crop.gif.b64 b/Documentation/DocBook/media/crop.gif.b64
deleted file mode 100644 (file)
index 11d936a..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-R0lGODlhuQJGAeMAAAAAAH9/fwCvAP8AANEA0dEAAK8Ar////wCOAAAA0QAA////////////////
-/////ywAAAAAuQJGAQAE/vDISau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqP
-yKRyyWw6n9CodEqtWq/YrHbL7Xq/4LB4TC6bz+i0es1uu9/wuHxOr9vv+Lx+z+/7/4CBgoOEhYaH
-iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6gQC9vr/A
-wcLDxMXGx8jJysvMzc7P0NHS09TV1tfYxbth2d3e3+DRAePk5ebn6Onl4ezt7u3q8fLqANtg7/j5
-+s/z/f4B+wIKHAjsn8F09ex5IciwobuDEM1Bi0ixosWLGDNqrJhQIZdk/htDihxJsiTJiSZTqlzJ
-MmNHj1q+tRznsKbNmzhzDoz3EiYWmTN7+vQJgOfQmN5mAjzKtCg9pj+TBoU61ClCqlaAthSKVZdV
-dFy7NtHKMqxYW1/PmT2bhOzKtWxlpZUYF4pblXDrvpq7Tq+Tu+UGCB5MuLDhw4gTK17MuLHjx5Aj
-S55MubLly5gza95MmVxev0EAkxsg8jNoVXNJ0zy9RPQ41RtNsz6V2vPstlLTwdYo+zap2qt9G3Ed
-YLdL4bGAL0VOhLhxjL2Zf1IeXboM56Wtt6KuPXRudM8vVu+eiTt5H9hDjj9vyfyIXrTW80gfO4OC
-+/jz69/Pv7///wAG/ijggAQWaOCBCCao4IIMNujggRe4J4IwBxBg4YUYZqjhhhx26OGHIIYo4ogk
-loihMBbi1k084VlklgLsWQKjBRJqgIwEBJRyY4UqZsNidhjMGOMkQlLgnjERwkdBjuVpk2QFTB5B
-H2/2DUlJkRNYhWQKUTKyJQpdFjHlcUFaSaQxo9nGQph/fCkDm0OMCV2VZh7iZpbnwCYfBnDKcecO
-fXq3ojotckRnnXr8SQGWEtQIphuKEhEoEHKKdygHCUiQ6QEJdDrEphWA2oGo3UXaAaMHOHrCpFmY
-2gSr6H2XJ5AXoHqBp5xyuimpPfCa6we+6uWqCaiqagKsTAxrBbLz/slqTqEUvWgBqLviSqqvnXpq
-rbbZTpDtt9ziSsG3unKraabkltutWMq+UOyswa3A7A/tfjGvDpW6eKm3v+a667i38vvvuQLzW7Cm
-AJ878L/W9ouuR/Xi8O6zasorRMRo3JtDvoaWOe2v4IIc7LUIE4zwtd1Sm7C6KZ8MLsmzYBzExIFV
-rILGJsgcB843cBztvgqHWnKwup5s8rroVivwwEc3DHLR/jKcis5K0JxmvDezQLUePNvgc0TSBix0
-1OuG6nS56nob7ssqp132wuIi7cnWU1j9ms1chkD3IF3X8DVEYe9AtNi37M2F3cXh/WgFhjPSNw1/
-HxS4CS97MPjH/ts5uQfieqbQuCWPzxC5QZPncPnYoXz+BueKY+Bm6J3AHsPo/5TOmup5sB5vxLJv
-0vsLtPtjO1W4D0Kz6r9nknwLwfczvFeam6IAmndjnfcsy2vtbM3qAT2KkhkULwj4SRITIbzLWYx9
-j9j82L3HvyljivzeG1tC9qCzf4379cEPigACCAYAB0jAAhrwgAhMoAIXyMAGOvCBEIygAVMVDBLo
-Ln1ZWx8SmjeP521CAEYiXypAGML1XHBPF8BfJVToue1drX+1GgUJZTHDFJywBSycRA5PwEF5eFAT
-NYRFEE9wwzXRYoc5c2H1YGgBW32QFkMk1vkoZr3FyQKJJeih/lH894kotsKLFpwi9zB4vSvqzxr8
-oxIXPQHGVbRRBEVUnxk3qMTEvS+GonjjBBCwxwMg4I+d0CMI4pjBOUqpjtACm/c4IUhASuCPfPQj
-I1lAyDLGAosk0OJT1hhIC0RSkpDsoyg9GUpAhtKPp6QAJD9pB0F+oJJWvOQZq5FGMuExFFHkYyR1
-OUpWqrKPvHykJIXZyzy40gOwXNURZ0mNWs6Jk5P0JChXKUxHXsCXwQTlKIe5h2OeSowvRKEFMOkI
-ck4IkbRqogyvaU1uZpOd1URlNXepSnriwZscSOaxlknHQekmnRVwIhAxgM09rtKXBrXnKalJzFTe
-AZ8b0Of9/vh5SH+CB6CLWicPEAoIiGpAoiQwp+OYOQ1nWgqaT0TBQTl6TUN4tH7oEyeUKDocdN5R
-nXnsAUv98FJO2i+kNBWTTZkYUI3SkJLgXKJMlxTU5gxVjbf8HxSRSqOY4rCpcXqqLXGKy6muAKQj
-EOkixPoBTV4FpQOdRU+jiicqkjGWsCCrB8wKlkWm9KhfTaod36pMDVbUR4TC6AQEmom1spGqjLOq
-Ef1aU4uiD6pclapaEWskxcpRlv0E7D9vWtScTjavVXXrUicgV0SUlgN0VYtd04pXFYBVBKc1RGxt
-pNVnsvWwn3WtXju3WEM2VrMX5WxGPdtaG+62dftkrFAd/utWyHa2q7k1bmjHOFocYfVitT3pbTsZ
-XRS8NgSzJUR4XZddfaG1sF7V7XTDeVXlOpW5Y3TucKFbXO8et4p99e1ygfvYrT5XsvUl4n35mlz9
-vpe/zfXvfAEcC8P+t63Uba+BswrfF8p3sEZtMGUhzN7eYvav7QuscDFMXA2DNrGilfCHfxvizRJ1
-wV1Mr3RRHGEPx5Wk0jCpebcbzQBLcb1KVfGNM9vi4L6YxPQ1sXpp3OHLDhnE+xPxkSVAWEw4uMcz
-rmyKbfyK8ZYPwfFVMJIZLMQNN8qyhVzxfovcX9tGNsbdFTCQ91pdHrmXwmC2sJipnOEyn1jLNXZy
-l3Es/g4pX5jPJfbzkgHd5DQ/mcVRdvGhD1DlS1z5rlnmcJC57Aov06i8HeMxphWd6TNvWdCdJjRK
-JL1nSvf5FZdGNJM3jepWeJpxoP7Zea0sY/vOmbe1ZsWtS5jnJU660paINXr/rGk6C3nQRI60kY/9
-alco+7sgGLYftN2oXCty15butZxn7WxO21rV/DB0q5FdCWXzmtmmDrSjoQ1lNKrbzQ/GrY9LgO0P
-cJsP/04tXcCdbHH/mNzAnneqo21vVuMbxvpWcqlThWZLPnrN0m6zdt8ccVL7GuHIneidsVthY6+7
-2l80M8VPrfBzM5yW9954vrm77zD+OuRAHbmgir1X/monGtYq/2lYr7tzNif44WOGc81H0G8P/HsP
-Afc24Fa77KXDccB1fjrX0O0MHYea4zSX+McZTeuWC5vrzfC6rkXNWrGPm+zlDvYqol7ynp/859YO
-esXhSm9IN3zad0+yx9/e7IRbvO8Y/7vGdwx2LA/+4HA3PN8XXm+YO1zmEA/74/mN9WdT3u+WBzzS
-ZU1moMN75fI+/OcTH/rFf33mjjf9oguP86HrnFJSlxzV3231EDS9A1rPA915nsipE7zdBuf8zfFb
-YDUf2OhhHr2r8Z7y0wsdtkTHfd2Lr/vjU8Ld4bb+3vPrfDxDX8/SZ/f3k29zkDNf5BMmOfEFS3ql
-/rsd8rR/f87jX/SMHx3zSddxsjdx1wde2UcvuUc6uxd+vTdInWduZ/dyzRRzjAd7ozaAY5d/BAZ/
-5Sd/52dy6YdyrHBtDyh3qjB8H2h3IUh9I6h3LKd6Lld5E3h5FZh5sZd34veCkxeDoDeDogeA9SeA
-ODh78dZoMBiBMlhSFPh6NniBQ0iA49d8F/d8/hd9QDh9goeBhFeEZXeEc4d2zKB238Z2VXd/yud+
-G7h/Hdh/ivd/NRiAmqeF+MeFcWd2XyiBSkiDTAiHN1h9RIh6RriDSNiDefiDbxiEcfiEGUiHkkd+
-U2h+VYh+V6h+kyBBlniJmJiJmriJluiCqSeI/neYhDm2hGvXeJzgCzEjQkxXgnZ4gmC4DGJofGS4
-CcAAC7XYfpFXe9h3ewi4ffSHhfGjiqvwC2eYi/pne/ynffM3YoiYOqhoi894dcuXhsi4hsqYgtyn
-gN5XHt1mi93oe6zoha6Ih6Ooh6VogTpSZ+3RG7/HAcGHBygYiSA4idCYisgUjqA4jqJYaOY4hqY4
-NepYCcI4cwWYbQcYK77IjMBYj3KxFu24Ae94B/HYhlZ4iAuZHAFJCQP5kBoQkXYwka3nhnvYjAyJ
-kWBXkP52kD0gcH2xjQBpj3CIkk6nks2SkFN2kWiRkZOgJByZAR5ZByDpg653jk1YCwM5jADQ/pN8
-QpM7wJIhR4l7oZOSoIoyCXxMiS8JWDsLaJRS+QgwQj5V6Y5XuTFZKTxbmZOvICRKEpYQOZY44JTv
-B5Xx0ZWKgCW+EIUc+IgeKI8qSI9YcZSiUCxp0YhSiHhUSJGSaJFyWTh0WQjv0guB6IiGCYmIOY+K
-GReA2QnHUxSEmZeTuZeV2ZeXWReZqQl2A5nHuIvJ2IvLeJOLuQ2leQmcA5lZ55Y9U5bOc5ZHEZtX
-cl+8mZK8iJCt6XO305h6cEK/KZbBuZK42UG6STzGeQdFlJw+aZte05w+9Jx/GZ10QEjUOU7W6TfY
-uUWzKCzcGQew9J2kFZ6QM56bVJ5+oZ6E/qBP6vmTdBCUhTiU/oiOtyGfgQBS1Gmfc4Cf5WiII4mT
-0uGffvBavymgckCg/GigRMmH1qGgm4OP5GWVy1mTwxl4Q2KheNB0memgO/OKyhCL3QefzAGiddCO
-R0micAChqyah+1mU58GicsCRwgijbyCj6daPsviPMYKjq4OhZdUTPOoGPtp1pFijFGomRMoGSvmN
-draawomNv/iaCXqeh2Ok51Sl1siaWKqQWlqhXJoFU4pr7Ck67nlWKgqlZ2oFaQolUZo/5Bih+hmk
-/IkoIfQHc8pUFKSXbBiSFXmgZcoedQoGf7qeWRKngrCkadekemqjfPokx+mlakilqQCp/mEoqSkq
-pJWaoSGKqdXYp5tqoiDhqdr4pqFqqi1KqqppqabAqbCoqlrpkq3aqK86jbW5AYlqWqiKDCi6qqCa
-q7Q1B4tqXR3wq4VAqydqq2aJq8bqqm6QrGCKWo4KlMF6DMN6q6w6rbIqpbBqgHqTrQ+6rdQDpJ+6
-p+C6rObqA9baNcy6behaDN0ard/arqKaBvGaRJzgrKmqrsTKrvo6V++aA/3KQwebBgArrNCam9Ja
-sPtKBgmLAvMqkfVKDPcKsfkqscdKseNqkCtwsfeZscOwsc4ZsR4bPgsbAxU7si0bBg3LrQ+bsh27
-sr4asy3wstojCTObrjQ6qU+Ks/7q/gU8yzw6uwU/a681m50qS7Q52wVH6wIkuwZLq7FNS57FCrVZ
-lLTFqIG92p4jdaczmqfrSqlcq7BoGrLAeZ2KcLUnm7XvubVpW7RVMLVsCqxk+6NBe7ZDW7cqULUu
-y7Yz2ZRe+wRwKwwo67Q3C7jlWjeEq6HNIl4mq7hy66Z067gWe7gwpYOSiZWPWrnBsLhaS7CaG7ic
-e5J4manMCQiJO7qXW1dPe7pfygR4O7l98LoFEbuqNbu0W7tJcLutC3Wiu7sC662Z+7swG7yRq5w1
-tXV7y6THi6/Jq7zLawTCi3vwWLy/QLpza7rWS7U6m73e8ZHce5e8O3CNG76bOwTk/otdJRu9kTq9
-HFu97Iu0M9O8bfkEgvsq54ua9Guz9nu/+Auv+tuRUtC/SqC73Zu+Lbm+BIy6PfC+h6Sk/8sXiWmo
-EQy/OkDBdMQGDIy+Acy4A7zBwHOeHowbahDCANy3A4u2JnybN5DCSqDAQcDCGGyZGhzDTlUDNNwa
-qQuB18iX2Yi84MvDbisDP5wsQSyOV0rEWYrEFQwDSzwWTVyYlEmoGTyhJCnFCOguB1yd3HDFpXqY
-WqzDXIygXly+nhiZWNwFNmwDOOy9mHvEa0yWOfiJn/sFcTwDc+zAT3nHQAyFnvvG90DGzkuIBWq2
-L/y3gqy9cwiIXZiPfIzIYryP/mUrkml8qI8snl/LiLpIrmrQx0IsplBMpp38F+NRxUhBBX88wqUL
-w6nMxq8Uxkv5BqS8x4MqlJrspF08y897j7zqeWuQy6ybxbxcqJsMzFEQm6xcyU7wyi5sxLLMzFkV
-UbacQnZgzG2ryHjay0L7y9b8wT61umXsJ6krzYxMzY48zlNMkOYcq9t8uOoMzn4rzu6swpnHlgi8
-B9x8y5jMt+tMvXaczz2MiPx8yf4cs/WszL6sxgatyjiZ0ADdB//MqAEtvdNM0NUc0eSMhmHbJu/a
-0Fv80Jzs0T8wPT1B0do8CNxM0mhs0ih9BTMCPiwNnoWQyzAtmjs801RQJPBx/tMzZSdcutNFzNHt
-7NNHwCgtPMm6zAvcadRRrNSQ+2lf0ZnHnNPGKdWoTNVSMDGoidXnTNQ0wNWu6dVfDU69INbyvAgX
-a9bEidZOgDioGdKOwKxw7aFybbvHFY2tmAiJmtcruNdNgJyl7NbVJdh+Sdh8Pcw4yiwGMAGRbQCU
-jQGRnQKXvQWPfcF0LLsQzNg+XIIgiiyVLQGUfdmZTQGpbQKr3cpPbcqhedT1W9CgjbDhqKBsktmT
-XdoHkNqtXdqnLdm7fdqVTdy7PcaGPMSxPdW1zbzD/GnHPNmm3duSXd0XIN3TTd3ajdoVwN1iIJ+K
-PZrNjQQS9Z1wIt3GPd28/m0B2L3d2e3dxJ3dY2DenA3IcTnezg3SUdvNwu3b1d3aqt3b8P3e6m3d
-AH7IIpvR87vRs93R+D3D48qbfbLaup3e7G3avD3g1G3c7W0GEl7fsPy9Dv7gof3c7prIolCa4d3T
-JO6+kQuYssPhgL0WK77MLU4ED7mWQ40KOg6oCt6pIV7HI37jg2vi50Q+SVoGxIjR3pzJDh3OEE3k
-tm3kR94RSa7k0VjjMi3l+Uvl5fqMV04GFaTlUH7SXL6FklyH/hrmZ+ALZH7PUX7mJa7fa2Iidn7n
-eJ7ner7nJgLiDC7AtC3neezG9wuXG2jmgr6KXh7Bhv5DiT4D1qqvja6d/o/+h0K9spPuu5UujXTO
-w5n+2ZsOjotOwJ9ewqGOi2ArxaUe6Keu6J0ew6s+5K3u6sZIjdYb60k962h+6R6L6/is64uY5myt
-vL4e58Ae7LwuscWO6Me+XclesMve7EqczUQb7dJOxdSOs9Z+7S4Q6e267dzexk5N6m3q2aYe7uVc
-yIVe7r0L6ugek/FM7OyuvudurAUgAfd+AAWw7z+Q7yfg79806utuk3F9uvyu7/qe7wCvAwtPAg3/
-UdmO6fP+wPVuJf5+7/uu8BXw8BmP8QrP7x0/AR0/8gl/8CKf8fhu8hpf8h4P8iHfuXpM7gAw8wBQ
-8zZ/8zif8zrf2e1e/vEWj/AIv/L4fgEXD/QXX/RFL/JAv/RLr/JDb/Qpr/QmD/ECz746f/VYj/U8
-T++sjigYz/Jfn/AYsPBC7/Rkj/JJ//Ri//Qr//FKz/JU/+omnPV0X/dbT/FdXyco//ZCbwEHH/Z/
-//drb/Z9H/htz/Ypr/Fp7+zx/rt1//hXf/eB7LhkP/Qk7/eCn/hwr/kjf/lBv/d7v/mKj/ahn+4x
-P/CQn/o5zNM2jtIPnwGvvwPeDq6qX/uSf99I3PkeEPtE7+JVH761r/q3f+g+zft+7/tyv8HBn/rD
-7+jvLurJz+jL//jNT+nPb/qEbvXTb/f2fegP8v3gH/7iP/7kX/7m/n/+6D/707r93K8bnPH+8B//
-8j//9F//9n//+E//oez47J/1SmHJEHDkpNVenPXm3X8wFEeyNM8RCFa2BVA4lme6tm8g13e+9/lW
-UDgkFgOvW1K5ZDadT6hSVURGrVdsdvnjdntGcHhY1ZbNZ3Ra3ZkSyWt4XF7z1rtivNi+5/f9f8BA
-wUHCQsNDxETFHaO3uUfISDa7vErLS8xMzU3OTr1Az1DRUdJS0yBHSdXVyL3TV9hY2dmjRdtb3NxB
-2iNW3985XeFh4mLjY+Rk5WUeYOdn6Gjpaepq62vsbO1t7m7vb/Bw8XHycvNz9HT1dfZ293f4ePl5
-+nr7e/x8/X3+G37/f4ABBQ4kWNDgQYQJFS5k2NDhQ4gRJdKLAAA7
diff --git a/Documentation/DocBook/media/dvb/.gitignore b/Documentation/DocBook/media/dvb/.gitignore
deleted file mode 100644 (file)
index d7ec32e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!*.xml
diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml
deleted file mode 100644 (file)
index ea56743..0000000
+++ /dev/null
@@ -1,1314 +0,0 @@
-<title>DVB Audio Device</title>
-<para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
-can be accessed through <constant>/dev/dvb/adapter?/audio?</constant>. Data types and and
-ioctl definitions can be accessed by including <constant>linux/dvb/audio.h</constant> in your
-application.
-</para>
-<para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
-the omission of the audio and video device.
-</para>
-<para>
-These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
-of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
-have been created to replace that functionality.</para>
-
-<section id="audio_data_types">
-<title>Audio Data Types</title>
-<para>This section describes the structures, data types and defines used when talking to the
-audio device.
-</para>
-
-<section id="audio-stream-source-t">
-<title>audio_stream_source_t</title>
-<para>The audio stream source is set through the AUDIO_SELECT_SOURCE call and can take
-the following values, depending on whether we are replaying from an internal (demux) or
-external (user write) source.
-</para>
-<programlisting>
-typedef enum {
-       AUDIO_SOURCE_DEMUX,
-       AUDIO_SOURCE_MEMORY
-} audio_stream_source_t;
-</programlisting>
-<para>AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
-DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY
-is selected the stream comes from the application through the <constant>write()</constant> system
-call.
-</para>
-
-</section>
-<section id="audio-play-state-t">
-<title>audio_play_state_t</title>
-<para>The following values can be returned by the AUDIO_GET_STATUS call representing the
-state of audio playback.
-</para>
-<programlisting>
-typedef enum {
-       AUDIO_STOPPED,
-       AUDIO_PLAYING,
-       AUDIO_PAUSED
-} audio_play_state_t;
-</programlisting>
-
-</section>
-<section id="audio-channel-select-t">
-<title>audio_channel_select_t</title>
-<para>The audio channel selected via AUDIO_CHANNEL_SELECT is determined by the
-following values.
-</para>
-<programlisting>
-typedef enum {
-       AUDIO_STEREO,
-       AUDIO_MONO_LEFT,
-       AUDIO_MONO_RIGHT,
-       AUDIO_MONO,
-       AUDIO_STEREO_SWAPPED
-} audio_channel_select_t;
-</programlisting>
-
-</section>
-<section id="audio-status">
-<title>struct audio_status</title>
-<para>The AUDIO_GET_STATUS call returns the following structure informing about various
-states of the playback operation.
-</para>
-<programlisting>
-typedef struct audio_status {
-       boolean AV_sync_state;
-       boolean mute_state;
-       audio_play_state_t play_state;
-       audio_stream_source_t stream_source;
-       audio_channel_select_t channel_select;
-       boolean bypass_mode;
-       audio_mixer_t mixer_state;
-} audio_status_t;
-</programlisting>
-
-</section>
-<section id="audio-mixer">
-<title>struct audio_mixer</title>
-<para>The following structure is used by the AUDIO_SET_MIXER call to set the audio
-volume.
-</para>
-<programlisting>
-typedef struct audio_mixer {
-       unsigned int volume_left;
-       unsigned int volume_right;
-} audio_mixer_t;
-</programlisting>
-
-</section>
-<section id="audio_encodings">
-<title>audio encodings</title>
-<para>A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the following
-bits set according to the hardwares capabilities.
-</para>
-<programlisting>
- #define AUDIO_CAP_DTS    1
- #define AUDIO_CAP_LPCM   2
- #define AUDIO_CAP_MP1    4
- #define AUDIO_CAP_MP2    8
- #define AUDIO_CAP_MP3   16
- #define AUDIO_CAP_AAC   32
- #define AUDIO_CAP_OGG   64
- #define AUDIO_CAP_SDDS 128
- #define AUDIO_CAP_AC3  256
-</programlisting>
-
-</section>
-<section id="audio-karaoke">
-<title>struct audio_karaoke</title>
-<para>The ioctl AUDIO_SET_KARAOKE uses the following format:
-</para>
-<programlisting>
-typedef
-struct audio_karaoke {
-       int vocal1;
-       int vocal2;
-       int melody;
-} audio_karaoke_t;
-</programlisting>
-<para>If Vocal1 or Vocal2 are non-zero, they get mixed into left and right t at 70% each. If both,
-Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and Vocal2 into the
-right channel at 100% each. Ff Melody is non-zero, the melody channel gets mixed into left
-and right.
-</para>
-
-</section>
-<section id="audio-attributes-t">
-<title>audio attributes</title>
-<para>The following attributes can be set by a call to AUDIO_SET_ATTRIBUTES:
-</para>
-<programlisting>
- typedef uint16_t audio_attributes_t;
- /&#x22C6;   bits: descr. &#x22C6;/
- /&#x22C6;   15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, &#x22C6;/
- /&#x22C6;   12    multichannel extension &#x22C6;/
- /&#x22C6;   11-10 audio type (0=not spec, 1=language included) &#x22C6;/
- /&#x22C6;    9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) &#x22C6;/
- /&#x22C6;    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  &#x22C6;/
- /&#x22C6;    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) &#x22C6;/
- /&#x22C6;    2- 0 number of audio channels (n+1 channels) &#x22C6;/
-</programlisting>
- </section></section>
-<section id="audio_function_calls">
-<title>Audio Function Calls</title>
-
-
-<section id="audio_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named audio device (e.g. /dev/dvb/adapter0/audio0)
- for subsequent use. When an open() call has succeeded, the device will be ready
- for use. The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the Audio Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an error
- code will be returned. If the Audio Device is opened in O_RDONLY mode, the
- only ioctl call that can be used is AUDIO_GET_STATUS. All other call will
- return with an error code.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific audio device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="audio_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened audio device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="audio_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call can only be used if AUDIO_SOURCE_MEMORY is selected
- in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in
- PES format. If O_NONBLOCK is not specified the function will block until
- buffer space is available. The amount of data to be transferred is implied by
- count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the PES data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode AUDIO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>Attempted to write more data than the internal buffer can
- hold.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="AUDIO_STOP"
-role="subsection"><title>AUDIO_STOP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to stop playing the current stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_STOP);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_STOP for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_PLAY"
-role="subsection"><title>AUDIO_PLAY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to start playing an audio stream from the
- selected source.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_PLAY);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_PLAY for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_PAUSE"
-role="subsection"><title>AUDIO_PAUSE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call suspends the audio stream being played. Decoding and playing
- are paused. It is then possible to restart again decoding and playing process of
- the audio stream using AUDIO_CONTINUE command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>If AUDIO_SOURCE_MEMORY is selected in the ioctl call
- AUDIO_SELECT_SOURCE, the DVB-subsystem will not decode (consume)
- any more data until the ioctl call AUDIO_CONTINUE or AUDIO_PLAY is
- performed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_PAUSE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_PAUSE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_CONTINUE"
-role="subsection"><title>AUDIO_CONTINUE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl restarts the decoding and playing process previously paused
-with AUDIO_PAUSE command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>It only works if the stream were previously stopped with AUDIO_PAUSE</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_CONTINUE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_CONTINUE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SELECT_SOURCE"
-role="subsection"><title>AUDIO_SELECT_SOURCE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call informs the audio device which source shall be used
- for the input data. The possible sources are demux or memory. If
- AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device
- through the write command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SELECT_SOURCE,
- audio_stream_source_t source);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SELECT_SOURCE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_stream_source_t
- source</para>
-</entry><entry
- align="char">
-<para>Indicates the source that shall be used for the Audio
- stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_MUTE"
-role="subsection"><title>AUDIO_SET_MUTE</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-&VIDIOC-DECODER-CMD; with the <constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant> flag instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the audio device to mute the stream that is currently being
- played.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_MUTE,
- boolean state);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_MUTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean state</para>
-</entry><entry
- align="char">
-<para>Indicates if audio device shall mute or not.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE Audio Mute</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE Audio Un-mute</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_AV_SYNC"
-role="subsection"><title>AUDIO_SET_AV_SYNC</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to turn ON or OFF A/V synchronization.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_AV_SYNC,
- boolean state);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_AV_SYNC for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean state</para>
-</entry><entry
- align="char">
-<para>Tells the DVB subsystem if A/V synchronization shall be
- ON or OFF.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE AV-sync ON</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE AV-sync OFF</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_BYPASS_MODE"
-role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to bypass the Audio decoder and forward
- the stream without decoding. This mode shall be used if streams that can&#8217;t be
- handled by the DVB system shall be decoded. Dolby DigitalTM streams are
- automatically forwarded by the DVB subsystem if the hardware can handle it.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_SET_BYPASS_MODE, boolean mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_BYPASS_MODE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean mode</para>
-</entry><entry
- align="char">
-<para>Enables or disables the decoding of the current Audio
- stream in the DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE Bypass is disabled</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE Bypass is enabled</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_CHANNEL_SELECT"
-role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-<constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant> control instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_CHANNEL_SELECT, audio_channel_select_t);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_CHANNEL_SELECT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_channel_select_t
- ch</para>
-</entry><entry
- align="char">
-<para>Select the output format of the audio (mono left/right,
- stereo).</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_BILINGUAL_CHANNEL_SELECT"
-role="subsection"><title>AUDIO_BILINGUAL_CHANNEL_SELECT</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. It has been replaced by
-the V4L2 <constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant> control
-for MPEG decoders controlled through V4L2.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to select the requested channel for bilingual streams if possible.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_channel_select_t
-ch</para>
-</entry><entry
- align="char">
-<para>Select the output format of the audio (mono left/right,
- stereo).</para>
-</entry>
- </row>
-</tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_GET_PTS"
-role="subsection"><title>AUDIO_GET_PTS</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. If you need this functionality,
-then please contact the linux-media mailing list (&v4l-ml;).</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to return the current PTS timestamp.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_GET_PTS, __u64 *pts);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_GET_PTS for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u64 *pts
-</para>
-</entry><entry
- align="char">
-<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
-</para>
-<para>
-The PTS should belong to the currently played
-frame if possible, but may also be a value close to it
-like the PTS of the last decoded frame or the last PTS
-extracted by the PES parser.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_GET_STATUS"
-role="subsection"><title>AUDIO_GET_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to return the current state of the Audio
- Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_GET_STATUS,
- struct audio_status &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_GET_STATUS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct audio_status
- *status</para>
-</entry><entry
- align="char">
-<para>Returns the current state of Audio Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_GET_CAPABILITIES"
-role="subsection"><title>AUDIO_GET_CAPABILITIES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to tell us about the decoding capabilities
- of the audio hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_GET_CAPABILITIES, unsigned int &#x22C6;cap);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_GET_CAPABILITIES for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned int *cap</para>
-</entry><entry
- align="char">
-<para>Returns a bit array of supported sound formats.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_CLEAR_BUFFER"
-role="subsection"><title>AUDIO_CLEAR_BUFFER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to clear all software and hardware buffers
- of the audio decoder device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_CLEAR_BUFFER);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_CLEAR_BUFFER for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_ID"
-role="subsection"><title>AUDIO_SET_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl selects which sub-stream is to be decoded if a program or system
- stream is sent to the video device. If no audio stream type is set the id has to be
- in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for AC3 and in [0xA0,0xA7]
- for LPCM. More specifications may follow for other stream types. If the stream
- type is set the id just specifies the substream id of the audio stream and only
- the first 5 bits are recognized.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>audio sub-stream id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_MIXER"
-role="subsection"><title>AUDIO_SET_MIXER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl lets you adjust the mixer settings of the audio decoder.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_MIXER,
- audio_mixer_t &#x22C6;mix);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_mixer_t *mix</para>
-</entry><entry
- align="char">
-<para>mixer settings.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="AUDIO_SET_STREAMTYPE"
-role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl tells the driver which kind of audio stream to expect. This is useful
- if the stream offers several audio sub-streams like LPCM and AC3.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_STREAMTYPE,
- int type);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_STREAMTYPE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int type</para>
-</entry><entry
- align="char">
-<para>stream type</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>type is not a valid or supported stream type.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="AUDIO_SET_EXT_ID"
-role="subsection"><title>AUDIO_SET_EXT_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl can be used to set the extension id for MPEG streams in DVD
- playback. Only the first 3 bits are recognized.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_EXT_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_EXT_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>audio sub_stream_id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>id is not a valid id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="AUDIO_SET_ATTRIBUTES"
-role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is intended for DVD playback and allows you to set certain
- information about the audio stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_ATTRIBUTES,
- audio_attributes_t attr );</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ATTRIBUTES for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_attributes_t
- attr</para>
-</entry><entry
- align="char">
-<para>audio attributes according to section ??</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>attr is not a valid or supported attribute setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="AUDIO_SET_KARAOKE"
-role="subsection"><title>AUDIO_SET_KARAOKE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl allows one to set the mixer settings for a karaoke DVD.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_KARAOKE,
- audio_karaoke_t &#x22C6;karaoke);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_KARAOKE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_karaoke_t
- *karaoke</para>
-</entry><entry
- align="char">
-<para>karaoke settings according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>karaoke is not a valid or supported karaoke setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section>
-</section>
diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml
deleted file mode 100644 (file)
index d0b07e7..0000000
+++ /dev/null
@@ -1,582 +0,0 @@
-<title>DVB CA Device</title>
-<para>The DVB CA device controls the conditional access hardware. It can be accessed through
-<constant>/dev/dvb/adapter?/ca?</constant>. Data types and and ioctl definitions can be accessed by
-including <constant>linux/dvb/ca.h</constant> in your application.
-</para>
-
-<section id="ca_data_types">
-<title>CA Data Types</title>
-
-
-<section id="ca-slot-info">
-<title>ca_slot_info_t</title>
- <programlisting>
-typedef struct ca_slot_info {
-       int num;               /&#x22C6; slot number &#x22C6;/
-
-       int type;              /&#x22C6; CA interface this slot supports &#x22C6;/
-#define CA_CI            1     /&#x22C6; CI high level interface &#x22C6;/
-#define CA_CI_LINK       2     /&#x22C6; CI link layer level interface &#x22C6;/
-#define CA_CI_PHYS       4     /&#x22C6; CI physical layer level interface &#x22C6;/
-#define CA_DESCR         8     /&#x22C6; built-in descrambler &#x22C6;/
-#define CA_SC          128     /&#x22C6; simple smart card interface &#x22C6;/
-
-       unsigned int flags;
-#define CA_CI_MODULE_PRESENT 1 /&#x22C6; module (or card) inserted &#x22C6;/
-#define CA_CI_MODULE_READY   2
-} ca_slot_info_t;
-</programlisting>
-
-</section>
-<section id="ca-descr-info">
-<title>ca_descr_info_t</title>
-<programlisting>
-typedef struct ca_descr_info {
-       unsigned int num;  /&#x22C6; number of available descramblers (keys) &#x22C6;/
-       unsigned int type; /&#x22C6; type of supported scrambling system &#x22C6;/
-#define CA_ECD           1
-#define CA_NDS           2
-#define CA_DSS           4
-} ca_descr_info_t;
-</programlisting>
-
-</section>
-<section id="ca-caps">
-<title>ca_caps_t</title>
-<programlisting>
-typedef struct ca_caps {
-       unsigned int slot_num;  /&#x22C6; total number of CA card and module slots &#x22C6;/
-       unsigned int slot_type; /&#x22C6; OR of all supported types &#x22C6;/
-       unsigned int descr_num; /&#x22C6; total number of descrambler slots (keys) &#x22C6;/
-       unsigned int descr_type;/&#x22C6; OR of all supported types &#x22C6;/
- } ca_cap_t;
-</programlisting>
-
-</section>
-<section id="ca-msg">
-<title>ca_msg_t</title>
-<programlisting>
-/&#x22C6; a message to/from a CI-CAM &#x22C6;/
-typedef struct ca_msg {
-       unsigned int index;
-       unsigned int type;
-       unsigned int length;
-       unsigned char msg[256];
-} ca_msg_t;
-</programlisting>
-
-</section>
-<section id="ca-descr">
-<title>ca_descr_t</title>
-<programlisting>
-typedef struct ca_descr {
-       unsigned int index;
-       unsigned int parity;
-       unsigned char cw[8];
-} ca_descr_t;
-</programlisting>
-</section>
-
-<section id="ca-pid">
-<title>ca-pid</title>
-<programlisting>
-typedef struct ca_pid {
-       unsigned int pid;
-       int index;              /&#x22C6; -1 == disable&#x22C6;/
-} ca_pid_t;
-</programlisting>
-</section></section>
-
-<section id="ca_function_calls">
-<title>CA Function Calls</title>
-
-
-<section id="ca_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named ca device (e.g. /dev/ost/ca) for subsequent use.</para>
-<para>When an open() call has succeeded, the device will be ready for use.
- The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the CA Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an error
- code will be returned.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="ca_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened audio device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section>
-
-<section id="CA_RESET"
-role="subsection"><title>CA_RESET</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_RESET);
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_RESET for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_GET_CAP"
-role="subsection"><title>CA_GET_CAP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_GET_CAP,
- ca_caps_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_GET_CAP for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_caps_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_GET_SLOT_INFO"
-role="subsection"><title>CA_GET_SLOT_INFO</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_GET_SLOT_INFO,
- ca_slot_info_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_GET_SLOT_INFO for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_slot_info_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_GET_DESCR_INFO"
-role="subsection"><title>CA_GET_DESCR_INFO</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_GET_DESCR_INFO,
- ca_descr_info_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_GET_DESCR_INFO for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_descr_info_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_GET_MSG"
-role="subsection"><title>CA_GET_MSG</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_GET_MSG,
- ca_msg_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_GET_MSG for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_msg_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_SEND_MSG"
-role="subsection"><title>CA_SEND_MSG</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_SEND_MSG,
- ca_msg_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_SEND_MSG for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_msg_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_SET_DESCR"
-role="subsection"><title>CA_SET_DESCR</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_SET_DESCR,
- ca_descr_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_SET_DESCR for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_descr_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="CA_SET_PID"
-role="subsection"><title>CA_SET_PID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = CA_SET_PID,
- ca_pid_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals CA_SET_PID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ca_pid_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-</section>
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
deleted file mode 100644 (file)
index 34f2fb1..0000000
+++ /dev/null
@@ -1,1162 +0,0 @@
-<title>DVB Demux Device</title>
-
-<para>The DVB demux device controls the filters of the DVB hardware/software. It can be
-accessed through <constant>/dev/adapter?/demux?</constant>. Data types and and ioctl definitions can be
-accessed by including <constant>linux/dvb/dmx.h</constant> in your application.
-</para>
-<section id="dmx_types">
-<title>Demux Data Types</title>
-
-<section id="dmx-output-t">
-<title>Output for the demux</title>
-
-<table pgwide="1" frame="none" id="dmx-output">
-    <title>enum dmx_output</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-               <entry align="char" id="DMX-OUT-DECODER">DMX_OUT_DECODER</entry>
-               <entry>Streaming directly to decoder.</entry>
-       </row><row>
-               <entry align="char" id="DMX-OUT-TAP">DMX_OUT_TAP</entry>
-               <entry>Output going to a memory buffer (to be retrieved via the
-                   read command). Delivers the stream output to the demux
-                   device on which the ioctl is called.</entry>
-       </row><row>
-               <entry align="char" id="DMX-OUT-TS-TAP">DMX_OUT_TS_TAP</entry>
-               <entry>Output multiplexed into a new TS (to be retrieved by
-                   reading from the logical DVR device). Routes output to the
-                   logical DVR device <constant>/dev/dvb/adapter?/dvr?</constant>,
-                   which delivers a TS multiplexed from all filters for which
-                   <constant>DMX_OUT_TS_TAP</constant> was specified.</entry>
-       </row><row>
-               <entry align="char" id="DMX-OUT-TSDEMUX-TAP">DMX_OUT_TSDEMUX_TAP</entry>
-               <entry>Like &DMX-OUT-TS-TAP; but retrieved from the DMX
-                   device.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-</section>
-
-<section id="dmx-input-t">
-<title>dmx_input_t</title>
-<programlisting>
-typedef enum
-{
-       DMX_IN_FRONTEND, /&#x22C6; Input from a front-end device.  &#x22C6;/
-       DMX_IN_DVR       /&#x22C6; Input from the logical DVR device.  &#x22C6;/
-} dmx_input_t;
-</programlisting>
-</section>
-
-<section id="dmx-pes-type-t">
-<title>dmx_pes_type_t</title>
-<programlisting>
-typedef enum
-{
-       DMX_PES_AUDIO0,
-       DMX_PES_VIDEO0,
-       DMX_PES_TELETEXT0,
-       DMX_PES_SUBTITLE0,
-       DMX_PES_PCR0,
-
-       DMX_PES_AUDIO1,
-       DMX_PES_VIDEO1,
-       DMX_PES_TELETEXT1,
-       DMX_PES_SUBTITLE1,
-       DMX_PES_PCR1,
-
-       DMX_PES_AUDIO2,
-       DMX_PES_VIDEO2,
-       DMX_PES_TELETEXT2,
-       DMX_PES_SUBTITLE2,
-       DMX_PES_PCR2,
-
-       DMX_PES_AUDIO3,
-       DMX_PES_VIDEO3,
-       DMX_PES_TELETEXT3,
-       DMX_PES_SUBTITLE3,
-       DMX_PES_PCR3,
-
-       DMX_PES_OTHER
-} dmx_pes_type_t;
-</programlisting>
-</section>
-
-<section id="dmx-filter">
-<title>struct dmx_filter</title>
- <programlisting>
- typedef struct dmx_filter
-{
-       __u8  filter[DMX_FILTER_SIZE];
-       __u8  mask[DMX_FILTER_SIZE];
-       __u8  mode[DMX_FILTER_SIZE];
-} dmx_filter_t;
-</programlisting>
-</section>
-
-<section id="dmx-sct-filter-params">
-<title>struct dmx_sct_filter_params</title>
-<programlisting>
-struct dmx_sct_filter_params
-{
-       __u16          pid;
-       dmx_filter_t   filter;
-       __u32          timeout;
-       __u32          flags;
-#define DMX_CHECK_CRC       1
-#define DMX_ONESHOT         2
-#define DMX_IMMEDIATE_START 4
-#define DMX_KERNEL_CLIENT   0x8000
-};
-</programlisting>
-</section>
-
-<section id="dmx-pes-filter-params">
-<title>struct dmx_pes_filter_params</title>
-<programlisting>
-struct dmx_pes_filter_params
-{
-       __u16          pid;
-       dmx_input_t    input;
-       dmx_output_t   output;
-       dmx_pes_type_t pes_type;
-       __u32          flags;
-};
-</programlisting>
-</section>
-
-<section id="dmx-event">
-<title>struct dmx_event</title>
- <programlisting>
- struct dmx_event
- {
-        dmx_event_t          event;
-        time_t               timeStamp;
-        union
-        {
-                dmx_scrambling_status_t scrambling;
-        } u;
- };
-</programlisting>
-</section>
-
-<section id="dmx-stc">
-<title>struct dmx_stc</title>
-<programlisting>
-struct dmx_stc {
-       unsigned int num;       /&#x22C6; input : which STC? 0..N &#x22C6;/
-       unsigned int base;      /&#x22C6; output: divisor for stc to get 90 kHz clock &#x22C6;/
-       __u64 stc;              /&#x22C6; output: stc in 'base'&#x22C6;90 kHz units &#x22C6;/
-};
-</programlisting>
-</section>
-
-<section id="dmx-caps">
-<title>struct dmx_caps</title>
-<programlisting>
- typedef struct dmx_caps {
-       __u32 caps;
-       int num_decoders;
-} dmx_caps_t;
-</programlisting>
-</section>
-
-<section id="dmx-source-t">
-<title>enum dmx_source_t</title>
-<programlisting>
-typedef enum {
-       DMX_SOURCE_FRONT0 = 0,
-       DMX_SOURCE_FRONT1,
-       DMX_SOURCE_FRONT2,
-       DMX_SOURCE_FRONT3,
-       DMX_SOURCE_DVR0   = 16,
-       DMX_SOURCE_DVR1,
-       DMX_SOURCE_DVR2,
-       DMX_SOURCE_DVR3
-} dmx_source_t;
-</programlisting>
-</section>
-
-</section>
-<section id="dmx_fcalls">
-<title>Demux Function Calls</title>
-
-<section id="dmx_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call, used with a device name of /dev/dvb/adapter0/demux0,
- allocates a new filter and returns a handle which can be used for subsequent
- control of that filter. This call has to be made for each filter to be used, i.e. every
- returned file descriptor is a reference to a single filter. /dev/dvb/adapter0/dvr0
- is a logical device to be used for retrieving Transport Streams for digital
- video recording. When reading from this device a transport stream containing
- the packets from all PES filters set in the corresponding demux device
- (/dev/dvb/adapter0/demux0) having the output set to DMX_OUT_TS_TAP. A
- recorded Transport Stream is replayed by writing to this device. </para>
-<para>The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of demux device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EMFILE</para>
-</entry><entry
- align="char">
-<para>&#8220;Too many open files&#8221;, i.e. no more filters available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>The driver failed to allocate enough memory.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call deactivates and deallocates a filter that was previously
- allocated via the open() call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fread">
-<title>read()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call returns filtered data, which might be section or PES data. The
- filtered data is transferred from the driver&#8217;s internal circular buffer to buf. The
- maximum amount of data to be transferred is implied by count.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>When returning section data the driver always tries to return a complete single
- section (even though buf would provide buffer space for more data). If the size
- of the buffer is smaller than the section as much as possible will be returned,
- and the remaining data will be provided in subsequent calls.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The size of the internal buffer is 2 * 4096 bytes (the size of two maximum
- sized sections) by default. The size of this buffer may be changed by using the
- DMX_SET_BUFFER_SIZE function. If the buffer is not large enough, or if
- the read operations are not performed fast enough, this may result in a buffer
- overflow error. In this case EOVERFLOW will be returned, and the circular
- buffer will be emptied. This call is blocking if there is no data to return, i.e. the
- process will be put to sleep waiting for data, unless the O_NONBLOCK flag
- is specified.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Note that in order to be able to read, the filtering process has to be started
- by defining either a section or a PES filter by means of the ioctl functions,
- and then starting the filtering process via the DMX_START ioctl function
- or by setting the DMX_IMMEDIATE_START flag. If the reading is done
- from a logical DVR demux device, the data will constitute a Transport Stream
- including the packets from all PES filters in the corresponding demux device
- /dev/dvb/adapter0/demux0 having the output set to DMX_OUT_TS_TAP.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t read(int fd, void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer to be used for returned filtered data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>No data to return and O_NONBLOCK was specified.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ECRC</para>
-</entry><entry
- align="char">
-<para>Last section had a CRC error - no data returned. The
- buffer is flushed.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>The filtered data was not read from the buffer in due
- time, resulting in non-read data being lost. The buffer is
- flushed.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ETIMEDOUT</para>
-</entry><entry
- align="char">
-<para>The section was not loaded within the stated timeout
- period. See ioctl DMX_SET_FILTER for how to set a
- timeout.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>The driver failed to write to the callers buffer due to an
- invalid *buf pointer.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call is only provided by the logical device /dev/dvb/adapter0/dvr0,
- associated with the physical demux device that provides the actual DVR
- functionality. It is used for replay of a digitally recorded Transport Stream.
- Matching filters have to be defined in the corresponding physical demux
- device, /dev/dvb/adapter0/demux0. The amount of data to be transferred is
- implied by count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>ssize_t write(int fd, const void &#x22C6;buf, size_t
- count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the Transport Stream.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>No data was written. This
- might happen if O_NONBLOCK was specified and there
- is no more buffer space available (if O_NONBLOCK is
- not specified the function will block until buffer space is
- available).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. The corresponding demux device is setup to
- receive data from the front- end. Make sure that these
- filters are stopped and that the filters with input set to
- DMX_IN_DVR are started.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="DMX_START">
-<title>DMX_START</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to start the actual filtering operation defined via the ioctl
- calls DMX_SET_FILTER or DMX_SET_PES_FILTER.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_START);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_START for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument, i.e. no filtering parameters provided via
- the DMX_SET_FILTER or DMX_SET_PES_FILTER
- functions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. There are active filters filtering data from
- another input source. Make sure that these filters are
- stopped before starting this filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="DMX_STOP">
-<title>DMX_STOP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to stop the actual filtering operation defined via the
- ioctl calls DMX_SET_FILTER or DMX_SET_PES_FILTER and started via
- the DMX_START command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_STOP);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_STOP for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_SET_FILTER">
-<title>DMX_SET_FILTER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets up a filter according to the filter and mask parameters
- provided. A timeout may be defined stating number of seconds to wait for a
- section to be loaded. A value of 0 means that no timeout should be applied.
- Finally there is a flag field where it is possible to state whether a section should
- be CRC-checked, whether the filter should be a &#8221;one-shot&#8221; filter, i.e. if the
- filtering operation should be stopped after the first section is received, and
- whether the filtering operation should be started immediately (without waiting
- for a DMX_START ioctl call). If a filter was previously set-up, this filter will
- be canceled, and the receive buffer will be flushed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_SET_FILTER,
- struct dmx_sct_filter_params &#x22C6;params);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_FILTER for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dmx_sct_filter_params
- *params</para>
-</entry><entry
- align="char">
-<para>Pointer to structure containing filter parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_SET_PES_FILTER">
-<title>DMX_SET_PES_FILTER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets up a PES filter according to the parameters provided. By a
- PES filter is meant a filter that is based just on the packet identifier (PID), i.e.
- no PES header or payload filtering capability is supported.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The transport stream destination for the filtered output may be set. Also the
- PES type may be stated in order to be able to e.g. direct a video stream directly
- to the video decoder. Finally there is a flag field where it is possible to state
- whether the filtering operation should be started immediately (without waiting
- for a DMX_START ioctl call). If a filter was previously set-up, this filter will
- be cancelled, and the receive buffer will be flushed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_SET_PES_FILTER,
- struct dmx_pes_filter_params &#x22C6;params);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_PES_FILTER for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dmx_pes_filter_params
- *params</para>
-</entry><entry
- align="char">
-<para>Pointer to structure containing filter parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. There are active filters filtering data from
- another input source. Make sure that these filters are
- stopped before starting this filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="DMX_SET_BUFFER_SIZE">
-<title>DMX_SET_BUFFER_SIZE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to set the size of the circular buffer used for filtered data.
- The default size is two maximum sized sections, i.e. if this function is not called
- a buffer size of 2 * 4096 bytes will be used.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- DMX_SET_BUFFER_SIZE, unsigned long size);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_BUFFER_SIZE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned long size</para>
-</entry><entry
- align="char">
-<para>Size of circular buffer.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_GET_EVENT">
-<title>DMX_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns an event if available. If an event is not available,
- the behavior depends on whether the device is in blocking or non-blocking
- mode. In the latter case, the call fails immediately with errno set to
- EWOULDBLOCK. In the former case, the call blocks until an event becomes
- available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The standard Linux poll() and/or select() system calls can be used with the
- device file descriptor to watch for new events. For select(), the file descriptor
- should be included in the exceptfds argument, and for poll(), POLLPRI should
- be specified as the wake-up condition. Only the latest event for each filter is
- saved.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_GET_EVENT,
- struct dmx_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_EVENT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dmx_event *ev</para>
-</entry><entry
- align="char">
-<para>Pointer to the location where the event is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="DMX_GET_STC">
-<title>DMX_GET_STC</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the current value of the system time counter (which is driven
- by a PES filter of type DMX_PES_PCR). Some hardware supports more than one
- STC, so you must specify which one by setting the num field of stc before the ioctl
- (range 0...n). The result is returned in form of a ratio with a 64 bit numerator
- and a 32 bit denominator, so the real 90kHz STC value is stc-&#x003E;stc /
- stc-&#x003E;base
- .</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_GET_STC, struct
- dmx_stc &#x22C6;stc);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_STC for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dmx_stc *stc</para>
-</entry><entry
- align="char">
-<para>Pointer to the location where the stc is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid stc number.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section>
-
-<section id="DMX_GET_PES_PIDS"
-role="subsection"><title>DMX_GET_PES_PIDS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = DMX_GET_PES_PIDS,
- __u16[5]);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_PES_PIDS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16[5]
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_GET_CAPS"
-role="subsection"><title>DMX_GET_CAPS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = DMX_GET_CAPS,
- dmx_caps_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_CAPS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_caps_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_SET_SOURCE"
-role="subsection"><title>DMX_SET_SOURCE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is undocumented. Documentation is welcome.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = DMX_SET_SOURCE,
- dmx_source_t *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_SOURCE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_source_t *
-</para>
-</entry><entry
- align="char">
-<para>Undocumented.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_ADD_PID"
-role="subsection"><title>DMX_ADD_PID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call allows to add multiple PIDs to a transport stream filter
-previously set up with DMX_SET_PES_FILTER and output equal to DMX_OUT_TSDEMUX_TAP.
-</para></entry></row><row><entry align="char"><para>
-It is used by readers of /dev/dvb/adapterX/demuxY.
-</para></entry></row><row><entry align="char"><para>
-It may be called at any time, i.e. before or after the first filter on the
-shared file descriptor was started. It makes it possible to record multiple
-services without the need to de-multiplex or re-multiplex TS packets.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = DMX_ADD_PID,
- __u16 *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_ADD_PID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 *
-</para>
-</entry><entry
- align="char">
-<para>PID number to be filtered.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-<section id="DMX_REMOVE_PID"
-role="subsection"><title>DMX_REMOVE_PID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call allows to remove a PID when multiple PIDs are set on a
-transport stream filter, e. g. a filter previously set up with output equal to
-DMX_OUT_TSDEMUX_TAP, created via either DMX_SET_PES_FILTER or DMX_ADD_PID.
-</para></entry></row><row><entry align="char"><para>
-It is used by readers of /dev/dvb/adapterX/demuxY.
-</para></entry></row><row><entry align="char"><para>
-It may be called at any time, i.e. before or after the first filter on the
-shared file descriptor was started. It makes it possible to record multiple
-services without the need to de-multiplex or re-multiplex TS packets.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = DMX_REMOVE_PID,
- __u16 *);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_REMOVE_PID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 *
-</para>
-</entry><entry
- align="char">
-<para>PID of the PES filter to be removed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-</section>
-
-
-</section>
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
deleted file mode 100644 (file)
index 8576481..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-<partinfo>
-<authorgroup>
-<author>
-<firstname>Ralph</firstname>
-<surname>Metzler</surname>
-<othername role="mi">J. K.</othername>
-<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
-</author>
-<author>
-<firstname>Marcus</firstname>
-<surname>Metzler</surname>
-<othername role="mi">O. C.</othername>
-<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
-</author>
-</authorgroup>
-<authorgroup>
-<author>
-<firstname>Mauro</firstname>
-<othername role="mi">Carvalho</othername>
-<surname>Chehab</surname>
-<affiliation><address><email>m.chehab@samsung.com</email></address></affiliation>
-<contrib>Ported document to Docbook XML.</contrib>
-</author>
-</authorgroup>
-<copyright>
-       <year>2002</year>
-       <year>2003</year>
-       <holder>Convergence GmbH</holder>
-</copyright>
-<copyright>
-       <year>2009-2015</year>
-       <holder>Mauro Carvalho Chehab</holder>
-</copyright>
-
-<revhistory>
-<!-- Put document revisions here, newest first. -->
-<revision>
-       <revnumber>2.1.0</revnumber>
-       <date>2015-05-29</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               DocBook improvements and cleanups, in order to document the
-               system calls on a more standard way and provide more description
-               about the current DVB API.
-       </revremark>
-</revision>
-<revision>
-       <revnumber>2.0.4</revnumber>
-       <date>2011-05-06</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
-       </revremark>
-</revision>
-<revision>
-       <revnumber>2.0.3</revnumber>
-       <date>2010-07-03</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               Add some frontend capabilities flags, present on kernel, but missing at the specs.
-       </revremark>
-</revision>
-<revision>
-       <revnumber>2.0.2</revnumber>
-       <date>2009-10-25</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               documents FE_SET_FRONTEND_TUNE_MODE and FE_DISHETWORK_SEND_LEGACY_CMD ioctls.
-       </revremark>
-</revision>
-<revision>
-<revnumber>2.0.1</revnumber>
-<date>2009-09-16</date>
-<authorinitials>mcc</authorinitials>
-<revremark>
-Added ISDB-T test originally written by Patrick Boettcher
-</revremark>
-</revision>
-<revision>
-<revnumber>2.0.0</revnumber>
-<date>2009-09-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Conversion from LaTex to DocBook XML. The
-       contents is the same as the original LaTex version.</revremark>
-</revision>
-<revision>
-<revnumber>1.0.0</revnumber>
-<date>2003-07-24</date>
-<authorinitials>rjkm</authorinitials>
-<revremark>Initial revision on LaTEX.</revremark>
-</revision>
-</revhistory>
-</partinfo>
-
-
-<title>LINUX DVB API</title>
-<subtitle>Version 5.10</subtitle>
-<!-- ADD THE CHAPTERS HERE -->
-  <chapter id="dvb_introdution">
-    &sub-intro;
-  </chapter>
-  <chapter id="dvb_frontend">
-    &sub-frontend;
-  </chapter>
-  <chapter id="dvb_demux">
-    &sub-demux;
-  </chapter>
-  <chapter id="dvb_ca">
-    &sub-ca;
-  </chapter>
-  <chapter id="net">
-    &sub-net;
-  </chapter>
-  <chapter id="legacy_dvb_apis">
-  <title>DVB Deprecated APIs</title>
-  <para>The APIs described here are kept only for historical reasons. There's
-      just one driver for a very legacy hardware that uses this API. No
-      modern drivers should use it. Instead, audio and video should be using
-      the V4L2 and ALSA APIs, and the pipelines should be set using the
-      Media Controller API</para>
-    <section id="dvb_video">
-       &sub-video;
-    </section>
-    <section id="dvb_audio">
-       &sub-audio;
-    </section>
-  </chapter>
-  <chapter id="dvb_examples">
-    &sub-examples;
-  </chapter>
-<!-- END OF CHAPTERS -->
-  <appendix id="audio_h">
-    <title>DVB Audio Header File</title>
-    &sub-audio-h;
-  </appendix>
-  <appendix id="ca_h">
-    <title>DVB Conditional Access Header File</title>
-    &sub-ca-h;
-  </appendix>
-  <appendix id="dmx_h">
-    <title>DVB Demux Header File</title>
-    &sub-dmx-h;
-  </appendix>
-  <appendix id="frontend_h">
-    <title>DVB Frontend Header File</title>
-    &sub-frontend-h;
-  </appendix>
-  <appendix id="net_h">
-    <title>DVB Network Header File</title>
-    &sub-net-h;
-  </appendix>
-  <appendix id="video_h">
-    <title>DVB Video Header File</title>
-    &sub-video-h;
-  </appendix>
-
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
deleted file mode 100644 (file)
index e579ae5..0000000
+++ /dev/null
@@ -1,1680 +0,0 @@
-<section id="frontend-properties">
-<title>DVB Frontend properties</title>
-<para>Tuning into a Digital TV physical channel and starting decoding it
-    requires changing a set of parameters, in order to control the
-    tuner, the demodulator, the Linear Low-noise Amplifier (LNA) and to set the
-    antenna subsystem via Satellite Equipment Control (SEC), on satellite
-    systems. The actual parameters are specific to each particular digital
-    TV standards, and may change as the digital TV specs evolves.</para>
-<para>In the past, the strategy used was to have a union with the parameters
-    needed to tune for DVB-S, DVB-C, DVB-T and ATSC delivery systems grouped
-    there. The problem is that, as the second generation standards appeared,
-    those structs were not big enough to contain the additional parameters.
-    Also, the union didn't have any space left to be expanded without breaking
-    userspace. So, the decision was to deprecate the legacy union/struct based
-    approach, in favor of a properties set approach.</para>
-
-<para>NOTE: on Linux DVB API version 3, setting a frontend were done via
-    <link linkend="dvb-frontend-parameters">struct  <constant>dvb_frontend_parameters</constant></link>.
-    This got replaced on version 5 (also called "S2API", as this API were
-    added originally_enabled to provide support for DVB-S2), because the old
-    API has a very limited support to new standards and new hardware. This
-    section describes the new and recommended way to set the frontend, with
-    suppports all digital TV delivery systems.</para>
-
-<para>Example: with the properties based approach, in order to set the tuner
-    to a DVB-C channel at 651 kHz, modulated with 256-QAM, FEC 3/4 and symbol
-    rate of 5.217 Mbauds, those properties should be sent to
-    <link linkend="FE_GET_PROPERTY"><constant>FE_SET_PROPERTY</constant></link> ioctl:</para>
-    <itemizedlist>
-       <listitem><para>&DTV-DELIVERY-SYSTEM; = SYS_DVBC_ANNEX_A</para></listitem>
-       <listitem><para>&DTV-FREQUENCY; = 651000000</para></listitem>
-       <listitem><para>&DTV-MODULATION; = QAM_256</para></listitem>
-       <listitem><para>&DTV-INVERSION; = INVERSION_AUTO</para></listitem>
-       <listitem><para>&DTV-SYMBOL-RATE; = 5217000</para></listitem>
-       <listitem><para>&DTV-INNER-FEC; = FEC_3_4</para></listitem>
-       <listitem><para>&DTV-TUNE;</para></listitem>
-    </itemizedlist>
-
-<para>The code that would do the above is:</para>
-<programlisting>
-#include &lt;stdio.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;sys/ioctl.h&gt;
-#include &lt;linux/dvb/frontend.h&gt;
-
-static struct dtv_property props[] = {
-       { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
-       { .cmd = DTV_FREQUENCY,       .u.data = 651000000 },
-       { .cmd = DTV_MODULATION,      .u.data = QAM_256 },
-       { .cmd = DTV_INVERSION,       .u.data = INVERSION_AUTO },
-       { .cmd = DTV_SYMBOL_RATE,     .u.data = 5217000 },
-       { .cmd = DTV_INNER_FEC,       .u.data = FEC_3_4 },
-       { .cmd = DTV_TUNE }
-};
-
-static struct dtv_properties dtv_prop = {
-       .num = 6, .props = props
-};
-
-int main(void)
-{
-       int fd = open("/dev/dvb/adapter0/frontend0", O_RDWR);
-
-       if (!fd) {
-           perror ("open");
-           return -1;
-       }
-       if (ioctl(fd, FE_SET_PROPERTY, &amp;dtv_prop) == -1) {
-               perror("ioctl");
-               return -1;
-       }
-       printf("Frontend set\n");
-       return 0;
-}
-</programlisting>
-
-<para>NOTE: While it is possible to directly call the Kernel code like the
-    above example, it is strongly recommended to use
-    <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
-    as it provides abstraction to work with the supported digital TV standards
-    and provides methods for usual operations like program scanning and to
-    read/write channel descriptor files.</para>
-
-<section id="dtv-stats">
-<title>struct <structname>dtv_stats</structname></title>
-<programlisting>
-struct dtv_stats {
-       __u8 scale;     /* enum fecap_scale_params type */
-       union {
-               __u64 uvalue;   /* for counters and relative scales */
-               __s64 svalue;   /* for 1/1000 dB measures */
-       };
-} __packed;
-</programlisting>
-</section>
-<section id="dtv-fe-stats">
-<title>struct <structname>dtv_fe_stats</structname></title>
-<programlisting>
-#define MAX_DTV_STATS   4
-
-struct dtv_fe_stats {
-       __u8 len;
-       &dtv-stats; stat[MAX_DTV_STATS];
-} __packed;
-</programlisting>
-</section>
-
-<section id="dtv-property">
-<title>struct <structname>dtv_property</structname></title>
-<programlisting>
-/* Reserved fields should be set to 0 */
-
-struct dtv_property {
-       __u32 cmd;
-       __u32 reserved[3];
-       union {
-               __u32 data;
-               &dtv-fe-stats; st;
-               struct {
-                       __u8 data[32];
-                       __u32 len;
-                       __u32 reserved1[3];
-                       void *reserved2;
-               } buffer;
-       } u;
-       int result;
-} __attribute__ ((packed));
-
-/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
-#define DTV_IOCTL_MAX_MSGS 64
-</programlisting>
-</section>
-<section id="dtv-properties">
-<title>struct <structname>dtv_properties</structname></title>
-<programlisting>
-struct dtv_properties {
-       __u32 num;
-       &dtv-property; *props;
-};
-</programlisting>
-</section>
-
-<section>
-       <title>Property types</title>
-<para>
-On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY and FE_SET_PROPERTY</link>,
-the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
-get/set up to 64 properties. The actual meaning of each property is described on the next sections.
-</para>
-
-<para>The available frontend property types are shown on the next section.</para>
-</section>
-
-<section id="fe_property_parameters">
-       <title>Digital TV property parameters</title>
-       <section id="DTV-UNDEFINED">
-       <title><constant>DTV_UNDEFINED</constant></title>
-       <para>Used internally. A GET/SET operation for it won't change or return anything.</para>
-       </section>
-       <section id="DTV-TUNE">
-       <title><constant>DTV_TUNE</constant></title>
-       <para>Interpret the cache of data, build either a traditional frontend tunerequest so we can pass validation in the <constant>FE_SET_FRONTEND</constant> ioctl.</para>
-       </section>
-       <section id="DTV-CLEAR">
-       <title><constant>DTV_CLEAR</constant></title>
-       <para>Reset a cache of data specific to the frontend here. This does not effect hardware.</para>
-       </section>
-       <section id="DTV-FREQUENCY">
-               <title><constant>DTV_FREQUENCY</constant></title>
-
-               <para>Central frequency of the channel.</para>
-
-               <para>Notes:</para>
-               <para>1)For satellite delivery systems, it is measured in kHz.
-                       For the other ones, it is measured in Hz.</para>
-               <para>2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
-                       E.g. a valid frequency could be 474143 kHz. The stepping is bound to the bandwidth of
-                       the channel which is 6MHz.</para>
-
-               <para>3)As in ISDB-Tsb the channel consists of only one or three segments the
-                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
-                       central frequency of the channel is expected.</para>
-       </section>
-       <section id="DTV-MODULATION">
-       <title><constant>DTV_MODULATION</constant></title>
-<para>Specifies the frontend modulation type for delivery systems that supports
-    more than one modulation type. The modulation can be one of the types
-    defined by &fe-modulation;.</para>
-
-
-<section id="fe-modulation-t">
-<title>Modulation property</title>
-
-<para>Most of the digital TV standards currently offers more than one possible
-    modulation (sometimes called as "constellation" on some standards). This
-    enum contains the values used by the Kernel. Please note that not all
-    modulations are supported by a given standard.</para>
-
-<table pgwide="1" frame="none" id="fe-modulation">
-    <title>enum fe_modulation</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="QPSK"><constant>QPSK</constant></entry>
-           <entry>QPSK modulation</entry>
-       </row><row>
-           <entry id="QAM-16"><constant>QAM_16</constant></entry>
-           <entry>16-QAM modulation</entry>
-       </row><row>
-           <entry id="QAM-32"><constant>QAM_32</constant></entry>
-           <entry>32-QAM modulation</entry>
-       </row><row>
-           <entry id="QAM-64"><constant>QAM_64</constant></entry>
-           <entry>64-QAM modulation</entry>
-       </row><row>
-           <entry id="QAM-128"><constant>QAM_128</constant></entry>
-           <entry>128-QAM modulation</entry>
-       </row><row>
-           <entry id="QAM-256"><constant>QAM_256</constant></entry>
-           <entry>256-QAM modulation</entry>
-       </row><row>
-           <entry id="QAM-AUTO"><constant>QAM_AUTO</constant></entry>
-           <entry>Autodetect QAM modulation</entry>
-       </row><row>
-           <entry id="VSB-8"><constant>VSB_8</constant></entry>
-           <entry>8-VSB modulation</entry>
-       </row><row>
-           <entry id="VSB-16"><constant>VSB_16</constant></entry>
-           <entry>16-VSB modulation</entry>
-       </row><row>
-           <entry id="PSK-8"><constant>PSK_8</constant></entry>
-           <entry>8-PSK modulation</entry>
-       </row><row>
-           <entry id="APSK-16"><constant>APSK_16</constant></entry>
-           <entry>16-APSK modulation</entry>
-       </row><row>
-           <entry id="APSK-32"><constant>APSK_32</constant></entry>
-           <entry>32-APSK modulation</entry>
-       </row><row>
-           <entry id="DQPSK"><constant>DQPSK</constant></entry>
-           <entry>DQPSK modulation</entry>
-       </row><row>
-           <entry id="QAM-4-NR"><constant>QAM_4_NR</constant></entry>
-           <entry>4-QAM-NR modulation</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</section>
-
-       </section>
-       <section id="DTV-BANDWIDTH-HZ">
-               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
-
-               <para>Bandwidth for the channel, in HZ.</para>
-
-               <para>Possible values:
-                       <constant>1712000</constant>,
-                       <constant>5000000</constant>,
-                       <constant>6000000</constant>,
-                       <constant>7000000</constant>,
-                       <constant>8000000</constant>,
-                       <constant>10000000</constant>.
-               </para>
-
-               <para>Notes:</para>
-
-               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
-               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
-               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
-                        for DVB-C depends on the symbol rate</para>
-               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
-                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
-                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
-               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
-               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
-       </section>
-       <section id="DTV-INVERSION">
-       <title><constant>DTV_INVERSION</constant></title>
-
-       <para>Specifies if the frontend should do spectral inversion or not.</para>
-
-<section id="fe-spectral-inversion-t">
-<title>enum fe_modulation: Frontend spectral inversion</title>
-
-<para>This parameter indicates if spectral inversion should be presumed or not.
-    In the automatic setting (<constant>INVERSION_AUTO</constant>) the hardware
-    will try to figure out the correct setting by itself. If the hardware
-    doesn't support, the DVB core will try to lock at the carrier first with
-    inversion off. If it fails, it will try to enable inversion.
-</para>
-
-<table pgwide="1" frame="none" id="fe-spectral-inversion">
-    <title>enum fe_modulation</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="INVERSION-OFF"><constant>INVERSION_OFF</constant></entry>
-           <entry>Don't do spectral band inversion.</entry>
-       </row><row>
-           <entry id="INVERSION-ON"><constant>INVERSION_ON</constant></entry>
-           <entry>Do spectral band inversion.</entry>
-       </row><row>
-           <entry id="INVERSION-AUTO"><constant>INVERSION_AUTO</constant></entry>
-           <entry>Autodetect spectral band inversion.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</section>
-
-       </section>
-       <section id="DTV-DISEQC-MASTER">
-       <title><constant>DTV_DISEQC_MASTER</constant></title>
-       <para>Currently not implemented.</para>
-       </section>
-       <section id="DTV-SYMBOL-RATE">
-       <title><constant>DTV_SYMBOL_RATE</constant></title>
-       <para>Digital TV symbol rate, in bauds (symbols/second). Used on cable standards.</para>
-       </section>
-       <section id="DTV-INNER-FEC">
-       <title><constant>DTV_INNER_FEC</constant></title>
-       <para>Used cable/satellite transmissions. The acceptable values are:
-       </para>
-<section id="fe-code-rate-t">
-<title>enum fe_code_rate: type of the Forward Error Correction.</title>
-
-<table pgwide="1" frame="none" id="fe-code-rate">
-    <title>enum fe_code_rate</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="FEC-NONE"><constant>FEC_NONE</constant></entry>
-           <entry>No Forward Error Correction Code</entry>
-       </row><row>
-           <entry id="FEC-AUTO"><constant>FEC_AUTO</constant></entry>
-           <entry>Autodetect Error Correction Code</entry>
-       </row><row>
-           <entry id="FEC-1-2"><constant>FEC_1_2</constant></entry>
-           <entry>Forward Error Correction Code 1/2</entry>
-       </row><row>
-           <entry id="FEC-2-3"><constant>FEC_2_3</constant></entry>
-           <entry>Forward Error Correction Code 2/3</entry>
-       </row><row>
-           <entry id="FEC-3-4"><constant>FEC_3_4</constant></entry>
-           <entry>Forward Error Correction Code 3/4</entry>
-       </row><row>
-           <entry id="FEC-4-5"><constant>FEC_4_5</constant></entry>
-           <entry>Forward Error Correction Code 4/5</entry>
-       </row><row>
-           <entry id="FEC-5-6"><constant>FEC_5_6</constant></entry>
-           <entry>Forward Error Correction Code 5/6</entry>
-       </row><row>
-           <entry id="FEC-6-7"><constant>FEC_6_7</constant></entry>
-           <entry>Forward Error Correction Code 6/7</entry>
-       </row><row>
-           <entry id="FEC-7-8"><constant>FEC_7_8</constant></entry>
-           <entry>Forward Error Correction Code 7/8</entry>
-       </row><row>
-           <entry id="FEC-8-9"><constant>FEC_8_9</constant></entry>
-           <entry>Forward Error Correction Code 8/9</entry>
-       </row><row>
-           <entry id="FEC-9-10"><constant>FEC_9_10</constant></entry>
-           <entry>Forward Error Correction Code 9/10</entry>
-       </row><row>
-           <entry id="FEC-2-5"><constant>FEC_2_5</constant></entry>
-           <entry>Forward Error Correction Code 2/5</entry>
-       </row><row>
-           <entry id="FEC-3-5"><constant>FEC_3_5</constant></entry>
-           <entry>Forward Error Correction Code 3/5</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</section>
-       </section>
-       <section id="DTV-VOLTAGE">
-       <title><constant>DTV_VOLTAGE</constant></title>
-       <para>The voltage is usually used with non-DiSEqC capable LNBs to switch
-       the polarzation (horizontal/vertical). When using DiSEqC epuipment this
-       voltage has to be switched consistently to the DiSEqC commands as
-       described in the DiSEqC spec.</para>
-
-<table pgwide="1" frame="none" id="fe-sec-voltage">
-    <title id="fe-sec-voltage-t">enum fe_sec_voltage</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="SEC-VOLTAGE-13"><constant>SEC_VOLTAGE_13</constant></entry>
-           <entry align="char">Set DC voltage level to 13V</entry>
-       </row><row>
-           <entry align="char" id="SEC-VOLTAGE-18"><constant>SEC_VOLTAGE_18</constant></entry>
-           <entry align="char">Set DC voltage level to 18V</entry>
-       </row><row>
-           <entry align="char" id="SEC-VOLTAGE-OFF"><constant>SEC_VOLTAGE_OFF</constant></entry>
-           <entry align="char">Don't send any voltage to the antenna</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-       </section>
-       <section id="DTV-TONE">
-       <title><constant>DTV_TONE</constant></title>
-       <para>Currently not used.</para>
-       </section>
-       <section id="DTV-PILOT">
-       <title><constant>DTV_PILOT</constant></title>
-       <para>Sets DVB-S2 pilot</para>
-       <section id="fe-pilot-t">
-               <title>fe_pilot type</title>
-<table pgwide="1" frame="none" id="fe-pilot">
-    <title>enum fe_pilot</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="PILOT-ON"><constant>PILOT_ON</constant></entry>
-           <entry align="char">Pilot tones enabled</entry>
-       </row><row>
-           <entry align="char" id="PILOT-OFF"><constant>PILOT_OFF</constant></entry>
-           <entry align="char">Pilot tones disabled</entry>
-       </row><row>
-           <entry align="char" id="PILOT-AUTO"><constant>PILOT_AUTO</constant></entry>
-           <entry align="char">Autodetect pilot tones</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-       </section>
-       <section id="DTV-ROLLOFF">
-       <title><constant>DTV_ROLLOFF</constant></title>
-               <para>Sets DVB-S2 rolloff</para>
-
-       <section id="fe-rolloff-t">
-               <title>fe_rolloff type</title>
-<table pgwide="1" frame="none" id="fe-rolloff">
-    <title>enum fe_rolloff</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="ROLLOFF-35"><constant>ROLLOFF_35</constant></entry>
-           <entry align="char">Roloff factor: &alpha;=35%</entry>
-       </row><row>
-           <entry align="char" id="ROLLOFF-20"><constant>ROLLOFF_20</constant></entry>
-           <entry align="char">Roloff factor: &alpha;=20%</entry>
-       </row><row>
-           <entry align="char" id="ROLLOFF-25"><constant>ROLLOFF_25</constant></entry>
-           <entry align="char">Roloff factor: &alpha;=25%</entry>
-       </row><row>
-           <entry align="char" id="ROLLOFF-AUTO"><constant>ROLLOFF_AUTO</constant></entry>
-           <entry align="char">Auto-detect the roloff factor.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-       </section>
-       <section id="DTV-DISEQC-SLAVE-REPLY">
-       <title><constant>DTV_DISEQC_SLAVE_REPLY</constant></title>
-       <para>Currently not implemented.</para>
-       </section>
-       <section id="DTV-FE-CAPABILITY-COUNT">
-       <title><constant>DTV_FE_CAPABILITY_COUNT</constant></title>
-       <para>Currently not implemented.</para>
-       </section>
-       <section id="DTV-FE-CAPABILITY">
-       <title><constant>DTV_FE_CAPABILITY</constant></title>
-       <para>Currently not implemented.</para>
-       </section>
-       <section id="DTV-DELIVERY-SYSTEM">
-               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
-               <para>Specifies the type of Delivery system</para>
-               <section id="fe-delivery-system-t">
-               <title>fe_delivery_system type</title>
-               <para>Possible values: </para>
-
-<table pgwide="1" frame="none" id="fe-delivery-system">
-    <title>enum fe_delivery_system</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-               <entry id="SYS-UNDEFINED"><constant>SYS_UNDEFINED</constant></entry>
-               <entry>Undefined standard. Generally, indicates an error</entry>
-       </row><row>
-               <entry id="SYS-DVBC-ANNEX-A"><constant>SYS_DVBC_ANNEX_A</constant></entry>
-               <entry>Cable TV: DVB-C following ITU-T J.83 Annex A spec</entry>
-       </row><row>
-               <entry id="SYS-DVBC-ANNEX-B"><constant>SYS_DVBC_ANNEX_B</constant></entry>
-               <entry>Cable TV: DVB-C following ITU-T J.83 Annex B spec (ClearQAM)</entry>
-       </row><row>
-               <entry id="SYS-DVBC-ANNEX-C"><constant>SYS_DVBC_ANNEX_C</constant></entry>
-               <entry>Cable TV: DVB-C following ITU-T J.83 Annex C spec</entry>
-       </row><row>
-               <entry id="SYS-ISDBC"><constant>SYS_ISDBC</constant></entry>
-               <entry>Cable TV: ISDB-C (no drivers yet)</entry>
-       </row><row>
-               <entry id="SYS-DVBT"><constant>SYS_DVBT</constant></entry>
-               <entry>Terrestral TV: DVB-T</entry>
-       </row><row>
-               <entry id="SYS-DVBT2"><constant>SYS_DVBT2</constant></entry>
-               <entry>Terrestral TV: DVB-T2</entry>
-       </row><row>
-               <entry id="SYS-ISDBT"><constant>SYS_ISDBT</constant></entry>
-               <entry>Terrestral TV: ISDB-T</entry>
-       </row><row>
-               <entry id="SYS-ATSC"><constant>SYS_ATSC</constant></entry>
-               <entry>Terrestral TV: ATSC</entry>
-       </row><row>
-               <entry id="SYS-ATSCMH"><constant>SYS_ATSCMH</constant></entry>
-               <entry>Terrestral TV (mobile): ATSC-M/H</entry>
-       </row><row>
-               <entry id="SYS-DTMB"><constant>SYS_DTMB</constant></entry>
-               <entry>Terrestrial TV: DTMB</entry>
-       </row><row>
-               <entry id="SYS-DVBS"><constant>SYS_DVBS</constant></entry>
-               <entry>Satellite TV: DVB-S</entry>
-       </row><row>
-               <entry id="SYS-DVBS2"><constant>SYS_DVBS2</constant></entry>
-               <entry>Satellite TV: DVB-S2</entry>
-       </row><row>
-               <entry id="SYS-TURBO"><constant>SYS_TURBO</constant></entry>
-               <entry>Satellite TV: DVB-S Turbo</entry>
-       </row><row>
-               <entry id="SYS-ISDBS"><constant>SYS_ISDBS</constant></entry>
-               <entry>Satellite TV: ISDB-S</entry>
-       </row><row>
-               <entry id="SYS-DAB"><constant>SYS_DAB</constant></entry>
-               <entry>Digital audio: DAB (not fully supported)</entry>
-       </row><row>
-               <entry id="SYS-DSS"><constant>SYS_DSS</constant></entry>
-               <entry>Satellite TV:"DSS (not fully supported)</entry>
-       </row><row>
-               <entry id="SYS-CMMB"><constant>SYS_CMMB</constant></entry>
-               <entry>Terrestral TV (mobile):CMMB (not fully supported)</entry>
-       </row><row>
-               <entry id="SYS-DVBH"><constant>SYS_DVBH</constant></entry>
-               <entry>Terrestral TV (mobile): DVB-H (standard deprecated)</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-
-</section>
-       </section>
-       <section id="DTV-ISDBT-PARTIAL-RECEPTION">
-               <title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
-
-               <para>If <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '0' this bit-field represents whether
-                       the channel is in partial reception mode or not.</para>
-
-               <para>If '1' <constant>DTV_ISDBT_LAYERA_*</constant> values are assigned to the center segment and
-                       <constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant> has to be '1'.</para>
-
-               <para>If in addition <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'
-                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> represents whether this ISDB-Tsb channel
-                       is consisting of one segment and layer or three segments and two layers.</para>
-
-               <para>Possible values: 0, 1, -1 (AUTO)</para>
-       </section>
-       <section id="DTV-ISDBT-SOUND-BROADCASTING">
-               <title><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></title>
-
-               <para>This field represents whether the other DTV_ISDBT_*-parameters are
-                       referring to an ISDB-T and an ISDB-Tsb channel. (See also
-                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>).</para>
-
-               <para>Possible values: 0, 1, -1 (AUTO)</para>
-       </section>
-       <section id="DTV-ISDBT-SB-SUBCHANNEL-ID">
-               <title><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></title>
-
-               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-               <para>(Note of the author: This might not be the correct description of the
-                       <constant>SUBCHANNEL-ID</constant> in all details, but it is my understanding of the technical
-                       background needed to program a device)</para>
-
-               <para>An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a
-                       set of connected ISDB-Tsb channels. In this set of channels every
-                       channel can be received independently. The number of connected
-                       ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum
-                       bandwidth available.</para>
-
-               <para>Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The
-                       broadcaster has several possibilities to put those channels in the
-                       air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8
-                       segments from position 1-8 to 5-13 or anything in between.</para>
-
-               <para>The underlying layer of segments are subchannels: each segment is
-                       consisting of several subchannels with a predefined IDs. A sub-channel
-                       is used to help the demodulator to synchronize on the channel.</para>
-
-               <para>An ISDB-T channel is always centered over all sub-channels. As for
-                       the example above, in ISDB-Tsb it is no longer as simple as that.</para>
-
-               <para><constant>The DTV_ISDBT_SB_SUBCHANNEL_ID</constant> parameter is used to give the
-                       sub-channel ID of the segment to be demodulated.</para>
-
-               <para>Possible values: 0 .. 41, -1 (AUTO)</para>
-       </section>
-       <section id="DTV-ISDBT-SB-SEGMENT-IDX">
-               <title><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></title>
-               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-               <para><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> gives the index of the segment to be
-                       demodulated for an ISDB-Tsb channel where several of them are
-                       transmitted in the connected manner.</para>
-               <para>Possible values: 0 .. <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - 1</para>
-               <para>Note: This value cannot be determined by an automatic channel search.</para>
-       </section>
-       <section id="DTV-ISDBT-SB-SEGMENT-COUNT">
-               <title><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></title>
-               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-               <para><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> gives the total count of connected ISDB-Tsb
-                       channels.</para>
-               <para>Possible values: 1 .. 13</para>
-               <para>Note: This value cannot be determined by an automatic channel search.</para>
-       </section>
-       <section id="isdb-hierq-layers">
-               <title><constant>DTV-ISDBT-LAYER*</constant> parameters</title>
-               <para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
-                       ISDB-T hierarchical layers can be decoded simultaneously. For that
-                       reason a ISDB-T demodulator has 3 Viterbi and 3 Reed-Solomon decoders.</para>
-               <para>ISDB-T has 3 hierarchical layers which each can use a part of the
-                       available segments. The total number of segments over all layers has
-                       to 13 in ISDB-T.</para>
-               <para>There are 3 parameter sets, for Layers A, B and C.</para>
-               <section id="DTV-ISDBT-LAYER-ENABLED">
-                       <title><constant>DTV_ISDBT_LAYER_ENABLED</constant></title>
-                       <para>Hierarchical reception in ISDB-T is achieved by enabling or disabling
-                               layers in the decoding process. Setting all bits of
-                               <constant>DTV_ISDBT_LAYER_ENABLED</constant> to '1' forces all layers (if applicable) to be
-                               demodulated. This is the default.</para>
-                       <para>If the channel is in the partial reception mode
-                               (<constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> = 1) the central segment can be decoded
-                               independently of the other 12 segments. In that mode layer A has to
-                               have a <constant>SEGMENT_COUNT</constant> of 1.</para>
-                       <para>In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb
-                               according to <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>. <constant>SEGMENT_COUNT</constant> must be filled
-                               accordingly.</para>
-                       <para>Possible values: 0x1, 0x2, 0x4 (|-able)</para>
-                       <para><constant>DTV_ISDBT_LAYER_ENABLED[0:0]</constant> - layer A</para>
-                       <para><constant>DTV_ISDBT_LAYER_ENABLED[1:1]</constant> - layer B</para>
-                       <para><constant>DTV_ISDBT_LAYER_ENABLED[2:2]</constant> - layer C</para>
-                       <para><constant>DTV_ISDBT_LAYER_ENABLED[31:3]</constant> unused</para>
-               </section>
-               <section id="DTV-ISDBT-LAYER-FEC">
-                       <title><constant>DTV_ISDBT_LAYER*_FEC</constant></title>
-                       <para>Possible values: <constant>FEC_AUTO</constant>, <constant>FEC_1_2</constant>, <constant>FEC_2_3</constant>, <constant>FEC_3_4</constant>, <constant>FEC_5_6</constant>, <constant>FEC_7_8</constant></para>
-               </section>
-               <section id="DTV-ISDBT-LAYER-MODULATION">
-                       <title><constant>DTV_ISDBT_LAYER*_MODULATION</constant></title>
-                       <para>Possible values: <constant>QAM_AUTO</constant>, QP<constant>SK, QAM_16</constant>, <constant>QAM_64</constant>, <constant>DQPSK</constant></para>
-                       <para>Note: If layer C is <constant>DQPSK</constant> layer B has to be <constant>DQPSK</constant>. If layer B is <constant>DQPSK</constant>
-                               and <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>=0 layer has to be <constant>DQPSK</constant>.</para>
-               </section>
-               <section id="DTV-ISDBT-LAYER-SEGMENT-COUNT">
-                       <title><constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant></title>
-                       <para>Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO)</para>
-                       <para>Note: Truth table for <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> and
-                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> and <constant>LAYER</constant>*_SEGMENT_COUNT</para>
-                       <informaltable id="isdbt-layer_seg-cnt-table">
-                               <tgroup cols="6">
-                                       <tbody>
-                                               <row>
-                                                       <entry>PR</entry>
-                                                       <entry>SB</entry>
-                                                       <entry>Layer A width</entry>
-                                                       <entry>Layer B width</entry>
-                                                       <entry>Layer C width</entry>
-                                                       <entry>total width</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>0</entry>
-                                                       <entry>0</entry>
-                                                       <entry>1 .. 13</entry>
-                                                       <entry>1 .. 13</entry>
-                                                       <entry>1 .. 13</entry>
-                                                       <entry>13</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>1</entry>
-                                                       <entry>0</entry>
-                                                       <entry>1</entry>
-                                                       <entry>1 .. 13</entry>
-                                                       <entry>1 .. 13</entry>
-                                                       <entry>13</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>0</entry>
-                                                       <entry>1</entry>
-                                                       <entry>1</entry>
-                                                       <entry>0</entry>
-                                                       <entry>0</entry>
-                                                       <entry>1</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>1</entry>
-                                                       <entry>1</entry>
-                                                       <entry>1</entry>
-                                                       <entry>2</entry>
-                                                       <entry>0</entry>
-                                                       <entry>13</entry>
-                                               </row>
-                                       </tbody>
-                               </tgroup>
-                       </informaltable>
-               </section>
-               <section id="DTV-ISDBT-LAYER-TIME-INTERLEAVING">
-                       <title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
-                       <para>Valid values: 0, 1, 2, 4, -1 (AUTO)</para>
-                       <para>when DTV_ISDBT_SOUND_BROADCASTING is active, value 8 is also valid.</para>
-                       <para>Note: The real time interleaving length depends on the mode (fft-size). The values
-                               here are referring to what can be found in the TMCC-structure, as shown in the table below.</para>
-                       <informaltable id="isdbt-layer-interleaving-table">
-                               <tgroup cols="4" align="center">
-                                       <tbody>
-                                               <row>
-                                                       <entry>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</entry>
-                                                       <entry>Mode 1 (2K FFT)</entry>
-                                                       <entry>Mode 2 (4K FFT)</entry>
-                                                       <entry>Mode 3 (8K FFT)</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>0</entry>
-                                                       <entry>0</entry>
-                                                       <entry>0</entry>
-                                                       <entry>0</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>1</entry>
-                                                       <entry>4</entry>
-                                                       <entry>2</entry>
-                                                       <entry>1</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>2</entry>
-                                                       <entry>8</entry>
-                                                       <entry>4</entry>
-                                                       <entry>2</entry>
-                                               </row>
-                                               <row>
-                                                       <entry>4</entry>
-                                                       <entry>16</entry>
-                                                       <entry>8</entry>
-                                                       <entry>4</entry>
-                                               </row>
-                                       </tbody>
-                               </tgroup>
-                       </informaltable>
-               </section>
-               <section id="DTV-ATSCMH-FIC-VER">
-                       <title><constant>DTV_ATSCMH_FIC_VER</constant></title>
-                       <para>Version number of the FIC (Fast Information Channel) signaling data.</para>
-                       <para>FIC is used for relaying information to allow rapid service acquisition by the receiver.</para>
-                       <para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
-               </section>
-               <section id="DTV-ATSCMH-PARADE-ID">
-                       <title><constant>DTV_ATSCMH_PARADE_ID</constant></title>
-                       <para>Parade identification number</para>
-                       <para>A parade is a collection of up to eight MH groups, conveying one or two ensembles.</para>
-                       <para>Possible values: 0, 1, 2, 3, ..., 126, 127</para>
-               </section>
-               <section id="DTV-ATSCMH-NOG">
-                       <title><constant>DTV_ATSCMH_NOG</constant></title>
-                       <para>Number of MH groups per MH subframe for a designated parade.</para>
-                       <para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
-               </section>
-               <section id="DTV-ATSCMH-TNOG">
-                       <title><constant>DTV_ATSCMH_TNOG</constant></title>
-                       <para>Total number of MH groups including all MH groups belonging to all MH parades in one MH subframe.</para>
-                       <para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
-               </section>
-               <section id="DTV-ATSCMH-SGN">
-                       <title><constant>DTV_ATSCMH_SGN</constant></title>
-                       <para>Start group number.</para>
-                       <para>Possible values: 0, 1, 2, 3, ..., 14, 15</para>
-               </section>
-               <section id="DTV-ATSCMH-PRC">
-                       <title><constant>DTV_ATSCMH_PRC</constant></title>
-                       <para>Parade repetition cycle.</para>
-                       <para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
-               </section>
-               <section id="DTV-ATSCMH-RS-FRAME-MODE">
-                       <title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
-                       <para>Reed Solomon (RS) frame mode.</para>
-                       <para>Possible values are:</para>
-<table pgwide="1" frame="none" id="atscmh-rs-frame-mode">
-    <title>enum atscmh_rs_frame_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="ATSCMH-RSFRAME-PRI-ONLY"><constant>ATSCMH_RSFRAME_PRI_ONLY</constant></entry>
-           <entry>Single Frame: There is only a primary RS Frame for all
-               Group Regions.</entry>
-       </row><row>
-           <entry id="ATSCMH-RSFRAME-PRI-SEC"><constant>ATSCMH_RSFRAME_PRI_SEC</constant></entry>
-           <entry>Dual Frame: There are two separate RS Frames: Primary RS
-               Frame for Group Region A and B and Secondary RS Frame for Group
-               Region C and D.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-               <section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
-                       <title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
-                       <para>Reed Solomon(RS) frame ensemble.</para>
-                       <para>Possible values are:</para>
-<table pgwide="1" frame="none" id="atscmh-rs-frame-ensemble">
-    <title>enum atscmh_rs_frame_ensemble</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="ATSCMH-RSFRAME-ENS-PRI"><constant>ATSCMH_RSFRAME_ENS_PRI</constant></entry>
-           <entry>Primary Ensemble.</entry>
-       </row><row>
-           <entry id="ATSCMH-RSFRAME-ENS-SEC"><constant>AATSCMH_RSFRAME_PRI_SEC</constant></entry>
-           <entry>Secondary Ensemble.</entry>
-       </row><row>
-           <entry id="ATSCMH-RSFRAME-RES"><constant>AATSCMH_RSFRAME_RES</constant></entry>
-           <entry>Reserved. Shouldn't be used.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-               <section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
-                       <title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
-                       <para>Reed Solomon (RS) code mode (primary).</para>
-                       <para>Possible values are:</para>
-<table pgwide="1" frame="none" id="atscmh-rs-code-mode">
-    <title>enum atscmh_rs_code_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="ATSCMH-RSCODE-211-187"><constant>ATSCMH_RSCODE_211_187</constant></entry>
-           <entry>Reed Solomon code (211,187).</entry>
-       </row><row>
-           <entry id="ATSCMH-RSCODE-223-187"><constant>ATSCMH_RSCODE_223_187</constant></entry>
-           <entry>Reed Solomon code (223,187).</entry>
-       </row><row>
-           <entry id="ATSCMH-RSCODE-235-187"><constant>ATSCMH_RSCODE_235_187</constant></entry>
-           <entry>Reed Solomon code (235,187).</entry>
-       </row><row>
-           <entry id="ATSCMH-RSCODE-RES"><constant>ATSCMH_RSCODE_RES</constant></entry>
-           <entry>Reserved. Shouldn't be used.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-               <section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
-                       <title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
-                       <para>Reed Solomon (RS) code mode (secondary).</para>
-                       <para>Possible values are the same as documented on
-                           &atscmh-rs-code-mode;:</para>
-               </section>
-               <section id="DTV-ATSCMH-SCCC-BLOCK-MODE">
-                       <title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
-                       <para>Series Concatenated Convolutional Code Block Mode.</para>
-                       <para>Possible values are:</para>
-<table pgwide="1" frame="none" id="atscmh-sccc-block-mode">
-    <title>enum atscmh_scc_block_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="ATSCMH-SCCC-BLK-SEP"><constant>ATSCMH_SCCC_BLK_SEP</constant></entry>
-           <entry>Separate SCCC: the SCCC outer code mode shall be set independently
-               for each Group Region (A, B, C, D)</entry>
-       </row><row>
-           <entry id="ATSCMH-SCCC-BLK-COMB"><constant>ATSCMH_SCCC_BLK_COMB</constant></entry>
-           <entry>Combined SCCC: all four Regions shall have the same SCCC outer
-               code mode.</entry>
-       </row><row>
-           <entry id="ATSCMH-SCCC-BLK-RES"><constant>ATSCMH_SCCC_BLK_RES</constant></entry>
-           <entry>Reserved. Shouldn't be used.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-               <section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
-                       <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
-                       <para>Series Concatenated Convolutional Code Rate.</para>
-                       <para>Possible values are:</para>
-<table pgwide="1" frame="none" id="atscmh-sccc-code-mode">
-    <title>enum atscmh_sccc_code_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="ATSCMH-SCCC-CODE-HLF"><constant>ATSCMH_SCCC_CODE_HLF</constant></entry>
-           <entry>The outer code rate of a SCCC Block is 1/2 rate.</entry>
-       </row><row>
-           <entry id="ATSCMH-SCCC-CODE-QTR"><constant>ATSCMH_SCCC_CODE_QTR</constant></entry>
-           <entry>The outer code rate of a SCCC Block is 1/4 rate.</entry>
-       </row><row>
-           <entry id="ATSCMH-SCCC-CODE-RES"><constant>ATSCMH_SCCC_CODE_RES</constant></entry>
-           <entry>to be documented.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-               </section>
-               <section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
-                       <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
-                       <para>Series Concatenated Convolutional Code Rate.</para>
-                       <para>Possible values are the same as documented on
-                           &atscmh-sccc-code-mode;.</para>
-               </section>
-               <section id="DTV-ATSCMH-SCCC-CODE-MODE-C">
-                       <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></title>
-                       <para>Series Concatenated Convolutional Code Rate.</para>
-                       <para>Possible values are the same as documented on
-                           &atscmh-sccc-code-mode;.</para>
-               </section>
-               <section id="DTV-ATSCMH-SCCC-CODE-MODE-D">
-                       <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></title>
-                       <para>Series Concatenated Convolutional Code Rate.</para>
-                       <para>Possible values are the same as documented on
-                           &atscmh-sccc-code-mode;.</para>
-               </section>
-       </section>
-       <section id="DTV-API-VERSION">
-       <title><constant>DTV_API_VERSION</constant></title>
-       <para>Returns the major/minor version of the DVB API</para>
-       </section>
-       <section id="DTV-CODE-RATE-HP">
-       <title><constant>DTV_CODE_RATE_HP</constant></title>
-       <para>Used on terrestrial transmissions.  The acceptable values are
-           the ones described at &fe-transmit-mode-t;.
-       </para>
-       </section>
-       <section id="DTV-CODE-RATE-LP">
-       <title><constant>DTV_CODE_RATE_LP</constant></title>
-       <para>Used on terrestrial transmissions. The acceptable values are
-           the ones described at &fe-transmit-mode-t;.
-       </para>
-
-       </section>
-
-       <section id="DTV-GUARD-INTERVAL">
-               <title><constant>DTV_GUARD_INTERVAL</constant></title>
-
-               <para>Possible values are:</para>
-
-<section id="fe-guard-interval-t">
-<title>Modulation guard interval</title>
-
-<table pgwide="1" frame="none" id="fe-guard-interval">
-    <title>enum fe_guard_interval</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="GUARD-INTERVAL-AUTO"><constant>GUARD_INTERVAL_AUTO</constant></entry>
-           <entry>Autodetect the guard interval</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-1-128"><constant>GUARD_INTERVAL_1_128</constant></entry>
-           <entry>Guard interval 1/128</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-1-32"><constant>GUARD_INTERVAL_1_32</constant></entry>
-           <entry>Guard interval 1/32</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-1-16"><constant>GUARD_INTERVAL_1_16</constant></entry>
-           <entry>Guard interval 1/16</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-1-8"><constant>GUARD_INTERVAL_1_8</constant></entry>
-           <entry>Guard interval 1/8</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-1-4"><constant>GUARD_INTERVAL_1_4</constant></entry>
-           <entry>Guard interval 1/4</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-19-128"><constant>GUARD_INTERVAL_19_128</constant></entry>
-           <entry>Guard interval 19/128</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-19-256"><constant>GUARD_INTERVAL_19_256</constant></entry>
-           <entry>Guard interval 19/256</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-PN420"><constant>GUARD_INTERVAL_PN420</constant></entry>
-           <entry>PN length 420 (1/4)</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-PN595"><constant>GUARD_INTERVAL_PN595</constant></entry>
-           <entry>PN length 595 (1/6)</entry>
-       </row><row>
-           <entry id="GUARD-INTERVAL-PN945"><constant>GUARD_INTERVAL_PN945</constant></entry>
-           <entry>PN length 945 (1/9)</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-               <para>Notes:</para>
-               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
-                       try to find the correct guard interval (if capable) and will use TMCC to fill
-                       in the missing parameters.</para>
-               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
-               <para>3) DTMB specifies PN420, PN595 and PN945.</para>
-</section>
-       </section>
-       <section id="DTV-TRANSMISSION-MODE">
-               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
-
-               <para>Specifies the number of carriers used by the standard.
-                   This is used only on OFTM-based standards, e. g.
-                   DVB-T/T2, ISDB-T, DTMB</para>
-
-<section id="fe-transmit-mode-t">
-<title>enum fe_transmit_mode: Number of carriers per channel</title>
-
-<table pgwide="1" frame="none" id="fe-transmit-mode">
-    <title>enum fe_transmit_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="TRANSMISSION-MODE-AUTO"><constant>TRANSMISSION_MODE_AUTO</constant></entry>
-           <entry>Autodetect transmission mode. The hardware will try to find
-               the correct FFT-size (if capable) to fill in the missing
-               parameters.</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-1K"><constant>TRANSMISSION_MODE_1K</constant></entry>
-           <entry>Transmission mode 1K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-2K"><constant>TRANSMISSION_MODE_2K</constant></entry>
-           <entry>Transmission mode 2K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-8K"><constant>TRANSMISSION_MODE_8K</constant></entry>
-           <entry>Transmission mode 8K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-4K"><constant>TRANSMISSION_MODE_4K</constant></entry>
-           <entry>Transmission mode 4K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-16K"><constant>TRANSMISSION_MODE_16K</constant></entry>
-           <entry>Transmission mode 16K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-32K"><constant>TRANSMISSION_MODE_32K</constant></entry>
-           <entry>Transmission mode 32K</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-C1"><constant>TRANSMISSION_MODE_C1</constant></entry>
-           <entry>Single Carrier (C=1) transmission mode (DTMB)</entry>
-       </row><row>
-           <entry id="TRANSMISSION-MODE-C3780"><constant>TRANSMISSION_MODE_C3780</constant></entry>
-           <entry>Multi Carrier (C=3780) transmission mode (DTMB)</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-
-               <para>Notes:</para>
-               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
-                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
-
-               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
-                       hardware will try to find the correct FFT-size (if capable) and will
-                       use TMCC to fill in the missing parameters.</para>
-               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
-               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
-               <para>5) DTMB specifies C1 and C3780.</para>
-</section>
-       </section>
-       <section id="DTV-HIERARCHY">
-       <title><constant>DTV_HIERARCHY</constant></title>
-       <para>Frontend hierarchy</para>
-
-
-<section id="fe-hierarchy-t">
-<title>Frontend hierarchy</title>
-
-<table pgwide="1" frame="none" id="fe-hierarchy">
-    <title>enum fe_hierarchy</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-            <entry id="HIERARCHY-NONE"><constant>HIERARCHY_NONE</constant></entry>
-           <entry>No hierarchy</entry>
-       </row><row>
-            <entry id="HIERARCHY-AUTO"><constant>HIERARCHY_AUTO</constant></entry>
-           <entry>Autodetect hierarchy (if supported)</entry>
-       </row><row>
-            <entry id="HIERARCHY-1"><constant>HIERARCHY_1</constant></entry>
-           <entry>Hierarchy 1</entry>
-       </row><row>
-            <entry id="HIERARCHY-2"><constant>HIERARCHY_2</constant></entry>
-           <entry>Hierarchy 2</entry>
-       </row><row>
-            <entry id="HIERARCHY-4"><constant>HIERARCHY_4</constant></entry>
-           <entry>Hierarchy 4</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</section>
-
-       </section>
-       <section id="DTV-STREAM-ID">
-       <title><constant>DTV_STREAM_ID</constant></title>
-       <para>DVB-S2, DVB-T2 and ISDB-S support the transmission of several
-             streams on a single transport stream.
-             This property enables the DVB driver to handle substream filtering,
-             when supported by the hardware.
-             By default, substream filtering is disabled.
-       </para><para>
-             For DVB-S2 and DVB-T2, the valid substream id range is from 0 to 255.
-       </para><para>
-             For ISDB, the valid substream id range is from 1 to 65535.
-       </para><para>
-             To disable it, you should use the special macro NO_STREAM_ID_FILTER.
-       </para><para>
-             Note: any value outside the id range also disables filtering.
-       </para>
-       </section>
-       <section id="DTV-DVBT2-PLP-ID-LEGACY">
-               <title><constant>DTV_DVBT2_PLP_ID_LEGACY</constant></title>
-               <para>Obsolete, replaced with DTV_STREAM_ID.</para>
-       </section>
-       <section id="DTV-ENUM-DELSYS">
-               <title><constant>DTV_ENUM_DELSYS</constant></title>
-               <para>A Multi standard frontend needs to advertise the delivery systems provided.
-                       Applications need to enumerate the provided delivery systems, before using
-                       any other operation with the frontend. Prior to it's introduction,
-                       FE_GET_INFO was used to determine a frontend type. A frontend which
-                       provides more than a single delivery system, FE_GET_INFO doesn't help much.
-                       Applications which intends to use a multistandard frontend must enumerate
-                       the delivery systems associated with it, rather than trying to use
-                       FE_GET_INFO. In the case of a legacy frontend, the result is just the same
-                       as with FE_GET_INFO, but in a more structured format </para>
-       </section>
-       <section id="DTV-INTERLEAVING">
-       <title><constant>DTV_INTERLEAVING</constant></title>
-
-<para>Time interleaving to be used. Currently, used only on DTMB.</para>
-
-<table pgwide="1" frame="none" id="fe-interleaving">
-    <title>enum fe_interleaving</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="INTERLEAVING-NONE"><constant>INTERLEAVING_NONE</constant></entry>
-           <entry>No interleaving.</entry>
-       </row><row>
-           <entry id="INTERLEAVING-AUTO"><constant>INTERLEAVING_AUTO</constant></entry>
-           <entry>Auto-detect interleaving.</entry>
-       </row><row>
-           <entry id="INTERLEAVING-240"><constant>INTERLEAVING_240</constant></entry>
-           <entry>Interleaving of 240 symbols.</entry>
-       </row><row>
-           <entry id="INTERLEAVING-720"><constant>INTERLEAVING_720</constant></entry>
-           <entry>Interleaving of 720 symbols.</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-       </section>
-       <section id="DTV-LNA">
-       <title><constant>DTV_LNA</constant></title>
-       <para>Low-noise amplifier.</para>
-       <para>Hardware might offer controllable LNA which can be set manually
-               using that parameter. Usually LNA could be found only from
-               terrestrial devices if at all.</para>
-       <para>Possible values: 0, 1, LNA_AUTO</para>
-       <para>0, LNA off</para>
-       <para>1, LNA on</para>
-       <para>use the special macro LNA_AUTO to set LNA auto</para>
-       </section>
-</section>
-
-       <section id="frontend-stat-properties">
-       <title>Frontend statistics indicators</title>
-       <para>The values are returned via <constant>dtv_property.stat</constant>.
-             If the property is supported, <constant>dtv_property.stat.len</constant> is bigger than zero.</para>
-       <para>For most delivery systems, <constant>dtv_property.stat.len</constant>
-             will be 1 if the stats is supported, and the properties will
-             return a single value for each parameter.</para>
-       <para>It should be noted, however, that new OFDM delivery systems
-             like ISDB can use different modulation types for each group of
-             carriers. On such standards, up to 3 groups of statistics can be
-             provided, and <constant>dtv_property.stat.len</constant> is updated
-             to reflect the "global" metrics, plus one metric per each carrier
-             group (called "layer" on ISDB).</para>
-       <para>So, in order to be consistent with other delivery systems, the first
-             value at <link linkend="dtv-stats"><constant>dtv_property.stat.dtv_stats</constant></link>
-             array refers to the global metric. The other elements of the array
-             represent each layer, starting from layer A(index 1),
-             layer B (index 2) and so on.</para>
-       <para>The number of filled elements are stored at <constant>dtv_property.stat.len</constant>.</para>
-       <para>Each element of the <constant>dtv_property.stat.dtv_stats</constant> array consists on two elements:</para>
-       <itemizedlist mark='opencircle'>
-               <listitem><para><constant>svalue</constant> or <constant>uvalue</constant>, where
-                       <constant>svalue</constant> is for signed values of the measure (dB measures)
-                       and <constant>uvalue</constant> is for unsigned values (counters, relative scale)</para></listitem>
-               <listitem><para><constant>scale</constant> - Scale for the value. It can be:</para>
-                       <itemizedlist mark='bullet' id="fecap-scale-params">
-                               <listitem id="FE-SCALE-NOT-AVAILABLE"><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition)</para></listitem>
-                               <listitem id="FE-SCALE-DECIBEL"><para><constant>FE_SCALE_DECIBEL</constant> - parameter is a signed value, measured in 1/1000 dB</para></listitem>
-                               <listitem id="FE-SCALE-RELATIVE"><para><constant>FE_SCALE_RELATIVE</constant> - parameter is a unsigned value, where 0 means 0% and 65535 means 100%.</para></listitem>
-                               <listitem id="FE-SCALE-COUNTER"><para><constant>FE_SCALE_COUNTER</constant> - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time.</para></listitem>
-                       </itemizedlist>
-               </listitem>
-       </itemizedlist>
-       <section id="DTV-STAT-SIGNAL-STRENGTH">
-               <title><constant>DTV_STAT_SIGNAL_STRENGTH</constant></title>
-               <para>Indicates the signal strength level at the analog part of the tuner or of the demod.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.001 dBm units, power measured in miliwatts. This value is generally negative.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-CNR">
-               <title><constant>DTV_STAT_CNR</constant></title>
-               <para>Indicates the Signal to Noise ratio for the main carrier.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.001 dB units.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-PRE-ERROR-BIT-COUNT">
-               <title><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></title>
-               <para>Measures the number of bit errors before the forward error correction (FEC) on the inner coding block (before Viterbi, LDPC or other inner code).</para>
-               <para>This measure is taken during the same interval as <constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant>.</para>
-               <para>In order to get the BER (Bit Error Rate) measurement, it should be divided by
-               <link linkend="DTV-STAT-PRE-TOTAL-BIT-COUNT"><constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant></link>.</para>
-               <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
-                     The frontend may reset it when a channel/transponder is tuned.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted before the inner coding.</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-PRE-TOTAL-BIT-COUNT">
-               <title><constant>DTV_STAT_PRE_TOTAL_BIT_COUNT</constant></title>
-               <para>Measures the amount of bits received before the inner code block, during the same period as
-               <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
-               <para>It should be noted that this measurement can be smaller than the total amount of bits on the transport stream,
-                     as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
-               <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
-                     The frontend may reset it when a channel/transponder is tuned.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
-                                <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link>.</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-POST-ERROR-BIT-COUNT">
-               <title><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></title>
-               <para>Measures the number of bit errors after the forward error correction (FEC) done by inner code block (after Viterbi, LDPC or other inner code).</para>
-               <para>This measure is taken during the same interval as <constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant>.</para>
-               <para>In order to get the BER (Bit Error Rate) measurement, it should be divided by
-               <link linkend="DTV-STAT-POST-TOTAL-BIT-COUNT"><constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant></link>.</para>
-               <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
-                     The frontend may reset it when a channel/transponder is tuned.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted after the inner coding.</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-POST-TOTAL-BIT-COUNT">
-               <title><constant>DTV_STAT_POST_TOTAL_BIT_COUNT</constant></title>
-               <para>Measures the amount of bits received after the inner coding, during the same period as
-               <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
-               <para>It should be noted that this measurement can be smaller than the total amount of bits on the transport stream,
-                     as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
-               <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
-                     The frontend may reset it when a channel/transponder is tuned.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
-                                <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link>.</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-ERROR-BLOCK-COUNT">
-               <title><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></title>
-               <para>Measures the number of block errors after the outer forward error correction coding (after Reed-Solomon or other outer code).</para>
-               <para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
-                     The frontend may reset it when a channel/transponder is tuned.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error blocks counted after the outer coding.</para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="DTV-STAT-TOTAL-BLOCK-COUNT">
-               <title><constant>DTV-STAT_TOTAL_BLOCK_COUNT</constant></title>
-               <para>Measures the total number of blocks received during the same period as
-               <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link> measurement was taken.</para>
-               <para>It can be used to calculate the PER indicator, by dividing
-               <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>
-               by <link linkend="DTV-STAT-TOTAL-BLOCK-COUNT"><constant>DTV-STAT-TOTAL-BLOCK-COUNT</constant></link>.</para>
-               <para>Possible scales for this metric are:</para>
-               <itemizedlist mark='bullet'>
-                       <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
-                       <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of blocks counted while measuring
-                       <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>.</para></listitem>
-               </itemizedlist>
-       </section>
-       </section>
-
-       <section id="frontend-property-terrestrial-systems">
-       <title>Properties used on terrestrial delivery systems</title>
-               <section id="dvbt-params">
-                       <title>DVB-T delivery system</title>
-                       <para>The following parameters are valid for DVB-T:</para>
-                       <itemizedlist mark='opencircle'>
-                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
-                       </itemizedlist>
-                       <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-               <section id="dvbt2-params">
-                       <title>DVB-T2 delivery system</title>
-                       <para>DVB-T2 support is currently in the early stages
-                       of development, so expect that this section maygrow and become
-                       more detailed with time.</para>
-               <para>The following parameters are valid for DVB-T2:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-STREAM-ID"><constant>DTV_STREAM_ID</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-               <section id="isdbt">
-               <title>ISDB-T delivery system</title>
-               <para>This ISDB-T/ISDB-Tsb API extension should reflect all information
-                       needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible
-                       that some very sophisticated devices won't need certain parameters to
-                       tune.</para>
-               <para>The information given here should help application writers to know how
-                       to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API.</para>
-               <para>The details given here about ISDB-T and ISDB-Tsb are just enough to
-                       basically show the dependencies between the needed parameter values,
-                       but surely some information is left out. For more detailed information
-                       see the following documents:</para>
-               <para>ARIB STD-B31 - "Transmission System for Digital Terrestrial
-                       Television Broadcasting" and</para>
-               <para>ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial
-                       Television Broadcasting".</para>
-               <para>In order to understand the ISDB specific parameters,
-                       one has to have some knowledge the channel structure in
-                       ISDB-T and ISDB-Tsb. I.e. it has to be known to
-                       the reader that an ISDB-T channel consists of 13 segments,
-                       that it can have up to 3 layer sharing those segments,
-                       and things like that.</para>
-               <para>The following parameters are valid for ISDB-T:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-ENABLED"><constant>DTV_ISDBT_LAYER_ENABLED</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-PARTIAL-RECEPTION"><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-SOUND-BROADCASTING"><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-SB-SUBCHANNEL-ID"><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-IDX"><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-COUNT"><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERA_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERA_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERA_TIME_INTERLEAVING</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERB_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERB_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERB_SEGMENT_COUNT</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERB_TIME_INTERLEAVING</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERC_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERC_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERC_SEGMENT_COUNT</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERC_TIME_INTERLEAVING</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-               <section id="atsc-params">
-                       <title>ATSC delivery system</title>
-                       <para>The following parameters are valid for ATSC:</para>
-                       <itemizedlist mark='opencircle'>
-                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                       </itemizedlist>
-                       <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-               <section id="atscmh-params">
-                       <title>ATSC-MH delivery system</title>
-                       <para>The following parameters are valid for ATSC-MH:</para>
-                       <itemizedlist mark='opencircle'>
-                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-FIC-VER"><constant>DTV_ATSCMH_FIC_VER</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-PARADE-ID"><constant>DTV_ATSCMH_PARADE_ID</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-NOG"><constant>DTV_ATSCMH_NOG</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-TNOG"><constant>DTV_ATSCMH_TNOG</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SGN"><constant>DTV_ATSCMH_SGN</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-PRI"><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-SEC"><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
-                       </itemizedlist>
-                       <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-               <section id="dtmb-params">
-                       <title>DTMB delivery system</title>
-                       <para>The following parameters are valid for DTMB:</para>
-                       <itemizedlist mark='opencircle'>
-                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-INTERLEAVING"><constant>DTV_INTERLEAVING</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
-                       </itemizedlist>
-                       <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               </section>
-       </section>
-       <section id="frontend-property-cable-systems">
-       <title>Properties used on cable delivery systems</title>
-       <section id="dvbc-params">
-               <title>DVB-C delivery system</title>
-               <para>The DVB-C Annex-A is the widely used cable standard. Transmission uses QAM modulation.</para>
-               <para>The DVB-C Annex-C is optimized for 6MHz, and is used in Japan. It supports a subset of the Annex A modulation types, and a roll-off of 0.13, instead of 0.15</para>
-               <para>The following parameters are valid for DVB-C Annex A/C:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-       </section>
-       <section id="dvbc-annex-b-params">
-               <title>DVB-C Annex B delivery system</title>
-               <para>The DVB-C Annex-B is only used on a few Countries like the United States.</para>
-               <para>The following parameters are valid for DVB-C Annex B:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-LNA"><constant>DTV_LNA</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-       </section>
-       </section>
-       <section id="frontend-property-satellite-systems">
-       <title>Properties used on satellite delivery systems</title>
-       <section id="dvbs-params">
-               <title>DVB-S delivery system</title>
-               <para>The following parameters are valid for DVB-S:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-               <para>Future implementations might add those two missing parameters:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="dvbs2-params">
-               <title>DVB-S2 delivery system</title>
-               <para>In addition to all parameters valid for DVB-S, DVB-S2 supports the following parameters:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-PILOT"><constant>DTV_PILOT</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-STREAM-ID"><constant>DTV_STREAM_ID</constant></link></para></listitem>
-               </itemizedlist>
-               <para>In addition, the <link linkend="frontend-stat-properties">DTV QoS statistics</link> are also valid.</para>
-       </section>
-       <section id="turbo-params">
-               <title>Turbo code delivery system</title>
-               <para>In addition to all parameters valid for DVB-S, turbo code supports the following parameters:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
-               </itemizedlist>
-       </section>
-       <section id="isdbs-params">
-               <title>ISDB-S delivery system</title>
-               <para>The following parameters are valid for ISDB-S:</para>
-               <itemizedlist mark='opencircle'>
-                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
-                       <listitem><para><link linkend="DTV-STREAM-ID"><constant>DTV_STREAM_ID</constant></link></para></listitem>
-               </itemizedlist>
-       </section>
-       </section>
-</section>
diff --git a/Documentation/DocBook/media/dvb/dvbstb.pdf b/Documentation/DocBook/media/dvb/dvbstb.pdf
deleted file mode 100644 (file)
index 0fa75d9..0000000
Binary files a/Documentation/DocBook/media/dvb/dvbstb.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/dvb/examples.xml b/Documentation/DocBook/media/dvb/examples.xml
deleted file mode 100644 (file)
index 837fb3b..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-<title>Examples</title>
-<para>In this section we would like to present some examples for using the DVB API.
-</para>
-<para>NOTE: This section is out of date, and the code below won't even
-    compile. Please refer to the
-    <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
-    for updated/recommended examples.
-</para>
-
-<section id="tuning">
-<title>Tuning</title>
-<para>We will start with a generic tuning subroutine that uses the frontend and SEC, as well as
-the demux devices. The example is given for QPSK tuners, but can easily be adjusted for
-QAM.
-</para>
-<programlisting>
- #include &#x003C;sys/ioctl.h&#x003E;
- #include &#x003C;stdio.h&#x003E;
- #include &#x003C;stdint.h&#x003E;
- #include &#x003C;sys/types.h&#x003E;
- #include &#x003C;sys/stat.h&#x003E;
- #include &#x003C;fcntl.h&#x003E;
- #include &#x003C;time.h&#x003E;
- #include &#x003C;unistd.h&#x003E;
-
- #include &#x003C;linux/dvb/dmx.h&#x003E;
- #include &#x003C;linux/dvb/frontend.h&#x003E;
- #include &#x003C;linux/dvb/sec.h&#x003E;
- #include &#x003C;sys/poll.h&#x003E;
-
- #define DMX "/dev/dvb/adapter0/demux1"
- #define FRONT "/dev/dvb/adapter0/frontend1"
- #define SEC "/dev/dvb/adapter0/sec1"
-
- /&#x22C6; routine for checking if we have a signal and other status information&#x22C6;/
- int FEReadStatus(int fd, fe_status_t &#x22C6;stat)
- {
-        int ans;
-
-        if ( (ans = ioctl(fd,FE_READ_STATUS,stat) &#x003C; 0)){
-                perror("FE READ STATUS: ");
-                return -1;
-        }
-
-        if (&#x22C6;stat &amp; FE_HAS_POWER)
-                printf("FE HAS POWER\n");
-
-        if (&#x22C6;stat &amp; FE_HAS_SIGNAL)
-                printf("FE HAS SIGNAL\n");
-
-        if (&#x22C6;stat &amp; FE_SPECTRUM_INV)
-                printf("SPEKTRUM INV\n");
-
-        return 0;
- }
-
-
- /&#x22C6; tune qpsk &#x22C6;/
- /&#x22C6; freq:             frequency of transponder                      &#x22C6;/
- /&#x22C6; vpid, apid, tpid: PIDs of video, audio and teletext TS packets  &#x22C6;/
- /&#x22C6; diseqc:           DiSEqC address of the used LNB                &#x22C6;/
- /&#x22C6; pol:              Polarisation                                  &#x22C6;/
- /&#x22C6; srate:            Symbol Rate                                   &#x22C6;/
- /&#x22C6; fec.              FEC                                           &#x22C6;/
- /&#x22C6; lnb_lof1:         local frequency of lower LNB band             &#x22C6;/
- /&#x22C6; lnb_lof2:         local frequency of upper LNB band             &#x22C6;/
- /&#x22C6; lnb_slof:         switch frequency of LNB                       &#x22C6;/
-
- int set_qpsk_channel(int freq, int vpid, int apid, int tpid,
-                int diseqc, int pol, int srate, int fec, int lnb_lof1,
-                int lnb_lof2, int lnb_slof)
- {
-        struct secCommand scmd;
-        struct secCmdSequence scmds;
-        struct dmx_pes_filter_params pesFilterParams;
-        FrontendParameters frp;
-        struct pollfd pfd[1];
-        FrontendEvent event;
-        int demux1, demux2, demux3, front;
-
-        frequency = (uint32_t) freq;
-        symbolrate = (uint32_t) srate;
-
-        if((front = open(FRONT,O_RDWR)) &#x003C; 0){
-                perror("FRONTEND DEVICE: ");
-                return -1;
-        }
-
-        if((sec = open(SEC,O_RDWR)) &#x003C; 0){
-                perror("SEC DEVICE: ");
-                return -1;
-        }
-
-        if (demux1 &#x003C; 0){
-                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux2 &#x003C; 0){
-                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux3 &#x003C; 0){
-                if ((demux3=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (freq &#x003C; lnb_slof) {
-                frp.Frequency = (freq - lnb_lof1);
-                scmds.continuousTone = SEC_TONE_OFF;
-        } else {
-                frp.Frequency = (freq - lnb_lof2);
-                scmds.continuousTone = SEC_TONE_ON;
-        }
-        frp.Inversion = INVERSION_AUTO;
-        if (pol) scmds.voltage = SEC_VOLTAGE_18;
-        else scmds.voltage = SEC_VOLTAGE_13;
-
-        scmd.type=0;
-        scmd.u.diseqc.addr=0x10;
-        scmd.u.diseqc.cmd=0x38;
-        scmd.u.diseqc.numParams=1;
-        scmd.u.diseqc.params[0] = 0xF0 | ((diseqc &#x22C6; 4) &amp; 0x0F) |
-                (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
-                (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
-
-        scmds.miniCommand=SEC_MINI_NONE;
-        scmds.numCommands=1;
-        scmds.commands=&amp;scmd;
-        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
-                perror("SEC SEND: ");
-                return -1;
-        }
-
-        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
-                perror("SEC SEND: ");
-                return -1;
-        }
-
-        frp.u.qpsk.SymbolRate = srate;
-        frp.u.qpsk.FEC_inner = fec;
-
-        if (ioctl(front, FE_SET_FRONTEND, &amp;frp) &#x003C; 0){
-                perror("QPSK TUNE: ");
-                return -1;
-        }
-
-        pfd[0].fd = front;
-        pfd[0].events = POLLIN;
-
-        if (poll(pfd,1,3000)){
-                if (pfd[0].revents &amp; POLLIN){
-                        printf("Getting QPSK event\n");
-                        if ( ioctl(front, FE_GET_EVENT, &amp;event)
-
-                             == -EOVERFLOW){
-                                perror("qpsk get event");
-                                return -1;
-                        }
-                        printf("Received ");
-                        switch(event.type){
-                        case FE_UNEXPECTED_EV:
-                                printf("unexpected event\n");
-                                return -1;
-                        case FE_FAILURE_EV:
-                                printf("failure event\n");
-                                return -1;
-
-                        case FE_COMPLETION_EV:
-                                printf("completion event\n");
-                        }
-                }
-        }
-
-
-        pesFilterParams.pid     = vpid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_VIDEO;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_vpid");
-                return -1;
-        }
-
-        pesFilterParams.pid     = apid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_AUDIO;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_apid");
-                return -1;
-        }
-
-        pesFilterParams.pid     = tpid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_TELETEXT;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux3, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_tpid");
-                return -1;
-        }
-
-        return has_signal(fds);
- }
-
-</programlisting>
-<para>The program assumes that you are using a universal LNB and a standard DiSEqC
-switch with up to 4 addresses. Of course, you could build in some more checking if
-tuning was successful and maybe try to repeat the tuning process. Depending on the
-external hardware, i.e. LNB and DiSEqC switch, and weather conditions this may be
-necessary.
-</para>
-</section>
-
-<section id="the_dvr_device">
-<title>The DVR device</title>
-<para>The following program code shows how to use the DVR device for recording.
-</para>
-<programlisting>
- #include &#x003C;sys/ioctl.h&#x003E;
- #include &#x003C;stdio.h&#x003E;
- #include &#x003C;stdint.h&#x003E;
- #include &#x003C;sys/types.h&#x003E;
- #include &#x003C;sys/stat.h&#x003E;
- #include &#x003C;fcntl.h&#x003E;
- #include &#x003C;time.h&#x003E;
- #include &#x003C;unistd.h&#x003E;
-
- #include &#x003C;linux/dvb/dmx.h&#x003E;
- #include &#x003C;linux/dvb/video.h&#x003E;
- #include &#x003C;sys/poll.h&#x003E;
- #define DVR "/dev/dvb/adapter0/dvr1"
- #define AUDIO "/dev/dvb/adapter0/audio1"
- #define VIDEO "/dev/dvb/adapter0/video1"
-
- #define BUFFY (188&#x22C6;20)
- #define MAX_LENGTH (1024&#x22C6;1024&#x22C6;5) /&#x22C6; record 5MB &#x22C6;/
-
-
- /&#x22C6; switch the demuxes to recording, assuming the transponder is tuned &#x22C6;/
-
- /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
- /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
-
- int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid)
- {
-        struct dmx_pes_filter_params pesFilterParams;
-
-        if (demux1 &#x003C; 0){
-                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux2 &#x003C; 0){
-                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        pesFilterParams.pid = vpid;
-        pesFilterParams.input = DMX_IN_FRONTEND;
-        pesFilterParams.output = DMX_OUT_TS_TAP;
-        pesFilterParams.pes_type = DMX_PES_VIDEO;
-        pesFilterParams.flags = DMX_IMMEDIATE_START;
-        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("DEMUX DEVICE");
-                return -1;
-        }
-        pesFilterParams.pid = apid;
-        pesFilterParams.input = DMX_IN_FRONTEND;
-        pesFilterParams.output = DMX_OUT_TS_TAP;
-        pesFilterParams.pes_type = DMX_PES_AUDIO;
-        pesFilterParams.flags = DMX_IMMEDIATE_START;
-        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("DEMUX DEVICE");
-                return -1;
-        }
-        return 0;
- }
-
- /&#x22C6; start recording MAX_LENGTH , assuming the transponder is tuned &#x22C6;/
-
- /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
- /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
- int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid)
- {
-        int i;
-        int len;
-        int written;
-        uint8_t buf[BUFFY];
-        uint64_t length;
-        struct pollfd pfd[1];
-        int dvr, dvr_out;
-
-        /&#x22C6; open dvr device &#x22C6;/
-        if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) &#x003C; 0){
-                        perror("DVR DEVICE");
-                        return -1;
-        }
-
-        /&#x22C6; switch video and audio demuxes to dvr &#x22C6;/
-        printf ("Switching dvr on\n");
-        i = switch_to_record(demux1, demux2, vpid, apid);
-        printf("finished: ");
-
-        printf("Recording %2.0f MB of test file in TS format\n",
-               MAX_LENGTH/(1024.0&#x22C6;1024.0));
-        length = 0;
-
-        /&#x22C6; open output file &#x22C6;/
-        if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT
-                                 |O_TRUNC, S_IRUSR|S_IWUSR
-                                 |S_IRGRP|S_IWGRP|S_IROTH|
-                                 S_IWOTH)) &#x003C; 0){
-                perror("Can't open file for dvr test");
-                return -1;
-        }
-
-        pfd[0].fd = dvr;
-        pfd[0].events = POLLIN;
-
-        /&#x22C6; poll for dvr data and write to file &#x22C6;/
-        while (length &#x003C; MAX_LENGTH ) {
-                if (poll(pfd,1,1)){
-                        if (pfd[0].revents &amp; POLLIN){
-                                len = read(dvr, buf, BUFFY);
-                                if (len &#x003C; 0){
-                                        perror("recording");
-                                        return -1;
-                                }
-                                if (len &#x003E; 0){
-                                        written = 0;
-                                        while (written &#x003C; len)
-                                                written +=
-                                                        write (dvr_out,
-                                                               buf, len);
-                                        length += len;
-                                        printf("written %2.0f MB\r",
-                                               length/1024./1024.);
-                                }
-                        }
-                }
-        }
-        return 0;
- }
-
-</programlisting>
-
-</section>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml b/Documentation/DocBook/media/dvb/fe-diseqc-recv-slave-reply.xml
deleted file mode 100644 (file)
index 4595dbf..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<refentry id="FE_DISEQC_RECV_SLAVE_REPLY">
-  <refmeta>
-    <refentrytitle>ioctl FE_DISEQC_RECV_SLAVE_REPLY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_DISEQC_RECV_SLAVE_REPLY</refname>
-    <refpurpose>Receives reply from a DiSEqC 2.0 command</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 dvb_diseqc_slave_reply *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_DISEQC_RECV_SLAVE_REPLY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-           <para>pointer to &dvb-diseqc-slave-reply;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Receives reply from a DiSEqC 2.0 command.</para>
-&return-value-dvb;
-
-<table pgwide="1" frame="none" id="dvb-diseqc-slave-reply">
-    <title>struct <structname>dvb_diseqc_slave_reply</structname></title>
-    <tgroup cols="3">
-    &cs-str;
-    <tbody valign="top">
-       <row>
-       <entry>uint8_t</entry>
-       <entry>msg[4]</entry>
-       <entry>DiSEqC message (framing, data[3])</entry>
-       </row><row>
-       <entry>uint8_t</entry>
-       <entry>msg_len</entry>
-       <entry>Length of the DiSEqC message. Valid values are 0 to 4,
-           where 0 means no msg</entry>
-       </row><row>
-       <entry>int</entry>
-       <entry>timeout</entry>
-       <entry>Return from ioctl after timeout ms with errorcode when no
-           message was received</entry>
-       </row>
-    </tbody>
-    </tgroup>
-</table>
-
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml b/Documentation/DocBook/media/dvb/fe-diseqc-reset-overload.xml
deleted file mode 100644 (file)
index c104df7..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<refentry id="FE_DISEQC_RESET_OVERLOAD">
-  <refmeta>
-    <refentrytitle>ioctl FE_DISEQC_RESET_OVERLOAD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_DISEQC_RESET_OVERLOAD</refname>
-    <refpurpose>Restores the power to the antenna subsystem, if it was powered
-       off due to power overload.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>NULL</paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_DISEQC_RESET_OVERLOAD</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>If the bus has been automatically powered off due to power overload, this ioctl
- call restores the power to the bus. The call requires read/write access to the
- device. This call has no effect if the device is manually powered off. Not all
- DVB adapters support this ioctl.</para>
-&return-value-dvb;
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml b/Documentation/DocBook/media/dvb/fe-diseqc-send-burst.xml
deleted file mode 100644 (file)
index 9f6a68f..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<refentry id="FE_DISEQC_SEND_BURST">
-  <refmeta>
-    <refentrytitle>ioctl FE_DISEQC_SEND_BURST</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_DISEQC_SEND_BURST</refname>
-    <refpurpose>Sends a 22KHz tone burst for 2x1 mini DiSEqC satellite selection.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>enum fe_sec_mini_cmd *<parameter>tone</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_DISEQC_SEND_BURST</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>tone</parameter></term>
-       <listitem>
-         <para>pointer to &fe-sec-mini-cmd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>This ioctl is used to set the generation of a 22kHz tone burst for mini
-    DiSEqC satellite
-    selection for 2x1 switches.
-    This call requires read/write permissions.</para>
-<para>It provides support for what's specified at
-    <ulink url="http://www.eutelsat.com/files/contributed/satellites/pdf/Diseqc/associated%20docs/simple_tone_burst_detec.pdf">Digital Satellite Equipment Control
-       (DiSEqC) - Simple "ToneBurst" Detection Circuit specification.</ulink>
-    </para>
-&return-value-dvb;
-</refsect1>
-
-<refsect1 id="fe-sec-mini-cmd-t">
-<title>enum fe_sec_mini_cmd</title>
-
-<table pgwide="1" frame="none" id="fe-sec-mini-cmd">
-    <title>enum fe_sec_mini_cmd</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="SEC-MINI-A"><constant>SEC_MINI_A</constant></entry>
-           <entry align="char">Sends a mini-DiSEqC 22kHz '0' Tone Burst to
-               select satellite-A</entry>
-       </row><row>
-           <entry align="char" id="SEC-MINI-B"><constant>SEC_MINI_B</constant></entry>
-           <entry align="char">Sends a mini-DiSEqC 22kHz '1' Data Burst to
-               select satellite-B</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml b/Documentation/DocBook/media/dvb/fe-diseqc-send-master-cmd.xml
deleted file mode 100644 (file)
index 38cf313..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<refentry id="FE_DISEQC_SEND_MASTER_CMD">
-  <refmeta>
-    <refentrytitle>ioctl FE_DISEQC_SEND_MASTER_CMD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_DISEQC_SEND_MASTER_CMD</refname>
-    <refpurpose>Sends a DiSEqC command</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 dvb_diseqc_master_cmd *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_DISEQC_SEND_MASTER_CMD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-           <para>pointer to &dvb-diseqc-master-cmd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Sends a DiSEqC command to the antenna subsystem.</para>
-&return-value-dvb;
-
-<table pgwide="1" frame="none" id="dvb-diseqc-master-cmd">
-    <title>struct <structname>dvb_diseqc_master_cmd</structname></title>
-    <tgroup cols="3">
-    &cs-str;
-    <tbody valign="top">
-       <row>
-       <entry>uint8_t</entry>
-       <entry>msg[6]</entry>
-       <entry>DiSEqC message (framing, address, command, data[3])</entry>
-       </row><row>
-       <entry>uint8_t</entry>
-       <entry>msg_len</entry>
-       <entry>Length of the DiSEqC message. Valid values are 3 to 6</entry>
-       </row>
-    </tbody>
-    </tgroup>
-</table>
-
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml b/Documentation/DocBook/media/dvb/fe-enable-high-lnb-voltage.xml
deleted file mode 100644 (file)
index c11890b..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-<refentry id="FE_ENABLE_HIGH_LNB_VOLTAGE">
-  <refmeta>
-    <refentrytitle>ioctl FE_ENABLE_HIGH_LNB_VOLTAGE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_ENABLE_HIGH_LNB_VOLTAGE</refname>
-    <refpurpose>Select output DC level between normal LNBf voltages or higher
-       LNBf voltages.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>unsigned int <parameter>high</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_ENABLE_HIGH_LNB_VOLTAGE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>high</parameter></term>
-       <listitem>
-           <para>Valid flags:</para>
-           <itemizedlist>
-               <listitem><para>0 - normal 13V and 18V.</para></listitem>
-               <listitem><para>&gt;0 - enables slightly higher voltages instead of
-                   13/18V, in order to compensate for long antenna cables.</para></listitem>
-           </itemizedlist>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Select output DC level between normal LNBf voltages or higher
-       LNBf voltages between 0 (normal) or a value grater than 0 for higher
-       voltages.</para>
-&return-value-dvb;
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-get-info.xml b/Documentation/DocBook/media/dvb/fe-get-info.xml
deleted file mode 100644 (file)
index ed0eeb2..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-<refentry id="FE_GET_INFO">
-  <refmeta>
-    <refentrytitle>ioctl FE_GET_INFO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_GET_INFO</refname>
-    <refpurpose>Query DVB frontend capabilities and returns information about
-       the front-end. This call only requires read-only access to the device</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 dvb_frontend_info *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_GET_INFO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-           <para>pointer to struct &dvb-frontend-info;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All DVB frontend devices support the
-<constant>FE_GET_INFO</constant> ioctl. It is used to identify
-kernel devices compatible with this specification and to obtain
-information about driver and hardware capabilities. The ioctl takes a
-pointer to dvb_frontend_info which is filled by the driver. When the
-driver is not compatible with this specification the ioctl returns an error.
-</para>
-&return-value-dvb;
-
-    <table pgwide="1" frame="none" id="dvb-frontend-info">
-      <title>struct <structname>dvb_frontend_info</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>char</entry>
-           <entry>name[128]</entry>
-           <entry>Name of the frontend</entry>
-         </row><row>
-           <entry>fe_type_t</entry>
-           <entry>type</entry>
-           <entry><emphasis role="bold">DEPRECATED</emphasis>. DVBv3 type. Should not be used on modern programs, as a
-               frontend may have more than one type. So, the DVBv5 API should
-               be used instead to enumerate and select the frontend type.</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>frequency_min</entry>
-           <entry>Minimal frequency supported by the frontend</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>frequency_max</entry>
-           <entry>Maximal frequency supported by the frontend</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>frequency_stepsize</entry>
-           <entry>Frequency step - all frequencies are multiple of this value</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>frequency_tolerance</entry>
-           <entry>Tolerance of the frequency</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>symbol_rate_min</entry>
-           <entry>Minimal symbol rate (for Cable/Satellite systems), in bauds</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>symbol_rate_max</entry>
-           <entry>Maximal symbol rate (for Cable/Satellite systems), in bauds</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>symbol_rate_tolerance</entry>
-           <entry>Maximal symbol rate tolerance, in ppm</entry>
-         </row><row>
-           <entry>uint32_t</entry>
-           <entry>notifier_delay</entry>
-           <entry><emphasis role="bold">DEPRECATED</emphasis>. Not used by any driver.</entry>
-         </row><row>
-           <entry>&fe-caps;</entry>
-           <entry>caps</entry>
-           <entry>Capabilities supported by the frontend</entry>
-          </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  <para>NOTE: The frequencies are specified in Hz for Terrestrial and Cable
-      systems. They're specified in kHz for Satellite systems</para>
-  </refsect1>
-
-<refsect1 id="fe-caps-t">
-<title>frontend capabilities</title>
-
-<para>Capabilities describe what a frontend can do. Some capabilities are
-    supported only on some specific frontend types.</para>
-
-<table pgwide="1" frame="none" id="fe-caps">
-    <title>enum fe_caps</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-       <entry id="FE-IS-STUPID"><constant>FE_IS_STUPID</constant></entry>
-       <entry>There's something wrong at the frontend, and it can't
-           report its capabilities</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-INVERSION-AUTO"><constant>FE_CAN_INVERSION_AUTO</constant></entry>
-       <entry>The frontend is capable of auto-detecting inversion</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-1-2"><constant>FE_CAN_FEC_1_2</constant></entry>
-       <entry>The frontend supports FEC 1/2</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-2-3"><constant>FE_CAN_FEC_2_3</constant></entry>
-       <entry>The frontend supports FEC 2/3</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-3-4"><constant>FE_CAN_FEC_3_4</constant></entry>
-       <entry>The frontend supports FEC 3/4</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-4-5"><constant>FE_CAN_FEC_4_5</constant></entry>
-       <entry>The frontend supports FEC 4/5</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-5-6"><constant>FE_CAN_FEC_5_6</constant></entry>
-       <entry>The frontend supports FEC 5/6</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-6-7"><constant>FE_CAN_FEC_6_7</constant></entry>
-       <entry>The frontend supports FEC 6/7</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-7-8"><constant>FE_CAN_FEC_7_8</constant></entry>
-       <entry>The frontend supports FEC 7/8</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-8-9"><constant>FE_CAN_FEC_8_9</constant></entry>
-       <entry>The frontend supports FEC 8/9</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-FEC-AUTO"><constant>FE_CAN_FEC_AUTO</constant></entry>
-       <entry>The frontend can autodetect FEC.</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QPSK"><constant>FE_CAN_QPSK</constant></entry>
-       <entry>The frontend supports QPSK modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-16"><constant>FE_CAN_QAM_16</constant></entry>
-       <entry>The frontend supports 16-QAM modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-32"><constant>FE_CAN_QAM_32</constant></entry>
-       <entry>The frontend supports 32-QAM modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-64"><constant>FE_CAN_QAM_64</constant></entry>
-       <entry>The frontend supports 64-QAM modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-128"><constant>FE_CAN_QAM_128</constant></entry>
-       <entry>The frontend supports 128-QAM modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-256"><constant>FE_CAN_QAM_256</constant></entry>
-       <entry>The frontend supports 256-QAM modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-QAM-AUTO"><constant>FE_CAN_QAM_AUTO</constant></entry>
-       <entry>The frontend can autodetect modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-TRANSMISSION-MODE-AUTO"><constant>FE_CAN_TRANSMISSION_MODE_AUTO</constant></entry>
-       <entry>The frontend can autodetect the transmission mode</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-BANDWIDTH-AUTO"><constant>FE_CAN_BANDWIDTH_AUTO</constant></entry>
-       <entry>The frontend can autodetect the bandwidth</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-GUARD-INTERVAL-AUTO"><constant>FE_CAN_GUARD_INTERVAL_AUTO</constant></entry>
-       <entry>The frontend can autodetect the guard interval</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-HIERARCHY-AUTO"><constant>FE_CAN_HIERARCHY_AUTO</constant></entry>
-       <entry>The frontend can autodetect hierarch</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-8VSB"><constant>FE_CAN_8VSB</constant></entry>
-       <entry>The frontend supports 8-VSB modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-16VSB"><constant>FE_CAN_16VSB</constant></entry>
-       <entry>The frontend supports 16-VSB modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-HAS-EXTENDED-CAPS"><constant>FE_HAS_EXTENDED_CAPS</constant></entry>
-       <entry>Currently, unused</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-MULTISTREAM"><constant>FE_CAN_MULTISTREAM</constant></entry>
-       <entry>The frontend supports multistream filtering</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-TURBO-FEC"><constant>FE_CAN_TURBO_FEC</constant></entry>
-       <entry>The frontend supports turbo FEC modulation</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-2G-MODULATION"><constant>FE_CAN_2G_MODULATION</constant></entry>
-       <entry>The frontend supports "2nd generation modulation" (DVB-S2/T2)></entry>
-       </row>
-       <row>
-       <entry id="FE-NEEDS-BENDING"><constant>FE_NEEDS_BENDING</constant></entry>
-       <entry>Not supported anymore, don't use it</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-RECOVER"><constant>FE_CAN_RECOVER</constant></entry>
-       <entry>The frontend can recover from a cable unplug automatically</entry>
-       </row>
-       <row>
-       <entry id="FE-CAN-MUTE-TS"><constant>FE_CAN_MUTE_TS</constant></entry>
-       <entry>The frontend can stop spurious TS data output</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-get-property.xml b/Documentation/DocBook/media/dvb/fe-get-property.xml
deleted file mode 100644 (file)
index 53a170e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<refentry id="FE_GET_PROPERTY">
-  <refmeta>
-    <refentrytitle>ioctl FE_SET_PROPERTY, FE_GET_PROPERTY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-      <refname>FE_SET_PROPERTY</refname>
-      <refname>FE_GET_PROPERTY</refname>
-    <refpurpose>FE_SET_PROPERTY sets one or more frontend properties.
-       FE_GET_PROPERTY returns one or more frontend properties.</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 dtv_properties *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_PROPERTY, FE_GET_PROPERTY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-           <para>pointer to &dtv-properties;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All DVB frontend devices support the
-<constant>FE_SET_PROPERTY</constant> and <constant>FE_GET_PROPERTY</constant>
-ioctls. The supported properties and statistics depends on the delivery system
-and on the device:</para>
-<itemizedlist>
-<listitem>
-    <para><constant>FE_SET_PROPERTY:</constant></para>
-<itemizedlist>
-<listitem><para>This ioctl is used to set one or more
-       frontend properties.</para></listitem>
-<listitem><para>This is the basic command to request the frontend to tune into some
-    frequency and to start decoding the digital TV signal.</para></listitem>
-<listitem><para>This call requires read/write access to the device.</para></listitem>
-<listitem><para>At return, the values are updated to reflect the
-    actual parameters used.</para></listitem>
-</itemizedlist>
-</listitem>
-<listitem>
-    <para><constant>FE_GET_PROPERTY:</constant></para>
-<itemizedlist>
-<listitem><para>This ioctl is used to get properties and
-statistics from the frontend.</para></listitem>
-<listitem><para>No properties are changed, and statistics aren't reset.</para></listitem>
-<listitem><para>This call only requires read-only access to the device.</para></listitem>
-</itemizedlist>
-</listitem>
-</itemizedlist>
-&return-value-dvb;
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-read-status.xml b/Documentation/DocBook/media/dvb/fe-read-status.xml
deleted file mode 100644 (file)
index bc0dc2a..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<refentry id="FE_READ_STATUS">
-  <refmeta>
-    <refentrytitle>ioctl FE_READ_STATUS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_READ_STATUS</refname>
-    <refpurpose>Returns status information about the front-end. This call only
- requires read-only access to the device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>unsigned int *<parameter>status</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_READ_STATUS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>status</parameter></term>
-       <listitem>
-           <para>pointer to a bitmask integer filled with the values defined by
-               &fe-status;.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All DVB frontend devices support the
-<constant>FE_READ_STATUS</constant> ioctl. It is used to check about the
-locking status of the frontend after being tuned. The ioctl takes a
-pointer to an integer where the status will be written.
-</para>
-<para>NOTE: the size of status is actually sizeof(enum fe_status), with varies
-    according with the architecture. This needs to be fixed in the future.</para>
-&return-value-dvb;
-</refsect1>
-
-<refsect1 id="fe-status-t">
-<title>int fe_status</title>
-
-<para>The fe_status parameter is used to indicate the current state
-    and/or state changes of the frontend hardware. It is produced using
-    the &fe-status; values on a bitmask</para>
-
-<table pgwide="1" frame="none" id="fe-status">
-    <title>enum fe_status</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="FE-HAS-SIGNAL"><constant>FE_HAS_SIGNAL</constant></entry>
-           <entry align="char">The frontend has found something above the noise level</entry>
-       </row><row>
-           <entry align="char" id="FE-HAS-CARRIER"><constant>FE_HAS_CARRIER</constant></entry>
-           <entry align="char">The frontend has found a DVB signal</entry>
-       </row><row>
-           <entry align="char" id="FE-HAS-VITERBI"><constant>FE_HAS_VITERBI</constant></entry>
-           <entry align="char">The frontend FEC inner coding (Viterbi, LDPC or other inner code) is stable</entry>
-       </row><row>
-           <entry align="char" id="FE-HAS-SYNC"><constant>FE_HAS_SYNC</constant></entry>
-           <entry align="char">Synchronization bytes was found</entry>
-       </row><row>
-           <entry align="char" id="FE-HAS-LOCK"><constant>FE_HAS_LOCK</constant></entry>
-           <entry align="char">The DVB were locked and everything is working</entry>
-       </row><row>
-           <entry align="char" id="FE-TIMEDOUT"><constant>FE_TIMEDOUT</constant></entry>
-           <entry align="char">no lock within the last about 2 seconds</entry>
-       </row><row>
-           <entry align="char" id="FE-REINIT"><constant>FE_REINIT</constant></entry>
-           <entry align="char">The frontend was reinitialized, application is
-           recommended to reset DiSEqC, tone and parameters</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml b/Documentation/DocBook/media/dvb/fe-set-frontend-tune-mode.xml
deleted file mode 100644 (file)
index 99fa8a0..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<refentry id="FE_SET_FRONTEND_TUNE_MODE">
-  <refmeta>
-    <refentrytitle>ioctl FE_SET_FRONTEND_TUNE_MODE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_SET_FRONTEND_TUNE_MODE</refname>
-    <refpurpose>Allow setting tuner mode flags to the frontend.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>unsigned int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_FRONTEND_TUNE_MODE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-           <para>Valid flags:</para>
-           <itemizedlist>
-               <listitem><para>0 - normal tune mode</para></listitem>
-               <listitem><para>FE_TUNE_MODE_ONESHOT - When set, this flag will
-                   disable any zigzagging or other "normal" tuning behaviour.
-                   Additionally, there will be no automatic monitoring of the
-                   lock status, and hence no frontend events will be
-                   generated. If a frontend device is closed, this flag will
-                   be automatically turned off when the device is reopened
-                   read-write.</para></listitem>
-           </itemizedlist>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Allow setting tuner mode flags to the frontend, between 0 (normal)
-       or FE_TUNE_MODE_ONESHOT mode</para>
-&return-value-dvb;
-</refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-tone.xml b/Documentation/DocBook/media/dvb/fe-set-tone.xml
deleted file mode 100644 (file)
index 62d44e4..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<refentry id="FE_SET_TONE">
-  <refmeta>
-    <refentrytitle>ioctl FE_SET_TONE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_SET_TONE</refname>
-    <refpurpose>Sets/resets the generation of the continuous 22kHz tone.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>enum fe_sec_tone_mode *<parameter>tone</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_TONE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>tone</parameter></term>
-       <listitem>
-         <para>pointer to &fe-sec-tone-mode;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>This ioctl is used to set the generation of the continuous 22kHz tone.
-    This call requires read/write permissions.</para>
-<para>Usually, satellite antenna subsystems require that the digital TV
-    device to send a 22kHz tone in order to select between high/low band on
-    some dual-band LNBf. It is also used to send signals to DiSEqC equipment,
-    but this is done using the DiSEqC ioctls.</para>
-<para>NOTE: if more than one device is connected to the same antenna,
-    setting a tone may interfere on other devices, as they may lose
-    the capability of selecting the band. So, it is recommended that
-    applications would change to SEC_TONE_OFF when the device is not used.</para>
-
-&return-value-dvb;
-</refsect1>
-
-<refsect1 id="fe-sec-tone-mode-t">
-<title>enum fe_sec_tone_mode</title>
-
-<table pgwide="1" frame="none" id="fe-sec-tone-mode">
-    <title>enum fe_sec_tone_mode</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char" id="SEC-TONE-ON"><constant>SEC_TONE_ON</constant></entry>
-           <entry align="char">Sends a 22kHz tone burst to the antenna</entry>
-       </row><row>
-           <entry align="char" id="SEC-TONE-OFF"><constant>SEC_TONE_OFF</constant></entry>
-           <entry align="char">Don't send a 22kHz tone to the antenna
-               (except if the FE_DISEQC_* ioctls are called)</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/fe-set-voltage.xml b/Documentation/DocBook/media/dvb/fe-set-voltage.xml
deleted file mode 100644 (file)
index c89a6f7..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<refentry id="FE_SET_VOLTAGE">
-  <refmeta>
-    <refentrytitle>ioctl FE_SET_VOLTAGE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>FE_SET_VOLTAGE</refname>
-    <refpurpose>Allow setting the DC level sent to the antenna subsystem.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>enum fe_sec_voltage *<parameter>voltage</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_VOLTAGE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>voltage</parameter></term>
-       <listitem>
-         <para>pointer to &fe-sec-voltage;</para>
-         <para>Valid values are described at &fe-sec-voltage;.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>This ioctl allows to set the DC voltage level sent through the antenna
-    cable to 13V, 18V or off.</para>
-<para>Usually, a satellite antenna subsystems require that the digital TV
-    device to send a DC voltage to feed power to the LNBf. Depending on the
-    LNBf type, the polarization or the intermediate frequency (IF) of the LNBf
-    can controlled by the voltage level. Other devices (for example, the ones
-    that implement DISEqC and multipoint LNBf's don't need to control the
-    voltage level, provided that either 13V or 18V is sent to power up the
-    LNBf.</para>
-<para>NOTE: if more than one device is connected to the same antenna,
-    setting a voltage level may interfere on other devices, as they may lose
-    the capability of setting polarization or IF. So, on those
-    cases, setting the voltage to SEC_VOLTAGE_OFF while the device is not is
-    used is recommended.</para>
-
-&return-value-dvb;
-</refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
deleted file mode 100644 (file)
index 01210b3..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-<title>DVB Frontend API</title>
-
-<para>The DVB frontend API was designed to support three types of delivery systems:</para>
-<itemizedlist>
-    <listitem><para>Terrestrial systems: DVB-T, DVB-T2, ATSC, ATSC M/H, ISDB-T, DVB-H, DTMB, CMMB</para></listitem>
-    <listitem><para>Cable systems: DVB-C Annex A/C, ClearQAM (DVB-C Annex B), ISDB-C</para></listitem>
-    <listitem><para>Satellite systems: DVB-S, DVB-S2, DVB Turbo, ISDB-S, DSS</para></listitem>
-</itemizedlist>
-<para>The DVB frontend controls several sub-devices including:</para>
-<itemizedlist>
-    <listitem><para>Tuner</para></listitem>
-    <listitem><para>Digital TV demodulator</para></listitem>
-    <listitem><para>Low noise amplifier (LNA)</para></listitem>
-    <listitem><para>Satellite Equipment Control (SEC) hardware (only for Satellite).</para></listitem>
-</itemizedlist>
-<para>The frontend can be accessed through
-    <constant>/dev/dvb/adapter?/frontend?</constant>. Data types and
-    ioctl definitions can be accessed by including
-    <constant>linux/dvb/frontend.h</constant> in your application.
-</para>
-
-<para>NOTE: Transmission via the internet (DVB-IP)
-    is not yet handled by this API but a future extension is possible.</para>
-<para>On Satellite systems, the API support for the Satellite Equipment Control
-    (SEC) allows to power control and to send/receive signals to control the
-    antenna subsystem, selecting the polarization and choosing the Intermediate
-    Frequency IF) of the Low Noise Block Converter Feed Horn (LNBf). It
-    supports the DiSEqC and V-SEC protocols. The DiSEqC (digital SEC)
-specification is available at
-<ulink url="http://www.eutelsat.com/satellites/4_5_5.html">Eutelsat</ulink>.</para>
-
-<section id="query-dvb-frontend-info">
-<title>Querying frontend information</title>
-
-<para>Usually, the first thing to do when the frontend is opened is to
-    check the frontend capabilities. This is done using <link linkend="FE_GET_INFO">FE_GET_INFO</link>. This ioctl will enumerate
-    the DVB API version and other characteristics about the frontend, and
-    can be opened either in read only or read/write mode.</para>
-</section>
-
-<section id="dvb-fe-read-status">
-<title>Querying frontend status and statistics</title>
-
-<para>Once <link linkend="FE_GET_PROPERTY"><constant>FE_SET_PROPERTY</constant></link>
-    is called, the frontend will run a kernel thread that will periodically
-    check for the tuner lock status and provide statistics about the quality
-    of the signal.</para>
-<para>The information about the frontend tuner locking status can be queried
-    using <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>.</para>
-<para>Signal statistics are provided via <link linkend="FE_GET_PROPERTY"><constant>FE_GET_PROPERTY</constant></link>.
-    Please note that several statistics require the demodulator to be fully
-    locked (e. g. with FE_HAS_LOCK bit set). See
-    <link linkend="frontend-stat-properties">Frontend statistics indicators</link>
-    for more details.</para>
-</section>
-
-&sub-dvbproperty;
-
-<section id="frontend_fcalls">
-<title>Frontend Function Calls</title>
-
-<refentry id="frontend_f_open">
-  <refmeta>
-    <refentrytitle>DVB frontend open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>fe-open</refname>
-    <refpurpose>Open a frontend device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access can either be
-              <constant>O_RDWR</constant> or <constant>O_RDONLY</constant>.</para>
-          <para>Multiple opens are allowed with <constant>O_RDONLY</constant>. In this mode, only query and read ioctls are allowed.</para>
-          <para>Only one open is allowed in <constant>O_RDWR</constant>. In this mode, all ioctls are allowed.</para>
-         <para>When the <constant>O_NONBLOCK</constant> flag is given, the system calls may return &EAGAIN; when no data is available or when the device driver is temporarily busy.</para>
-         <para>Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-    <para>This system call opens a named frontend device (<constant>/dev/dvb/adapter?/frontend?</constant>)
- for subsequent use. Usually the first thing to do after a successful open is to
- find out the frontend type with <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
-<para>The device can be opened in read-only mode, which only allows monitoring of
- device status and statistics, or read/write mode, which allows any kind of use
- (e.g. performing tuning operations.)
-</para>
-<para>In a system with multiple front-ends, it is usually the case that multiple devices
- cannot be open in read/write mode simultaneously. As long as a front-end
- device is opened in read/write mode, other open() calls in read/write mode will
- either fail or block, depending on whether non-blocking or blocking mode was
- specified. A front-end device opened in blocking mode can later be put into
- non-blocking mode (and vice versa) using the F_SETFL command of the fcntl
- system call. This is a standard system call, documented in the Linux manual
- page for fcntl. When an open() call has succeeded, the device will be ready
- for use in the specified mode. This implies that the corresponding hardware is
- powered up, and that other front-ends may have been powered down to make
- that possible.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>open</function> returns the new file
-descriptor. On error -1 is returned, and the <varname>errno</varname>
-variable is set appropriately. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The caller has no permission to access the
-device.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The the device driver is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file
-exists.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough kernel memory was available to complete the
-request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of
-files open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The limit on the total number of files open on the
-system has been reached.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODEV</errorcode></term>
-       <listitem>
-         <para>The device got removed.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<refentry id="frontend_f_close">
-  <refmeta>
-    <refentrytitle>DVB frontend close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>fe-close</refname>
-    <refpurpose>Close a frontend device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-<para>This system call closes a previously opened front-end device. After closing
- a front-end device, its corresponding hardware might be powered down
- automatically.</para>
-</refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>The function returns <returnvalue>0</returnvalue> on
-success, <returnvalue>-1</returnvalue> on failure and the
-<varname>errno</varname> is set appropriately. Possible error
-codes:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-&sub-fe-get-info;
-&sub-fe-read-status;
-&sub-fe-get-property;
-&sub-fe-diseqc-reset-overload;
-&sub-fe-diseqc-send-master-cmd;
-&sub-fe-diseqc-recv-slave-reply;
-&sub-fe-diseqc-send-burst;
-&sub-fe-set-tone;
-&sub-fe-set-voltage;
-&sub-fe-enable-high-lnb-voltage;
-&sub-fe-set-frontend-tune-mode;
-
-</section>
-
-<section id="frontend_legacy_dvbv3_api">
-<title>DVB Frontend legacy API (a. k. a. DVBv3)</title>
-<para>The usage of this API is deprecated, as it doesn't support all digital
-    TV standards, doesn't provide good statistics measurements and provides
-    incomplete information. This is kept only to support legacy applications.</para>
-
-&sub-frontend_legacy_api;
-</section>
diff --git a/Documentation/DocBook/media/dvb/frontend_legacy_api.xml b/Documentation/DocBook/media/dvb/frontend_legacy_api.xml
deleted file mode 100644 (file)
index 8fadf3a..0000000
+++ /dev/null
@@ -1,654 +0,0 @@
-<section id="frontend_legacy_types">
-<title>Frontend Legacy Data Types</title>
-
-<section id="fe-type-t">
-<title>Frontend type</title>
-
-<para>For historical reasons, frontend types are named by the type of modulation
-    used in transmission. The fontend types are given by fe_type_t type, defined as:</para>
-
-<table pgwide="1" frame="none" id="fe-type">
-<title>Frontend types</title>
-<tgroup cols="3">
-   &cs-def;
-   <thead>
-     <row>
-       <entry>fe_type</entry>
-       <entry>Description</entry>
-       <entry><link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> equivalent type</entry>
-     </row>
-  </thead>
-  <tbody valign="top">
-  <row>
-     <entry id="FE-QPSK"><constant>FE_QPSK</constant></entry>
-     <entry>For DVB-S standard</entry>
-     <entry><constant>SYS_DVBS</constant></entry>
-  </row>
-  <row>
-     <entry id="FE-QAM"><constant>FE_QAM</constant></entry>
-     <entry>For DVB-C annex A standard</entry>
-     <entry><constant>SYS_DVBC_ANNEX_A</constant></entry>
-  </row>
-  <row>
-     <entry id="FE-OFDM"><constant>FE_OFDM</constant></entry>
-     <entry>For DVB-T standard</entry>
-     <entry><constant>SYS_DVBT</constant></entry>
-  </row>
-  <row>
-     <entry id="FE-ATSC"><constant>FE_ATSC</constant></entry>
-     <entry>For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US.</entry>
-     <entry><constant>SYS_ATSC</constant> (terrestrial) or <constant>SYS_DVBC_ANNEX_B</constant> (cable)</entry>
-  </row>
-</tbody></tgroup></table>
-
-<para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
-supported via the new <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
-</para>
-
-<para>In the old days, &dvb-frontend-info; used to contain
-    <constant>fe_type_t</constant> field to indicate the delivery systems,
-    filled with either FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC. While this is
-    still filled to keep backward compatibility, the usage of this
-    field is deprecated, as it can report just one delivery system, but some
-    devices support multiple delivery systems. Please use
-    <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.
-</para>
-<para>On devices that support multiple delivery systems,
-    &dvb-frontend-info;::<constant>fe_type_t</constant> is filled with the
-    currently standard, as selected by the last call to
-    <link linkend="FE_GET_PROPERTY">FE_SET_PROPERTY</link>
-    using the &DTV-DELIVERY-SYSTEM; property.</para>
-</section>
-
-<section id="fe-bandwidth-t">
-<title>Frontend bandwidth</title>
-
-<table pgwide="1" frame="none" id="fe-bandwidth">
-    <title>enum fe_bandwidth</title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry id="BANDWIDTH-AUTO"><constant>BANDWIDTH_AUTO</constant></entry>
-           <entry>Autodetect bandwidth (if supported)</entry>
-       </row><row>
-           <entry id="BANDWIDTH-1-712-MHZ"><constant>BANDWIDTH_1_712_MHZ</constant></entry>
-           <entry>1.712 MHz</entry>
-       </row><row>
-           <entry id="BANDWIDTH-5-MHZ"><constant>BANDWIDTH_5_MHZ</constant></entry>
-           <entry>5 MHz</entry>
-       </row><row>
-           <entry id="BANDWIDTH-6-MHZ"><constant>BANDWIDTH_6_MHZ</constant></entry>
-           <entry>6 MHz</entry>
-       </row><row>
-           <entry id="BANDWIDTH-7-MHZ"><constant>BANDWIDTH_7_MHZ</constant></entry>
-           <entry>7 MHz</entry>
-       </row><row>
-           <entry id="BANDWIDTH-8-MHZ"><constant>BANDWIDTH_8_MHZ</constant></entry>
-           <entry>8 MHz</entry>
-       </row><row>
-           <entry id="BANDWIDTH-10-MHZ"><constant>BANDWIDTH_10_MHZ</constant></entry>
-           <entry>10 MHz</entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-
-</section>
-
-<section id="dvb-frontend-parameters">
-<title>frontend parameters</title>
-<para>The kind of parameters passed to the frontend device for tuning depend on
-the kind of hardware you are using.</para>
-<para>The struct <constant>dvb_frontend_parameters</constant> uses an
-union with specific per-system parameters. However, as newer delivery systems
-required more data, the structure size weren't enough to fit, and just
-extending its size would break the existing applications. So, those parameters
-were replaced by the usage of <link linkend="FE_GET_PROPERTY">
-<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> ioctl's. The
-new API is flexible enough to add new parameters to existing delivery systems,
-and to add newer delivery systems.</para>
-<para>So, newer applications should use <link linkend="FE_GET_PROPERTY">
-<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
-order to be able to support the newer System Delivery like  DVB-S2, DVB-T2,
-DVB-C2, ISDB, etc.</para>
-<para>All kinds of parameters are combined as an union in the FrontendParameters structure:
-<programlisting>
-struct dvb_frontend_parameters {
-       uint32_t frequency;     /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
-                               /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
-       &fe-spectral-inversion-t; inversion;
-       union {
-               struct dvb_qpsk_parameters qpsk;
-               struct dvb_qam_parameters  qam;
-               struct dvb_ofdm_parameters ofdm;
-               struct dvb_vsb_parameters  vsb;
-       } u;
-};
-</programlisting></para>
-<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
-frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
-the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
-OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
-</para>
-
-<section id="dvb-qpsk-parameters">
-<title>QPSK parameters</title>
-<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_qpsk_parameters {
-        uint32_t        symbol_rate;  /&#x22C6; symbol rate in Symbols per second &#x22C6;/
-        &fe-code-rate-t;  fec_inner;    /&#x22C6; forward error correction (see above) &#x22C6;/
- };
-</programlisting>
-</section>
-
-<section id="dvb-qam-parameters">
-<title>QAM parameters</title>
-<para>for cable QAM frontend you use the <constant>dvb_qam_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_qam_parameters {
-        uint32_t         symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
-        &fe-code-rate-t;   fec_inner;   /&#x22C6; forward error correction (see above) &#x22C6;/
-        &fe-modulation-t;  modulation;  /&#x22C6; modulation type (see above) &#x22C6;/
- };
-</programlisting>
-</section>
-
-<section id="dvb-vsb-parameters">
-<title>VSB parameters</title>
-<para>ATSC frontends are supported by the <constant>dvb_vsb_parameters</constant> structure:</para>
-<programlisting>
-struct dvb_vsb_parameters {
-       &fe-modulation-t; modulation;   /&#x22C6; modulation type (see above) &#x22C6;/
-};
-</programlisting>
-</section>
-
-<section id="dvb-ofdm-parameters">
-<title>OFDM parameters</title>
-<para>DVB-T frontends are supported by the <constant>dvb_ofdm_parameters</constant> structure:</para>
-<programlisting>
- struct dvb_ofdm_parameters {
-        &fe-bandwidth-t;      bandwidth;
-        &fe-code-rate-t;      code_rate_HP;  /&#x22C6; high priority stream code rate &#x22C6;/
-        &fe-code-rate-t;      code_rate_LP;  /&#x22C6; low priority stream code rate &#x22C6;/
-        &fe-modulation-t;     constellation; /&#x22C6; modulation type (see above) &#x22C6;/
-        &fe-transmit-mode-t;  transmission_mode;
-        &fe-guard-interval-t; guard_interval;
-        &fe-hierarchy-t;      hierarchy_information;
- };
-</programlisting>
-</section>
-</section>
-
-<section id="dvb-frontend-event">
-<title>frontend events</title>
- <programlisting>
- struct dvb_frontend_event {
-        fe_status_t status;
-        struct dvb_frontend_parameters parameters;
- };
-</programlisting>
- </section>
-</section>
-
-<section id="frontend_legacy_fcalls">
-<title>Frontend Legacy Function Calls</title>
-
-<para>Those functions are defined at DVB version 3. The support is kept in
-    the kernel due to compatibility issues only. Their usage is strongly
-    not recommended</para>
-
-<section id="FE_READ_BER">
-<title>FE_READ_BER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the bit error rate for the signal currently
- received/demodulated by the front-end. For this command, read-only access to
- the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_BER">FE_READ_BER</link>,
- uint32_t &#x22C6;ber);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_BER">FE_READ_BER</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ber</para>
-</entry><entry
- align="char">
-<para>The bit error rate is stored into *ber.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_SNR">
-<title>FE_READ_SNR</title>
-
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal-to-noise ratio for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, uint16_t
- &#x22C6;snr);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SNR">FE_READ_SNR</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint16_t *snr</para>
-</entry><entry
- align="char">
-<para>The signal-to-noise ratio is stored into *snr.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_SIGNAL_STRENGTH">
-<title>FE_READ_SIGNAL_STRENGTH</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal strength value for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, uint16_t &#x22C6;strength);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint16_t *strength</para>
-</entry><entry
- align="char">
-<para>The signal strength value is stored into *strength.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_READ_UNCORRECTED_BLOCKS">
-<title>FE_READ_UNCORRECTED_BLOCKS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the number of uncorrected blocks detected by the device
- driver during its lifetime. For meaningful measurements, the increment in block
- count during a specific time interval should be calculated. For this command,
- read-only access to the device is sufficient.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Note that the counter will wrap to zero after its maximum count has been
- reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link>, uint32_t &#x22C6;ublocks);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ublocks</para>
-</entry><entry
- align="char">
-<para>The total number of uncorrected blocks seen by the driver
- so far.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-<section id="FE_SET_FRONTEND">
-<title>FE_SET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call starts a tuning operation using specified parameters. The result
- of this call will be successful if the parameters were valid and the tuning could
- be initiated. The result of the tuning operation in itself, however, will arrive
- asynchronously as an event (see documentation for <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> and
- FrontendEvent.) If a new <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> operation is initiated before
- the previous one was completed, the previous operation will be aborted in favor
- of the new one. This command requires read/write access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_GET_FRONTEND">
-<title>FE_GET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call queries the currently effective frontend parameters. For this
- command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-
-<section id="FE_GET_EVENT">
-<title>FE_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns a frontend event if available. If an event is not
- available, the behavior depends on whether the device is in blocking or
- non-blocking mode. In the latter case, the call fails immediately with errno
- set to EWOULDBLOCK. In the former case, the call blocks until an event
- becomes available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The standard Linux poll() and/or select() system calls can be used with the
- device file descriptor to watch for new events. For select(), the file descriptor
- should be included in the exceptfds argument, and for poll(), POLLPRI should
- be specified as the wake-up condition. Since the event queue allocated is
- rather small (room for 8 events), the queue must be serviced regularly to avoid
- overflow. If an overflow happens, the oldest event is discarded from the queue,
- and an error (EOVERFLOW) occurs the next time the queue is read. After
- reporting the error condition in this fashion, subsequent
- <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>
- calls will return events from the queue as usual.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>For the sake of implementation simplicity, this command requires read/write
- access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = QPSK_GET_EVENT,
- struct dvb_frontend_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_event
- *ev</para>
-</entry><entry
- align="char">
-<para>Points to the location where the event,</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>if any, is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-<para>Overflow in event queue - one or more events were lost.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
-       <title>FE_DISHNETWORK_SEND_LEGACY_CMD</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>WARNING: This is a very obscure legacy command, used only at stv0299 driver. Should not be used on newer drivers.</para>
-<para>It provides a non-standard method for selecting Diseqc voltage on the frontend, for Dish Network legacy switches.</para>
-<para>As support for this ioctl were added in 2004, this means that such dishes were already legacy in 2004.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>int ioctl(int fd, int request =
-       <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link>, unsigned long cmd);</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char">
-       <para>unsigned long cmd</para>
-</entry>
-<entry align="char">
-<para>
-sends the specified raw cmd to the dish via DISEqC.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-&return-value-dvb;
-</section>
-
-</section>
diff --git a/Documentation/DocBook/media/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml
deleted file mode 100644 (file)
index b5b701f..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-<title>Introduction</title>
-
-<section id="requisites">
-<title>What you need to know</title>
-
-<para>The reader of this document is required to have some knowledge in
-the area of digital video broadcasting (DVB) and should be familiar with
-part I of the MPEG2 specification ISO/IEC 13818 (aka ITU-T H.222), i.e
-you should know what a program/transport stream (PS/TS) is and what is
-meant by a packetized elementary stream (PES) or an I-frame.</para>
-
-<para>Various DVB standards documents are available from
-<ulink url="http://www.dvb.org" /> and/or
-<ulink url="http://www.etsi.org" />.</para>
-
-<para>It is also necessary to know how to access unix/linux devices and
-how to use ioctl calls. This also includes the knowledge of C or C++.
-</para>
-</section>
-
-<section id="history">
-<title>History</title>
-
-<para>The first API for DVB cards we used at Convergence in late 1999
-was an extension of the Video4Linux API which was primarily developed
-for frame grabber cards. As such it was not really well suited to be
-used for DVB cards and their new features like recording MPEG streams
-and filtering several section and PES data streams at the same time.
-</para>
-
-<para>In early 2000, we were approached by Nokia with a proposal for a
-new standard Linux DVB API. As a commitment to the development of
-terminals based on open standards, Nokia and Convergence made it
-available to all Linux developers and published it on
-<ulink url="https://linuxtv.org" /> in September 2000.
-Convergence is the maintainer of the Linux DVB API. Together with the
-LinuxTV community (i.e. you, the reader of this document), the Linux DVB
-API will be constantly reviewed and improved. With the Linux driver for
-the Siemens/Hauppauge DVB PCI card Convergence provides a first
-implementation of the Linux DVB API.</para>
-</section>
-
-<section id="overview">
-<title>Overview</title>
-
-<figure id="stb_components">
-<title>Components of a DVB card/STB</title>
-<mediaobject>
-<imageobject>
-<imagedata fileref="dvbstb.pdf" format="PS" />
-</imageobject>
-<imageobject>
-<imagedata fileref="dvbstb.png" format="PNG" />
-</imageobject>
-</mediaobject>
-</figure>
-
-<para>A DVB PCI card or DVB set-top-box (STB) usually consists of the
-following main hardware components: </para>
-
-<itemizedlist>
- <listitem>
-
-<para>Frontend consisting of tuner and DVB demodulator</para>
-
-<para>Here the raw signal reaches the DVB hardware from a satellite dish
-or antenna or directly from cable. The frontend down-converts and
-demodulates this signal into an MPEG transport stream (TS). In case of a
-satellite frontend, this includes a facility for satellite equipment
-control (SEC), which allows control of LNB polarization, multi feed
-switches or dish rotors.</para>
-
-</listitem>
- <listitem>
-
-<para>Conditional Access (CA) hardware like CI adapters and smartcard slots
-</para>
-
-<para>The complete TS is passed through the CA hardware. Programs to
-which the user has access (controlled by the smart card) are decoded in
-real time and re-inserted into the TS.</para>
-
-</listitem>
- <listitem>
- <para>Demultiplexer which filters the incoming DVB stream</para>
-
-<para>The demultiplexer splits the TS into its components like audio and
-video streams. Besides usually several of such audio and video streams
-it also contains data streams with information about the programs
-offered in this or other streams of the same provider.</para>
-
-</listitem>
-<listitem>
-
-<para>MPEG2 audio and video decoder</para>
-
-<para>The main targets of the demultiplexer are the MPEG2 audio and
-video decoders. After decoding they pass on the uncompressed audio and
-video to the computer screen or (through a PAL/NTSC encoder) to a TV
-set.</para>
-
-
-</listitem>
-</itemizedlist>
-
-<para><xref linkend="stb_components" /> shows a crude schematic of the control and data flow
-between those components.</para>
-
-<para>On a DVB PCI card not all of these have to be present since some
-functionality can be provided by the main CPU of the PC (e.g. MPEG
-picture and sound decoding) or is not needed (e.g. for data-only uses
-like &#8220;internet over satellite&#8221;). Also not every card or STB
-provides conditional access hardware.</para>
-
-</section>
-
-<section id="dvb_devices">
-<title>Linux DVB Devices</title>
-
-<para>The Linux DVB API lets you control these hardware components
-through currently six Unix-style character devices for video, audio,
-frontend, demux, CA and IP-over-DVB networking. The video and audio
-devices control the MPEG2 decoder hardware, the frontend device the
-tuner and the DVB demodulator. The demux device gives you control over
-the PES and section filters of the hardware. If the hardware does not
-support filtering these filters can be implemented in software. Finally,
-the CA device controls all the conditional access capabilities of the
-hardware. It can depend on the individual security requirements of the
-platform, if and how many of the CA functions are made available to the
-application through this device.</para>
-
-<para>All devices can be found in the <constant>/dev</constant>
-tree under <constant>/dev/dvb</constant>. The individual devices
-are called:</para>
-
-<itemizedlist>
-<listitem>
-
-<para><constant>/dev/dvb/adapterN/audioM</constant>,</para>
-</listitem>
-<listitem>
-<para><constant>/dev/dvb/adapterN/videoM</constant>,</para>
-</listitem>
-<listitem>
-<para><constant>/dev/dvb/adapterN/frontendM</constant>,</para>
-</listitem>
- <listitem>
-
-<para><constant>/dev/dvb/adapterN/netM</constant>,</para>
-</listitem>
- <listitem>
-
-<para><constant>/dev/dvb/adapterN/demuxM</constant>,</para>
-</listitem>
- <listitem>
-
-<para><constant>/dev/dvb/adapterN/dvrM</constant>,</para>
-</listitem>
- <listitem>
-
-<para><constant>/dev/dvb/adapterN/caM</constant>,</para></listitem></itemizedlist>
-
-<para>where N enumerates the DVB PCI cards in a system starting
-from&#x00A0;0, and M enumerates the devices of each type within each
-adapter, starting from&#x00A0;0, too. We will omit the &#8220;
-<constant>/dev/dvb/adapterN/</constant>&#8221; in the further discussion
-of these devices.</para>
-
-<para>More details about the data structures and function calls of all
-the devices are described in the following chapters.</para>
-
-</section>
-
-<section id="include_files">
-<title>API include files</title>
-
-<para>For each of the DVB devices a corresponding include file exists.
-The DVB API include files should be included in application sources with
-a partial path like:</para>
-
-<programlisting>
-       #include &#x003C;linux/dvb/audio.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/ca.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/dmx.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/frontend.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/net.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/osd.h&#x003E;
-</programlisting>
-<programlisting>
-       #include &#x003C;linux/dvb/video.h&#x003E;
-</programlisting>
-
-<para>To enable applications to support different API version, an
-additional include file
-<constant>linux/dvb/version.h</constant> exists, which defines the
-constant <constant>DVB_API_VERSION</constant>. This document
-describes <constant>DVB_API_VERSION 5.10</constant>.
-</para>
-
-</section>
-
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml
deleted file mode 100644 (file)
index da095ed..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-<title>DVB Network API</title>
-<para>The DVB net device controls the mapping of data packages that are
-    part of a transport stream to be mapped into a virtual network interface,
-    visible through the standard Linux network protocol stack.</para>
-<para>Currently, two encapsulations are supported:</para>
-<itemizedlist>
-    <listitem><para><ulink url="http://en.wikipedia.org/wiki/Multiprotocol_Encapsulation">
-       Multi Protocol Encapsulation (MPE)</ulink></para></listitem>
-    <listitem><para><ulink url="http://en.wikipedia.org/wiki/Unidirectional_Lightweight_Encapsulation">
-       Ultra Lightweight Encapsulation (ULE)</ulink></para></listitem>
-</itemizedlist>
-
-<para>In order to create the Linux virtual network interfaces, an application
-    needs to tell to the Kernel what are the PIDs and the encapsulation types
-    that are present on the transport stream. This is done through
-    <constant>/dev/dvb/adapter?/net?</constant> device node.
-    The data will be available via virtual <constant>dvb?_?</constant>
-    network interfaces, and will be controlled/routed via the standard
-    ip tools (like ip, route, netstat, ifconfig, etc).</para>
-<para> Data types and and ioctl definitions are defined via
-    <constant>linux/dvb/net.h</constant> header.</para>
-
-<section id="net_fcalls">
-<title>DVB net Function Calls</title>
-
-
-<refentry id="NET_ADD_IF">
-  <refmeta>
-    <refentrytitle>ioctl NET_ADD_IF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>NET_ADD_IF</refname>
-    <refpurpose>Creates a new network interface for a given Packet ID.</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 dvb_net_if *<parameter>net_if</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_TONE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>net_if</parameter></term>
-       <listitem>
-         <para>pointer to &dvb-net-if;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>The NET_ADD_IF ioctl system call selects the Packet ID (PID) that
-    contains a TCP/IP traffic, the type of encapsulation to be used (MPE or ULE)
-    and the interface number for the new interface to be created. When the
-    system call successfully returns, a new virtual network interface is  created.</para>
-<para>The &dvb-net-if;::ifnum field will be filled with the number of the
-    created interface.</para>
-
-&return-value-dvb;
-</refsect1>
-
-<refsect1 id="dvb-net-if-t">
-<title>struct <structname>dvb_net_if</structname> description</title>
-
-<table pgwide="1" frame="none" id="dvb-net-if">
-    <title>struct <structname>dvb_net_if</structname></title>
-    <tgroup cols="2">
-       &cs-def;
-       <thead>
-       <row>
-           <entry>ID</entry>
-           <entry>Description</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-       <row>
-           <entry align="char">pid</entry>
-           <entry align="char">Packet ID (PID) of the MPEG-TS that contains
-               data</entry>
-       </row><row>
-           <entry align="char">ifnum</entry>
-           <entry align="char">number of the DVB interface.</entry>
-       </row><row>
-           <entry align="char">feedtype</entry>
-           <entry align="char">Encapsulation type of the feed. It can be:
-               <constant>DVB_NET_FEEDTYPE_MPE</constant> for MPE encoding
-               or
-               <constant>DVB_NET_FEEDTYPE_ULE</constant> for ULE encoding.
-               </entry>
-       </row>
-        </tbody>
-    </tgroup>
-</table>
-</refsect1>
-</refentry>
-
-<refentry id="NET_REMOVE_IF">
-  <refmeta>
-    <refentrytitle>ioctl NET_REMOVE_IF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>NET_REMOVE_IF</refname>
-    <refpurpose>Removes a network interface.</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>int <parameter>ifnum</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_TONE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>net_if</parameter></term>
-       <listitem>
-         <para>number of the interface to be removed</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>The NET_REMOVE_IF ioctl deletes an interface previously created
-    via &NET-ADD-IF;.</para>
-
-&return-value-dvb;
-</refsect1>
-</refentry>
-
-
-<refentry id="NET_GET_IF">
-  <refmeta>
-    <refentrytitle>ioctl NET_GET_IF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>NET_GET_IF</refname>
-    <refpurpose>Read the configuration data of an interface created via
-       &NET-ADD-IF;.</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 dvb_net_if *<parameter>net_if</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-        <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fe_fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>FE_SET_TONE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>net_if</parameter></term>
-       <listitem>
-         <para>pointer to &dvb-net-if;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>The NET_GET_IF ioctl uses the interface number given by the
-    &dvb-net-if;::ifnum field and fills the content of &dvb-net-if; with
-    the packet ID and encapsulation type used on such interface. If the
-    interface was not created yet with &NET-ADD-IF;, it will return -1 and
-    fill the <constant>errno</constant> with <constant>EINVAL</constant>
-    error code.</para>
-
-&return-value-dvb;
-</refsect1>
-</refentry>
-</section>
diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml
deleted file mode 100644 (file)
index 71547fc..0000000
+++ /dev/null
@@ -1,1968 +0,0 @@
-<title>DVB Video Device</title>
-<para>The DVB video device controls the MPEG2 video decoder of the DVB hardware. It
-can be accessed through <emphasis role="bold">/dev/dvb/adapter0/video0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="bold">linux/dvb/video.h</emphasis> in your
-application.
-</para>
-<para>Note that the DVB video device only controls decoding of the MPEG video stream, not
-its presentation on the TV or computer screen. On PCs this is typically handled by an
-associated video4linux device, e.g. <emphasis role="bold">/dev/video</emphasis>, which allows scaling and defining output
-windows.
-</para>
-<para>Some DVB cards don&#8217;t have their own MPEG decoder, which results in the omission of
-the audio and video device as well as the video4linux device.
-</para>
-<para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
-supported on some MPEG decoders made for DVD playback.
-</para>
-<para>
-These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
-of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
-have been created to replace that functionality.</para>
-<section id="video_types">
-<title>Video Data Types</title>
-
-<section id="video-format-t">
-<title>video_format_t</title>
-<para>The <constant>video_format_t</constant> data type defined by
-</para>
-<programlisting>
-typedef enum {
-       VIDEO_FORMAT_4_3,     /&#x22C6; Select 4:3 format &#x22C6;/
-       VIDEO_FORMAT_16_9,    /&#x22C6; Select 16:9 format. &#x22C6;/
-       VIDEO_FORMAT_221_1    /&#x22C6; 2.21:1 &#x22C6;/
-} video_format_t;
-</programlisting>
-<para>is used in the VIDEO_SET_FORMAT function (??) to tell the driver which aspect ratio
-the output hardware (e.g. TV) has. It is also used in the data structures video_status
-(??) returned by VIDEO_GET_STATUS (??) and video_event (??) returned by
-VIDEO_GET_EVENT (??) which report about the display format of the current video
-stream.
-</para>
-</section>
-
-<section id="video-displayformat-t">
-<title>video_displayformat_t</title>
-<para>In case the display format of the video stream and of the display hardware differ the
-application has to specify how to handle the cropping of the picture. This can be done using
-the VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
-</para>
-<programlisting>
-typedef enum {
-       VIDEO_PAN_SCAN,       /&#x22C6; use pan and scan format &#x22C6;/
-       VIDEO_LETTER_BOX,     /&#x22C6; use letterbox format &#x22C6;/
-       VIDEO_CENTER_CUT_OUT  /&#x22C6; use center cut out format &#x22C6;/
-} video_displayformat_t;
-</programlisting>
-<para>as argument.
-</para>
-</section>
-
-<section id="video-stream-source-t">
-<title>video_stream_source_t</title>
-<para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
-the following values, depending on whether we are replaying from an internal (demuxer) or
-external (user write) source.
-</para>
-<programlisting>
-typedef enum {
-       VIDEO_SOURCE_DEMUX, /&#x22C6; Select the demux as the main source &#x22C6;/
-       VIDEO_SOURCE_MEMORY /&#x22C6; If this source is selected, the stream
-                              comes from the user through the write
-                              system call &#x22C6;/
-} video_stream_source_t;
-</programlisting>
-<para>VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
-DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY
-is selected the stream comes from the application through the <emphasis role="bold">write()</emphasis> system
-call.
-</para>
-</section>
-
-<section id="video-play-state-t">
-<title>video_play_state_t</title>
-<para>The following values can be returned by the VIDEO_GET_STATUS call representing the
-state of video playback.
-</para>
-<programlisting>
-typedef enum {
-       VIDEO_STOPPED, /&#x22C6; Video is stopped &#x22C6;/
-       VIDEO_PLAYING, /&#x22C6; Video is currently playing &#x22C6;/
-       VIDEO_FREEZED  /&#x22C6; Video is freezed &#x22C6;/
-} video_play_state_t;
-</programlisting>
-</section>
-
-<section id="video-command">
-<title>struct video_command</title>
-<para>The structure must be zeroed before use by the application
-This ensures it can be extended safely in the future.</para>
-<programlisting>
-struct video_command {
-       __u32 cmd;
-       __u32 flags;
-       union {
-               struct {
-                       __u64 pts;
-               } stop;
-
-               struct {
-                       /&#x22C6; 0 or 1000 specifies normal speed,
-                          1 specifies forward single stepping,
-                          -1 specifies backward single stepping,
-                          &gt;>1: playback at speed/1000 of the normal speed,
-                          &lt;-1: reverse playback at (-speed/1000) of the normal speed. &#x22C6;/
-                       __s32 speed;
-                       __u32 format;
-               } play;
-
-               struct {
-                       __u32 data[16];
-               } raw;
-       };
-};
-</programlisting>
-</section>
-
-<section id="video-size-t">
-<title>video_size_t</title>
-<programlisting>
-typedef struct {
-       int w;
-       int h;
-       video_format_t aspect_ratio;
-} video_size_t;
-</programlisting>
-</section>
-
-
-<section id="video-event">
-<title>struct video_event</title>
-<para>The following is the structure of a video event as it is returned by the VIDEO_GET_EVENT
-call.
-</para>
-<programlisting>
-struct video_event {
-       __s32 type;
-#define VIDEO_EVENT_SIZE_CHANGED       1
-#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
-#define VIDEO_EVENT_DECODER_STOPPED    3
-#define VIDEO_EVENT_VSYNC              4
-       __kernel_time_t timestamp;
-       union {
-               video_size_t size;
-               unsigned int frame_rate;        /&#x22C6; in frames per 1000sec &#x22C6;/
-               unsigned char vsync_field;      /&#x22C6; unknown/odd/even/progressive &#x22C6;/
-       } u;
-};
-</programlisting>
-</section>
-
-<section id="video-status">
-<title>struct video_status</title>
-<para>The VIDEO_GET_STATUS call returns the following structure informing about various
-states of the playback operation.
-</para>
-<programlisting>
-struct video_status {
-       int                   video_blank;   /&#x22C6; blank video on freeze? &#x22C6;/
-       video_play_state_t    play_state;    /&#x22C6; current state of playback &#x22C6;/
-       video_stream_source_t stream_source; /&#x22C6; current source (demux/memory) &#x22C6;/
-       video_format_t        video_format;  /&#x22C6; current aspect ratio of stream &#x22C6;/
-       video_displayformat_t display_format;/&#x22C6; selected cropping mode &#x22C6;/
-};
-</programlisting>
-<para>If video_blank is set video will be blanked out if the channel is changed or if playback is
-stopped. Otherwise, the last picture will be displayed. play_state indicates if the video is
-currently frozen, stopped, or being played back. The stream_source corresponds to the seleted
-source for the video stream. It can come either from the demultiplexer or from memory.
-The video_format indicates the aspect ratio (one of 4:3 or 16:9) of the currently
-played video stream. Finally, display_format corresponds to the selected cropping
-mode in case the source video format is not the same as the format of the output
-device.
-</para>
-</section>
-
-<section id="video-still-picture">
-<title>struct video_still_picture</title>
-<para>An I-frame displayed via the VIDEO_STILLPICTURE call is passed on within the
-following structure.
-</para>
-<programlisting>
-/&#x22C6; pointer to and size of a single iframe in memory &#x22C6;/
-struct video_still_picture {
-       char &#x22C6;iFrame;        /&#x22C6; pointer to a single iframe in memory &#x22C6;/
-       int32_t size;
-};
-</programlisting>
-</section>
-
-<section id="video_caps">
-<title>video capabilities</title>
-<para>A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the following
-bits set according to the hardwares capabilities.
-</para>
-<programlisting>
- /&#x22C6; bit definitions for capabilities: &#x22C6;/
- /&#x22C6; can the hardware decode MPEG1 and/or MPEG2? &#x22C6;/
- #define VIDEO_CAP_MPEG1   1
- #define VIDEO_CAP_MPEG2   2
- /&#x22C6; can you send a system and/or program stream to video device?
-    (you still have to open the video and the audio device but only
-     send the stream to the video device) &#x22C6;/
- #define VIDEO_CAP_SYS     4
- #define VIDEO_CAP_PROG    8
- /&#x22C6; can the driver also handle SPU, NAVI and CSS encoded data?
-    (CSS API is not present yet) &#x22C6;/
- #define VIDEO_CAP_SPU    16
- #define VIDEO_CAP_NAVI   32
- #define VIDEO_CAP_CSS    64
-</programlisting>
-</section>
-
-<section id="video-system">
-<title>video_system_t</title>
-<para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
-following system types can be set:
-</para>
-<programlisting>
-typedef enum {
-        VIDEO_SYSTEM_PAL,
-        VIDEO_SYSTEM_NTSC,
-        VIDEO_SYSTEM_PALN,
-        VIDEO_SYSTEM_PALNc,
-        VIDEO_SYSTEM_PALM,
-        VIDEO_SYSTEM_NTSC60,
-        VIDEO_SYSTEM_PAL60,
-        VIDEO_SYSTEM_PALM60
-} video_system_t;
-</programlisting>
-</section>
-
-<section id="video-highlight">
-<title>struct video_highlight</title>
-<para>Calling the ioctl VIDEO_SET_HIGHLIGHTS posts the SPU highlight information. The
-call expects the following format for that information:
-</para>
-<programlisting>
- typedef
- struct video_highlight {
-        boolean active;      /&#x22C6;    1=show highlight, 0=hide highlight &#x22C6;/
-        uint8_t contrast1;   /&#x22C6;    7- 4  Pattern pixel contrast &#x22C6;/
-                             /&#x22C6;    3- 0  Background pixel contrast &#x22C6;/
-        uint8_t contrast2;   /&#x22C6;    7- 4  Emphasis pixel-2 contrast &#x22C6;/
-                             /&#x22C6;    3- 0  Emphasis pixel-1 contrast &#x22C6;/
-        uint8_t color1;      /&#x22C6;    7- 4  Pattern pixel color &#x22C6;/
-                             /&#x22C6;    3- 0  Background pixel color &#x22C6;/
-        uint8_t color2;      /&#x22C6;    7- 4  Emphasis pixel-2 color &#x22C6;/
-                             /&#x22C6;    3- 0  Emphasis pixel-1 color &#x22C6;/
-        uint32_t ypos;       /&#x22C6;   23-22  auto action mode &#x22C6;/
-                             /&#x22C6;   21-12  start y &#x22C6;/
-                             /&#x22C6;    9- 0  end y &#x22C6;/
-        uint32_t xpos;       /&#x22C6;   23-22  button color number &#x22C6;/
-                             /&#x22C6;   21-12  start x &#x22C6;/
-                             /&#x22C6;    9- 0  end x &#x22C6;/
- } video_highlight_t;
-</programlisting>
-
-</section>
-<section id="video-spu">
-<title>struct video_spu</title>
-<para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
-following format:
-</para>
-<programlisting>
- typedef
- struct video_spu {
-        boolean active;
-        int stream_id;
- } video_spu_t;
-</programlisting>
-
-</section>
-<section id="video-spu-palette">
-<title>struct video_spu_palette</title>
-<para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
-</para>
-<programlisting>
- typedef
- struct video_spu_palette {
-        int length;
-        uint8_t &#x22C6;palette;
- } video_spu_palette_t;
-</programlisting>
-
-</section>
-<section id="video-navi-pack">
-<title>struct video_navi_pack</title>
-<para>In order to get the navigational data the following structure has to be passed to the ioctl
-VIDEO_GET_NAVI:
-</para>
-<programlisting>
- typedef
- struct video_navi_pack {
-        int length;         /&#x22C6; 0 ... 1024 &#x22C6;/
-        uint8_t data[1024];
- } video_navi_pack_t;
-</programlisting>
-</section>
-
-
-<section id="video-attributes-t">
-<title>video_attributes_t</title>
-<para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
-</para>
-<programlisting>
- typedef uint16_t video_attributes_t;
- /&#x22C6;   bits: descr. &#x22C6;/
- /&#x22C6;   15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) &#x22C6;/
- /&#x22C6;   13-12 TV system (0=525/60, 1=625/50) &#x22C6;/
- /&#x22C6;   11-10 Aspect ratio (0=4:3, 3=16:9) &#x22C6;/
- /&#x22C6;    9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca &#x22C6;/
- /&#x22C6;    7    line 21-1 data present in GOP (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    6    line 21-2 data present in GOP (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 &#x22C6;/
- /&#x22C6;    2    source letterboxed (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    0    film/camera mode (0=camera, 1=film (625/50 only)) &#x22C6;/
-</programlisting>
-</section></section>
-
-
-<section id="video_function_calls">
-<title>Video Function Calls</title>
-
-
-<section id="video_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named video device (e.g. /dev/dvb/adapter0/video0)
- for subsequent use.</para>
-<para>When an open() call has succeeded, the device will be ready for use.
- The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the Video Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an
- error-code will be returned. If the Video Device is opened in O_RDONLY
- mode, the only ioctl call that can be used is VIDEO_GET_STATUS. All other
- call will return an error code.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="video_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened video device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="video_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call can only be used if VIDEO_SOURCE_MEMORY is selected
- in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in
- PES format, unless the capability allows other formats. If O_NONBLOCK is
- not specified the function will block until buffer space is available. The amount
- of data to be transferred is implied by count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the PES data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURN VALUE</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>Attempted to write more data than the internal buffer can
- hold.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_STOP"
-role="subsection"><title>VIDEO_STOP</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-&VIDIOC-DECODER-CMD; instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to stop playing the current stream.
- Depending on the input parameter, the screen can be blanked out or displaying
- the last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_STOP, boolean
- mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_STOP for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Boolean mode</para>
-</entry><entry
- align="char">
-<para>Indicates how the screen shall be handled.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE: Blank screen when stop.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE: Show last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_PLAY"
-role="subsection"><title>VIDEO_PLAY</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-&VIDIOC-DECODER-CMD; instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to start playing a video stream from the
- selected source.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_PLAY);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_PLAY for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_FREEZE"
-role="subsection"><title>VIDEO_FREEZE</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-&VIDIOC-DECODER-CMD; instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call suspends the live video stream being played. Decoding
- and playing are frozen. It is then possible to restart the decoding
- and playing process of the video stream using the VIDEO_CONTINUE
- command. If VIDEO_SOURCE_MEMORY is selected in the ioctl call
- VIDEO_SELECT_SOURCE, the DVB subsystem will not decode any more
- data until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_FREEZE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_FREEZE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_CONTINUE"
-role="subsection"><title>VIDEO_CONTINUE</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
-&VIDIOC-DECODER-CMD; instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call restarts decoding and playing processes of the video stream
- which was played before a call to VIDEO_FREEZE was made.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_CONTINUE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_CONTINUE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SELECT_SOURCE"
-role="subsection"><title>VIDEO_SELECT_SOURCE</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. This ioctl was also supported by the
-V4L2 ivtv driver, but that has been replaced by the ivtv-specific
-<constant>IVTV_IOC_PASSTHROUGH_MODE</constant> ioctl.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call informs the video device which source shall be used for the input
- data. The possible sources are demux or memory. If memory is selected, the
- data is fed to the video device through the write command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SELECT_SOURCE,
- video_stream_source_t source);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SELECT_SOURCE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_stream_source_t
- source</para>
-</entry><entry
- align="char">
-<para>Indicates which source shall be used for the Video stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_BLANK"
-role="subsection"><title>VIDEO_SET_BLANK</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to blank out the picture.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SET_BLANK, boolean
- mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_BLANK for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean mode</para>
-</entry><entry
- align="char">
-<para>TRUE: Blank screen when stop.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE: Show last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_STATUS"
-role="subsection"><title>VIDEO_GET_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to return the current status of the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_STATUS, struct
- video_status &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_STATUS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_status
- *status</para>
-</entry><entry
- align="char">
-<para>Returns the current status of the Video Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_FRAME_COUNT"
-role="subsection"><title>VIDEO_GET_FRAME_COUNT</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
-ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant> control.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to return the number of displayed frames
-since the decoder was started.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_GET_FRAME_COUNT, __u64 *pts);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_FRAME_COUNT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u64 *pts
-</para>
-</entry><entry
- align="char">
-<para>Returns the number of frames displayed since the decoder was started.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_PTS"
-role="subsection"><title>VIDEO_GET_PTS</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
-ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant> control.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to return the current PTS timestamp.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_GET_PTS, __u64 *pts);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_PTS for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u64 *pts
-</para>
-</entry><entry
- align="char">
-<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
-</para>
-<para>
-The PTS should belong to the currently played
-frame if possible, but may also be a value close to it
-like the PTS of the last decoded frame or the last PTS
-extracted by the PES parser.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_FRAME_RATE"
-role="subsection"><title>VIDEO_GET_FRAME_RATE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to return the current framerate.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_GET_FRAME_RATE, unsigned int *rate);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_FRAME_RATE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned int *rate
-</para>
-</entry><entry
- align="char">
-<para>Returns the framerate in number of frames per 1000 seconds.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_EVENT"
-role="subsection"><title>VIDEO_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is for DVB devices only. To get events from a V4L2 decoder use the V4L2
-&VIDIOC-DQEVENT; ioctl instead.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns an event of type video_event if available. If an event is
- not available, the behavior depends on whether the device is in blocking or
- non-blocking mode. In the latter case, the call fails immediately with errno
- set to EWOULDBLOCK. In the former case, the call blocks until an event
- becomes available. The standard Linux poll() and/or select() system calls can
- be used with the device file descriptor to watch for new events. For select(),
- the file descriptor should be included in the exceptfds argument, and for
- poll(), POLLPRI should be specified as the wake-up condition. Read-only
- permissions are sufficient for this ioctl call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_EVENT, struct
- video_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_EVENT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_event
- *ev</para>
-</entry><entry
- align="char">
-<para>Points to the location where the event, if any, is to be
- stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-<para>Overflow in event queue - one or more events were lost.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_COMMAND"
-role="subsection"><title>VIDEO_COMMAND</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
-ioctl has been replaced by the &VIDIOC-DECODER-CMD; ioctl.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl commands the decoder. The <constant>video_command</constant> struct
-is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
-&VIDIOC-DECODER-CMD; documentation for more information.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_COMMAND, struct video_command *cmd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_COMMAND for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_command *cmd
-</para>
-</entry><entry
- align="char">
-<para>Commands the decoder.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_TRY_COMMAND"
-role="subsection"><title>VIDEO_TRY_COMMAND</title>
-<para>DESCRIPTION
-</para>
-<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
-ioctl has been replaced by the &VIDIOC-TRY-DECODER-CMD; ioctl.</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl tries a decoder command. The <constant>video_command</constant> struct
-is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
-&VIDIOC-TRY-DECODER-CMD; documentation for more information.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_TRY_COMMAND, struct video_command *cmd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_TRY_COMMAND for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_command *cmd
-</para>
-</entry><entry
- align="char">
-<para>Try a decoder command.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_GET_SIZE"
-role="subsection"><title>VIDEO_GET_SIZE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl returns the size and aspect ratio.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- VIDEO_GET_SIZE, video_size_t *size);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_SIZE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_size_t *size
-</para>
-</entry><entry
- align="char">
-<para>Returns the size and aspect ratio.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_DISPLAY_FORMAT"
-role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to select the video format to be applied
- by the MPEG chip on the video.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request =
- VIDEO_SET_DISPLAY_FORMAT, video_display_format_t
- format);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_DISPLAY_FORMAT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_display_format_t
- format</para>
-</entry><entry
- align="char">
-<para>Selects the video format to be used.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_STILLPICTURE"
-role="subsection"><title>VIDEO_STILLPICTURE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to display a still picture (I-frame). The
- input data shall contain an I-frame. If the pointer is NULL, then the current
- displayed still picture is blanked.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_STILLPICTURE,
- struct video_still_picture &#x22C6;sp);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_STILLPICTURE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- video_still_picture
- *sp</para>
-</entry><entry
- align="char">
-<para>Pointer to a location where an I-frame and size is stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_FAST_FORWARD"
-role="subsection"><title>VIDEO_FAST_FORWARD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to skip decoding of N number of I-frames.
- This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_FAST_FORWARD, int
- nFrames);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_FAST_FORWARD for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int nFrames</para>
-</entry><entry
- align="char">
-<para>The number of frames to skip.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_SLOWMOTION"
-role="subsection"><title>VIDEO_SLOWMOTION</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the video device to repeat decoding frames N number of
- times. This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SLOWMOTION, int
- nFrames);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SLOWMOTION for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int nFrames</para>
-</entry><entry
- align="char">
-<para>The number of times to repeat each frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_GET_CAPABILITIES"
-role="subsection"><title>VIDEO_GET_CAPABILITIES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the video device about its decoding capabilities. On success
- it returns and integer which has bits set according to the defines in section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_GET_CAPABILITIES,
- unsigned int &#x22C6;cap);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_CAPABILITIES for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned int *cap</para>
-</entry><entry
- align="char">
-<para>Pointer to a location where to store the capability
- information.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_ID"
-role="subsection"><title>VIDEO_SET_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl selects which sub-stream is to be decoded if a program or system
- stream is sent to the video device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = VIDEO_SET_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>video sub-stream id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid sub-stream id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_CLEAR_BUFFER"
-role="subsection"><title>VIDEO_CLEAR_BUFFER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call clears all video buffers in the driver and in the decoder hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_CLEAR_BUFFER);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_CLEAR_BUFFER for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_STREAMTYPE"
-role="subsection"><title>VIDEO_SET_STREAMTYPE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl tells the driver which kind of stream to expect being written to it. If
- this call is not used the default of video PES is used. Some drivers might not
- support this call and always expect PES.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SET_STREAMTYPE,
- int type);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_STREAMTYPE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int type</para>
-</entry><entry
- align="char">
-<para>stream type</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_FORMAT"
-role="subsection"><title>VIDEO_SET_FORMAT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the screen format (aspect ratio) of the connected output device
- (TV) so that the output of the decoder can be adjusted accordingly.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_FORMAT,
- video_format_t format);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_FORMAT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_format_t
- format</para>
-</entry><entry
- align="char">
-<para>video format of TV as defined in section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>format is not a valid video format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_SET_SYSTEM"
-role="subsection"><title>VIDEO_SET_SYSTEM</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the television output format. The format (see section ??) may
- vary from the color format of the displayed MPEG stream. If the hardware is
- not able to display the requested format the call will return an error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SYSTEM ,
- video_system_t system);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_FORMAT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_system_t
- system</para>
-</entry><entry
- align="char">
-<para>video system of TV output.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>system is not a valid or supported video system.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_SET_HIGHLIGHT"
-role="subsection"><title>VIDEO_SET_HIGHLIGHT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the SPU highlight information for the menu access of a DVD.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_HIGHLIGHT
- ,video_highlight_t &#x22C6;vhilite)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_HIGHLIGHT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_highlight_t
- *vhilite</para>
-</entry><entry
- align="char">
-<para>SPU Highlight information according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-
-</section><section id="VIDEO_SET_SPU"
-role="subsection"><title>VIDEO_SET_SPU</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl activates or deactivates SPU decoding in a DVD input stream. It can
- only be used, if the driver is able to handle a DVD stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SPU ,
- video_spu_t &#x22C6;spu)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_SPU for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_spu_t *spu</para>
-</entry><entry
- align="char">
-<para>SPU decoding (de)activation and subid setting according
- to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid spu setting or driver cannot handle
- SPU.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_SET_SPU_PALETTE"
-role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the SPU color palette.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SPU_PALETTE
- ,video_spu_palette_t &#x22C6;palette )</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_SPU_PALETTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_spu_palette_t
- *palette</para>
-</entry><entry
- align="char">
-<para>SPU palette according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid palette or driver doesn&#8217;t handle SPU.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_GET_NAVI"
-role="subsection"><title>VIDEO_GET_NAVI</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl returns navigational information from the DVD stream. This is
- especially needed if an encoded stream has to be decoded by the hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_NAVI ,
- video_navi_pack_t &#x22C6;navipack)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_NAVI for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_navi_pack_t
- *navipack</para>
-</entry><entry
- align="char">
-<para>PCI or DSI pack (private stream 2) according to section
- ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>driver is not able to return navigational information</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section id="VIDEO_SET_ATTRIBUTES"
-role="subsection"><title>VIDEO_SET_ATTRIBUTES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is intended for DVD playback and allows you to set certain
- information about the stream. Some hardware may not need this information,
- but the call also tells the hardware to prepare for DVD playback.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_ATTRIBUTE
- ,video_attributes_t vattr)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_ATTRIBUTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_attributes_t
- vattr</para>
-</entry><entry
- align="char">
-<para>video attributes according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-&return-value-dvb;
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid attribute setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
diff --git a/Documentation/DocBook/media/dvbstb.png.b64 b/Documentation/DocBook/media/dvbstb.png.b64
deleted file mode 100644 (file)
index e8b52fd..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-iVBORw0KGgoAAAANSUhEUgAAAzMAAAGaCAYAAAA7Jx25AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
-WXMAAA3XAAANiQFmEOuiAAAgAElEQVR42uzdd1RU18I28GdgKFZUBE0saFA0KoqFFkEhKhbAQmxJ
-bIkNNEpMEUwsMZarJMZrw4KxRExQczUqil0jRBA1GAjGQqLYC4TemdnfH76cj3HodYDntxaLmTll
-zuw57Zmz9z4yIYQAkYZzcnJCSkoKGjZsyMIgIiIiquPS09PRoEEDyBhmqCaQyWRo06YN3nvvPRYG
-ERERUR137Ngx/Pnnn5CzKKgmMDAwwKpVqxhmiIiIiAj29vZ4//33ocWiICIiIiKimohhhoiIiIiI
-GGaIiIiIiIgYZoiIiIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIiGGGiIiIiIgYZoiIiIiIiBhm
-iIiIiIiIGGaIiIiIiIgYZoiIiIiIiGGGiIiIiIiIYYaIiIiIiIhhhoiIiIiIGGaIiIiIiIgYZoiI
-iIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIqFLIWQRElSMsLAy2trZo1KgR5HJualTxEhIS8P33
-3+PDDz+sM5+5bdu2ePDgAZo2bcoVgCplm3J0dMS5c+fqzGf++uuvsWTJEm5TVClSU1ORk5ODBw8e
-oHXr1gwzRDVJbm4uAGDRokUwMDBggVCFmzlzJrKysurUZ3727BksLCzg4eHBFYAq3IIFC5CQkFCn
-PnNGRgYAYNWqVVwBqMJFRUVh48aNUCqVlfYeDDNElWzGjBkMM1QpNm7cWOc+c8uWLTFjxgzMmDGD
-KwBVuLt37yIkJKTOfW5nZ2duU1SpYaYysc0MERERERHVSAwzRERERETEMENERERERMQwQ0RERERE
-xDBDREREREQMM0RERERERAwzREREREREDDNERERERMQwQ0RERERExDBDRERERETEMENERERERMQw
-Q0REREREDDNEREREREQMM0RERERERAwzRERERETEMENERERERMQwQ0RERERExDBDREREREQMM0RE
-RERERAwzREREREREDDNEREREREQMM0RERERExDBDRERERETEMENERERERMQwQ0REREREDDNERERE
-REQMM0RERERERAwzRERERETEMENERERERMQwQ0REREREVGnkLAKimunBgwdISkoq8/SGhoZ47bXX
-WJCV6NmzZwgMDMS5c+ewd+9eFgiVSVZWFkJCQnD16lU8evQICoUChoaG6NChA2xsbNCxY0fIZDI8
-efIEp06dwuTJk0s876CgIJiYmKBLly4saKq2Y5Wuri6aNm0KQ0NDaGnxd3ZimCGqE/78808EBgbi
-p59+QkJCgsowLS0tyGQy6blSqYQQQmWcjz/+GGvXrmVBVoKtW7di+/btuHbtGoQQMDQ0ZKFQqf37
-77/w8fHBtm3bkJCQgCZNmsDS0hLGxsZ48OABtm/fjidPnsDU1BR2dnYICwtDz549SxxmlEol5s6d
-CxsbG+zZs4cFTpV2rDpx4gQOHDiAJ0+eqAzT09ODUqlETk4OAEBfXx/dunWDvb093Nzc0LdvX5Vj
-GVFBGH+JaqihQ4di06ZNOHr0qMrrly5dgkKhQG5urvSnVCqRlZWF27dvY8mSJQCA7OxsFmIlmTFj
-Bs6ePctfu6nMTp48iTfffBOrV6+Gnp4e9uzZg+fPn+PUqVPw9/fHkSNH8PDhQxw9ehRCCOzevRu3
-bt1CWlpaqd4jJiYG+/btw+PHj1noVGnHqnXr1uHcuXMqr+/fvx8ZGRnIzs5GSkoKIiIi8M0330BH
-Rwdr166Fvb09evXqhdOnT7MQiWGGqDazsrJSeV5Y1TFdXV107NgRX331FSZPniz9ElbTnDp1SuOX
-USaToXHjxujevTtXUCq1H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VE9gGtpwcXFBdeuXYONjQ0A
-ID09vcTvs2HDBgBATk4OfH19WfBUqTp16gS5/P9XCDI3N5euujRs2BAWFhb46KOP8Ntvv+HIkSNo
-3rw5rl+/DicnJ3z66adQKpUsRGKYIaqNdHR0Sl3HeNy4cTXyysyBAwdq1EkX635TaV29ehVTpkyB
-UqlEw4YNcfToUbRs2bLIaZo0aYIjR47AyMioxFdm7ty5g6CgIGhrawMAtmzZgoyMDH4BVGlkMhl0
-dXVLNJ6rqyvCwsLQqlUrAMB3332Hjz/+mIVIDDNEtfkgURqOjo5YunRpjfqMd+7cwfTp0/llU62l
-VCoxY8YM6arp/Pnz0b59+xJNa2RkBC8vrxJfmfH19YWVlRUmTJgAAIiPj2cnFaRRxypTU1McOnRI
-CtwbNmzA4cOHWYjEMENUl+Xm5iIhIQH6+vowMTEpcJz8HQUIIdQ6DijoBKy0CppnUfN59uwZnJ2d
-S9V7mxCiVMtW2mWqiPckyu/EiROIiIgAAGhra8Pd3b1U00+aNAlZWVnFjpeamoqdO3di9uzZmD17
-tvT6f//732K3d6KqZGlpiRkzZkjPvby8it3HlmY/XNh+v6jtoCTHRU1RlmNSac8BGGaIqEpduXIF
-CxYsUHs9MTERfn5+sLa2xrVr15CSkoJJkyZBX18fbdq0QWRkpMrOLTAwEMOHD4epqSnat2+Pxo0b
-o3///vDz8yu0LU5ubi7Onz8PDw8PmJubS+87d+5cGBoaQi6Xw8LCQq2x5+XLl2Fra4s7d+4AAEJD
-Q+Hi4gIXFxfMnz9fZdzs7Gz4+vrC2toa+vr60NHRQdeuXeHj41PgSV5Zl+lVx44dw8CBA/Haa6+h
-Q4cO6NmzJw4cOFBn17OgoCC1XouoeD/++KP02NbWFkZGRqWa3sjICDt37ix2PH9/f8jlcowdOxaW
-lpawtrYGAERHR+Ps2bP8IjRQaGgooqKi6mTYnDNnjvT41q1buHTpkto4pdn3CyFw7do1eHt7o127
-dkhMTIQQAv7+/rCwsIBcLkfTpk3x8ccfS9Wxc3NzsXnzZvTu3Ru6urqoX78+3n33XbWeRPfv34/x
-48dLx6jFixdLw5KSkjB37lwMHz5cGp6/hkRsbCzmz58vDcv7++KLL5Cbm4vDhw9j7Nix0utz587F
-s2fPylUWZTkH0NTURqTxDAwMxN69e2vUMgcHBwsAIjExsdLfS1tbWwAQAMTdu3cLHW/hwoVi5syZ
-0vMrV66IESNGCF1dXWn63377TfTv31/o6+tLry1YsEAIIUR6eroYPXq00NPTE7t37xY5OTlCCCFu
-374t+vbtKwCIHj16iNjYWJX3PXXqlHBycpLm16JFCxEdHS06duwoHB0dhYuLi6hfv74AIHR0dMQf
-f/whTfvXX3+J06dPC2NjYwFA2NraitOnT4vTp0+L8PBwabynT5+KPn36iOnTp4vIyEjx6NEjcejQ
-IdGiRQsBQPTt21ekpaVVyDLlUSgUYvbs2UIul4stW7aI7OxsIYQQ0dHRwsLCQjRq1EgAEIaGhpXy
-vZubmwtfX1+NW/fzyrRdu3Zi5syZIiAgQDx58qRC5t22bVuN/MwVoVWrVlLZeXp6Vsp7KJVK0bVr
-V+Hl5SW95u/vL72vs7NznT7WeHt7Czs7O41brmnTpgkAwsDAQIwYMUKsX79eREZGCqVSWSGfuaq+
-9wYNGkjr2l9//VXi6dq3by9Nt3jxYpVhpdn3X7p0SYwePVrI5XKV5Rg8eLCwsrIS7u7u4u2335aG
-ff755+LJkyfirbfeEo6OjmLWrFli1KhRQktLSwAQrq6uast67949af6DBw9WGx4dHS0ds18td6VS
-KZYtWya9f+/evVWGr1y5Uujq6oqAgIACv/vSHgdLew5QFpGRkQKA2nlBRQgMDBQGBgaCYYYYZmpZ
-mDl48KAIDQ2V/i5duiTOnj0rvv76a6Grq6sSZtLS0kR2drZ0oAQgnJycxKFDh0RqaqqYOHGiaNKk
-iTh9+rRQKpVi7NixAkCBJ5MpKSmic+fOAoDo1KmTSElJURtn6NChAoDQ19cXlpaWIiIiQhr2xx9/
-SJ9jypQpatOamJgIAGLEiBFqw7Kzs0WfPn3EqFGj1Hbw+/fvlz6bt7d3hS7TokWLBACxZs0atWGP
-Hz+WDtx1Lcw0a9ZMKnMdHR3pwF4R4aa2hpnk5GSpzApbpyrC2bNnhUwmU/nRIzMzU/qxAIC4efMm
-w4yG8fDwkE6gtbS0hJ6eXoWFm5oQZkaOHClNN3r06HLv+xcsWCANs7GxUflhTKlUSu/XoEEDYWlp
-KS5cuKAy/erVq6XpY2Ji1JbX1NS00DCT/3hWULkrlUoxZMgQ6bvOK6f09HTRsWNH8d133xU4z7KU
-RWnOARhmiBhmqizMFPeXP8zk+eGHH6ThX331VYHvcezYMQFANG3aVGRlZRU4zpEjR6T5fPHFF2rD
-P/roI2n4s2fP1Ib369dPCkOlCTNbt24VAMS5c+fUhmVmZkq/MDVt2lS6mlTeZbpx44bQ1tYWhoaG
-hZbH8OHD62SYMTIyKnT9K2+4qa1h5p9//lEpp61bt1bK+4waNarAX5PzgjkAMWvWLIYZDQwz+a8m
-5P8rb7ipCWFmxowZ0nSOjo7l3vdv375dml9YWJjatPv27ZOGb9q0SW34zZs3peG7du1SG96pU6ci
-w0xe2Cms3O/fvy9d2XdychJKpVJMmzZNODg4CIVCUeA05TkOluQcQJPDjJw1UYlql5s3b6o07hdC
-IC0tDZcuXcKHH35Y4DT5718xZMiQAsfJ6xLZysqq0O41hw0bBmNjYzx//hxbt27F0qVLVe4rkNcr
-DQAYGxurTZ/XDWd8fHypPrOfnx8AIDw8HNHR0WrDmzVrhsePHyMhIQE3btxQuf9LWZdp3bp1UCgU
-GDhwYKHl0ahRI66Qr8jfpurevXvYsWMHvv/+e+Tm5qJdu3YYPHgwHB0d0b9//2K7JK7NFApFhc8z
-NjYWhw8fxvHjx9WGzZw5EytXroRCocCuXbuwfPlyNG3alCtsDZB3U+S8dhlHjx7FiRMnkJWVBQMD
-Azg4OGDAgAFwcHBAt27dSt37pSbIv8z5j1dl3ffn3+83aNCg0P1+3jxe1aJFC+nxw4cPK/zztmnT
-Bt988w3c3d1x6tQpTJo0CYcPH0ZUVFShXf6X5zhYknMATcYwQ1TL6OnpQV9fX+W1evXqYfjw4Viw
-YIHUkL4w+Xfy+Q+WFy5cAAA0b968yGn79++PAwcOID4+HtHR0ejRo0eJlz1vJy1K0cg1OTkZ165d
-g7a2dqGNzseMGaP2HuVZJiGE1EVo586dq/Uk5v79+7h27ZpGrYO5ubllDjfff/89tm/fDoVCIYWb
-3r17w9XVtVaHm1eDQ1xcXIW/x5YtW/DGG29g0KBBBZ68ubm54cCBA0hPT8f27dvx+eef18l9aFpa
-msZtUy9evChzuDly5AiCgoKQnZ2Nxo0bw9HREf369YO9vT369OlTI76Tf//9V3r8+uuvV/q+v6Dj
-oMrJc74f6Srr/kzTp0/Hvn37cP78efj7+2Pjxo2F9kJakWVR3GdnmCGqQ4QG9jrz9ttv4+7du6We
-Lj4+XroZX3Enqp06dZIeP3z4sFRhpizu3r0rdT+5Zs2aKtkRv3jxAk+fPgVQvVdfsrOzsWrVKqxa
-tarWbDf516979+5h69atUkifOnVqpVyx0ARNmjSRrmoCQExMTIXOPyMjA35+flAoFCq/yL66nefZ
-sGED5s2bp3LSVlfcuHGjxpzkl/RYlNcrV3JyMg4fPiz9GOPo6CiFA01269Yt6XHv3r2rbd9flbS0
-tODn5wdzc3NkZGTg1KlTmDVrVoFX1mp7WTDMEFWDFy9eYPny5Rq3XD179sTGjRtLPV3+E8i8k/jC
-GBoaSo+rYoeaF7KEELh//36JbzJYHvl/Nc/MzKy271NPTw/ffvttodUHq4uZmVmZryzo6ekhKysL
-enp6sLS0hJOTE/r37w8bGxvo6uoiMDCw1u437OzscPDgQQAvu+KtSAEBAUhNTYWPj0+Rv8quWLEC
-T58+xYMHD3Do0CGVX3Prip49exZYFa86ffbZZ/jhhx9KddUzj46ODpRKJZRKJTp06IChQ4fCwcEB
-ffv2hbGxMRYsWIDExESNPp5GRUVJz11cXKpt31/V0tLSpOPvkSNHsG/fPowfP14jjoMMM0S12Llz
-5zBgwABMnTq11nym5s2bQ0dHBzk5OYiOjoYQotB61/lv0PXGG29U+rLVr19fehwSElIlO3E9PT3p
-8d9//11t34tMJkP9+vU1rm1Daerk6+vrIzMzUyW8ODo6Ftk2q7YaO3asFGbu3LmDqKgo6f5H5SGE
-wIYNGzBmzBjMnTu3yHHj4+Px1VdfAXh5E826GGby7jOiSfLvc4qjq6sLhUIBpVKJjh07YsiQIXBw
-cIC9vX2R1YQ11c6dO6WaDi4uLmjXrl217furUlZWFiZMmIClS5di48aNePToEebMmYMBAwao3YOq
-tpdFcXjTTKIKolQqsXz5cgwYMAAAMHz48Fp1cM+7sV5cXBxu3LhR6Lh59XVbtWqFjh07VvqymZqa
-SifPfn5+RVbvS01NxcyZM8v9nq1bt5YaTF64cIF3TS+FvPZcenp6sLOzwxdffIHg4GAkJycjODgY
-ixYtgp2dXZ0LMgDg5uamchLy3XffVch8L168iIiICEyfPr3YcWfOnCmt25cuXUJ4eDhXWg2nq6sL
-bW1tyGQymJmZwd3dHQcOHMCLFy9w69YtrFu3DqNGjaqRQebx48dSNVpdXV2sXr26Wvf9FaUkx4yF
-CxeicePGmD9/PjZv3iwdfz09PTXiOMgwQ1TLvHjxAoMGDcKSJUsAvLxjcUE9oFTWTjH/1ZDKOrH+
-4IMPpMcBAQGFjpd38uPu7l7qXnOKWva8eeXV/c7TqFEjKWgFBwdjz549BU6fm5uLKVOmwMnJqdzL
-pKenh/79+wN4WVc5KCioyGnrWtjJq/Lwanixt7dneCmCjo4ONm3aJD3ftWsXTp8+XeLpExMT4erq
-qnZX8NWrV8PMzAz29vbFzqNly5YYPXq09Hzt2rXcwWsApVIpVTcqaXjJX+W3Jp3E50lISMDIkSOR
-kJAAANi0aRO6dOlSZfv+8sirYp2enl5gGaSkpBQ5/a+//oqNGzfCz88PWlpacHV1xbvvvgsA+Omn
-n3D06NEqPQ4yzBDVcufPn0fXrl1x8eJFKJVKaGlp4bPPPquy909PT1c5QJSlZ5X8YaiwOtmTJk2C
-paUlAGDz5s0F1rG+ffs2goODYWZmhnnz5qkNL67xdl7PVgUd8PKqfdy+fVsanp2djcePH6v8UjVt
-2jSsX79e6s0HeFllx8XFBdnZ2XBzc6uQZcr/+Tw8PNS650xMTERISAiAl41uU1NT68w2kXcAfzW8
-XLx4keGlGEOHDsWaNWuk525ubiVqJxQaGgpLS0v069dPpdvYK1euICgoCGPGjCnxjwvvvfee9PjA
-gQPVWpWS/v8JsBCixoWXV/e1+dsYFhZshBA4deoU+vTpgytXrkBXVxfbtm3DtGnT1MYt674//zGv
-LMfE4n5AzLvCevnyZdy+fVulDFasWCHtIwu6DUFycjImT56MBQsW4M0335ReX7dunfQdu7u7qx2D
-y3McLMk5AMMMUS2kVCrx9ddfY+DAgYiPj0dubi7kcjnGjx+Ptm3bVtlynDx5UuV5YVcJipK/u+bf
-f/+9wHHkcjkOHTqETp06IT4+HhMmTFD5BT4hIQETJ05EmzZtEBgYWGDf/flPivJ6bcp/QPjzzz8B
-vOxONDk5WWW4ra2tNI/58+fj4MGDeOedd/Dvv/9i3LhxGDdunBQ+PD090bx5c/To0QOmpqYwMzND
-UlIS/P391U7oyrpMw4YNg4eHBwDg/v376NWrF1asWIHAwEBs27YNjo6OMDAwkA4O3bt3r3WX9gtz
-7do1ZGVlMbyU0SeffIJ9+/ahWbNmSE1NhaurK9zc3HDy5EmVX3pTU1MRFBSEd955By4uLli2bJlK
-d8qZmZmYNWuWtP2WVF6bhLyTr3nz5hV78keVa968eYiLi6tR4eVV58+fV1mP9u3bh5iYGPz999/4
-/fffcfjwYSxatAg9evTA4MGDce/ePbi5ueH69euFVpEs674/f2+BBQWK2NhY6XFB1aofPHggPX78
-+LHa8LyaDNnZ2bCzs4OXlxe8vb1hbm4OIQQcHBwAAGFhYXj//fdx7Ngx6bxi2rRpUCqV8PLyUpmn
-kZGRVPvj8ePHmDJlikrwKM9xsCTnAJqe9ok0noGBgdi7d6/GLM+TJ0+Eg4OD2h2ZZTKZiIyMFEII
-ERwcLACIxMTESlkGPz8/MWjQoALvCm1nZyc+/fTTYudx5swZ4erqKrS0tKRp9fT0xKRJk8T27dsL
-nCYpKUnMmzdPNGrUSLz++utixowZ4sMPPxQmJibC3d1dxMXFqU0TGhoqxo8fr7KMXbp0EV9++aUQ
-QoiTJ08KJycnleE9e/YU27Ztk+YRGxsrWrduLQ1//fXXxfnz56XhOTk5YsmSJdJdk/P+DAwMxMKF
-C0VGRkaFL5NCoRDffPONaNq0qcp4JiYm4ty5c+L9998XhoaGwsPDQwQHBxd65+ayMjc3F76+vnVq
-X9C2bds685nj4uLEkiVLRNu2bVX2MYaGhqJZs2YCgGjTpo1YtGiR2na3f/9+0blzZ2k6uVwuRo0a
-JY4fP17o+/31119i8uTJol27dmr7lN69e4tffvml1pe5t7e3sLOzq1PblLe3d6F3oq+oY5WTk5PQ
-1dVVW6/y/zVu3Fh06dJFjB07VmzatEk8fPiwRPMvzb7/119/FbNmzRJ6enoq+2tvb28RGxsr/v77
-bzFv3jzRvHlzabiurq7w8PAQFy5cEBkZGeLzzz8X7du3V9m23N3dRWBgoPQ+SqVSLF26VOX43KxZ
-M+n44ezsLNq3by+8vb1FaGioyM3NFcHBweLtt98WAISRkZHw8fFR+Zznzp0TDg4OKp/R1tZWZZsu
-7XGwLOcApRUZGSkAiNjY2ApftwIDA4WBgYGQCbZcpRqgSZMm8PX1Van+UJ2/Lo0ZMwYpKSkq7Tfk
-cjkcHR1x6tQpAC97FLG3t0diYqL0C31tkpWVhT/++ANxcXFo2rQpevToodKjSmVIS0tDWFiY1PNV
-QT38ZGRk4Pr160hISICRkRG6d+9eqp6AyloW169fR1xcHIyNjdGzZ0/I5XLExMTAxMRE5e7KFal7
-9+7w8PCQrhDVBSYmJvD29q5Tn1kIgdu3b+PPP/9EXFwclEoljI2N0bVrV3Tq1KlG3tFdUy1YsAAh
-ISEIDg6uU585Kiqqxnd7Xh37/uK8ePEC169fR7169dCnTx+pDeE///yDdu3alfomzjWxLKKiotC9
-e3fExsZWeK2VY8eO4f3332fXzEQlpVAosGzZMixbtky6HPzq8C+++KLOlIeenh6srKyq9D0bNGgg
-9RZXmHr16klV0qqyLPIaX+bXoUMHbjhUbjKZDJ06dVK5IS0RVf++vzhGRkYYNGiQ2uuVfdsCTSyL
-ysQwQ1QCT58+xZgxYxAWFlZg3XEtLS1YWFhI9WCJiIiIqPKxAwCiYpw5cwbdunVDeHh4kb18LFy4
-kIVFRERExDBDVP0UCgUWL14MJycnJCQkqN3fJI9MJoOJiQlGjBjBQiMiIiKqQqxmRlSAR48eYfz4
-8QgLC5P69y+MtrY2vvjii0pryEdEREREDDNEJXLq1CkMHjwYurq6Jbp5lIGBASZNmsSCIyIiIqpi
-/CmZKB8hBPbv3w8AhVYry09XVxdeXl68ISARERERwwxR9ZLJZNi+fTvWr18PLS2tYquO6ejoYMaM
-GSw4IiIiIoYZIs0wZ84cnDlzBo0aNSr0hoe6urr46KOPauUNMYmIiIgYZohqMEdHR4SGhkJbW7vA
-O2wrlUp4enqyoIiIiIgYZog0z6pVq9CsWTO4uLhAW1tbel1XVxeTJ0/Ga6+9xkIiIiIiYpgh0izr
-1q1DQEAA/ve//+Hw4cNYvnw5tLS0IJPJkJ2dDS8vLxYSEREREcMMkWa5cOECPvvsM/j6+sLGxgYy
-mQze3t4IDAyEEAI2Njbo2LEjC4qIiIioGvE+M0SvuH//PsaOHYtp06Zh6tSpKsOGDh2KW7duISsr
-iwVFRERExDBDpDnS09Ph5uYGMzMzrFu3rsBxzMzMWFBEREREDDNEmsXDwwNPnz7F1atXeSNMIiIi
-IoYZopohr8H/r7/+ipYtW7JAiIiIiBhmiDRfXoP/LVu2wMbGhgVCREREVAOwNzOq84pq8E9ERERE
-DDNEGqkkDf6JiIiISDOxmhnVaWzwT0RERFQLwsz333+P77//Hg0aNGCpUIVTKBTIycnB//73Pxgb
-G2vEMrHBPxEREVEtCTMxMTEIDQ2Fl5cXS4UqXFRUFM6fP4/MzEyNWB42+CciIiKqRWEGAJydnbFq
-1SqWClVKmDl+/LhGLAsb/BMRERHVDuwAgOoUNvgnIiIiqj3YAQDVKWzwT0RERMQwQ1TjsME/ERER
-EcMMUY3DBv9EREREtQ/bzFCtxwb/RERERAwzRDUOG/wTERER1V6sZka1Ghv8ExERETHMENU4bPBP
-RERExDBDVOOwwT8RERFR7cc2M1TrsME/EREREcMMUY3DBv9EREREdQermVGtwgb/RERERAwzRDWO
-pjb4X716NQwMDPgFUYWLioqqc5/54cOHWL16NZKTk7kCUKXsr83Nzevc5z527BhWr17NFaAYycnJ
-uH//Ptq1a4eGDRuyQDTkOMUwQ7WCJjb4b9iwIUxMTHDixAloabFGJ1W8Nm3awMjIqE59ZkdHR9y/
-fx8HDhzgCkAVrl27dujZs2ed+sytWrVCmzZtuE29QqlUIi0tTeUvJycHMpkM+vr66NKlCwupBLKz
-s2FqalqptWUYZqjG09QG/xYWFrh37x6/IKIKdObMGRYCUQX66KOP8NFHH9XpMlAoFIiOjkZ4eDgu
-X76My5cv48aNGxBCoHPnznBycoKVlRVsbGwQFRWFhQsX4urVq1x5NATDDNVobPBPREREpfHo0SMp
-tFy+fBnXrhOJlUQAACAASURBVF1DamoqWrZsCWtra4wfPx42Njbo06cPGjdurDLtjRs3WIAMM0QV
-hw3+iYiIqDCpqam4evUqwsPDERYWhvDwcDx69Aj169dH7969YWVlhdmzZ8Pa2hpt27ZlgTHMEFUd
-TW3wT0RERFWvuOpi1tbWWLhwIWxsbNCtWzfI5TwNZpghqiaa2OCfiIiIqk55qosRwwxRtdHUBv9E
-RERUOVhdjBhmqFZgg38iIqLajdXFiGGGai02+CciIqpdWF2MGGaoTjhx4gT27dvHBv9EREQ1FKuL
-EcMM1Um5ubn48ccfsXXrVjb4JyIiqgFYXYwYZojwssF/eno63n77bTb4JyIi0lCsLkYMM0SvyGvw
-r6WlhUmTJrFAiIiINACrixHDDFEJeHh44NmzZ2jQoAEvPxMREVUDVhcjhhmiMli3bh0CAgLw66+/
-YsiQISwQIiKiKlCS6mLW1tawtLRkdTFimCEqyIULF/DZZ59hy5YtbPBPRERUSVhdjBhmiCrY/fv3
-MXbsWEybNo0N/omIiCoIq4sRw0wVCAoKgomJCbp06cJvpw7Ka/BvZmaGdevWsUCIiIjKiNXFiGGm
-iimVSsydOxc2NjbYs2cPv506KK/B/5UrV6Crq8sCISIiKgFWFyOGGQ1w8uRJxMTEIDY2FqtXr8br
-r7/Ob6gOyd/gv2XLliwQIiKiAigUCty4cUPlqgurixHDjAbYsGEDACAnJwe+vr5Yvnx5lb7/qVOn
-4OTkxLWiGrDBPxERUcFYXYyoBoSZO3fuICgoCNra2lAoFNiyZQu+/PJL1KtXr0re/8CBA9i7dy/D
-TDVgg38iIqKXWF2MqIaGGV9fX1hZWeHNN9/E7t27ER8fj71792LatGlVEqSmT58OBwcHrhFVjA3+
-iYiormJ1Mc329OlThISEYPTo0UWOFxMTg3/++Yc/iNflMJOamoqdO3di/fr1UpgBgP/+97+YOnUq
-ZDJZieclhFAbX6lUQktLq8Dxnz17BmdnZyQlJZVqmYUQEEIUOt/yLFNFTfvqfACUqiyrAhv8ExFR
-XcHqYjXLzZs3MW7cOMTFxaFp06aFjrdnzx4cPXqUYaaaaGnCQvj7+0Mul2Ps2LGwtLSEtbU1ACA6
-Ohpnz54tdvrc3FycP38eHh4eMDc3BwAkJiZi7ty5MDQ0hFwuh4WFBU6fPq0y3eXLl2Fra4s7d+4A
-AEJDQ+Hi4gIXFxfMnz9f7X2ys7Ph6+sLa2tr6OvrQ0dHB127doWPjw+ysrIqZJnKO21+V69excSJ
-E2Fvb4/Bgwejbdu26N27N3bs2CGFm+qU1+D/wIEDbPBPRES1SmpqKi5cuAAfHx+4ubmhdevWaN26
-NSZOnIjQ0FD06dMHO3bsQGxsLJ48eYJffvkFX3zxBQYMGMAgoyFsbGygq6uLkJCQIse7cOECHB0d
-WWDVRfwfb29v4ezsLKqaUqkUXbt2FV5eXtJr/v7+AoAAUOwynTp1Sjg5OUnjt2jRQkRHR4uOHTsK
-R0dH4eLiIurXry8ACB0dHfHHH39I0/7111/i9OnTwtjYWAAQtra24vTp0+L06dMiPDxc5X2ePn0q
-+vTpI6ZPny4iIyPFo0ePxKFDh0SLFi0EANG3b1+RlpZW7mUqz7T5bdq0SchkMuHp6SkUCoUQQoi0
-tDRhZ2cnAIgVK1ZU6fccGRkpAIjY2FghhBDnz58XcrlcbN++vUTTGxgYiL179woiIiJNk5ubKyIj
-I4Wfn5+YNm2aMDc3F9ra2kJLS0t06dJFfPDBB2Lz5s0iIiJC5OTksMBqkH79+olPPvlEer53717R
-tm1b6Xl6errQ09MTR44cYWFVscDAQGFgYCCqPcycPXtWyGQycffuXem1zMxMKWAAEDdv3ix2PkOH
-DhUAhL6+vrC0tBQRERHSsD/++ENoa2sLAGLKlClq05qYmAgAYsSIEQXOOzs7W/Tp00eMGjVKKJVK
-lWH79++XltPb27vClqk80z548EAafurUKZVhAQEBAoBo1KiRyMrKqpYwExsbK4yMjIS7u3uJp2eY
-ISIiTfHw4UPxv//9T8yfP1/0799fNGzYUAAQLVu2FCNGjBArVqwQZ86cEUlJSSysGm7x4sWiZ8+e
-hYaZ8+fPC21tbZGQkMDCqqYwU+3VzDZu3AgXFxe0a9dOek1PTw8zZ86Unq9fv77Y+ZiamgIAMjMz
-ERgYCAsLC2lY9+7d0bdvX6kqWWnt3LkTV69exZw5c9TanAwfPhz6+voAgK1btyI3N7dClqk8096+
-fRsKhQIAEBcXpzLM2NgYAJCSkoK7d+9W+fedkZHBBv9ERMTqYlQjODo64o8//kBCQkKBw8+fP4/u
-3bujSZMmLKxqUq0dAMTGxuLw4cM4fvy42rCZM2di5cqVUCgU2LVrF5YvX15k4yttbW21E/b8WrVq
-BQCIj48v9XL6+fkBAMLDwxEdHa02vFmzZnj8+DESEhJw48YNdO/evdzLVJ5p+/Xrh08//RRZWVkY
-OXKkyrD8Yay0nR5UhC+//JIN/omISCOxdzF6lY2NDXR0dBASEgJXV1e14WwvU8fDzJYtW/DGG29g
-0KBBBZ6su7m54cCBA0hPT8f27dvx+eefl/m98nr/EqVs+J6cnIxr165BW1sbT548KXCcMWPGqL1P
-ZS5TcdPK5XJ8++23Kq+lp6cjICAAO3bskF5TKpVV/p0fOXIEFy9eZIN/IiKqduxdjIqjr68Pa2tr
-XLhwQS3MZGRk4PLly/jss89YUHUxzGRkZMDPzw8KhUK6kvGq/FcdNmzYgHnz5lX5ryB3796FEAJK
-pRJr1qxRuWJSE9y7dw/r16/HrVu3MHXqVCxZsqRauw5csWIFbGxsuOUREVGV4s0oqawcHBxw9OhR
-tdcvX76M3Nxc2Nvbs5DqYpgJCAhAamoqfHx8iryasWLFCjx9+hQPHjzAoUOHVK6CVIW0tDQAL6+A
-3L9/H+3bt68RX2xaWhoWLFgAf39/+Pr6Ys2aNZDJZLhw4UK1Ltft27dx//59HiiIiKjSsLoYVSRH
-R0csX74ciYmJKq+zvUwdDjNCCGzYsAFjxozB3Llzixw3Pj4eX331FYCXN9Gs6jBTv3596XFISEiN
-CDNJSUlwdHREREQEgoKCMGTIEI1Ztl69esHExASTJk2Cn58f280QEVG5sboYVaa8djPBwcEqr7O9
-jGaolt7MLl68iIiICEyfPr3YcWfOnAkdHR0AwKVLlxAeHl6ly2pqaio1mvfz8yuyfUtqaqpKL2zV
-ZeXKlYiIiICJiYlGBRkAcHZ2BgD88MMPePPNN3HixAluhUREVGLsXYyqWv52M3ny2ss4ODiwgOpi
-mFm9ejXMzMxKVMewZcuWGD16tPR87dq1ZXrPokJIXljJzs5WG9aoUSNYW1sDAIKDg7Fnz54C55Gb
-m4spU6aUqj1KWRr+l2TavN7h9PT01Ibl5ORU+0oXFRUF4GV7JGdnZ4wcORL//PMPt0YiIlKhUCgQ
-FRWF7du3Y/r06VKVngEDBmD37t1o0qQJFi5ciIiICCQlJeHixYv49ttvMWbMGFZnpgrl4OCA8+fP
-S8/DwsLYXqauhpkrV64gKCgIY8aMUbtnS2Hee+896fGBAwfw999/F7jDK0reSXxBISCvy+fbt29L
-w7Ozs/H48WMAgKenpzTutGnTsH79emRlZUmv3blzBy4uLsjOzoabm1uFLFN5ps3rpezOnTv4888/
-pdczMzOxe/dulV8VyhuqyqJbt2745JNPYGBgAF1dXcTExKBbt2746quvpGUiIiLNdP36ddy5c6dS
-5v3o0SMcPHgQXl5ecHBwQJMmTdC9e3csWrQIL168wPjx43Hy5EkkJCQgOjoaO3bsgLu7OywsLNju
-hSpV3v1m0tPTAbysYtajRw+2l6lrYSYzMxOzZs0CgFLtdPLfUFOhUGDevHlq3QrnDzjPnz9XGSaE
-kE7qk5KSkJycrDLc1tZWmsf8+fNx8OBBvPPOO/j3338BAOPGjcO4ceOkEOHp6YnmzZujR48eMDU1
-hZmZGZKSkuDv768S0MqzTOWZNu/qkBACgwYNwsKFCzF79mz06NEDXbt2lcZbtWoVlixZgh9++KHK
-V7wlS5ZAX18fPXr0wN27dzFr1ixs3rwZXbp0waFDh7hlEhFpmN9//x0jR45Er169EBAQUO75sboY
-1SR57WZu3rwphRlWMdMQ4v94e3sLZ2dnUVn2798vOnfuLAAIAEIul4tRo0aJ48ePFzrNX3/9JSZP
-nizatWsnTZf317t3b/HLL7+I0NBQMX78eJVhXbp0EV9++aUQQoiTJ08KJycnleE9e/YU27Ztk94n
-NjZWtG7dWhr++uuvi/Pnz6ssS05OjliyZIlo1KiRyrwMDAzEwoULRUZGhjRueZapIj5PUlKScHBw
-UBnH2dlZxMTECIVCIczNzaXXR40aJdLT00Vli4yMFABEbGys9NquXbuEvr6+mDx5sqhfv744dOiQ
-mDt3rpDL5WLIkCHi1q1b0rgGBgZi7969goiIqtaVK1eEq6urkMlkwsnJSYSEhJR6Hrm5uSIyMlL4
-+fmJadOmCXNzc6GtrS20tLREly5dxAcffCA2b94sIiIiRE5ODgudNFK/fv3EsGHDRJs2bYSenp44
-cuQIC6UaBQYGCgMDAyET/1fHaMGCBYiKikJgYGCdDHVpaWkICwuDnp4eLC0tC2xvArysmnX9+nUk
-JCTAyMgI3bt3L3Tcag6piIyMxJMnT/Dmm2/CxMREGpaSkoLQ0FA0b94cPXv2LHF1v/KIiopC9+7d
-ERsbK9VjFkLA3t4eTZo0QYcOHeDn54fDhw+jRYsWmDNnDkJDQ/HJJ5/gyy+/ROvWreHr66tS5ZCI
-iCpPeHg4vv76axw7dgxDhgzB4sWLpZoMxSmudzErKyv2LkY1zpIlS+Dv74/U1FTEx8cjLi6O1cyq
-0bFjx/D++++DFUz/T4MGDTBgwIBix6tXr16Jd+bVSSaToUePHujRo4fasEaNGlXrjTPzL+PGjRvR
-p08f/PLLLwCAESNG4PDhwzh//jwCAgLw6aefwt/fXyM6LiAiqgvCwsLw9ddfIygoCMOGDUNYWJjU
-EU5BeDNKqivy7jfToEEDtpfRIAwzVK0sLCwwY8YMzJs3D5GRkSqB5t1334Wrqyu+/vprfPPNN1i+
-fLlaux8iIqoYv/32G77++mucPn0azs7OCA8Ph6Wlpco4vBkl1WXW1taQy+VISUlhexmGGaL/b9my
-Zfj555/x7bffSl1v5wWagQMHwsfHB1u2bIFcLoeFhQXmzJmDxYsX8xcRIqIKEBwcjKVLl+LcuXNw
-dXXFlStX0Lt3bwBFVxezsrLizSipTqlXrx7Mzc1x7do1hhmGGaL/z9DQECtXroSnpycmT55cYKDR
-0tKCt7c39PX1MW/ePAQEBGD9+vUq9yAiIqKS+/XXX7F06VJcuHABI0eOREhICLKzs3H27FmsWLGC
-1cWICtC8eXMA4P1lGGaIVH344YfYunUrPv30Uxw4cEAt0ORxc3PD0KFDsXLlSrXuuYmIqHjnz5/H
-0qVLERwcjF69emHUqFG4c+cO+vXrx+piRMXw9vbGixcvWDuEYYZIlZaWFjZs2IC+ffvi1KlTcHJy
-Ugk0+Xtcq1evHpYtW8ZCIyIqhb1792LChAkAAG1tbSiVSsTGxsLIyAgjR47E2rVrWV2MqBjW1tYY
-PHgwC4JhhkidjY0NPvzwQ3h6eiIyMhI6OjpSoFm/fr10o9Ca4s8//8TEiRPRrFkzaGlp8QumCvf8
-+XMsX74crq6udeYzv/POO3j48CFPuEshOTkZMTEx0o2ggZcN+QHgxYsXCAoKQlBQEJYtWwaZTCZd
-hcn7r6Ojo/JcLpdDJpNBW1sbLVq0gKGhYa0pq3///RdvvfUWNmzYUGfWj++//x7r16+HsbExN5YS
-ysrKwqBBg1gQJZCdnY309HQcO3as0tYxhhnSKCtXroSZmRnWrVuHzz77DDKZDGvXrsWWLVuwZs0a
-vP322xg4cGCN+CyJiYm4fv063N3dYWBgwC+XKtzq1avx8OHDOvWZDx48iMaNG8PDw4MrQCk4OjpK
-ISYnJ0f6r1QqkZ2drfZfCIGsrCzpf94JHABkZmZK/9u3b4+OHTvWqm0qOzu7Tq0bMTExiIyMhJeX
-FzcUqnBRUVG4ePGitN9gmKFaz8jICEuXLsWXX36Jd999F61atYJMJoO+vj5sbW1VOgWoKVatWsUw
-Q5Xi+PHjde4zt23bFt7e3gwzVClkMhlCQkLq3Od2dnbGqlWruAJQpYSZyj5Wse4LaZzZs2ejQ4cO
-mD9/vsrrEyZMwPTp0zFixAicOXOGBUVERERUxzHMkMbR1tbG+vXrERAQgODgYOn1vCpnDDRERERE
-BLCaGWkoe3t7zJw5E8+ePVN5PS/QAKiRVc6IiIiIiGGG6gBfX98CX2egISIiIiKGGaqxGGiIiIiI
-iGGGGGiIiIiIiGGGiIGGiIiIiBhmiBhoiIiIiIhhhhhoiIiIiIhhhoiBhoiIiIgYZogYaIiIiIiI
-YYaIgYaIiIiIYYaIgYaIiIiIGGaIGGiIiIiIiGGGiIGGiIiIiBhmiIGGiIiIiBhmiBhoiIiIiIhh
-hoiBhoiIiIgYZogYaIiIiIgYZogYaIiIiIiIYYaIgYaIiIiIGGaIGGiIiIiIGGaIGGiIiIiIiGGG
-iIGGiIiIiBhmiBhoiIiIiIhhhoiBhoiIiIhhhoiBhoiIiIiqNcxcuHABZ86cYalQhYuKimKgISIi
-IqLKCzNpaWkYNGgQS4XqPAYaIiIiohoUZv7zn//gP//5D0uEiIGGiIiIqGaFGSJioCmMEALh4eE4
-ceIEnj17BmNjY1haWuLtt99GvXr1kJiYiJ9//hnTpk2Tpnnw4AGSkpLK/J6GhoZ47bXXih0vKysL
-ISEhuHr1Kh49egSFQgFDQ0N06NABNjY26NixI2QyGZ48eYJTp05h8uTJXLGpWgUFBcHExARdunTR
-mGV69uwZAgMDce7cOezdu1dl2L179+Dh4QEDAwNs3boVBgYG/BKpytbLFy9eFDq8adOmaNWqVYHH
-rOjo6AKnad++PRo0aFBh63ZR2w4xzBAx0GiAFy9eYNKkSThx4gSaN28OW1tb3L9/H76+vsjKyoKL
-iwsePnwIuVyuEmb+/PNPBAYG4qeffkJCQoLKPLW0tCCTyaTnSqUSQgiVcT7++GOp3Avy77//wsfH
-B9u2bUNCQgKaNGkCS0tLGBsb48GDB9i+fTuePHkCU1NT2NnZISwsDD179mSYoWqlVCoxd+5c2NjY
-YM+ePdW+PFu3bsX27dtx7do1CCFgaGioNs6aNWtw4sQJAICtrS08PT35RVKV+Oeff+Dn54ddu3ap
-HCM6deqE8ePHo1+/foWGmaCgIPz22284fPgwAMDAwACzZs3CRx99JIWZ8qzbJdl2qIoIohrAwMBA
-7N27t1qXQalUCk9PT1G/fn1x+vTpYscPDg4WAERiYmKNLfeMjAxhYWEhAIjJkyeLjIwMaVh2drbY
-vHmzqFevngAgOnfuXOA8QkJCBADpLyQkpMDxsrKyxO3bt8WSJUsEADFr1qxCl+vEiRPC2NhYABAt
-W7YUe/bsEdnZ2SrjKBQKcfToUfHGG29I7+3q6lqrtgtzc3Ph6+tbp/YFbdu2rdGf+fjx4wKA0NHR
-EY8ePar25VEqlSIpKUl07dpVABCGhoZq42zbtk0AEDKZTJw9e7ZWr1/e3t7Czs6uTm1T3t7ewtnZ
-WaOX0cfHR+U48tNPP5V42i5duggA4sSJExW6bpdk2yEhIiMjBQARGxtb4fMODAwUBgYGQotxjqh0
-V2imT5+OESNG1Ime/7Zt24br16+jSZMm2Lx5M/T19aVhOjo6cHd3x5kzZ1CvXj08evSowHlYWVmp
-PC/oVzQA0NXVRceOHfHVV19h8uTJyMnJKXC8H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VG7+uPi
-4oJr167BxsYGAJCens4VmarVhg0bAAA5OTnw9fXViP1a48aN0b1790LHmT59Oi5fvoyoqCi8/fbb
-/BKpys2bNw9vvvmm9DwkJKSkP9gjLi4OdnZ2GDx4cIWu2yXZdqhqMMwQMdAU6siRIwAAU1NT1KtX
-r8Bx3nrrLXzzzTdISUlBSkqK2nAdHR1oaZVuVzNu3DhkZ2ervX716lVMmTIFSqUSDRs2xNGjR9Gy
-Zcsi59WkSRMcOXIERkZGSEtL40pM1ebOnTsICgqCtrY2AGDLli3IyMjQjJOBYrZRKysrdO3alV8i
-VQu5XI7FixdLz/39/Uu0Pw8PD8fz58/x0UcfVdq6XdrjGzHMEDHQVKHHjx9LJ2FFXdWYPn06WrRo
-IY1fUJmVhqOjI5YuXarymlKpxIwZM6QrNvPnz0f79u1LND8jIyN4eXnxygxVK19fX1hZWWHChAkA
-gPj4eDYYJiqh0aNHw8TEBACQlJSEHTt2FDvN999/j+bNm2PkyJEsQIYZIqqLgaZJkyYAgOTkZCxY
-sKDQ8XR1dTFp0iT8+++/5X7PFy9eQF9fXzpo5Tlx4gQiIiIAANra2nB3dy/VfCdNmoSsrCyuvFQt
-UlNTsXPnTsyePRuzZ8+WXv/vf/+r1vlFVRBCQKlUlmm6kirL/IkKI5fL8fHHH0vP165dC4VCUej4
-KSkp+PHHHzF58mTo6elV2Lpd1m2nPNNyW2KYIWKgKaP8N9Fdv349Pv744wKrfwGAj48PbG1ty/V+
-SqWy0J7ifvzxR+mxra0tjIyMSjVvIyMj7Ny5kysuVQt/f3/I5XKMHTsWlpaWsLa2BgBER0fj7Nmz
-RU67f/9+jB8/Hi4uLnBxcVGpbpOUlIS5c+di+PDh0vBXr2rmd+zYMQwcOBCvvfYaOnTogJ49e+LA
-gQNFvn9KSgp++OEHDB48GOvWrSvyRC0wMBDDhw+Hqakp2rdvj8aNG6N///7w8/MrtB0cUUlNnTpV
-6j757t27Uk9lhR0z0tLSMH369HKv22XddgAgOzsbvr6+sLa2hr6+PnR0dNC1a1f4+PgU+gMbt6XS
-p0Qi9mZWCb2c1YbezOLi4sRrr72m0ouMhYWFCA8PL9V8tLW1penv3r1b6HghISHCxMSkwGGtWrWS
-5uHp6cmNgr2Z1RhKpVJ07dpVeHl5Sa/5+/tL63NJepK6d++ekMvlAoAYPHiw2vDo6GhpOytofgqF
-QsyePVvI5XKxZcsWqfe/6OhoYWFhIRo1aqTWI1N0dLQYO3as0NfXl5b1m2++KXD50tPTxejRo4We
-np7YvXu3yMnJEUIIcfv2bdG3b18BQPTo0aNSejRib2a1vzez/D7//HNpfezbt2+h21zPnj1Fv379
-ChxemnW7LNtOnqdPn4o+ffqI6dOni8jISPHo0SNx6NAh0aJFC2n509LSauW2VJW9mTHMEMNMJQWa
-2hBmhBDi999/F82bN1cJNADExIkTxcOHD0sdZg4ePChCQ0NV/n799VexZcsW0a5duwLDTHJyssp7
-r1mzhhsFw0yNcfbsWSGTyVSCfGZmptS9OABx8+bNYudjampaaJgRQggTE5NCw8yiRYsK3XYeP34s
-GjRooHZClpqaKjIzM8Xu3buLPOFTKpVi7NixAkCB301KSoro3LmzACA6deokUlJSGGYYZsrswYMH
-UrAHIMLCwtTGuXLligAg/P39C5xHSdftsm47Qry8fUGfPn3EqFGjhFKpVBm2f/9+6X29vb1r5bZU
-lWGG1cyIWOWsSD179sS1a9fUuq3cs2cPOnfujG3btpWqHr2bmxtsbW1V/vr37w93d3fcu3evwGni
-4uJUnjds2JArHdUYGzduhIuLC9q1aye9pqenh5kzZ6pU4yyOXC4v0/C//voLK1euhKGhYYG9Or32
-2msYMGCA2usNGjSAnp4e7O3ti3zfoKAg7N+/H02bNsXUqVPVhjds2BA+Pj4AgFu3buE///kPVwoq
-s9atW2PcuHHS8++++05tnK1bt6Jp06Z45513CpxHSdftsm47ALBz505cvXoVc+bMUesEZ/jw4dKt
-DrZu3Yrc3FxuS+XAMENUSYHm6tWrteaztW3bFmfOnMG+ffvwxhtvSK+npqZi5syZRd4X5lU3b95E
-RkaG9Jeeno6kpCRcvXoVffv2LdE8imr0SaRJYmNjcfjwYZVG/3lmzpwpddO8a9cuJCQkVMoyrFu3
-DgqFAgMHDoSurm6B4zRq1KjQ6V+9h9Or8u6XY2VlVej8hw0bBmNjY7WTN6Ky+OSTT6THP//8M2Jj
-Y6XnycnJ+OmnnzBx4kSVe6OVZd0uz7bj5+cH4GX30Bs3blT58/PzQ7NmzQAACQkJuHHjBrclhhki
-zQs0RfX+VVM/29ixY3Hjxg0sXbpU5VfgPXv2YPLkySW6QqOnpwd9fX3pr169emjcuDF69+6NzZs3
-FzhN06ZNVZ6/eqWGSFNt2bIFb7zxhkpnGnlatWoFNzc3AC9v6Lp9+/YKf38hhNRIunPnzhU+f6VS
-iQsXLgAAmjdvXuh42tra6N+/P4CXXVJHR0dz5aAy69WrFxwcHKR1MP+VzZI0/K/sbSc5ORnXrl2D
-trY2njx5gpiYGLW/MWPGwNPTE56entDS0uK2VA5ybhJElRNoHj9+XKKeTmoaPT09LF68GEOGDMGI
-ESPw9OlTAMBPP/2EUaNGYcyYMWWed7du3dCqVSu115s0aQJjY2M8f/4cABATE8MVjTReRkYG/Pz8
-oFAoCr1LeHx8vPR4w4YNmDdvXrHVyUrjxYsX0jZa1NWXsoqPj5duXljcL8SdOnWSHj98+BA9evTg
-SkJl9umnn0on/35+fliyZAkaNWqErVu3wtbWFt26dau2befu3btSN8xr1qyRrsAW937clhhmiDQq
-0MyZM6dGh5nU1FQ0aNCg0BteWllZITg4GLa2ttKVEl9f33KFGZlMht9++63AYXZ2djh48CAAIDQ0
-lCsZDE9QJwAAGAdJREFUabyAgACkpqbCx8enyLuEr1ixAk+fPsWDBw9w6NChcm1Dr8p/FTMzM7PC
-P2P+Kp95J36FMTQ0lB6X5OSOqCjDhg1Dp06dcOvWLaSkpGD79u2wt7fH9evXK6Qb/vJsO3mhRAiB
-+/fvl+gGz9yWGGaINDLQ1GTu7u6YNWsW3nrrrULH6dChA3x8fPDhhx8CAP74448KXYaHDx/CyMgI
-enp6GDt2rBRm7ty5g6ioKJibm3NFI40khMCGDRswZswYzJ07t8hx4+Pj8dVXXwF4eRPNigwz+W8W
-+Pfff1f452zevDl0dHSQk5OD6OhoCCEK3fflv/Ff/rZ3RGWhpaWFTz75ROpIY926dYiMjETjxo0r
-ZBsqz7ZTv3596XFISEiJwgy3pXKsC9wciKiwoLJ8+fJix8t/o8yS3GW5pJKSkmBpaSldbndzc1M5
-IBTUgw2Rprh48SIiIiJKVG9/5syZUkPkS5cuITw8vMwB6lWtW7eW5n3hwoVS9TxYEnK5XLoBaFxc
-nNSQuSBPnjwB8LKtUMeOHbmSULlNnDhRal9y//597N69GxMmTECDBg3KPe/ybDumpqZSEPHz8yty
-2ryOdLgtMcwQUSWEmaCgoCLvsAy8bBeQx8bGpsQnWcVZtGgROnfuLB2UdHR0sGnTJmn4rl27cPr0
-6RLPLzExEa6urnj27Bm/XKp0q1evhpmZWbFdvwJAy5YtMXr0aOn52rVrCxwvrzpJenp6gdtYSkqK
-2ut6enpSY+G7d+8iKCioyG20oG21uO33gw8+kB4HBAQUOl5eSHN3d6/xV65JM9SrVw+zZs1Sea00
-Df+LWrfLs+00atRICibBwcHYs2dPgdPm5uZiypQpcHJy4rbEMENElRFm8nauRf1ClL9dUP7uMvNk
-ZmaqXBIv7sQor3rOhg0b1HqAGjp0KNasWSM9d3NzQ2BgYLGfJTQ0FJaWlujXrx9atGjBL5cq1ZUr
-VxAUFIQxY8aU+ETjvffeU9mmCqrWkndl8vLly7h9+7b0ukKhwIoVK6SQk79TAQCYN2+e9NjDwwMP
-Hz5UC/ohISEAXvbClJqaqjI8f7frBTVMnjRpEiwtLQEAmzdvRmJioto4t2/fRnBwMMzMzFSWh6i8
-Zs2aJdUK6NOnDywsLEo8bXHrdnm2HU9PT+nxtGnTsH79emRlZUmv3blzBy4uLsjOzpZ6NeS2xDBD
-RJUQZhISEmBnZ4effvpJpYGiUqnEjh07pBt4LV++vMBfoV8NGzt27EBYWBhiYmJw79493L17Fzdv
-3sTFixexadMm2NvbS20MBg4cqDa/Tz75BPv27UOzZs2QmpoKV1dXuLm54eTJkyq/WKempiIoKAjv
-vPMOXFxcsGzZMnz++ef8YqlSZWZmSr8Ul6ZXsvw31FQoFJg3b57KjwB5PywAQHZ2Nuzs7ODl5QVv
-b2+Ym5tDCCF1VRsWFob3338fx44dA/CyobSHhweAl1VxevXqhRUrViAwMBDbtm2Do6MjDAwMpBO6
-7t27q9zQM/+PGbdu3VJbdrlcjkOHDqFTp06Ij4/HhAkTpAbQefuQiRMnok2bNggMDKyQKkBEeVq0
-aIGJEycCAGbMmFGqaYtbt8uz7YwbN066uWdOTg48PT3RvHlz9OjRA6ampjAzM0NSUhL8/f2lHz24
-LZWRIKoBDAwMxN69e2vUMgcHBwsAIjExsUaWuVKpFAYGBmLJkiXCy8tLmJmZiRYtWoghQ4YIV1dX
-0bZtWwFAmJqaip9//lltej8/PzFgwAChra0tAJT6z8DAQOTm5ha6fHFxcWLJkiXScgAQMplMGBoa
-imbNmgkAok2bNmLRokUiLi6uVm4X5ubmwtfXt07tC9q2bauxn3n//v2ic+fO0vool8vFqFGjxPHj
-xwud5q+//hKTJ08W7dq1U9sGevfuLX755ReVbXLp0qVCLpdL4zRr1kxs27ZNCCGEs7OzaN++vfD2
-9hahoaEq249CoRDffPONaNq0qcp7mJiYiHPnzon33/9/7d1/dNV1/cDxF9vdxgZzTn4VET/q2DIC
-A9EgEaxOBxI9kOmRUA6dOqEQET+UMDrQOXKC6mQHS4qAlHM8mgdPHTMMzBN4GHFU1CUJyVkonFJ+
-jDMYsrGN7dMfftnXxa8pG9y7PR5/7W73fnbv+3Mv7LnPfX12e9KtW7dk2rRpyebNm5OGhoZk06ZN
-yYwZM5Lu3bs3e41NnDgxeeyxx055LEeOHElmz56dFBYWJr17906mTp2afOMb30j69euX3HXXXRnx
-Opw/f34ycuTIDvWamj9/fjJu3LiMfgw7duxICgsLk6qqqhZd//08tz/Ia+ek+vr6ZNGiRUlhYeEp
-/7/94Ac/SGpqak57/9rDa+mkV199NYmIZM+ePa2+7T/96U9JUVFR0ilp7WlAaAOXXnppLF++vNlb
-MdJdaWlpXHfddXH48OGm39xkmqeffjpuuOGGk7/4iF27dkVZWVkcOnQo8vPzY9CgQTF06NCznnb2
-AvxCJnbt2hX/+Mc/oqKiIhobG6Nnz54xcODAKCkpadfvJx48eHBMmzat6TeHHUG/fv1i/vz5Heox
-/6+DBw9GWVlZ5Ofnx7Bhw5r+yvnu3bujf//+Z3091tbWRllZWVRUVETPnj1jyJAhkUqlory8PPr1
-63fOv4jeErW1tfH3v/89Kioqori4OK688spmZ3dKZ/fee2+UlpbG5s2bO8zz6d57743t27e36C27
-6ezll1+OoUOHttn2z+e1U1NTE2VlZVFZWRk9evSIwYMHt+iEOZn8Wjpp+/btMXjw4NizZ0/07du3
-Vbe9bt26uP32252aGTizkyET8e6ppktKSpr9sa50kK73C9pKjx49Tpkni2jZKVrz8vKaBpPf6+Tb
-SltDXl5eXHPNNXYUF1Rbhsz5vnby8/ObnfnTa6l1mZkBAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAA
-AGIGAAAQMwAAAGIGAABAzAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBm
-AAAAxAwAAICYAQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAA
-QMwAAACIGQAAADEDAACIGQAAgDSTsgTQttauXRtFRUUWgla3ffv2DveYKyoqYu3atdG9e/cO85gb
-Ghri+PHj0aVLF096/163iXXr1sXatWs9AVqguro68vPzo1OnThYjTf6fEjPQVi+u1Lsvr9mzZ0dO
-To4FoU3k5eV1qMdbVFQUGzdujLKysg7zmOvq6qK6ujry8vKic+fOfohqQ5WVlTF69OgO9Zjz8/Mj
-IuLOO+/0BDiH2traqKmpiYKCgsjNzbUgLXDkyJGIiMjKars3g4kZaCPDhw+PJEksBLSit956q8M9
-5rq6uli1alUsXbo0qqqqYubMmTFr1qwoLi72hOC8LVy4MBYuXGghzmL9+vUxd+7c2Lt3b9x3330x
-Z86cpgjk4jMzAwBpLDc3N6ZPnx7l5eXxox/9KB566KEYMGBALFq0KCorKy0QtJHy8vIYP358jBs3
-LoYPHx67du2KBQsWCBkxAwCIGkhPhw8fjrvvvjsGDhwYVVVVsW3btli9enV8+MMftjhiBgAQNZB+
-Tpw4EcuXL4/LL7881q5dG2vWrImNGzfGkCFDLI6YAQBEDaSn9evXx5VXXhnf+973YtasWfHPf/4z
-Jk6caGHEDAAgaiA9mYsRMwCAqIGMYi5GzAAAogYyirkYMQMAiBrIOOZixAwAIGogo5iLETMAQDuN
-moULF4oa2iVzMWIGAGjnUfPwww+LGtoVczFiBgAQNZBxzMWIGQBA1IgaMkp5eXlMmDDBXIyYAQBE
-jaghM7x3LubIkSPmYsQMACBqRA3pzVwMYgYAEDVkHHMxiBkAQNSQUczFIGYAAFFDRjEXg5gBAFo9
-apYsWSJqaDPmYhAzAECbRc20adNEDW3CXAwt1SlJksQykPZP1E6dYvDgwTFp0iSLAZCGGhoa4sUX
-X4yNGzdGbW1tXHvttTFy5EjzDLwvhw4dinXr1sXOnTvjqquuijFjxkRhYaGF4RTr1q2LzZs3ixky
-wzXXXBNVVVXRtWtXiwGQxpIkiYqKiti3b180NDREz549o1evXpGdnW1xOGsMv/3223HgwIHo2rVr
-9OnTJwoKCiwMZ1RdXR1du3YVMwBA66urq4vVq1fHkiVLoqqqKmbOnBmzZ8+O4uJii0OTEydOxG9+
-85tYtGhRFBQUxI9//GNvJ+N9ETMAgKjhglu/fn3MnTs39u7dG/Pnz485c+Z4WyJiBgAQNaSv8vLy
-uPvuu+Opp56Kr3/967F48WKnWeYDczYzAKDNOfsZ/l4MbcGRGQDggnOkpuMwF4OYAQBEDRnHXAxi
-BgAQNWQUczFcKGZmAICLzkxN+2AuhgvNkRkAIO04UpNZzMUgZgAARE3GMReDmAEAEDUZxVwM6cDM
-DACQ9szUpA9zMaQTR2YAgIzjSM2FZy4GMQMAIGoyjrkYxAwAgKjJKOZiSHdmZgCAjGempnWZiyFT
-ODIDALQ7jtR8MP87F7N06dL42te+ZmEQMwAAoiZ9mYtBzAAAiJqMYi6GTGZmBgBo98zUnMpcDO2B
-IzMAQIfTHo/UvPnmm/Hmm2/G9ddff9brmYtBzAAAdPCoOXbsWDz77LMxfvz4i/44du3aFSUlJU2P
-KScn57TXMxdDe+NtZgBAh3U+bz/75S9/GRMmTIilS5de1Mewc+fOuPbaayM7OzuysrLigQceOOU6
-5eXlMWHChBg3blwMHz48du3aFQsWLBAyZDxHZgAA/k9Lj9QcO3YsPvrRj0ZlZWVkZ2fHlClTYsWK
-FZFKpS7o/S0rK4svfOELcfTo0Thx4kRERHTp0iXeeOON6NGjRxw+fDgWL14cv/jFL+Jzn/tc3H//
-/TFkyBA7GjEDANBRo+anP/1pLFiwIOrr6yMiIicnJ0aOHBl/+MMfoqio6ILcx5deeik+//nPR3V1
-dTQ0NDR9Pjc3NyZNmhRXX321uRjEDACAqPn/qLnzzjtj0KBBp7wNLTc3NwYMGBDPPPNM9O3bt03v
-15YtW2LMmDFx/PjxZiHzXgUFBfH973/fXAxiBgBA1LwbNQcPHoz6+vrTRkROTk5ccsklsWHDhrjq
-qqva5L5s2rQpvvzlL0ddXV00Njae9jpZWVkxZMiQ2LZtm52HmAEAIKKysjL69OkT1dXVZ7xOdnZ2
-pFKpePzxx1v9TGcbNmyI8ePHR319/RlD5r1B87vf/S5uvfVWO452y9nMAABaaNWqVU1zMmfS0NAQ
-dXV1cfPNN8eyZcta7Xs/9dRTceONN571iMx7JUkS3/3ud+P48eN2HGIGAKAjO3bsWCxZsuScMXMy
-JBobG2POnDnx7W9/+4xzLS31xBNPxM033xwnTpyIlr6pJkmSePvtty/6qaNBzAAAXGTLli2Lo0eP
-vq/bNDY2xsqVK+Omm26Kd9555wN930ceeSRuu+229xVEeXl50alTp4iIeO2118JUAe2VmRkAgHOo
-qamJgoKCiHj3rGV1dXXv6/a5ubnxiU98IjZs2BC9e/du8e1Wr14dU6dObdF8TCqVirq6uhgwYEBM
-mDAhxo4dG6NGjYrOnTvbgYgZAICObN++fbF169bYunVrPPfcc1FWVhZ1dXWRl5fXooH8nJycKC4u
-jmeffTYGDRp0zu/34IMPxne+850zHlXJy8uLurq6yM3NjS9+8Ytx0003xdixY6N///52FmIGAIAz
-q6+vj5dffjmef/75+Nvf/habNm2K/fv3RyqViuzs7KitrT3lNllZWZGXlxe///3vY+zYsWfc9s9+
-9rOYN29es0By9AXEDABAm/nPf/4TL7zwQmzZsiU2bdoUr776atTX10fnzp2jtra22VGWX/3qV3HX
-XXedso377rsvFi5cGBHvnua5sbHR0RcQMwAAF1ZdXV288sorsXXr1ti8eXOUlpbGgQMHmr7+pS99
-KdavXx9ZWe+ek2natGnx61//OiIi+vfvH1/5ylccfQExAwBcKPv27Ys//vGPFuIMDh8+HP/617/i
-6aefjoaGhujbt2/ccccdsX79+vj3v/8dH/rQh2L06NHRrVs3i3UWI0eOjE996lMWQsyIGQCg9ZSW
-lsZ1110XvXr1ii5duliQczj5N2mysrKaTqfM2e3evTuWL18e06ZNsxgdXMoSAABt4fXXX4+ioiIL
-QasbPHiwRSAi/NFMAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBmAAAAxAwAAICY
-AQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAAQMwAAACIGQAA
-ADEDAACIGQAAADEDAAAgZgAAADEDAAAgZgAAAMQMAACAmAEAANqBlCUAADh/VVVVsXfv3vP7wSyV
-ik9+8pOxf//+OHjw4BmvV1xcHB/5yEdO+XySJPHaa6+d9jYDBgyILl262FGIGQAAmvvLX/4St9xy
-y3lto2fPnrF///7YvXt3rFy5Mh5++OFIkqTp6yUlJTFx4sQYNWrUGWPmz3/+c2zZsiWefPLJiIgo
-KiqK6dOnx4wZM8QMYgYAgFPV1NRERETv3r1jwYIF8dnPfjYuu+yySKVSUVpaGpMmTYqIiI997GPx
-3HPPRZIkcfz48XjrrbfiySefjGXLljVtY8SIETFixIi44oorYt68eU3f44c//GFMnDjxjPchKysr
-7rnnnrjnnnti4MCBsWPHjnj88cdjzJgxdhBiBgCA06uuro6cnJz461//GiUlJc2+1qNHj6aPc3Jy
-ok+fPk2XL7/88hg9enRceumlsXjx4ma3mz17djz00EOxc+fOiIgoLS09a8yclCRJVFRUxMiRI4UM
-7ZoTAAAAtIKampoYP378KSHTUjNmzIjGxsZoaGho+lwqlYqFCxc2XX7kkUfi2LFj59zWCy+8EAcO
-HIgZM2bYMYgZAADOHTPjxo37wLe/7LLLYtiwYXH8+PFmn7/llluiX79+ERFx5MiR+O1vf3vOba1e
-vTq6d+8eEyZMsGMQMwAAnN28efNiypQp57WNLVu2REFBQbPPpVKpmDVrVtPln//8582O3vyvo0eP
-xqOPPhpTpkyJvLw8OwYxAwDAOX6oysqKTp06ndc2srOzT7uNb37zm1FUVBQREW+88UbTmcpO59FH
-H41jx47Ft771LTsFMQMAwMVVWFgYU6dObbp8//33n/Z6SZLEihUrYtSoUR94dgfEDAAArWrmzJmR
-Sr17ItotW7bE888/f8p1XnrppXjllVeahQ+IGQAALqo+ffrEbbfd1nT5dEdnVqxYEcXFxfHVr37V
-giFmAABIH3PmzGn6+Iknnog9e/Y0Xa6qqorHHnssJk+eHJ07d7ZYiBkAANLH0KFD4/rrr4+IiMbG
-xnjggQeavmbwHzEDAEBamzt3btPHK1eujKqqqqbB/xEjRsSnP/1pi4SYAQAg/dxwww1NZyo7evRo
-rFq1KrZt2xZlZWUG/xEzAACk8Q9vWVnNZmeWLVsWDz74YFxyySVx6623WiDEDAAA6Wvy5MnRvXv3
-iIjYu3dvrFmzJu64447o0qWLxUHMAADQehobG1t1e/n5+TF9+vRmnzP4j5gBAKDVvfPOO00f19TU
-tMo2p0+fHnl5eRERMWzYsPjMZz5joREzAAC0rmeeeabp471798aOHTvOe5u9evWKyZMnR0QY/EfM
-AADQeg4dOhRTpkyJIUOGxIoVK5p97eqrr44bb7wxfvKTn5zX95gzZ04UFhbGxIkTLTgdUsoSAAC0
-vm7dusWaNWva9HtcccUVsWnTpigsLLTgdEiOzAAAZLChQ4daBMQMAACAmAEAABAzAAAAYgYAABAz
-AAAAYgYAAEDMAAAAYgYAAEDMAAAAiBkAAEDMAAAAiBkAAAAxAwAAIGYAAAAxAwAAIGYAAADEDAAA
-IGYAAADEDAAAgJgBAADEjCUAAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAAAGIGAAAQMwAAAGIGAABA
-zAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAACA9JCyBABAW+jVq1cUFBRYCFpdZWWlRSAiIjolSZJY
-BgCgtVRUVMTGjRstBG1q6NCh8fGPf9xCiBkxAwAAZB4zMwAAQEZKvb79xaYLJYOutiIAAEBGcGQG
-AADISP8FpxZnWS0U37cAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/fieldseq_bt.gif.b64 b/Documentation/DocBook/media/fieldseq_bt.gif.b64
deleted file mode 100644 (file)
index b5b557b..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-R0lGODlhcwKfAucAAAAAAElJDK+vr0gSElYMDC8kDV5bEBcHOwYGSEQODmEaGgoKOBkTVC0tVyAg
-aDcJC6Ojoys8DAAYGqSkxV9fFFtdEJmZmUA4EF0wMAAAcAoTHTZHJ0gYGAcMTwcSO29ISFUHB2AV
-FXd3YAcHMRUVQiIAGg4HT3t7eywOJ3d3dwcHSEEgABMuDnd3OGpkSQAAYlZGBzEEBGJlDCstCxwc
-WQcHSzkRGWBtYC0AACA3ABAKNhAQTTMwDA0VQD4AAEYVFVVVVSQMJQULOB8fQScnYBgYRD5VPmZm
-DEZRB2ZiDAoKSgAAVAwQOH5+lBwcS+7u7hoaST4+X3d3WACPADMzMyBRIDgAAGBgc0JCEHEAAEwN
-DRkwDAoKOR8kPZR7eyA1IABpABgNQBA9EABVAAsLRww/DAwMPgBNAENDCgc9B8zMzAUFQQBDAD4M
-DAwOKgAAcQA5AEtLFYqKAA0NTC8HBxEREQgfCAArAAApACIqMkkGBhoqKnwAAAsGQ6qqqkoKCg4O
-MlkcHAoZJCcrW6SkpFQAAAAAOBAOSwAVGh0ROgMPHWZmB00QEGUAAFQaGjEyC2w4OLe3n4qKioiI
-iBAVMC4uXhkZUGIAAHJYWHd3AAAAPhAQUQUGL0BAIGggIBgAGkIVFV9fEAwcJR8KJA8MU9EAAAcH
-VRoaYWhoaDcAALu7AGZmZnAAAGRkZGQVFVhqWD4KCgwOUzMzDAAAmgklBzEHBzExClhYWBMTPAYJ
-Qy8fCFpaB///////ACISRExUDUQrDAwMVhISSEYYGHd3IDhcOERERElJAAkPNTsHF1hYckgGBj05
-CFYAADg4OCAVO0hCDDAwMLu7ilpaDR8qCDg+EBxGHN3d3REGNjo9CDQ8DBwYRGZmHFMAABQ+FBE+
-ESIiIhs+BxU0FWVeBw04DYqKsxAsEB8hQAwuDAc2BwwqDAoqCgcIL1dMDQAA0Q0iDQwiDAckBxAQ
-EDwAAAAAU0JCDAkJPru7u5oAADg4bAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALwALAAAAABzAp8C
-AAj+AHkJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
-MGPKnEmzps2bOHPq3Mkz5z0AQIMCSNHyZ0WjE5GqNAZAqcGmT+8VZMoL6k6rEp0KfEJl489VBcEB
-GGjBwk8LBJsyFQqU15MUdQDUWfVk4JNVccER5ZXCT8+/gAN/xFp0LEWtDxEfRKo44s8n1/YeJCyQ
-8GO+1xhSbvwxRWaklBEiXoVW4886BNW0FQjkyem6laUKdLqKSuZrQIxtpbLqc51JbsHBFkw8pYUT
-w4uHDK2SM0PnCqHPNiz9uWGFoS1fb7h5u0nQshf+ar2G2isAKn4FpqByHQivn8YkY3WK9RoANXx1
-kwUncBVw5QCSdAsA8jiDXIAeEQYXAMbgp0YKKQAFYVxEPbjgXm/FBURmD1pQxz1qsDfUdAVlCMCG
-vFg4lhpMgbOKYX6IBY5fHX642FBx0cULbnKlUFdQkgS1IxA91mWMBWJRYQF7dZQ2HVBIsdhjbG4R
-WUeE4f3UFlQN6hUiUK1puV1Q93Sp24LglNYlAGmmKGJrvBxJ4YWxiUkmLzGymZ6ULnqXAlgC5Tmj
-QRE2qd+NkwDKCziTwAjcT6rhV1WW28013D11UfHfVrItieCnHw0YVIEHgnoRVutllgJ/X+F54hP+
-fjT1FWR68WXbXV3dU4cxmBoDnGpSaZUqru/NJRUVrV3DXrHBAnCNrrwmN9Cs17jIC2+QUUEUY4Zh
-qyxR52X2IlFwFWSUUU/8tmObXBrzxBNEhveeYVCd5wd5RD1Ra3eVzajGPeCoSq8x4qJ2ZXDghvlq
-rFJBBR6z82aGbLbe+TqbjT9lNtCq4npHUMblqQEOUr3Nmx+VJJIVl7aSToqQan/ZydbMNNds8804
-56zzzjzXbGpFWA0q0IdKWSWrswIhyUuTAtn3L9IE2ddsQUzveF/GKUJtwVirSAZECliLpnUdqmns
-ockml500agCkx625YxnlqUCT6NaU2lbL+zD+AKXNpTHK09Lr5MaCk+h3WrIZ3fDULnc90Nd4b12Q
-VY6zJtmiTnoc+LV+QYiUfuiyS6lB96wHAKDMAa5TZBC27vrrsMcu++y012777bjDHg3N4Dgj7c8P
-YTXzPUUnTvx1Rgl/PFlUgBMv2gMp/zaJawUFtuabT6fUudTFjfxYVk2/uVERCmX38tHrTe/iTa8C
-Th1A4MevyykCsStV9Bt1jfvwy288lQ5bX5zYcr3spU8g1ZMQ4gbCH7HxIlGLetp7/sOYOjxhPthz
-FX40VRDPqA54IISIqAhkoN+F0CFBkxf0FBe2s1XNaVG6D5W08sKrGcY+ZuPa5aB3I7OBI3L+qHkb
-EPPXPbiZzAKHSh8Om6YdAKowQ/TLnlUOhrbwbQeKinNiFaVSuYEskReSI4iNeNFFg1StKgnRH9lY
-NZYUSEopX8NgWpIDlVURJFawSd0J92iQW5DKhHzkTnhS9UALFq9Op6MVuW5VG7RF6oFt46GtrkEs
-pRgjWcvSVbCIhrwdUqtW3tLWvOqClFCCSzbiIxG61PUtlxnDXfBqosusAgQ42TGSHwPAj2TDSqbs
-kkS1rMst/zdLxjkMYza6JMWmshdNQqx0fAkYGanjyW6J0iiHUkq65DiQV2aGWMFB0T1EmbVAmjMh
-lDwnRRS0MvwcclI/WZCOTAQnpSwoPgD+mIRW6EnK6zyBKYZKmozQYk/vqIiKPEKoWNRAHtQkdC9W
-TNn4DPMlKkIllldyYy61mKK1UAE/AI3aQq2CJDbBhW2oXJFH/YeyekmlodeSYUnb5BaAIrEgk3CP
-QNlUmgi55UVNMoxPNwpJd95HMk5p1Ojsghe5lGwrTa1V0nSqzqpadSXVmckOr7rHdAEyNbDRVU+A
-MDiumvWsHclqTO6xKbSeMAVlPcgqWgMvReWkWm7Nq14tota9+vUjb2FILF/FE7P89bCITaxiF8vY
-xjr2sZCNrGQnS9nKWvaymM2sZjfL2c569rOgDa1oR1uSfxHvtKhNrWpXy9rWuva1sI3+7WkBaVrZ
-2va2uM0tbNOo29769re7FQ1wh0vc3/K2uMhNbnAN4hrlOve5p21ZQvIxi+pa97rYza52t8vd7nr3
-u+CtbgZUOBBP4OO86E2vetfL3va6973wja98z1uIhHBDFfjNr373y9/++ve/AA6wgAeMX24kxBpg
-SLCCF8zgBjv4wRCOsIQnTOEEWyMhSwivhjfM4Q6DlwaiYcV8R0ziEptYvp5gSD7cweIWu/jFMI6x
-jGdM4xrb+MYsngV5BeKJUvj4x0AOspCHTOQiG/nISE6yjy+REGL04slQjrKUp0zlKlv5yljOspaf
-TIyEVGEKYA6zmMdM5jKb+cxoTrP+mtcM5iok5AU4jrOc50znGztANPhQsp73zOc+JznFC1lxnQdN
-6ELTWMcI6bGfF83oRhuZyQhx8pYnTelKWzrLXUbIl9nM6U57+tNqdjNC4GzoUpt60HdeTJ4dzepW
-LxrQChH0qWdN60PvmBeKdrWud/3oJl/618AONpYzfZBNg/rYyE72mUV9EFLX+tnQdkeqSbdqXlv7
-2qWAdULOYYZue/vb4A63uMdN7nKb+9zo7jYXIIAQDhDg3fCOt7znTe962/ve+M63vt9di4TI4ggA
-D7jAB07wghv84AhPuMIXDnBZJOQd6Ii4xCdO8Ypb/OIYz7jGN87xiL8jIexIt8j+R07ykqPbDQiB
-wB/2zfKWu/zl+uaAiqNNc1oj+iC5xrbOWw3pg0ha2EAP+qWJbRBjK/voSP80sw3i7Jo7ndDTNle1
-d051RmsbIbJ+utbnfHOD5LzqYN9zzw3yc6Gb/exWJnpBjJ70trvdzEsvSNO3TncbR/1jUw+73pF8
-9YNkve6Al3HXC/L1vRt+yGMvSNnRznjGq50gbH+75N8ed4LMPfCYb/Hdp5X3w3v+x303yN8zn/nB
-E6Twn/d84gmy+Ma7PuiPH0jkJ0/7o1d+IJcnfeA3P5vOp/7woS/IEOZA/OIb//jIT77yl8/85jv/
-+cUnBEJ+oIXqW//62M++9rf+z/3ue//74K8+LBKChWmY//zoT7/618/+9rv//fCPv/mxkBBzkOP+
-+M+//vfP//77//8AGIACeH/mkBD2AH0ImIAKuIDPxwQIQQjhF4ESOIEUGH4/MHO6p3umV16/14Gr
-NxCt93oi+GuxJxCzV3soCGq3JxC5l4F0x3vv4XsdqHfBRxCj54J0t4E8NoOp94ECEYIjGISTVoK8
-cIIpeIRstoK80II4+HQweA8yyINVV4MDcYNN+HQ6iGtSqHq+JoReWGlEaIRIOIbL9mZXuHt4toXA
-h4FnmIO3hnpquHM+yAtA+IV2OGVhSIZ6mIRm2IYvmIZxSIMMAQUvUIiGeIj+iJiIiriIjNiIjviI
-kFiIS8BuB5EA83CJmJiJmriJnNiJnviJoBiKoniJOJAQ2ZAJqJiKqriKrNiKrviKsBiLsjiLqJgN
-CREPbJCLuriLvNiLvviLwBiMwjiMxJiL8ZAQhhCJyriMzNiMkDgCKZcKoziN1FiN1iiKCcCGfoiF
-bxiIejeHdXiH4tgLebiH5liGo7aNW/eEUeiNvEaFAmGF6lhrWQiH7shr4DiO+oiHXnaO/khmSsiE
-8zhr7HiPU6iNAwlt9WiQVJeP+/iQ5NiP/ziRUxCQCVlzBcmQOgePvEAEHvaRIBmS3pUBAoAQrsAH
-KJmSKrmSLNmSLvmSMBn+kzI5kyjZDAkRCgSWkzq5kzw5YKGQEGJQYUI5lERZlBQmBhgmkkq5lCC5
-CQghAI1Ak1I5lVRZlTPpCgzRAG+wlVzZlV75lWAZlmI5lmRZlma5lfRQkgehACfWlm75lvBVXwgR
-B3JQl3Z5l3iZl3q5l3zZl375l4BZl3GQEOJwBoZ5mIiZmIq5mIzZmI75mJAZmYYpDgmhCWd5mZiZ
-mZppliTwlCIGl6AZmm2pAAh5kTbXjRqJbQ4JkfpYjhTpjxZpmtCWkalpbRwpj7JZaAtZm9a2mqwp
-jq75muYYm7lJa7TJm7p2m8VJj6iJnLrmm79ph8EpnHpInMtpasfpnKz+xpFOUAPe+Z3gGZ7iOZ7k
-WZ7meZ7omZ7eqQKUaBADAALwGZ/yOZ/0WZ/2eZ/4mZ/6uZ/wGQMJgQa7EKACOqAEWqAGeqAImqAK
-uqAMGqBokBDrkA4SOqEUWqEWeqEYmqEauqEc2qESug4JsQbqOaIkWqImmp4LkHJ6wJ8s2qIu+qL7
-OQCleZ2EtpvayXNdGJ13OJ3UOYbWSaOFlp03anUzCqR0ZqND2mjQqaNCyKM9eoQ/aqR1JqRJ2mfK
-KaW62ZxVumhLyqQj6KRPioJRiqVyRqVbqmdXSqZ1hqRnymdd6qWvB6ZhSntjqqZ2BohtaqUM0Z0n
-2qd++qfmyZ4I8Z7+MFqohnqo+OmfCAGgDdqojvqokLqgD4oQEeqhlnqpmJqpHAqiCCGigPqpoNqn
-KXoQELCiiHqqqFqoMhpodrqmWpqnevamcNp4cjqnklenrUpjZgqrRpamuYpjbMqrSCars4p2tWqr
-boervxpjuyqsQ+ary1pjweqsRUasxWp2x4qsSaes0epizUqtQMaRWrmZ5Fqu5jqWaYkQbCma7Nqu
-cZkQdBmY8jqv9FqvfzmYCFGYkrmv/Nqv/gqZlIkQlnmuBFuw5NqZByEAn+muDNuw+ECaC+GRTDmx
-FDuSamkQJ2mVGruxHAuTNokQONmTIjuyJAtgP4kQQWmUKruyLBv+YUiJEBlWsTI7s9XllAkblR2b
-szqrsVjJqt1qY9MKrkJmrdcKexKprWLahz+rq3gqtEUGrUsLY0HrtD9GtEUrbNmKtMrGrUv7rU4L
-tVHrYlNLtaVgtVcLbFmrtcjGtT/rtULLkVHgAHI7t3Rbt3Z7t3ibt3q7t3zbt3JLA7eGAZ4wuIRb
-uIZ7uIibuIq7uIzbuI47uKCQEJ1ADJRbuZZ7uZibuZq7uZzbuZ77uZTbCQnxBVVQuqZ7uqibuqq7
-uqzbuq77urBbul+QELjgt7Z7u7ibu317DqIRCI/7u8AbvMLruBhAWsZ7vMibvMq7vMzbvM77vNAb
-vdI7vdRbvdb+e73Ym73au73c273e+73gG77iO77kW77me77om77qy1VnBEblsRXNlEGawRa6ARr0
-K0nzEhRCcxDlwxZScRdxYSnRIxRwsr4GfMAPkQJUxQtAYFdDhRhqQCSEhRCh8TBGdMHumx5ptB3k
-gSK4UQcaYxXKssAIXMImPBCqARsXpMF+EBcSxUB0wRVJNDnkZcFEdcPRJB7bcUkFUUuAEysnHMRB
-TFMt7EVpUkRTEVYZVMEChMEGZDV/cyN2IUOpoUtRBMRCnMUHrMD9IRm+kkqE0kCTUcNNjMMvHEVS
-fMYcNcJa3Mbqm8JLIylcDMZ2ARe3VhVskTIzsy0eoxV6BD3+ilEv5vNVblzI3qskMXIx/aTGhUQw
-2EHGH4S/TvFFDrQVVIzCVvzHhrzJ3ptTldO/ZIIYq3LHB3TBTEw622FH0bHDJOzDaMzJsAy+9vFD
-qHzGFyRdCXHKryzJ1+EhGlzJTQM/t2E/IUzKsXzM19s8aSwzvDIzuQzJeJzHzJy/QLG/G1wiTXU4
-kYzM3NzN3vzN4BzO4jzOZpUCr3TOr4TLH4FE6PxKcUXO8BzP8jzP9FzP9nzP+JzP+rzP/NzP/vzP
-AP1YuTPQBF3QBn3QUexXrHPQDN3QDk3QCb1XpfPQFF3RFg0hjtUzGr3RHN3RPGPMZiUzHj3SJF3S
-NwPSXAX+yia90ixN0hm9VXr1Eyh9VTKdWDWNWEOF0/K7VyOCWDd9WD/9V0HtVzl9WEWtWD0N1Joc
-0kvNVUO9V0dN1DutV0ntBZhw1Vid1Vq91Vzd1V791WAd1mKN1YEz01b10zfwCmq91mzd1m791nAd
-13I913Rd12p9A2WdWDl9DWPd137914A91l5AOC/NgWRLZD331DGNFWKotlub1zrNeYdNZLAW1YiV
-1PZItond1DTN2I5Np5Bt1MjTjlRb2VOdV5g92YgX2kLt2Z99q6wt1ZKt2kFm2oW9g7QNZJtt1lX1
-04392ioY21A92rkdroTdWEnNCKm63Mytn8sg3IsdHur+oKnUXd3WvaHqAN15ldOE0Nze/d3yyQjH
-zVipXdxLpt1u5dvATXnojVY5DYXm7WO2jdySkdlUu9s27drrva3tfVbvTdpfO96LVd7mjd8+rd/7
-bXv9Xc7EHd/zTd71Hd9lu+BOjeAJnmzMptjb3eDm/eADLhmECt4inqqKOi+8rU4/XanXveIsrqmc
-auJ6fR2lOuI0fqqryhen7VYEXtwGrtTh8dsXvmYZztlW9d8S7uFIHeHx3eOt/eNBruDaE+Oz3eEC
-nuSGXeAU3tlO/uQYnuVFzuHFjeSJldTr6rBmLppyCeMHHh76+q9u/uZw3pgBq+aiPRAKe+Z4DpoQ
-i+P+t80LjpAFgB7ogj7ohF7ohn7oiJ7oir7ogO4DXt7bWOENLTvplL6y3vDo6pTTAtANjN7pnv7p
-oL7ojlDlY67kWB7lay57XN7lqF7nvXfkpH7Zps7jmH5O6r3qxzbkJ35ORu7gsX5YO57bTO5Xt47r
-Slfr5tTrVK4eOY5WST0MbRDt0j7t1F7t1n7t2J7t2r7t3B7tdIDsgfTT8FAG5F7u5n7u6J7u6r7u
-7N7u7v7u5A4P4M5HOQ0BD9Dt+J7v+r7v3D4Mv/5XwU7bwy7RFm7sfNjqf6XsYf7vfhXwqj3w0a3q
-Bu9pui7lr+7rzN7n9u20EJ9XxT7xB0/nCQ/muS3+5rJ+5bSO8MRe8CCPZhUf2Re/7HxO3wNBfRV4
-8zif8903fipP8OFhfwMY9EI/9EQfgAXY83rF3Tq/9Eyf8xeY8TSP26cu8iu/5S0v5PO+Rwpf8gzP
-07Mu7Fl/Qh9/9S4f9iG09bRt8sD+9QJv9iA09mQPd24PPGiv2moP8Gz/8HP/M3Af9wC596ZS95N9
-9w0vGe4Gc4if+Ip/b/2G9B6PFRDXcZI/+ZRf+Rv3cY7vVvW+covf+Z6P+DIH9RCO8mCf+WjV934v
-Zi/v6jEI66L/4aTf9qZ/Vqif+m0G+KAi+IdN+F4f+3o/+0xt9bb/98Cf0iSf9l1P1ZIRAnne/G3+
-meYant5Y8Q1jUP3Wf/3Yn/3av/3c3/3e//3gX/3fgPufoukL6/zoL18hkPyoLRl/HurwH//yj+iO
-XvxaPhCSXun6v/8Sdun2/+UAwUuggG5ZDB5EmFDhQoYNHT6EGNGgI4G8UgComFHjRo4dPX4EGVLk
-yIwAUlT0VErlSpYtXb6EGVPmTJo1VV6qeA/APZI9ff4E2lMnT4FVphxFmlTpUqZNnT6FGlXq0So5
-dwbFmlUryYs58dkEG1bs2JqeKnbdmlbt2oomUZKFG1fuTJwCh7LFm3fk3aJT/f4FHFhqVbtX9R5G
-nBEtr3tf5z6GDNeswMWJLSd2KzBlZM6d6Vr+JXpZtFq+vIwKRp1a9VPCjA2Php11cWPPtW2vnGwR
-Y2zeWzPzwuBJ+HDixY0fR55c+XLmzYWDAt1butDXX6pcx55d+3bu3b1/Bx9e/PUv0aefBzk7kHP2
-7d2/b47h7G709UH+tp/fdWj99kv3r+8/AM+rbEAC6TMwP/wS7E1ABmNz8MHRIpTwsgIrHO1CDGNb
-cEPLKPRQLxBDxGtEEtfS8MS8UlTxMABWuSdGGWeksUYbb8QxRx135DHHSV5rUUQAJumxSCOPRDLJ
-GH/kL0i8LlIySimnNHIVBJ1EDAAtt+SySy+/BDNMMccks0wzm8SSNDPXZLNNN9/0Es00t7r+CE47
-78TTzTkTo7JPP/+U8Yk92XoCUEMPRVLQQdW6BlFHH8VxUUknpbRSSy/FNFNNN+W0U08/BTVUUUcl
-tVRTT0U1VVVXZbVVV1+FNVZZZ6W1VltvxTVXXXfltdfD6rAgIwvqyOiJk1zDyktjkOVFWWYz0mlL
-cPz4qEsqQrtmlToAACcFQaPt8pYvj7WACi2pCFYgbjWyUk5f34V31xSAyAiIVRTbTaeN1ABCSyAU
-5QjIwtRFU1+NDOZlWGo7MuwJbQW9po5VruFFDSqo0EjgZvlbhYqF/aDi3mYBUCOjbd2NN2WVY1UD
-AEWfAGBhXvzYdmCNwFnliSeoWJbhgnf+0xhhqxQDx6PXYObJGHoreqLbktB8zQJwAOblCWCbpeLY
-mc1FeWWvv0YVnHRprugasfO9khdjFBU6458J3qjtZ3m5BgCKAw7Nap1J1mgSjNuCOjQqJtkoBYyH
-LFqgVZgEu3HHUZ1Xca2NIRLtj1JIHO+4gX774Cs1hrvqVaiVW2iNXwsao53AKZmXOuru+nHZZ6+0
-ZUHraD1yg+UWyNg6UPbSZi9PKv1zd50t/umNUH97pxROAnlj2qen/lJ0/Uj8njq+tXyjSeow5m6f
-Nw8d2rSFrlt8tyv6UQ2YW2f/7/IBr2hw7w+/R42iF5e+ev//T9Mk7HWsOnEpRmnDXOz++me++dmM
-gWfJ3PL4cxWlFctp9FufQIZFNasF6yqse90CAThCEmKobqwj39yqxreQpK6BKnyWwowWmu8JJGIT
-q9jFMqi8inTsYyGDm+H+BroSFtGI9qFCBIfmGi4ZA1xbmmEKv8TELS3ridOqFpeoAL9sbatbVBNh
-A8t1LsLBrWVlJOIR1bhGNrbRjW+EYxzlOMdQpcAYd8SjMeCHGAvkEY/pomMgBTlIQhbSkIdEZCIV
-uUhGNtKRj4RkJCU5SUpW0pKXxGR98rRJTnZyS1pD1RM9OUpSnmlVoixlKlXJJVgBwBjPg2UsZTlL
-WtbSlrfEZS51mcsOlUonq9hlMIX+OUxiFvN57Trli4y5TGY2M5jGSJuqelmqaY7KRKC65qey6SkW
-naqao/pmqLbZqXFyqpyb6qapwhmqdWozjaI6p6bimal0UlNryshHPvW5T37205//BGhABTpQguoT
-fu30VGlc0AKGNtShD4VoRCU6UYpW1KIXZagLzJOq0lSioB8FaUhFStAozKeVWsuHO1S6Upa21KUv
-hWlMZTpTmtZUpbMIDULJ+Rpi9MKnPwVqUIU6VKIW1ahHRWpSfUqMjYbyNS+waVSlOlWq1tQBJn3V
-b1JaVa521asyxWlbQHmq0vRUqWdFa1rVilSmFkaB7gwNVL86V7py9aqUiWaqtFr+V772laZhVddY
-TVXWtRbWsIc9alv3k8y4+tWxj13pXXVz0opsFbKXrStgmyVYX/IUsZ8FrWEVO09MlUaumEWtVyVb
-T1L9BgovgG1sZTtb2tbWtrfFbW51u1vYLgECYmVsRWxxDOIW17jHRW5ylbtc5jbXuc8lri2aStbX
-GIK318VudrW72xFg1VV7TW14q6pZnZrTs6FFb3oTO93BPlW875XqavOKKvDC175gzSlnSUVY9fbX
-v0tlb2cbe18Cv1S+lBWIZQu8YHeQV7/WPO9/JRza0b5TnO5lMIMPnFWtEWEWHwZxiEU8YhKX2MQn
-RnGKVfzhDAgAuKoqTShUMWP+GtfYxjfGcY51vGMe99jHMw5FgPf7miWs2MhHRnKSVbwJ77bqNw14
-Q5SlPGUqV9nKV8ZylrW8ZS5HmR4uDmxwBRIHOZTZzGdGc5rVvGY2t9nNb4ZzmeMgZAiHRhNdxnOe
-9bxnLpOgyayqb4YJ7GAx88KsE0b0YSv81oRiWNAE3vB3UfroAhMaxhFOdKbTuuhCn5bS8I20kyf9
-aftamqOY1nSq2UpneDqa1OINNaC15oQa1NrWt8Z1rnW9a1732te/BnatVfDbMF86NGjYRbKVvWxm
-N9vZz4Z2tKU9bWonGw2svnBo1hBsbnfb298G9gL+vKpAvzq1pnZqaA6tanb+F5XTxq6Ip82N2liT
-e9TzPnd+C73udvcbqO8+9YDxTe9xS/PeA78suqmrbn83/N/YxqarEf7Yehu8shPHrMLby3CHOxzg
-6Y43xi9bcb3OGtwnR3nKfT3sFwe8IsiudsxlPnOaT/vabi30tlW+c56fXNx4RTAvFCzyvmpcwBXh
-d8fZ/fGFh5zojiU5fQ/+9MzqG94CSbrSU830jTud6nyNujen/vWvGn3IHNd6u7l+dIHIm+yqLXjJ
-KwJlPtfd7nfP8pdbDvIxx9nvfwd84OE8Z5xfnRd3xnviFV93PwOdwxXxsJIlP3nKn7jFe2+6QGT8
-Y8533vOf73GQC+9ygRT+ufKnR73kmex4SV/87XQ1e52RnvZ+r/3sXn893Fkvatfn3quxbzXaab91
-iMMV976vatjVOXbkSxX42Z798FVte9m3vfldVb49KzKEYHTf+98Hf/jFP37yl9/850d/95VA7M0W
-WhZHgH/85T9/+tff/vfHf/71v3/4y6L4jQ6NEUi/ASTAAjRA9HODuJO63ru+qXq+iBM+6Us06gu+
-42tAm8q+1mK+C5ypBzQ+rJNA4hs9vuMFt+PAmcpAcNrAE4QpDwTA6AvBCfy/nRI4FqSpFBSVcrPB
-mHJBGoTBGJwwCoQ+69vBG1RAsdu+OVDCJWTCJnTCJ4TCKJTCKaTCKlz+QkLAvK4TCCyYhi70wi8E
-wzAUwzEkwzI0wzNEwy7Eghk0r9CwByuEwziUwzmsQiY4wuVjwCJsQasjPUMDQhkcwcwrQT1EwTvU
-vgQjRPzKQrbzwz8MQjbcFNNKxJjCQXZawUTswTb8QUfsLyGEQAucRJWqRFDRwVBsMD4kwazjRAqD
-RHmSOFN0h1H8lN9oAmWwxVvExVzUxV3kxV70xV8ExmC8RfEpr0h8DRGQgmRUxmVkxmZ0xmeExmiU
-xmmkxmQUgVbMlNIQxm3kxm70RmG8AkPUQFkrNBI0x1NhLRUkR8M7Ry1MlXTMwQdTR3YUxHYsFXhk
-J3Dwo33kx370x3/+BMiAFMiB5MdidEWeIciEVMiFZEiC5JpkQsiGlMiJpEiBBIf5OpWK1MiN5Mg/
-WhU16MiQFMmF3KNTAcmRRMmU7MdMYsmWdMmXhMmYlMmZpMmatMmbxMmc1Mmd5Mme9MmfBMqgFMqh
-JMrzuJqKGJZiORbeGQnkAZousaLz4RIsAomWWZr5QSWTQCXisZaFcaUHEoh+OShncZaiNEv0iJyK
-sBd8caCK4Bd/ASMeeiAX8hykrAOZ6Yg6ARgieg3eEZoU2J6RKaNngZkOARILO8vEFA3b6Z2YqQia
-6Z6MwBmd4ZkoqsswgqG/VKKNAJajxMzy8UvjaRZjCMxnmQRwOE3+CZJLxWTN3hAbgSAbGzqbthSI
-taHN1RSezgFLurEbj/ADl1mFq+TL0AjNjKGYnaCCpUGYrKmbkjxMRmvN6ESRpQGmiqCc3cFIzLHM
-udTNJcIgjgjOmXGZFwLNaPpLNMofxzSY5uSFrNmhz5TO+MwLxsQdyqAX7OwI3wGeLhGeLuHKFPpO
-zlyYOkDP8SmMLuEJUTrKqwDMQtkNvxGIGlrN4ZHPCsWL68mewMRP7wEf9VHNy6TL3UyfjvhNLSLP
-BSrOHkocwwgZgzEXLsHL57TQGc0LAapO3UBQuUmgFuqcEPVOi9jMHhIZ8TzO4yFO80QQgzGMlumK
-ERUIIApQxKT+0SkdiRMqSWZpm/cRCbr0UQeSIY6wGrwkUPjsSyTlzvnACMPJCAmdHyml0jf9iCTi
-COxsIlTaziWaIlGKSmnBS41IyozomJFhpe9EpajMiLqhFiAxF15AzUN1zDYNHjiV1Eml1Eq11Ev1
-HzvaxyvNiz7aR0DC1FAV1VEl1VI11VNF1VRV1VVl1VZ1VQNxpliV1Vl9Hme4BVrF1VzdJVRwBlTQ
-1V8FVlniVV8N1mLV1WE11mSl1VtwBmV11llVl1WS1mml1mq11mvF1mzV1m3l1m711m8Nk2KTJmdY
-FUkAAEko13NNV3RVFWfASFFBC4PUFAAgV1UxV3ZNlXtd11X+cVdWiVd5zMF6zVd1tVeCHVh8RZV+
-XZV/dUtIcdg+2UuBVYOHpdgoqQh9tYuK1dgjuViD3diP7ZGOxVeQJdkcqQiFrZqSVVkagR+GTbDU
-g9mYTbEMyCmB9QR8wNmc1dmd5dme9dmfBdqgFdqhxdlCENmK4AbQU9qlZVoe44ajFQhrAIOppdqq
-tdqrxdqs1dqt5dqu9dqptQao5QXTk9myNdtZoIGTpY97YAWiddu3hdu4HdrccFmhg8WWIi+bvY29
-7Yy64AWMbcRV7ESxPY3VMNzDFYzWAFwTDEXJQlna4NvInQu6BZpLJMS8fQvJ1Vyy8FvAVUXBRSzF
-AtzCRdz+0jVdp1Bcg2XcSXTctXWMzYVdm6BccR06WMRczYjd3KWJzjXYzwVd0SLc0xXe4UWK1MXX
-1U3E1vUK3WVemJjd9hOIczCD6aXe6rXe68Xe7NXe7eXe7vXe6eUC9qPXiuAAAjDf80Xf9FXf9WXf
-9nXf94Xf+DXfWhDb9+O/+8Xf/NVf/fM/gQDcd0CHABbgASbgAjbgA0bgBFbgBWbgAH4HsWWH75Xg
-CabgCvbeBBQIlIWAP5DfDvbgDwbh+OUArCrFULxdXtiM5lXhmxBb3/3dtRJdgyVd4qVhwzVeUGxc
-tV3eFV7h5y3hSTzhFOZh5uVdfHXhF9604K3hJV6NGyb+wrsVRR22i9cdYt31YcvVwyCu4uYt4k1E
-YkVTYiYW48Bw4kGE4ijOYNfdYua94jy03ZrN3DWO3S4GwS8GrRjG1xke4z2GijJGXkJU3imW49xt
-Y4EYAjpE5ERWZCrEQnUR2B/QgkiW5Emm5Eq25EvG5EzW5E3m5EiGBbHlwjQU5VEm5VI+wzX0X4M1
-B3Jg5VZ25VeG5ViW5Vmm5Vq25VtmZXMQ2zdc5F72ZUS2wzSuCELo5GI25mNG5k7+ARLG4iLU4kGG
-XToOXDsG41TOYz7G5qjw4zNGY154XCqG5sgtZLvl5mcOZ8mV5iOm5lWz5orQ42yGZ6oQ2z/Ww0Bm
-DHD+PufbGOfaNUVzzue9Ted1Dt0wjueCnoJt5mZ7htx/3tt95uZTbAu9ZWiAbmGBrua/lWGD1miE
-PmOFxueJ5oxx5r4DJOmSNunyW7+IrohhaIOWdumXhumYlumZpumatumbxumWpoP63d+e9umfzr/+
-xWh8hYcyMOqjRuqkVuqlZuqmduqnhuqoNmp4EFsBPOmrxmqSxmBvpg8IeICcBuuwFuuxxulhYGY3
-7mc4xl2Qto2AtujCwmN31miD5mgo9mi2tg2HLme1RmG8rg23fmu1iuu+mOt4ruu7vWu/7gy9PmN/
-VuzHAOzARqvBNo3CNux5fujEfmzIGOfIO9vPTr3+y3PkinAFPjDt00bt1Fbt1Wbt1nbt14bt2Dbt
-ZhDbzWva28Zt0BO9oa4IMfja3wbu4BZurxUDsSVb0EbuyVs9rq4IAWgE2Ybu6Jbu6Y5tVzhrgaC7
-xdPu7c47MGsWgVUAuRXv8SbvoDXadu47wVPv9WbvNiM83hYIcTiD+abv+rbv+8bv/Nbv/ebv/vbv
-+RYHsUU87ibwAn+DxmPugWjb8mbwBhdvBbhucm5svhbizZaLyJZspaLsd7ZsJj5sWNRsC5cLxoZi
-xxZxzq3oDJ9sgu7wMf5wUwzxEycLEr9bE5fxsMBwFV8v9K7sFufjF89hYRbkG5eMCKe1nkPyJF/+
-OfEV2AEAgSeH8iiX8imn8iq38ivH8izX8iePAbGFuZoD8zAXc2i7OfjmhXVIhzRX8zVn8zZ38zeH
-8ziX8zmn8zRfB7HVOSXX8z2vgZ9LcF6AAD3Y8kEn9EI3dC0fgAjnZxOmcCKHixzXcXdjcR9fYiBn
-XSm+Z0efcUV/aBvX9M/gcXWO9F7YcErfY0tPXkxf6E+XXU7fa5Vea1a3CUgfdaEqdVMXY1QHZFX/
-aFl3XlefcFjva1+vCVqv9YfjcQ7H9dPV9XrmdWIviwgvAj6ndiVv5O+uCEY49G3n9m7H8mUQ23oY
-83En9zCvB7FVhzpX93Vn93anc3XA82qX953+83OUJQRvx/d873ZGAPYSb3RoB3UzF/VIv/Vlr+Fm
-L8IYB3iXoPE3FvYKX/iWMPZjB7BkN/hKx+yEfvaI/3XH+2FM/HeOd4mJp/iCv/jhRfgdVHiRL4Vx
-zm4Dh3nF07vRFojwdvCbx3nzFlsya++e93n1fm/Ale//JvqiN/qj7+8A5/EBj/mmtzsER1kBWPCc
-p/qqxwcI9/gOS+6tlzzRxnaBKG3qFvuxJ3vXpm0et+3cVvu117HdBlzfHu64l/u539ri5vHj5vq8
-T7HljvrnLvu/B3yxt+6sR2tGf3iWH/kUp3iiMvmTZ/aM7+iNR3zc6PcaD/nJLwWSP/bGd/z+0k15
-G1x5kW/4tD58zGfhUF98Sbf4zhfez2fB0Of4ca6E7aL92rf93FoCvg6ES+D93vf93wf+4Bf+4Sf+
-4jf+4+d9KwDlTGD+5nf+54f+6Jf+6af+6rf+62d+VDZzFmCD7vf+7wf/8Bf/8Sf/8jf/80f/7mcB
-sbWu23f/96d9XFD1QkD++rf/+8f/4w+ECNcrgUUVwAUIXgIHEixo8CDChAoXMmx4UBIASQ4nUqxo
-8aJAiBIxcuzo0aEzAB9HkiyZQiQvAClKsmxpEYAzlzJnItRI8+ZNmzh3ttTJ8+fHkECHejwpUCXR
-pBdhKm3q0KfTqA8jSq1qEKrVqkKzcjX+mnLVvbBix5Ita/Ys2rRq17JVCyBa27hy59KtG7YVgFZ2
-9/LtGxevXr+CBwsGTPgw4rnRACRu7BjtKpQAJlOubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
-7fo17NiyZ78W+Pg27rCSIOTufViAJAG+h/sFLpw48rrGkzOXC0FS8+hxuVKvbv069uzat3Pv7v07
-+PDix5Mvb/48+vTq17Nv7/49/Pjy59Ovb/8+/vz69/Pv7/8/gAEKOCCBBRp4IIIJKrgggw06+CCE
-EUo4IYUVWnghhhlq2N0TFvBizEIgJmSMMSlQoUaIaohI0IofbvgijDGilwKIIF5DhTH+JxbUokE1
-NsTjQC0CKSORRRqp1CQe+rHSkj5a4Acv1/BYIonXuPjhNeCkoOU1JuqYQgoe8rJll7xYQAUVHoLo
-B47gCDTkkXHKOadH1wDByyrXPOFji0vueA8v96xyJZ+8qHHnjR+iGKSLVDzBCzh78uLoE3XQeSmm
-mVrkIxBW+mgoECvtyKiIhVpQolFTYqnllvd8Cqemscp66SSrqEliHacGusqjPQIq6KSGFqrGSh1e
-SeqVkzT6RKWzOvssndcA0OubLq6CY4kFgUnio9eC6aKIXkJZarUgnknFSmvieOex0Lr7Lrzxyjsv
-vQx1CSaYVta7L7/9+vsvwAELPDD+wQUbfDDCCSu8MMMNO/wwxBFLPHF1VOhrgbK8GNuuQiSSqOaH
-HqfLIonoHlRHyYt6uZKKxqBM5ctK4kjFuIMKtAqsCIUpkJ0DiZkzySSOzMvLxqhYUNHUBukyiSiu
-/GbJYlL0hJs3L2os0AQVjWKNIrfrsckGvazjmGiudCrT28ZcdtjG2Ixn1tqK2bNAPzvkcbZde/x1
-yaIS1PLLvLCZI5Qh57jo1FXjuWjhcQu0tYhFgzxQ0ifnKOrgNJuJK5VMG822qG4PhHNFFtedsZnV
-/ugxyHh/CvXlBqGNMpMzFz424hdNknGnAtGoepQz5w58uaMyerPUx0u6s5l+Czn+0D1APPoEEK4q
-Do7jAx0qUJK2odSil8kTTyiLxgN70IrMWzB0sBYBsSgVA/3e4o2H9ziqqsfjKf6Vy4u5vv6Opb50
-XS97AtkeL7o3JnINBAho4p+q8gc8WyFERNGbXvWuRLeKvE8g8TPU9whyD+Hd73gSvNL5jBe/C2os
-g8RL3/8IOBDsVWR3AundAoFXP7KVr3wnXBEF0Wcb6bUQUCLa4EUSRTWBNAl4T4oSkCJoPB2yq4dP
-YN+xnnczfUUJZ6uAkh9IV5FITcpK1GPgzTxYQhP2UH9wWtHzVvTBigAwjEycH0GeKKU1Fq+Nx0Ki
-6q74tQDC0YdfFJwYKUJG0xH+C43EEojiAgiuKf6xisbL00CuMagjWnIidbSZGMGHIkAOkmNa5Jjq
-QIRJnr3tlHE8ZBgNGDyNVa2RToTSHik5ST+uiJSqW2UXNdhJi1jMT5JC40D8tKO9gYt1pRwf0XBl
-xDa6cplqGBRYZDkmCzzhgyk4GioltcymXaloppSkG30YtYssMQVQOiYqBec3ygmtXM48JSpfVodp
-prOf5bomnlxlkTB184biBBIp8cY1w+WNlxUcn97AMTyHtBNKk/ADMpM5z8fVM3IeW6g/tZYjcOQy
-pIUkFUCzScxrKFN6GZVnj5ipt4YS8qHnxJ1HdrcKFPUOmYfaKETPqb+ECqT+oNXUHzA1CaL4xU+b
-h8JYoIbWoiumQGlBfSbw3lhTbRrkfR/sKcd+KkQfUrKXwxSRUampVmQxNZ4LeaqyUsDPqa6CV3zc
-ZU15NsxfclGTbqWIV1tIPhGuAqil/CE6r3SopLZyrcVrqzZ16rS5/i1UY0WWQ/VqU8b+1SJ2+qDH
-cnUsQVlVkq974eggyKgB5jVQRKSeQFNQ2M4mhAq9m91pO3jZVPoRhW+bImu5WhAL1BV2uWoRaW2K
-2dYGUa2sRa3vYugi2WJxIra1Eo1cxr49cVGXp31mc8332gwKN4/FBZzRWgRA5Q42rym0YvXGCyjo
-brNuI6MubQ/yWd/hin3+yd0tXukb3h6yELb5BexGPUqia9XTuwxNF+vAZljJ+c5smWWi7VwkLU/p
-bo6qK5oAzOngaDYNbyup3G6fdmCG1KFwpBIZg7PlYBOTOL19s9zHKhw2+oKuWhtecUEm4eFyeuwE
-2CPRXWc60+zGTrmZa9xIWtxDEx9Zxpml8NZQjLSPCi7Dre2xhgHAYfclmKMLxhZQI4g3hqKtyZd9
-MjQpJuc5y+he+OouR/AFpvmqZ3344t9F/AwmQGfFzvn6iKFTgOfz6FmuIxE0865zj0aPJNGLNk+j
-+dyRTNO5057+NKhDLepRk7rUpj41qlOt6lWzutWufjWsY91q0frMUgP+EWSgULIUy4DoHpLhda4N
-4mvKgMPFB/F1rpPHmGFbZiWX6bVlNJcSTWvN1rdeRR0AUIeqHuUy3aYMDvkIhN9KK3d+YwxGmE2Z
-YKfE29MuiLqLrRBkpwS5IsEMiDDz7cnIm91dBcDwXDUZ3ap7Mr+qTL8REm1AneQy1JZ1VFJgyXET
-xCv0ruzASzsQdMNbMg+/OPR0bQEpIwTZvq4DtTh+FE2rPOQVR/m7DeKHybi4m71Tg21XfhCOPwHb
-pX1kMq2dwEh6JebXzjYPha1rlxudIC3398iN3fFuow7kLX+6zn0Hc5DfejLzVAMAlHXFrS+d6WYi
-+c7n23OYew/i1gH+e6+eAAAX+yHbbS8IOHjVTVhhnd59L7u/xxTJqfvayldn+cfLjm6s82LcFPdd
-JMFuJca33MoDmQS10b7je9g966Mznc9LDni/P7zpgd9SQvzusl5ZHfFpd/rBDzIJcMyeRfNMU+DN
-LviEqFzufOa6260CDjHVPZPDRwnwjcF6wG888Z7X/d15JmbR5xrsizo87JVekOljXe5+GPlAqIA6
-2zyK8pq2wOBRWVyNAbyotNf10x39fBGO3uOvpz9Bfnxsj+c88Ng3yNWhCPBNiqK1H/vljhpYyQCC
-nP4BIJ9VCrUMYPBFHLvM1ptgHvIxn/ykX/Npn+nlXu4xXrAh2+/+NN3/4Z/8ZAzWgZ/3zV8HOiAK
-ZtJvMZGtnYn8yBX8lZ73XBoIkt79QZ8Ikh7YQUnrZR8M+o7NAF+5EWD0TZ0HvuAR9pyxSeAENgXc
-EY3K3Am9SeDY6WC7VcbdXcZKAB/XBaFIIBvVeMgJfiFljKFl0BrWWVbjsYsIPtvzcd1FnQyUAEHG
-jJC/ieDIjV/HVUbsseFkiMjTlaEO+mAKoFwRbhywGSJSgKCQcY+tSWDBZeD26aAdQl8VSkWa+EHV
-cN6jbCHzTQLK8KAL+qATxmCUTN/+sRspruHfEcQqVM3TyZ1lPIr4DRegmF8eDd5ejQmvTF+lFOIH
-3gM4gIMX9qD+/R2h7jWgE3IcFYDF0q0hFFrA9AEfFVgGLhmgbXjIAi6dNBphAoEjFX5iUkzCuIlK
-wxEi8LUKQ9RiMtZfxXFg211cqNCi8zHd06Ff13kI6nUdlABjkMwT9SCEGuTKB2Wis1Eb5wliLE5j
-6SXi0g3kRHIc2BWdCVak63FdA1bjm8yTZY3jPfKe6zWhOkaFtEiUB3Kd3E3UD/pjP8Zg1KXeGepa
-pfDjE7Lb01keENyJzVnJjXyQQa6d0lgAoUEK7T3h0/UiQ5DhM25iK94k9Rldw5njB3Zk7pkIQaCi
-90zCo6CiAjLfxVnlD4KlJ65kU1ABB5piZRhDJqKkB+pbwUH+G7FJHeEt3STQorcx4NxJIgSAo5lM
-i8Zgm7bZlSQuXmWEm0ElxEks2sV5m8NdJQpixi9aRq7l5bxN5aRcI8tVZstpyWa2YVNmUmAGSjcC
-AMGJYWkCQMLtXGUkXTqypW3eJm7mpm7uZp65DjnhRJvhzVJSSHA6E060jOsYFnsUZ47xpnM+J3RG
-p3ROJ3VWp3VeJ3Zmp3Zu54D4pnd+J3iGp3iOJ3mWp3nKpH8gp3muJ3u2p3uyJ3r2B3O+J33Wp32S
-p4LA5n3uJ3/yZzc24374Grb0J4EWqHn+Z4GchIEuKIOCJzhooIBM4oD4GoDqB4UWyIUSCEcKyIYW
-iIQKSIb+TqgI9keIciiE9keHEsiHBkiJsuiI8keLAkiK/seMRqjfeAEm5KiO7iiP9qiP/iiQBqmQ
-DimR6mjIVWh+hOgNvAKTNqmTPimURqmUTimVVqmVXimT3sCRJqiuXUORfimYhqmYFqkXyM+JAoiE
-ekIprCmbtqmbvimcxqmczimd1qmdruklbCmBhGgVTIGf/imgBqqgDiqhFqqhHiqiJqqfVoGeDkjR
-3QM+3KmkTiqlVqqdeoKZ5qffqKmldqqnfuqc5qn3ICl+8KminiqqpqqqJiqjjiqXQk+kgqqszmqn
-YqrvnOl/pCmt7iqv1qmo5hqp3oepriqxFquxGmqrAuv+q9pGrPaqsz5rKdjqmOCqf+gqtF7rrv5q
-jP7HsB6rt37rqibrtvrHozYrtp6rp0prjQaIhNpAMrwrvMarvM4rvdarvd4rvuarvr7rAzQqiKrc
-FoSDwA4swRaswR4swiaswi4swzaswG6BvwZI0RHCvlasxV4sxu6rDWRqgkioA7gDyIasyI4syZas
-yZ4syqasyq4syL5AxAJIiBJDL8wszdaszd4szuaszu4sz/asz84sMbwsjeraPcwCyx4t0iat0q6s
-A3Asgnjs0kat1E5tyrqsq+6pysnsz24t13at1/Zs0F6toxKt0VKt2Z5t1DbtrWrqQHws2r4t3Fat
-0Pr+R8x+rd3eLd7ybNgqq4aSbdz+LeCGrNpOK9sKhNsGLuKirdXyrYjymdbmLeRG7tfu7biiqN8m
-LuZS7eCuK5r6DQqUAOiGruiOLumWrumeLuqmruquLuh+wtySqMrRAhvMLu3Wru3eLu7mru7uLu/2
-ru/OLi28Ln8UHQSwrvEeL/ImL+uigNMeiLWiK/RWqra+aICqXJ+CK/Zm76GKK/XqR7lGL/hOqrpS
-a388b/ier5xOb7DaR7dqr/u+L/eub318L/rWL5yOb+HyAqfaL//iqfBWL59d7/sOcPbG77IGirn2
-b/3ib8d6rvI+MARHcOq6rtj+K59RQw5ksAZvMAf+d7AHfzAIh7AIjzAJZzA1/K/36lrxSjALtzAE
-M+/aNnDbZi4NR+3iVi6MZq3k7jAPgy0K58ejlm0NDzHLbi758gfUErESy20Fu6jj9jAURzHNUm73
-AvHlLjEWk6wR5+/hZrEXu8MNV3Gp6rAUl/EOU7H80kcQfzEbb7EMGy4bf3EYp/F81K0Z33HeovEB
-F20ce7EbP63fhIEJDDIhF7IhHzIiJ7IiLzIjN7IjD3If/PAY81nAOqwlXzImZzLDQmwTy6iuEcIj
-h7IojzIpP3IYNK+BmK8Co6/6Yqj1EjAsg6sB9y2srjL/MjAgD8T+2vL5tjLWBnAsB7OxzvLY1jL+
-L6MvLjvvph4zK0uysL6yMEdzqhKziRozM4NvMqfyMl8z+Ppy4w6EAEuzOG+vM9sH/XIz9Gazh/rN
-NpCCO78zPMezPM8zPdezPd8zPuezO7NDOddHiD6CDAS0QA80QRe0QR80Qie0Qi80Qwf0I/SzGqsw
-GegzRVe0RV90Pm8DKq/zDPcxFs+xKz8xHo/05EL0fKyxRy/xHytzR6c0EYP0Lw/E45I0TfusHtOy
-bQixS9fwSmtzS+80DcP0NwvETNe0UefsTRdzTgP1EPc0RwvEKcyCVE81VVe1VV81Vme1Vm81V3e1
-VC+BSctHiFKAKpS1WZ81Wqe1Wq81W7e1W7/+NVyXNQWEdXwUnQBkgFfntV7vNV939SlstIr6jSNk
-AWEXtmEfNmIntmIvNmM3tmM/NmH7AF3DR4iKwxlcNmZntmZvNmd3tmd/NmiHtmhftjhM9nvYdTdA
-tmqvNmu39mM7AmAPiCqj87V6swWD8zjnNrKatnucM21jqzoHti7/NrrathPjtm4nd6BSs8QSbQIT
-t7MGt2xvM3RDq3HDLDQrt3Yztydbc3VHd2zb6ECgQBCUt3mfN3qnt3qvN3u3t3u/N3yXNwUz7m0L
-xAxEAH7nt37vN3/3t3//N4AHuIAPOH7PAG+3B/GOQnwvOIM3uIPDNwwT7hvzQhczdeIKdX3+80JR
-HzWHT/GBswdKWzjmOrVww7GIYy6GHzdRdziL12xSV/NSn3jikvh0/7SM/22KY7dItziLv3hzQ49O
-33jc0rh4m7iQ4/iHr4cd83iH+3h3x/iRD3l4s6vfPEMYXDmWZ7mWbzmXd7mXfzmYh7mYX7kOJLl6
-hGg1/IKarzmbt7mbvzmcx7mczzmd17maV4OZp8fEjjmf97mf//mYP8OUd+5wf/ezXje3Zrd2Jzd3
-D613G/quSneR6y+kOyui062iL3puNzq5Onel96qkU3mhfzqtXjrsArOmM3qez4inkzqthjqhC8Qu
-u/qnmnoOo3qqb/qqM1qr0zqownqusjP+Rg87sRf7PfNzJyc6nwF0Qze7sz87tC/0Qyd7pw8EBEy0
-sWe7tg+7RsdwLht5lL9tjiu7TDN5j+86pl1xuKMtkYs6uK+72Y47pu+4uRu1kzs6lMO72bZ7rFO4
-visuupfHktd7Td97tef7v0stvwf7QER1Xz88xEe8VoM1tZ/6QFRAXGe8xm88x8N1BQQ8edg1Xks8
-yZf8w/+1t7O0QAy2a7e8y788Y0t2xd/6QFj2aN88zue8zod2ac/8fqA2zAe90Ls8bKe8T8u6r8uq
-rQMwcuf6OHO65T560lcqsFcrdU+9pS69hWa60wsz1A9vr2M91Q86wyO92Gc9yI9H+3b+vdenvXj4
-9tlLatWXr9/4wgHcPd7nvd7vPd/3vd//PeAHvuDfPTa4fXiEaDYggeIvPuM3vuM/PuRHvuRPPuVX
-vuJng+GDB/EOPud3vud//uD7AtlbvY0n/NLKu8WvOMHbe+Z/R4ibftqOPt2XPuwjLerTvOqvPk0b
-fNQjfO0j7cKT/rv//tHePtPnvu6PNO+DPZAT/9IG/+wPv/OrrPFvPb0n/x0v/8+r+/Qzrewjsd8k
-AuiPP/mXP+AXvs9b/0Bog+W3v/u/P/xXvja0vndMrPnfP/6XfyJ8/37Mdtz7KkDwEngPwD2BBxEm
-VLiQYUOHDyFGfEjQoMAqUzBm1Lj+kWNHjx9BhhQ5EmOVgxQlplS5kmVLgSkAnMRXimZNmzdx5tS5
-k2dPnz9pejoI02VRo0ddAkhx0BNQp0+hRv156WRBpFexYkVpkWRXr1/BjjQ50GpWs2dVEh04U2pb
-t295Cn0ZE21duxCVMoW7l69bqmQr3hVsdyuvi2ERJ1YMciyvwoMhZ1XrmG1fy5fjDqUbmfPZvAId
-ZRE9mnRp06dRp1a9mnVr0T6qBu48u2VhcWdw59a9m3dv37+BBxc+HLe42LSRs5wsoJtr58+hR2/t
-SHNy6y0/8zo1i3t379/Bhxc/nnx58+e5Lzl+nX3DwhVUxZc/n359+/fx59e/n3/+/Arr2wsQoeUy
-QM/AAxFM8LxTqhPQQYWyc8CdCSms0MILMcxQww057NDDCV8A8MH2CiOmlxNRTFHFFVls0cUXYYxR
-xhOJEXHE6ya7Z5YPeezRxx89dKDBGx+MEMgjkUySwxABI5LEsngxccYpqazSyhhrbNJJHDfTUckv
-wURSyLm2dNDIMNFMc0kby+ysxCvhjFNOGLN0DMo2Z8txRzX57HPCMXmZDE/rsjvkhUMRTVTRRRlt
-1NFHIY1U0kMNYXPQwQrLJpNNOe3U009BDVXUUUkt1dRNs7H00rsmg2CJSWGNVdZZJT1kyFVpy64p
-zHjtlaa/7JQNV8EKO2yxY5H+Dauxx4ZltcvKfI2WL7kC3axZznSVVtu9gGX2WrSKTVbccUVa9s5v
-0coR2m3ZfYpaQdEVLNt26XWq23PjzSpccvnttyRV8z1K3XoJ9uldawOua96CGcbpXmETRmpffylO
-1lyIIzZq4IY5rungjO3K7pkwSC7Z5JNRTlnllVlu2eWXSdYBYJBXKqyaX3DOWeedee7Z55+BDlro
-oXGuZmaaU5qMEJiZbtrpp2F+5lakrzrTz6vDZDJYqo96c86vwYazTm+5TqvLPbFOO0lA4S27KKvV
-jttHrcl2OyKvw85b7xfHxtfuiPSUW/Ae2Ub4b5bgHlzxDOn2+3CH8N5b8sn++8b48YYCX1xzDAu/
-PKmlBJJw89EpbNxyzxWKfPLVw64cdcDPJl32zl9XKbsmlMld9915793334EPXvjhidf96NoLE0GK
-5Zlv3vnnoY9e+umpr9765UU4/vXJrine++/BD7/4Jqau/aHszF+o7vS3Zl99x9lv230y53cI/frb
-x19L/fPXX/75/6e/+9VvfekroPkOWLsAxs9w/OMFAMBhDAlOkIIVtOAFMZhBDW6Qgx3UIBXgZ0AA
-UMGDJTThCVGYQgmC8HTpg4kKYRhDGZoQHA3k3wxxmEMdTlANDuSFGnYYRCGisIcOtMAQkZjEDPqQ
-iU104hOhGEUpTpGKVbT+4hWxmEUtbpGLXfTiF8EYRjGOkYxlNOMZ0ZhGNa6RjW104xvhGEc5zpGO
-dbTjHfGYRz3ukY999OMfARlIQQ6SkIU05CERyQsgrAIh1wBAEV9ykBBCDgCVtKSdBGJJTWZSWASx
-JDj8QMlMGgMhBHmgJitJSlRWMpOaBCVZGAKERybkHsaoJBCK6ElNGkSXEAwlQ2Cyynv08pUKUQMj
-z9fChFhlkispyBOM8YRETvMufqgDQiYBjgFt5lxPWEUdRgjJ1BnOlA/E2LnKyQsL1OGX72vlJKqC
-kDv5DUopqIM004mQJ1QSdAJRAwDg+QR74rOB6VxnOxmSz3TCRJoJMYb+OIF5jZRYJQUSzYpVLIBM
-am7ULOw8CBX6eQ9wSlJYq6CCRL/Z0HGu1JwLQae1UqDNhNIFAMa4JyxJKs9zysYq+TxINrOJEGP0
-kxdUsAAmWfoSmbrHWvk8lxqWelFlJsUgT6iDRTma1aOsApn7LOITwDEJbgorBYFxnE+RSs9OWsuR
-WKUlTe9BBSDglJM6dSlPe4jWolZ0lrzwKkLUIFG95rOtooynJN0aKNAZwwI1NCoI63BUq6gBsqCj
-LD/rapUnyDKypFRDCuz5GW9WchXSHG0dYFKRVcBTq611iTUFYgEqDKWsY2VqYg9bSrje9a3LtFw5
-C/LPUDqVpzsdCjL+0erIHoKUrr1Nal2ZqlvaKsQYrB0hSvNiz5ailhfXqINBqvtDZhrEKsYAwhOe
-AELH1IGRfpilMUq7WUbG9BqjrcgkSOla/a7Eo0BgbVyR2tKFrJO179tlWlGZ35f6dqZ1HShx5Zng
-VmoSdGidxGx5MYlrBvitqGyugBtcFVQe1a4P/GU5TWkV9uK2u+M1Z2ExSZCGFsSRDf0nLyIrEEdW
-RK/79fFCUlBaAEjUqry0LS3BAY4WohW4xpXuQWDM0rJQYRUQzimEAmOBIXNYICDUZCiVW8qjDpat
-W45ubr254SuXBcUxsco1VgGOOuBSnVQAhyzJm+d0OjLABeklK6H+xGYb/pjQ/owshv+cF3TWocBn
-frJanavUM5fln4Kap5Pr6tMoU1kgQ0UIEJZC5gFF1Z255XJZBA3LOwm0Dv8soouDa2ZTppPGhgMH
-iXc8EDUXmtcISXKj6XouKgA7xI/GNF0POunABLPE0GVwTn2aAgwLRMNkmYQ0NSzYgm4m2Yalqzfn
-KlTr8pguKTYIdwMFDldnGAChdLF50ateWoM3vqsgJX3t+5L89prf1cItrT0szGIfdpXM9DAxESpl
-2aj3yhM+8J3AEWpUxrTRjjyxl+lsp4lrvJLF9DbHb6nSlyAz1Zi0ih8w3sPQDhWgLoYmBFcRk3n7
-VZYAOO9clJL+giL6t98997lDrkHqutyjoSJFilVF/nOl/7zKg4k4zTVaFNAuneorOaIFSSwYIFqQ
-qFy7egWz3pJrdB0tQCRt0lsS9aqvne1td/vb4R53uc+d7nW3+93xnne9F1KJffd72PG3db8PXogQ
-rZ/gCZ94HEIRgop3PAwHOD+CkPDxlS8hC304ectvnoM1ZDzZ6xd59yXwdaRHnek9t8DQg35+omcf
-6i8H+8fJ/nCqbz3r3ed6EU619M3sPe9RZ/vc91MSrzD+8ZGffOUvn/nNd/7zoR/942NV9wiEEiaw
-n33tb5/73ff+98EffvGPX/vaOz2UpJ9+9a+f/dK/QfkcmJ3+YlSM/scCg1lxv3u9dKxj1KL93wqD
-DepvABGjMYSPfeSPABXQK+5PkvLP+gJjV/ivYfzP984vMARwATUwJAxw0PAnATcwBDuiATPpAZEH
-SiRwAgumAoHPcwJQBGFQIzrw8w5i/mIwBknwgUzw9/ZPBVfQ/FwQSjLwBkVwBp8oO7qgB5RwCZmw
-CZ3wCaEwCqVwCqmwCpeQEBww86DkAtqhC73wC8EwDMVwDMmwDM3wDNGwCy8ACGMPSpDBCuEwDuVw
-DquQEuCPf7IjH2SHdGYB/7QwMKSEdQTxa1zHgQrjBfZwdGjHifIwETenD7PQEKEkEAexEq+kEPnn
-EB1Rcxb+sYkacRMVBxJL8A8PghIt8RRnBBP1RxNBcXA6kYk+sRXlRhR1kBQFwhRRMRddRBXxhxVl
-MW5e0YeyIw9EoRiN8RiRMRmVcRmZsRmd8RmhsRgFAQIiMROhpACAIRu1cRu5sRu98RvBMRzFcRzJ
-MRsLgA1nD0o0IBrZsR3d8R2hUQPuUID6yQaJMARzsPpOMAJ9kGFY0BZ5YQjvUQONkBHrcSDx0Q8l
-kR/7kWD+cSEPQiARkgAL0hMPciIXMB938AJ7sCHb5SGtEQMxcgErEhb7aQOIIyVVciVZcjjgQACq
-cRWhBBSkoyZt8iZXAxTQ8XAK4w5a8ieBMiiDwzjoxyD+D6ISFCQplXIpyyMDYHIUIVIgKKA/qLIq
-rfIq+YMCdhIAoWQJmPIrwVIpGWAeP7Cf9PAX44YW9ZEHb1EX3ZJvttJufBEtsSYY488s6VJt1HIj
-gxAQ3/IvV4QXCQhKEDEv65IsV+8gztIw/WQvARIXAdMtBVPyCJMxr8Yu8bCfuqADOLMzPfMzQTM0
-RXM0SbM0TfM0OTMXqBEqQ/IgeGAcYDM2ZXM2abM2bfM2cTM3dXM3YZMH4tJtCoMTUHM4ibM4jfM0
-3QAxb68GR1IBNRIgU9AjtwUkZVIkm3MAS1IYL/I66e85o5IXolM6pYU6e1EIubP+svMumfM8K8Y7
-W1P+IMJTPH2FPAfTOtnTX9IzM9fzPvvFPauzI+UzWuiTMu2TP8klP+nxIIbgOBm0QR3UNLGQNf9T
-IKCBNy30QjE0Q3cTGn6zbAojFx40REW0QZlAOYdPMS2zMRXyPaMkMl10MkevMlOUTzAzQQViMWcU
-TRzzOyHTRVERRl9PRnMUTWq0LFF0SHV0RSe0RX30L4FU/wSiMJEUTIo0MW90SsNkR1m0R5u0Ep8U
-Ag9CSrF0bUwUAftpDyQgTdV0Tdm0Td30TeE0TuV0Tuk0TRFhNWvxO3VhBfi0T/30TwE1UAV1UAm1
-UA31UPlUFzqUawpDEer0USE1UiWVTuWxKC1yPw3+dFz8szwZMkDHc1Gp5gUz9UDLNH1AcFTFZVPr
-E0A9lVcGNEYLFFWPBUGNVCDsUVbtT0k5lVVb9TJeNUhjFVcTg1atlBfQdFKRNVmVNU7vNCZ3VSD2
-FFGldVqptVoNVVH3Z0kddVm5tVuRtVKrhQavdEyVREuXlEu7VBC/dB/DlFyVpEqXc1zd9UjM9VmZ
-NF1zcV3ZkhfEdF59BF5PVF791UfqdVXbEl/zFVSRZi4HlkcA1kyPtGF7pGAJtBQRNmGz1V77VWI7
-5GFNtZ8WdERFdmQh1FkNlhcqVENVdmVZFjc5NGNPFkRJdmZpljNL1FJNElOFNTFUtWLhs1cFVGH+
-aUZUd1YxiDVeeeFWizYsehZWeRVop0VoQYZol1ZZStV8TrVqwaJpgfVpoRYufhVKA1JrC/Bqaydr
-ybYruFZs4/NrwVZqM4Zq05YkjjZgeeEcYiFv9XZv+bZv/fZvATdwBXdwCTdvyQBP15IjBYIHkqBx
-HfdxITdyJXdyKbdyLfdyMbdxfRNmfZYX2KFwQTd0RXd0CTc5cVY7I5ZjPYRinfZgL9YS9VVx+VV1
-HdZsXycWaZdDWLdrXfd1BzF2+7Jdc7djbRd1cHd4M2R3xRZdfTdvgLcNA2NjkddCPBZr+wkpwzJ7
-tbcpnzJPWXQqsTJ8xXd880MrObd1ecErt3f+fdmXO8bydNVTIFBSKOm3fn/yJU22c2kSJ/m3f2tS
-J8+Xd3nBJ+23gA14KIvXc9B2bkVibcH0Z93WV+E2YuSWgTkwgS9ngS34IxyYXSE4gvsibB94bDdY
-LDD4cTS4hDmig/e1bUFYKkTYg0lYhRnjhA9nGOExh3V4h51xGvMXfbGxHIV4iIm4iMfxHANYbNeR
-h5m4iXMYXA/wY1N3ei9EeUeYeZsXbJ43HaOXijWkes8WL70YQ6xYhrE4i+dki3lSSMe4QsD4dsW4
-jSukjPf1jNE4TtSYK7tYjt3Yhv/meOWYjmXXju/4Eic4YRhWjt/YeDWTDh35kSGZCiPUe5f+lAvT
-8JIxOZM1+QzXMIlH+A0jOZRF2ZHtEH7101ZpOCRYWHZd+IWhIob3VSJTeSPqFmJReZY9YpWD94Nd
-+S1gWXZlGZf/xZRtNGmFeQR19WRbuZeB4pd3eYaPOSNqWYpvOZozQpeh12uZuZkPOWAq+Jin2XoP
-Am9Jt5zN+ZwD93B/WIAZN3Pd+Z3hOZ4vd3P7x14/F53xOZ/L2XTD9QjjmI/dQZCfmZALuUryWC7Z
-mI8XWYH/mY8FOpt7t6Cdt5vzJZHbeKEzuKEDOZk7l6AlOhUpOl4seowxGoX7aRDaN6W11ynXWWwN
-gHxhOqbF1wBCGl0KQ31VOqeXcgf82G7+smN+DziohfoM8FdC7XV//TeplVo1ALieT5aAhzqq7Zco
-+9koq9mapwCbuVibt9lgavpbvlmYwzmMdTaatXqNO7Wro8KZIRqarXms4bisj/ms9Zir1Xon2Hqr
-BSKYxbqn3QYJPSCwBXuwCbuwDfuwETuxFXuxGVuwEZcv25oZYGCyKbuyLfuyMTuzNXuzObuzPXuy
-meGrr6UwhKCxTfu0UTu1GRsQ/LpsALmNH1qv7/WjW0e0m2Wkvbikb1ijYZuj0dejaZtObHtYcJuK
-dfuPeXuMYxutLTa4a9uTZVh6Sbq1uea1ldu3BRi4nbtFDho4E1qRqZtqskMZ8qG8zfv+vNE7vdV7
-vdm7vd37veHbvCEpcZ/ZBVrgvvE7v/V7v/m7v/37vwE8wAX8vl1guHGlMCohvhV8wRm8weE7CsIb
-aeiboQFySS0cf6JYnFH3Oy/8ZP3HA4v1lFm0wzv3wxkvgjgvxTFowtOR8lT8xVfIAoPQxWFcxT3v
-iWo8xyUI8A5Px3Pc8OYH8Xw8xfeuyI38yJE8yZV8yZm8yZ38yaE8yqV8yqm8yq38yrE8y7V8y7m8
-y738y8E8zMV8zMm8zM38zNEcInLsINZJnyoMxO1HwoBLzsnJlRIuIVgNANhrxlYJyr4JglIA7UTM
-koDgGhKNxdP8y1Mg3ARikbbpw37+qOZujiHwpcmeC9k8iiFMSqKuAQgUDGO8axUkirKmLamugYSa
-LdFVHbAAoKH2qZ2sqdxsLb5QndIhxtIjzdRiqiGgJMz8xrz0KawGzr1SfdWN/dYEArZ07NZknbqK
-btAqfbdyvbmiLCH2/CSkCV/+CptK/cmSfd9AzNiNfdEFYhX6qbrazCF23dYV7tJPzXLWaYR0ruFM
-DdLpauxETsbFHcz/SZpa7SXmKt0XgtVOp88RjMK47N0hR9oAgOTo3N3JYsSKfd8T3aj8QKZEiqDs
-XcOMgcXoHaei/bmqvSHcq4e0va9+Sui+7ZsmnuLRfBIWCXSCaZfQKqamKuTDHdL+82ndXSrf82wh
-gL3T7uHpSq259N3lu9yR1I2lfGrbk6ndpz3Aug3oO96vTMrZGmnF2O2mih7cWh7pzdzOSu3PjCHR
-eP3WaarPyR7kPG7g/1zrTwmVKgLOwKmmkN3ACN3nwX7v9UcNiI3vAT/wBf+OUuCCgPwsvo6CeLwo
-MGjwHf/xIT/yJX/yKb/yLf/yMT/zNZ8zQKvzPf/zQT/0RX/0Sb/0Tf/0Ub+ifGjsUr/1Xf/1YR/2
-Pf71Yr/2bf/2YZ/xCm73eb/3ff/3gT/4hV/utXD4jf/4kT/5g78FL2fmlf/5oT/6f19cR9xeSdx9
-Mrz54dxur1+Au9+Ftn97wp/+mqvfw60fw8c/9dKfrAViAsrh/eE//uV//um//u3//vE///Uf/g18
-VQojEgBCmsCBBAsaPIgwocKFDBsKjMQr4j0A9yJavIgxo8aNHDt6/AjSYwoAFp+UO4kypcqVLFu6
-fAkzpkyUEyyODIkzp86dPDUCSGHRwayhRIsaPYo0qdKlTJs6HbrE4sSKPatavRpyqkVuqrp6/Qo2
-rNixZMuaPYu2KzepFLG6ffv2psQMT+vavYvXqQObJOH6/Vv1Z1B3hAsbPow4seLFjBs7fkz4BVuq
-gCtbzqg1IrFenDt7/gw6tOjRpEubPs2Z2OTLrFnL5XVvFuTZtGvbfrw34uv+1rwtC47o4Lbw4cQb
-S5bYtrdyt5l5bUYNPbr06aZVI6e8PDvP17GLe/8+PDev3drL8/zNKzj49eyNrzYPH2Tz59Tr278/
-2jrs5PH7b+QuW3sCDkiYeOT5h2BG6O1gSoMOPghhhBJOSGGFFl6IYYMIvJdgh83Vs0uIIo5IYokm
-nohiiiquyGKI9XDYIYKvEZJhjTbeiGOGO/AVY48WoacegUKCd9x+2PkI33z4Lcmkffo1hyR8AA5J
-pXcG9hVlgkBWyaVwRUKZpXZKNklmmaU9yV+Y2k3ZZZuzXakmglu6Sad718VZ3phm7slnL2geiSdv
-bNZJKGJwBgrfnIUuGhn+jIi2pmefkjL556PKDcpooYdamh16wuQIaqiiWsiJo5xW1pwsi6zKaquu
-vgprrLLOSmuttq4qi6mn/vUaBAiMCmywoQrD467KKZopoV+maexfkU4KbX2VNlsZpsnSuSm1lyF7
-rZvLAqotVs9GSy5004YLl7Xddpktun9xuy6X37oL17jl3kvaufRepW68VLa7r1vonZJXwQYfzFRU
-dwZ8VXNxyAFxxBJPTHHFFl+MccYabwxxHLoynNNrAtCFcMkmF3xKsSALDFRElrwBc8wyz0xzzTbf
-jHPOOu8MsyYfrywffxSkRXTRRh+NFgU/Ay0SlgLQw3PUUk9N9c6WqMz+dGAtp+evt0tnvZG9+I79
-mb5gg9Rv1wQCfDZO8KpN4LxtZ8UffWTfXfbXc6vcHdxVsr23R2/73Z7cgXckNt5jm314RmkTvh7g
-jfu0dRFmXI555ppvznnnnn8OeuiiX86O3oE390gAqq/Oeuuuvw577LLPTnvtqj9i+t69cjF6777/
-DrzoRWA9eUeDQ05k7nMnrvi9jBevG5Z9Iz+g5ND/uHWQ1BeufNvMN0/u89A/vj1x1l/Py/HlD2c4
-+gs7B37z4hdP/vq3nX+9+vbb1r7738c/qflNrn77ow3+oIceEsxhgQxsoAMfCMEISnCCFKygBRdo
-j+6drTlYmIYHPwj+whCKcIQkLKEJT4jCFHoQCxoE24wuCMMYynCGFyQB8dx3Ef0VcDb9Q9//ANgn
-ATaOgDvEzQ1xGBEdFtExPbzeD4G4JyEejohLZMwBi6fEKi6midB7IhTLJMXAUVGLibni5LJIRsRw
-sXhe/GKTwqg76QUojbUxY+PQA4Vg6HGPfOyjH/8IyEAKcpCELKQeR9DCrKXqCIxspCMfCclISnKS
-lKykJS/JyFy9D4e9UoIhPwnKUIqykFA4IhLRSMfCrHFybXTjkuA4tzGmskCmxCEqZ7nKxrXSlfeB
-ZdtkOUs7Hu6Wqczl4XbJS2klkmnATKUwAzewk0lzmk1RmJGQ+L7+h3Fsm9zspjc15rFNuk9kJKOm
-Oc85i5RFD5sK2trLqgbPeMoTZz4Tpw+FhrR86nOfZlGaPa8nMqjNc6AEhefV1snOHGZvlrQx5unq
-lszwLRNozaTjM/dGTDo6dG/IjKh0fHm2iqbxonPLaBo3ujyIejSAE12ZSMlI0rahJxEmqKlNb4rT
-nOp0pzztqU9/CtSaluqfXeQPC8KB1KQqdalMbapTnwrVqEp1qkhlQUtB1qs+BHWrXO2qV4GaiFq6
-Dz2eKIVZz4rWtKp1rWxtq1vfCte4mvUSV2VYc6owhbzqda987atf/wrYwAp2sITNaxXqGjDu4EOu
-jG2sYx8bV0/+iBV9ZIWsZS+L2bfSlahs5A9eCwva0Ip2tIM9LGcHKL3FZna1rLWsZBGa0CRurayt
-ra1tNYvYfd2VtLztrW8Fa9prYlOxty2ucc/62vFgKbaVPa5za7tZ4SJxt7+trnV5G1wwoY+4z+1u
-ZpN7IGyihxEgKK95z4ve9Kp3vextr3vfC9/yLiO39GqOOtKB3/zqd7/87a9//wvgAAt4wPhVB33d
-NaP4KnjBDG5wfBkx2fzN1rsUtmx0tetEz153wxwu7YHRxd0Ki1iu4F1uQps74hS79cLMuidlPtvh
-GMt4CtltMUBTq+Ics7XEscWeRWir4yDP9cPhou6Mj3zdGoP+a3w4FrKQedzj9E3YyUFm8ZI7+2Ik
-a7m6SmZniKmsYij3GD0JmIeZz4zmNKt5zWxus5vfDOc4mxkHRNZWc+yAhzzrec987rOf/wzoQAt6
-0ITOsx3qTK1epULOjG60ox8d5wREGIFTBrOKrcxOI29506Lt8nCbbOkUi5m5lQ61iDGNTU1zetUe
-Pu0QQW3qCo/6xKWOtXdRPV0Ns3rXwEV0s75s6+7Omp1khrSxj43sN9PZ1cfkTzzYAO1oS3va1K62
-ta+N7Wxre9vQjoevjaXoZIt73MeWNGxJ/eNgVxjXOFQ1r9+tV08jEdjqPu6wxVvrehuX3f7TNbz/
-bdhv74r+3vq+7b1Pme+C25bfLrYIjAEOb3lzEtYKN/iksZjwirOW4RnOMsT/LfFxUlzjrT24LbdG
-XgerfOUsb+98mf1QyqAjDTSvuc1vjvOc63znPO+5z39Oc3QI/FQJbrnRj75yCJ+b1ukm+W05XlSP
-f/zdId/uyJ3+3YufMeNYt/DQOeXuqXO66jeWimq7zlqTj5XraHcs1LHscLFT/euWInjbH6t2yrL9
-7nJ9Oyv9LfdVk53JZud71pdO7K1xgACMb7zjHw/5yEt+8pSvvOUvz/ha0P1RzXkHOj4P+tCLfvSk
-L73pT4/61Kv+8+/YPKJ69QfMy372tK/95Tmg9Tvu3fD+uIU5RwEf+E0Pnn5X5z2Jcz/M3RufrX7X
-JfCDr+Xho7bwy8c78qGp/OqntfnNljr0tyz9V1Nf+4zNu4QtogB8qH/97G+/+98P//jLf/70r7/6
-C+H6QDXHG2Dov///D4ABKIADSIAFaIAHiID95w35hyciwwr2B4ERKIETWH8KcH0YtTWOkAUbyIEd
-6IEfCIIhKIIjSIIlaIIb6AMMGCfNIQ5n4IIvCIMxKIMzSIM1aIM3iIM56ILioIJqIjLdcIJBKIRD
-SIQm6AgXWFLZR35D5nsp5X3fh2ThN0XFt4RrZX6U1nRVCFfcF3NxB4Xg14NhYndamFZXiHFZSIZt
-xYX+v/eEXyhjUihGVJiGZmWGW2cRw9AGeaiHe8iHfeiHfwiIgSiIg0iIeUgHYZglzQEPZcCIjeiI
-jwiJkSiJk0iJlWiJl8iI8ICIUdIrD1CInwiKoSiKhDgMSChTSriEa+iEXuiGRwaHcTR+c2iFpng2
-KCaLaqWK3vN8rchhrxhLcjiHdah7aHiLaJWLG7SLvJhkm4gkYyiLwph8xFiMTChd7ZaMyshlzOgj
-zhiMtAg26PEBkCCO40iO5WiO54iO6aiO68iO7SiOGKCNPdIcRlAM9WiP94iP+aiP+8iP/eiP/wiQ
-9WgE8Rgjr6EG7oiQCamQC+mOH+CNWYMe1nhlfzeTkc5XkVOYUOGFcJlmY1HHkRcZhxlpYon3kSWZ
-ah1JfCIZZeljDCngki8JkzEpkzNJkzVpkzeJkzlpk6uAkn+3CjoJlEEplENJlC7JkyAZR0WplEvJ
-lEFpDCMpXgAglVNJlVVplVeJlVmplVvJlV3ZlUiZUl4plmNJlmVpllUJlr90lmvJlm1plisJl3Ep
-l3O5NwEBADs=
diff --git a/Documentation/DocBook/media/fieldseq_tb.gif.b64 b/Documentation/DocBook/media/fieldseq_tb.gif.b64
deleted file mode 100644 (file)
index 7b4c176..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-R0lGODlhdQKaAucAAAAAAElJDK+vr1YMDBUVZC8kDQAAVkYQEBcHOwYGSCEJHSAgaKOjoys8DDMz
-CgAYGp+fn19fFJmZmQoKO10wMA0VIAAAcDsICCsMDAcMT1MMD2ZmAAcSO29ISFUHByIAGoiIAA4H
-T0pKDJaFhXd3d0EgABoaVGYyAC4AKXd3ODs7BwAAN1MAKQAAYlZGB2JlDBwcWWBtYCA3ABAQTQAA
-ZQ0VQD4AAFVVVUhjSCQMJQAAfBMHMkQgIEtLSzAyDD5VPmZmDEZRB2FhEWZiDFo2ETkdCwAAVEUt
-Gu7u7js7Ozc3N3d3WACPADU1NTMzMyBRIDgAAEJCEHEAAEwNDZeXAABpAEQFBSMjIxgNQDooCBA9
-EEhIbwBVAAw/DAwMPgBNAENDCgc9B8zMzABDAD4MDAwOKjwKCkQWKUscHAAAcUtLFRMTEwohCoqK
-AA0NTBEREQgfCBUqIgApADIAAA4ULzg+DEEfH3wAAAcHSaqqqlkcHDgMDKSkpFQAABUVRjEwCGZm
-B00QEDAwXSUMJGUAAJaWlhQUUnx8jVQaGgcGLggSGy8GBmw4OGNAL4qKioiIiGIAAEsHB3JYWHd3
-AAAAPlctLYQyAGggIBgAGkIVFQwcJRgYSA8MU9EAAAcHVQAALRoaYbu7AEY1H2ZmZlxdEHAAAD82
-DlhqWExGHgwOUzMzDAAAmgA5KTEHB2ZmPlpaB///////ACISRExUDTJPJUQrDAwMVhISSEhISHd3
-IC4xCjhcOA4ORERERBkVXElJAG5gYFhYcnt1ZkgGBlYAAAUFMTg4ODo3BTJrAFESEmZmMF5jBwoG
-Q1paDUkKChxGHN3d3RwYRGZmHCgoKFMAACYmJi4YLhQ+FCIiIhU0FT0AKR4eHmVeBw04DRAsEAwu
-DAc2BwoqCgAAPFdMDQAA0WAqKgwiDEgZGRkQRAckBxsTPDEwDBAQEDwAAEJGDAAAU0FBQEJCDLu7
-u2IYGJoAABgYRjg4bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALAALAAAAAB1ApoC
-AAj+AGEJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
-MGOelAegpk0AJFrSrLhTpYQ3AHoeDFpQqMCfQQHIXEh0olGBYkZtpGkTW56B0EYBfTMKCUEJEqja
-7DpQDIAbBJsOJHF1qdu3cOOqVKtTKcWnEOnmlQALWk6Eep8C4Ou3YWC7JUlAg9VUL0K8vcRMRUwC
-gFdoXBdD6+WE4A0kQqE5kSqwsuWBepFg8yq3tevXsPPKg4n3YW2HjnHPZrp7oODehoHDui2ysfDH
-iKFi42iU6A20A5G84SsQrdE8iKdPR3181KPY4MP+NySBC4L4lHRJAI0MSwwJ0++B5nSvHqdAJPVv
-LHb/U54YJzX99RR+QOnX3ntKidELANiMYlce2DB4FX9vHMdYTfIQeNZ+8dlHkFg9QSihQEQpyKCD
-H9q0E4X+AfhGTir6ZhMskWGTU33Y8EWffFC5OB+CONX3V1BixVgfe7DgWFlB7621nmRMAjBdLwk1
-Bw0SAEBZ1mKw5PHddQ9aNgp0jB0nQWfnpanmDTVNU56aI6lFghOLkbAcTVJh9xl28uCJBDQ2Jkkn
-EqN0Js8bvWTYy3dmzfbUnFcWOhxXsznxmWhKHeooANAcmihrBhEFKaGGAtAVoH9xN1ymFa66GFH+
-lv4JYEFE7eRphi/21ephJDqRR6fY1MlqnlnCkitmfZra5VlI8Fnms89CmuRy6jkKVEGLlkbntEwG
-CwuKyK2VE3HfLhaapQKNuSxrjpkF50Sg9SnvvPTWa++9+Oar77789lsvPDcBsE0Tqb67kVpWDVSh
-UMbRxKUEy23XV5YOFwRNrckZS93FYlRs1sNKjZLqDSRUnBBREnNsMsS0bvrtyDD6x+lRGWPsqkCZ
-pSVcT4MZtCRN7M6Ws0AM70bU0UbPljDO8uQ4kAQ177a0scA5TWKVAQ8mVJECUbnqTZ/h3NYb30Hb
-ssEQFZn12my37fbbcMct99xxo62RWlknq2r+mVsrhbfeRzmBDZsu68xdT33TGHDJGYc629+JG77T
-gjfFHLmqtiKWFTZv3CAZr9CKcQOiC66q6uadd4yYcc+ynrdav5EYMHAIYx2dVljunGnZtWF3E5q5
-5Wb3QfH6a/zxyCev/LwAB3xFEoUMnxHCuu9N5Myw/KSxQCrbZRaUNhOUMsV2XQzyy0U1fvb4qj/8
-xtk7iey4+TTDn2njBJpNtF1N5Wp60QQhEABb97ikwQIbwrFa9qImEAQmRGKMsZ2MaESmdCmFBFCq
-zShIs6xXWUh40gthStgEAHZYSksitIictvWIN4BmdUnzE6oEFalSQaVYjwDAVR41KEkJpRf+l5qV
-piYFuOEUjESzGZUPTfWnQEmOVdYqIAVlxcDMKewvdtKf6aBFtr4s6IWq8p+dBog0xrRFVCx0YbWG
-EyFslU1aLfRKyaa1GHDNMUW3QwtmDOSXa3ltiwF8Q1tw9p12qS+FiCxJoTyXyOkBpz5OkAwZk1Uf
-smgobEI5UmUeMaD8eEUoSFjQlI4SIadlsnEAEsMlP4kToJDliaRkEHWIEkopSeCPSPwfYvIAoLNI
-JpUEwcz7mgIxBqmnQjDsUi89N8lniRIWwIQklKSJyyRxUJokygmhbMm/I6otbH3RijFp5J4JFkR7
-BJFU3rJXwUa6UySgemddxHPEhZBLnij+AVRDVEm097XmBtTBp0AHOrx7ukUeZXOIQQk6klFYqCBj
-QgISbsBBuOiToRjNaHgWCieOarQjhVnIRGsCzriE5aMoTalKV8rSlrr0pTCNqUxnStOa2vSmOM2p
-TnfK05769KdADapQh0rUohr1qEhNqlKXipARSOKpUI2qVKdK1apa9apYzapWocolgxwiGGANq1jH
-StaymvWsaE2rWtca1oTE4BRwjatc50rXutr1rnjNq173CtcYJEQYSwisYAdL2MIa9rCITaxiF8vY
-wAojIVuNrGQnS9mtAgMh0GCrZjfL2c6y9RAOYUQnRkva0pr2tKhNrWpXy9rWuna09Hj+6ALIQdva
-2va2uM2tbnfL29769re0bUFCnsCE4hr3uMhNrnKXy9zmOve50C3uExKSi1hY97rYza52t8vd7nr3
-u+ANr3VzkRBIvPa86E2vel17icesArjwja985/vbBYR2vfjNr35ZG1uEzJa+AA6wgHkrXIQQN7oI
-TrCCF/zc6SKkuuKNsIQnTGHwkhch5t2vhjeM3/YeRB7vHbCIRwxg+zZEtBxOsYr5K1sSu/jFvi3w
-QQ7M4Brb+MbMdfBBIFzhHvv4x9298EEyvOIiG7kTHjYIiGHM5CbX1sQMQfGRp8zh/h7kv07OMoll
-bBAa4/jLYF6wjg3CYyCb+cwUFrL+QYhM5TbnN8lFCbGW5yxgKC/EDlPIs573zOc++/nPgA60oAdN
-aD3zASF+cIOiF83oRjv60ZCOtKQnTelKK9oLCfFGNzbN6U57+tOgDrWoR03qUpt6095ISBSawepW
-u/rVsI61rGdN61rb+tasjkJCzFDoXvv618Am9B4QwgdLG/vYyE62pf1wXzc7e71WNgiW6Uxt+XK5
-IF4Os7a3vdwxF6TMaA63uLmr5oKw+dnobi2cPyTnaru7vs1Ot7xXG+2CTPvd+NbttQmSbW77m9ve
-Jgi4x03wcZebIOeet8JJu27ftDvfELetnRUi5YVbvBP1Jsi9Ix7xfQ+k3/8O+Zf+Az6QgRf85GY+
-+EASfnF5N5xoD+c4xCeekIq3fN4ZH8jGZY5vjwsE5CIPOoNJLhCTo/zoFVa5QFh+82e/fDgx5/m7
-aY4QHgzg6ljPuta3zvWue/3rYA+72K/uDAYgpB5eSLva1872trv97XCPu9znTve0JyIh5uiC3vfO
-9777/e+AD7zgB0/4wuvdHAlRBRAWz/jGO/7xkI+85CdP+cpbfvGqSEgrxs75znv+82LHAEIYMIG6
-m/70qE893esR76bLO+cC2bnUq+1zWABd6LiPLtFhYXSk+168SocF013f5qcvefYzbz3xnw17WMge
-+XOu/e1zT/0cU/f32E9zeZf+73L3Qj/fVD+Izbnf5uY///tOln7116/762f//eEN/vDJX2TjRx39
-WQ6/QcpBj/77//8AGIACOIAEWIAGeIAI2H+lIAAIYQJp8IAQGIESOIEUWIEWeIEYmIEa+ICUkBDZ
-8AUgGIIiOIIkWIImeIIomIIquIIgmA0JoQZtEIMyOIM0WIM2eIM4mIM6uIM8GINqkBB9kIBCOIRE
-WIQImAwIIQDvsIFM2IRO+IQaaAIOUQlSUIVWeIVYmIVauIVc2IVe+IVgWIXUwIAHAQqrcIZomIZq
-uIZs2IZu+IZwGIdyeIZGkBDXUAV4mId6uId82Id++IeAGIiCOIh4eA0JEQH+oZCIiriIjNiIjviI
-kBiJkjiJlJiIEZAQNhCGmriJnNiJYJgJSWgBcziKpFiKpiiHoKB89Ddl5od/7qZ+7BeL1vdg8FeL
-3iV/q+hs9ueK1aZ/BTF+uVhkrciLdAaLsniMx7V7vWeL8IeLwUhlu0iMc+aLBAGMz5hiwyiNWWaM
-yIiMysiM4IhdzniNRhaN2uhk1DgQaBAJ7NiO7viO8BiP8jiP9FiP9niP7DgMZncQt+AJ/viPABmQ
-AjmQBFmQBnmQCJmQ/lgMCREO4PCQEBmREjmRFFmRFnmRGJmRGvmQ4ZAQYPAKIBmSIjmSJFmSJnmS
-KJmSKrmSIAkGCWEF+Bj+kzI5kzR5j8N2EAyQAAq5kzzZkz6ZkLegiuRYZS12juk3XN2YlN8YjuE4
-jkOpYuZolDCWjgJhjU+pX9kolS/GjUkZi0vJlMzolFe5YVGplSRGlbBglWMJbUVpli7GlV25fl8J
-lrUolmupX2XplgOGlmp5l+iVlXo5YHAZl9Q3l3T5fnbpl+uVl4FZYg6RCTUZmZI5mfZ4aAcxAz+Z
-mZq5mQeZAAnxDWEQmqI5mqRZmqZ5mqiZmqq5mqwZmt+QECIACLI5m7RZm7Z5m7iZm7q5m7zZm7Ip
-AglxAZQ5nMQpmTdpEHzAmcq5nJs5A0KpmOkFmI0JYINJmLhnmIeJfYn+CZ3oxZjTKV98yZ1Y2Zbf
-SZ1IaZ3sh53Z6XvbKZ7s5X3lGWDh6Z5s6V/xGWDViZ4ip57reXTtSZ+r5Z336VvzCaB/SZ4DCl/5
-qZ//xp/9eXL/aaCoJaAJultoeQ6QkKEauqEc2qEe+qEgGqIiOqIkmqF9sI8GwQvisKIs2qIu+qIw
-GqMyOqM0WqM2uqKfkBDpMAY82qM++qNAGqRCOqREWqRGeqQ8mg4JoQKT0KRO+qRQGqVSOqVUWqVW
-eqVY2qQqkBBQUKJe+qVgGqYk2gqjtwI3eqZomqZqaqO88JwSmlrSWaG9taAMCnDu96C/F6FvWloU
-Kqe4VaB7ymL26af+wEWndaptDoqnBrd9gapu8EmoBOqmjUpacQqpuGWohwpmiaqo4aanjdqnlkoO
-FyqmpFqqpiqiJ4oQKrqmrNqqrjqjOYoQcCAHtFqrtnqruJqrurqrvNqrvvqrtAoHCfEHv1Csxnqs
-yJqsyrqszNqszvqs0Fqsf8Clp1qt1lqqZIqTZvqq3NqtrNqmJzapgnploTqn55mpQbepnHpmnhqo
-oGqpgCqup1Wp5Rpc54quIaeu6wpk7bqn7wqp8SqvpUWv9Yqp+Gpj+rqvPtavb/qvhBqwAgtbCFqv
-tmWwBzt0d6qwBMewEuqwfoqWHXAJIjuyJFuyJnuyKJuyKruyLNv+siOLQgRhDwswszRbszZ7szib
-szq7szzbsz47szCQELTwBERbtEZ7tEibtEq7tEzbtE77tERLCwmhDLlQtVZ7tVibtVq7tVzbtV77
-tWBbtcqQEHrgsmZ7tmibti1LAQghBj/7tnAbt3L7s/bAVHZ7t3ibt3q7t3zbt377t4AbuII7uIRb
-uIZ7uIibuIq7uIzbuI77uJAbuZI7uZRbuZb7UhCUPf50HwJySIYRMFTCM6ALSDJSFYPkM2szG4Sy
-Fa90ITZRUpcbu7KLESRQQRRFEEtCulBBQrB7NumTS78bvJp7uh+WHHukGaPDJU0hGu00u877vPt0
-GrCAJYOUB9f+orsH1BVI4ATVZDjB6xh4YRRZpBBGAUQF8RzAuyzQu77sqxBWY71YkSN2ARmsQRzg
-yz/HEb7Giz3hch/FQhBm4RVqgR3tW8AGnCTQIT9dw0nz67ncAhj5i79K1jixI0HYS0Dcgy4HvMHP
-G8DGMk3W0cAIIUAnEzD7IzuVg70V3L8XfDQ30QvxxMEybLlOIAEQ0k+sdMIG0UK90FVDEcHpa054
-hBX8W7zR8b9lcRogNMNMLLmPQFFYlDd4MUYMcb9BrMNDXBrLQb7JYb6eAR1L3MRi3LgXgw0wu0UD
-gsQKYcVapMKI8RPEO8HB1DnI+wbK+1BjnMeMKzhG/DU2kSj+WXMyQOy6N+HHNRG6NzE1Fnwf4jQ0
-bazHkBzJkjzJlFzJlnzJNEUCvbDJnIwkInFLnbzJAYXJpFzKpnzKqJzKqrzKrNzKrvzKsBzLsjzL
-tFzLtnzLGhHKurzLvNzLvvzLwBzMwuzLo8xSCjLMyJzMyrzMy3zGKnXMzBzN0jzNyXxTDELN2JzN
-2uwhLkUT3KvN4BzOyAwgePxR3izO6JzOvNxGNsXNLuXOLEUT5axR8gxT9fxSuVtT8MxS+6xS99zN
-YZxR/9xS+UxT/axSB41SAx3PAY1RC71SBT1T3CwMjFDRFn3RGJ3RGr3RHN3RHv3RIG3RXZXQ5qwW
-OLALKJ3+0iq90izd0i790jAd0zI90yiNAzIyzwKtFiG90zzd0z4d0h2wFg7cUtzcl5MabSRNz2ox
-fRd7Yzr20P6sFvMnrkkW0TJV1BGLWkhdT1HdG0zd1DX21A3NUP881ZNa1UPNz6li1I261fa81GDt
-b2KN0w4t1Vl9WmhtzWt916bl1i/1z18d1wo212/dG2b9qUKt1+pYnIzd2Paoj6jB1Sn1z2zQmpZ9
-2Zid2azJBjdd2AMBk44d2qLNjsdp1TGF1XxNqb2R1Dnt1YK9bYT913ad2qOV1+2817SNcast2QoN
-168dZrEN0Iad20iW2Lc9EGwdqH4t3B/328Dd2bI93Ln+bdv6nCpU6InYnd3a3YVjGNmeLRAfyILi
-Pd7kXd4q6IL7Q9dkrRaZuN3u/d7YDYqlkdYrxc38Z4T4nd/6XYAL6N3RPRBaQIgCPuAEXuCDqAXQ
-zdwCEYT73eAOjt9ION+KXZXEvdwtBdjOrakJfuGzTdvUbdC4TdsWztCuneE4FtwcLt0ebtzVjdwV
-vtvfbXsmfuIbTuIrR9wfLtGpgqHX2uM+jqooytp13RuzCqxGfuRInuS+KqzpHeNd+uNQHuUZmq1J
-Qt8IHeKpPeIrheEzjrA1vuUdnto5ftVYztda3tXN3eVh/eVovnQ4zuIg7uK5feaT7dtqLmZsXucq
-Lub+cK7jci7iMP7fP3fnGNvkgi58by7hxy0QeBZsjv7okC5olskYvF3SvaFpp5bpmr7pnF5qqWbo
-Cg4LvBbppF7qjl7aVp5SqA3o/h3qgU3oyIXiNu7m093nZP7nWR7org7rg53nvb3nfD3mp13md03n
-v57mvN5+oJ7iN17rit7iFD7nus7sg57syr4q6k1QZZ3oVT7hsMADZBDu4j7u5F7u5n7u6J7u6r7u
-7B7uZhDkla7UvZF3hlfv9n7v+E54iLfssw4Li9DuAB/wAj/w7C56zx7n0c7q2RTjr27tsg7mwH7X
-wg5Tq57rrU7tMm7t0PXwbY7ozt7ti56WL37x/d7+8MnO8Xre7Ct+8H4uENcN3zAf89xNhpQe4+Ft
-3jif8zp/guiN7THe3jIf9EIvBfIN8tAOC/f94Eq/9PxN80K+3r1xhwY+9VRf9YBoiPwO8QPB4Ezf
-9V5PDxFu9Agv8tJO8lpf7RrvXCh/7LS+8mLf8mSv8DV/6CbP62tv6SrP5yx/6wlv8QtP92nfYL6O
-922v92/P998Oeoq/+IwPdmVn9h1vDt8w+ZRf+ZZ/+Zif+Zq/+Zzf+Z4/+fvu84e+eY1f+qav+AZ/
-+MOO62Y+7SUf+Go/+PKe98Fu66vf960P+SmP9rCvXHc/+4Vf+3t/+3Hv93O/673fbbLf2rQv8bb+
-T/HEntXGTvgZn/zJ9fvMH/zOP/zQPxCS8NPgH/7i/9Fa8vTarhY/QNPqv/7s3/4z/QPLP+QDQQHj
-X//2L/7P/1LmT1D7L1BQvfsAAUvgQIIFDR5EmFDhQoYNEcoDIM/hRIoVLV4USAIARo4dPXYEQOLj
-SJIlQ5ZEmbIiRIkqXb48yBLmzJkyad5MqRHnTpgnef4EKRLo0JURiR51aBPp0odGmT4tqBPqVIQA
-epHAmlXrVq5dvX4FG1bs2LA+qT6FOIrsWrZt3b7FOsrpWaZp4d7Fm3dtr410/QIAHFjwYMKFDR9G
-nFjxYsZC/SKFyFjyZMqVLQ9u+fho5MudPX/+pqxZ9GjSpU2fRp1a9WrWrV2/hh1b9mzatW3fxp1b
-927evX3/Bh5c+HDixY0fR55c+XLmzZ0/hx5d+nTq1a1fx55d+3buFN9IICjhDUEkQiFyJNwL1nlY
-6df3JcgZALY8Cgc7yQxt1Jv5JJC8J+yGwoSSwAnAnABPoPkKkiuz7h6EMEKKSLiBoBtGIUgq9ggS
-Q0AAbvivKgcFYm+ugTY8ET7x6hNRICT2+w+aN0aBBhYxnHCiIBMVdHAUJ1jMwwkM2wNADIL4G1FC
-JZdUUgwAQkQCABZhyYM/EuEbCJtRkEDCCfVaLKjEJFG8MkNsEporSol6qXAgJLBxrL0k55L+AJsQ
-XfyuPSccC3JHJv8EVDtsEqxyIGgG7YtMWHoJUdGB/BTTIEVRhAaAGg9K8w0uiyzokRwfnTMzJx4x
-iIQcAXjkTIFGecTPQF+FFToKV3Wsl0fYc3QgElTFdMy+IMWyTIJcldPFUeqbFEs/5wJWTmyMhOWN
-SpOMtVprj3PyvzegnRXXYN0k4Q1qFRxMWMJESlbHcd1LF1SDmPVVTqyoPHXca+/FtzcE81BVHk3f
-E7bTN3q5FMz4fo03TCwrLVjdgVoVI0poH/6Ux3dFJbXTesU4k9Vi8wU55N0euVAojTBTdFd73VXY
-4pZfzojXi4dds00X4aR5ZoHEuxMWJPL+NOpZaT8WuWijY6v0WUkTDVbihpolOsWlB1oRzcweGQ8W
-GWm0EUeHv171R4GCHNIoUz8l9mi11x7NCZmlBjCwXuQDzOqpiSyXbvXko88+wZyYWD/+4Ow5apep
-NhCAUd11MuO02YY8csknp7xyyy/HPPNYSeilc897mRgmCT73PEHNT0c9ddVXZ71111+HPXbZZ6e9
-dttvxz133XeHXB7ffwc+eOGHJ754449HPnnlC08OCeWfhz566acXnnnkoKE+e+23n7460L4HP/zA
-ViaObvHPR38x8oc7OX333y/M+1G4p7/++ltdXziIbrW/f/+hx59zNPI/AhaweHLxXpz+lKOU5TBw
-gY8jjlSaI0HpmKWBEByOA5OjQeRQcDkehI4FH5i/4HDwOCY0DgiTo0LnmEUQC4BhDGU4QxrW0IY3
-xGEOdbhDGNYgRSQEjlJQkQsiFtGIR0RiEpW4RCY20YlPJCIqfihA+MgDBjzEYha1uMUdCkJX33qO
-WRZADjKW0YxnRGMa1bhGNrbRjW8kYwum2Byl5CIWd8RjHvW4Rz720Y9/BGQgBXnHXMyRORKUxyrg
-uEhGNtKRb1zAFxM4kDE+0pKXxCQb5XglIP6mjoMEZShFOUpBFpKTVDyRIjO5SlZaMpIZAWMLHVPJ
-VtbSlpo05AUzY0dS9tKXv/yjKd/+00nfIFKVt0RmMsnxSliwsDlmMUEapDlNalbTmtfEZja1uU1u
-dlOalMjlCAeihjaU05znRGc61blOdrbTne+EZznVEM4VwkcA7/BmPvW5T3520wSSpI5ZQLEKghbU
-oAdFaEIVulCGNtShDyWoEeiJHKVEIBQXxWhGNbpRjnbUox8FaUhFetEITPQ4EhSABSC6Upa21KUP
-BQVApyNGZdbUlpscpnM+CUye9rSXwkRhcYxpU6KukpnOZA5Ni7rUR+I0qOWbCy99OlWqBtOkKazi
-MZm6VUjKtIKz5GpY3ehUDOovqlVFa1rxCNSyBmeoYoVrGo8ay2c65haewGte9br+V7721a9/BWxg
-BTtYvBbjqsVRChhesVjGNtaxj4VsZCU7WcpW1rKLBcNhIwgfBiSAsJ8FbWhFO9hbeDU6So1rauOo
-2QyeVa2vnSpbidmbt6o2tXOdpEBoaVu4knW2vNkpbIX7S9mikkRa5W1YcRtQsCa3t6w16y6HO92f
-QtetWXUuXJc70+Zml6u+1alrqTveQRZ3gtj1Lle3+9WBzGC074VvfAObAOsGcS4iAER+9btf/vbX
-v/8FcIAFPGAC51cE9f2NBPkgXwY3OL4zMG0Iu5vepYKXjuIlb4b9aN5DopfCS13vaSf8YZtamDnB
-1XCK9cjhD3qYxDYNsYQp+eL+oppYlwORqop1HAsWK6e2NFZmjMM4YiDf0sbiFEiOd5ziHtczlUWu
-qZBlORBeiMPKV8ZylrW8ZS532ctfBnOYrfwJBPtGKSqYRJrVvGY2t9nNb4ZznOU8ZzqnWQVlpi1n
-VyBmPvfZz38OMy8iPOQZQzmZR94ghpes4SZ30MWGrqWU61poSN8Uz8BV9KLJ2+iTPrrSRh30lHX7
-aUuf8sLS1TSTL72bH5M6k5JOqmOqDGha19rWXiazqU88lz/8wte/BnawhT1sYhfb2MdGdrJ9/YdV
-60aCDNjzraU9bVoLGpa5hcVuXY1JRFM006meLqex+uRtg/razKV0uS/Z7RP+fhvcwhW3UD2t7kbC
-ejmopXdTm50bFL873PvGTavzzUh7KwffA2cku43Tb3/DG+C3ETjCu3pu7rbXwRfHuGDpq+sbCyQe
-lwV5yEU+csvG4+G2UXDGVb5yvUKY4uwdtcQbqXDEurvhaY33Zskt80UWPDkH53kbaQ5VVN98uDln
-37yDrkafIwfoS1fj0FtbdKPDFunCiTjU0dj04zxd62eUenRxXPWjn7w2Wf96GbluHLNswhZvh3vc
-5T53utfd7nfHe971/nbDchzJsFAFEAQ/eMIX3vCHR3ziFb94xjde8KowO22ejYe9V97yl8e83jcR
-6knHPO1Rj/xsGE72ql7+/bo7//zWOR/rdKfejGEvoc1J31PTAwftn197cbyeetjbl+qzL33oZXP7
-tOeeOGJ8afKVv/yGStTvic6MNEY6fepX3/oilYbwY4NIlTLf+99PvvGHYxYxGND89tM+bJRyfvZz
-L/2vkaDz2j9/6U0MqfdWIPTD+9vdPDXpz7k/g8s/b+M/3fA/sTsvAKQr1ju1/XPABDSumYKfCZzA
-AuQ3CsRA97HAgMvADhSf6tCLEBTBEcyKhlEOaCDBFFRBtzDBDVrBF4TBr+CdGaTBGrTBG8TBHNTB
-HeTBHvTBHwTCIBTCISTCIjTCI0TCJFTCJeSOPKGarHER81jAhWCXXxn+jL35Fr6ZkoRwEpuJGvMJ
-CfNBl/tgEas4GAvhFHK5QryRGyZ0Q9OYlYG4kAxhGoPoEMAAEbt5Gag5w515gy08iJO5E2KZC0dB
-kXD5D8DIGIBxEcDIPxNpqzeUxKfIlkackiqpw4LQEi7xEj3sQz6Em5hZiO9wQsNhGUaEGYuxin9B
-xVRJFZ05nEmURc0YlLGBwkORgEwkCEYJGFiEG1DsRYZJiDx4klGwGULMDEMMFkuREydokw3Zk0oJ
-naiJxFm0xp+IQ7UYCFvxFoXYFU/8xYTpw1M0CGOkkieJxZzpxVBsJseRBydBlr6QRljYE7AxxWvE
-R6SoxG3JiArpxoP+KA9xQZNyYcRzQUV2vEeB+EOFdEeDMR+JoBsnNBtNYQ9PEQissUeDzMeNHIp9
-6Zd/+UeBIRj7SBhgPEhhPAhi/Jt0PEVlJIhRUBWnEBL2SJzA2EJI3ECO1EmOIBltbCbC8J1vURmG
-gBqTPMS3eckhOccaQUaE7MVIsZGQ2AiUpEelpMac3MmspIikmUZGJBOnIcqSFMdQrBqAXMiBeANS
-acp1fEqE+aKNMBWCwEhyrEattEuOcJuYYBrBmBvCAEdz8Uu9iZv5AMTwgMKwYcO6ackqJIhKqQ8T
-MRBYwIZF1BopoUu/vMvM1MzN5MzO9Ewe5BzSAZ2bGB3RNJ3PRM3+1FTN1WTN1nTN14TN2JTN2aTN
-2jwd0cTN3NTN3eTN3vTN3/zNNZgG4CTO4jTO4yROJVgDJUDO5nTO5wRO5WRO6KTO6qRO6bTO7NTO
-4pyGNdjO7wRP3hwWbAjP8jRPAGAH81TP7awGAKiG9YTP6mzP94zP+mzO+bTP/DROdrAK/fTP38QG
-ZRlApzMG53AEAHAEA0VQBU3Q5jCGKdS5RxnQrivQ5jjQBmWOC2VQ53hQBRyWCWW7Cs3QBbVQEh1R
-DF2ODo3A9nCMEZCEF4XRGJXRGaXRGrXRG8XRHNVRGC0YABDRQwiGIBXSISXSIjXSI0XSJFXSJWVS
-IR0IDRWIGDj+hSml0iq10ivF0izV0i3l0i710imNgSc1UWFYgjI10zNF0zRV0zVl0zZ10zeF0zIV
-BjHF0B210zvF0zzdUWAYCBXVmiYF1EAV1EFt0kPwKrNghE5Q1EVl1EZ11EeF1EiV1Eml1EpVVHrI
-DB9tPddbLYGAUlh4AiYQ1VEl1VI11VNF1VRV1VVl1VYV1Seg07EDPpyLVYGABEvF1VzV1V2t1Evo
-U6VLvfVCVF4l1mI11knF1EcRUW3jVHLAqU8NVVeV1mml1mplVVj1VBNVsln1KWH61Fs91nAVV2L1
-VYHw00Rq1jMSVsdI1HF113dF1kxd1nR9vVoFVWvF13zV11X+xVZY+NRt5Vae8lYTBVd4NdiD7YRy
-hYVzRa5mXdeBaFeEldhxTVYFmVd67VR/NdFo3deO9Vhr7dd/Ddjgy1YMLdiJRdliVViGxVgyeliB
-sIMpkNmZpdmatdmbxdmc1dmd5dmenVk+UNaB8AM3INqiNdqjRdqkVdqlZdqmddqnJVovsFdv6Iaq
-tdqrxdqs1dqt5dqu9dqvBduq9QZ7jYJmMNuzRdu0Vdu1Zdu2ddu3hdu4NdsosFcz8Nm7xdu81due
-3YNfHQg+gNrAFdzBJVyo9YNDZdeUVVxirdj2uFiMfdaN/djJpdxrtVeAHVlfGliTXdzOzdWVBVbc
-Q1yI9dz+0qXUxtVUz6PXyMVQjq3c14XdkNXWzI0tez1Z08VdRgVd1EvXl4WFiM3d4O0E1H3c1bVX
-14Xd5P1Y2cVQzKXdUdrcgbhd4TXd3T2ull2m0RUI4KVe0yXeTeVU1h0I5FXe8s1X5pXV5wWm6LXV
-7g1e612PhuVU3+WBAbDf+8Xf/NXf/eXf/vXf/wXgALZfZ2CAoBWIevCCBFbgBWbgBnbgB4bgCJbg
-CabgBE4EezWHLtDgDebgDvbgDwbhEBbhESbhEtZgc7DXwHO8FWbhFnZhxoO8kh2IVhDgGrbhG8bh
-AMYAvxUIBpiACgbiIBbiIabgetDe33Xf3P1e1U1X8RX+CPI13yieVvRNMvUVWNtNYtyFX3RtWd/l
-3ixW3CXONux14nuV4jOmViqGBee14vLCYjD23C2WX9fzYjj2XDFm1vA9XjTmY1dVYzZu40BiX1iY
-XjuWWDnGXt8tB3pg5EZ25EeG5EiW5Emm5Eq25Etm5FIQAAOGhWjqp08G5VDWJnCSYYHIhi9A5VRW
-5VVm5VZ25VeG5ViW5VlG5WywV3KKp1zW5V3m5Xeap1KGhT7A5GEm5mI25ktOBh6GhXsS5WZ2ZlD+
-p5czi0qQgmq25mvG5mzW5m3m5m725m8G52qmhk222IEYKPBD53RuPnu9hipw53eG53iW53mm53q2
-53v+xud8dudrsFeLur5/BuiA/qiSAmYbCOeDRuiEVmhwzgRlTil1huiILqiYkubENeQwllfwdb0y
-huI+9uhR/eNA1tw3vmiUReQuPuIvLmmDxWMy3uOPhulSDWmRJqVBLuSVfteTxtg6xmmJbemW5eiY
-FupXvVyarmmS7mmD1Wl6pV8ycOqnhuqoluqppuqqtuqrxuqsdmozKOByFgi3y7ywFuuxvru+01gM
-NYdvUOu1Zuu2duu3huu4luu5puu6VmsUBuZ1CIC95uu+9uu/BuzAFuzBJuzCNuy9Xgd7XQStZuzG
-duzHzuodNlfOojyytuzLDuvNq2jSTeqD/WnIfen+oYbpmTbqULLpzj7Ype7dlEZtls5oJm7WoBbt
-0S7q0jZtpG5tcVVth2Xt3HbXzzZeYO7o2Y5i0rbtUsJt3zbW3Z7f3lbucAXuJg5t4uZj4z5uQDrt
-5w5X5qbjI86ESADv8Bbv8Sbv8jbv80bv9Fbv9Q5voPVqWHAvlpPvi9u4sx6IbwiD/Nbv/ebv/vbv
-/wbwABfwASfw/P4Ge8WvAlPwBWfwBh+wAwPmC2DvCafwCrfw9e7byf7b+ebwBnO5n/xQztZuY43u
-2J5u6j5j677uDUvuEddV7g5W53ZxXi1xPRZuFO9jFV9xPsruGedVGBfdzd5eH2fc1x5joD5xHDf+
-Xx3f8RVrcSKnVCAvPhmHckut8Y1OciVXXiZv8rV68iqPVCn/Ot89B0gw8zNH8zRX8zVn8zZ38zeH
-8zg38z7oaselMmrD8zwHs1yzb4FIhzEA9EAX9EEn9EI39ENH9ERX9EUH9HSwVzSrs0iX9Emn9Dm7
-M2CGAjnX9E3n9E6P81ZQZmjT81En9SuzNhCXUBEH80q9ct7Lci2P3dru8j7q8VWPcmXm4p2mcluP
-1Fb/PNmG9SWX9Vnfo1rn9TDH9TmOcSFH4mOPV07OYyy/8WAXdmAG5CY3dmd3VDHXOkU+5m8H93Cv
-ZE3mZALQgXNH93RX93Vn93Z393eH93iX93P+NwB71QIuwPd81/d95/d+9/d/B/iAF/iBx3ctsFch
-oIKEV/iFZ/iGd/iHh/iIl/iJp/iEFwJ7FWZx1/iN//Zk1nCBEAAamPeRJ/mSN3l5J4AjpuaFZvmW
-d/luHmdOPmeJpnnwc74+h4V21ued5/me93l85mdg9meBJvqivz6CxnmDfvmlZ3qWb+iPX+buq/mp
-Xz6KRnUFsWhth1RfTztgp/bk5fJZz3atX1RuhzqeJntH5fqv8/qvf92w7/KxT3uzXzq0T3tGXXut
-a3u3p1y4x/Yv13q6Dzrf7YBLMPzDR/zEV/zFZ/zGd/zHh/zIP/yJSV1YsAcuwvzM1/wcggH+e6WF
-JwD90Bf90Sf90jf900f91Ff91Qd9WrBXZYCi2Jf92af9J1IGe9UDydf93ef93o98ClBmMdj84Sd+
-zbeHI04qEV2OT11+E21+FFUOP+2wEG8h5VcO5r9+589+6E8O6W8x6n8m608O7B9/7S9/7kcO7/cx
-ZbmKGHT/F+yP95f/EewBAOiB+cd/vaj/+8///n+L/QcIEgIHEixo8CDChAoXMmyoEBsAhxInUqxo
-cWAvALA2wgLg8SPIkCJHkixp8iTKlCpXsmzp8iXMmDJn0qxp8ybOnDp38uzpUyfHoEKHEi1q9CjS
-pEqXMm3q9CnUqFKnUq1q9SrWrFq3cu3+6vUr2LBix5Ita/Ys2rRq17Jt6/Yt3Lhy59Kta/cu3rx6
-9/Lt6/cv4MCCBxMubPgw4sSKFzNu7Pgx5MiSJ1OubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
-7fo17NiyyyKRAKsXUtxGe/Ui4URMbjG6gw6/Pfs48uSbSeDGDc1Jr99Ciw9trpQ6x+LYlXPv7t3v
-I9t5SMAab11CHljQqPfmDc34bWjYSMyH5lu6QNuw6NuHJcGJE7bhlgd02Gy03XcJKrigWtDcAMso
-0CBhXXHjTScPLPKMAh+FsIjx4HO3AZedcU4gAQs2E8JiIhJvMPgijDGWZd0N71nn4Q3+5E1Hom4d
-StAbCRqxF9989MlzI4IyKrkkk009MoqAvL3xY4ajnFgdhhqu6GGHYpBXG3w8wvdIiUi02CSaaapZ
-FDQAXHmgcaNA15tQAvF2opwCGafbfen1CCdu/zlB3oDQPRjmmokquiijjTr6aFn2EfQepJVaeimm
-mWq6KaedevopqKGKOiqppZp6KqqpqspWHhtu5ARH+iU51Bu83Vgrb8AVh2svb2bXC67A3aejrQFC
-5QSlEpAJC5izTmergLfZSihxvA1KFK7S7QcgecIByxtzuIoHnRN+ugqhs0ORoJ+DscJ53bTw8Spc
-tdHpGJS3uG407IHWjtgUEgZuNMr+iOkhitS8Pca7q62+clTrtfty65+UQH7bi2383nbuKOnWye6h
-/r2blK0Y71kyosXey1G+vJVHrsHF/stUqxzBulHMTPEqL7SI8urwRhDrSGB06f34LXMXCzvxxhx1
-TJXAYrgqj0aI3qffjiQerN1GWhI13LobSUDtq1A9smyN+9640XPRzTwyoFmPDGV1G6kYtn/3ct31
-DSciccORAqPoMb6Hhtd11cXdACDWWmu999yNE8cR3mPD1+5TN4x4sxiJByUPuW+nDPfoVX5d9n76
-WQ432KoTKjg2hLNsuH7Mwb24sXLHPbnjdJ+eYd/MAn55yE1F7WrncIPudt2P667+m9dZwypP8H9j
-yDrlrt8Gu+xFjZJe2H//6TTqz5MOOYLDcT3czU6FGDDOtheHnnrYDTmk45jzjgTZI0MeIUeg0bHv
-ledpTknRit4jvpF5aSOCc9y7IBcm/cltfWwrHlMsVzN0wY0EwKEg9rbGu4NFMISlG10vCNiq7jnw
-RMjykO3C1EAUNU9MI5wgBrUGQLZtSDcgXAoB8WbA4nhQPTncG/789zvc7FA950Lf5FKYnhVSpWYm
-2g+9SKgiWvEmWrDY2QnTB8HmWEtyTEGWhVS0tqBY6FkuO1kXT0hCXL0BQ1B0HHt6ITUIHekp60LC
-zTw4vqD8sGS6Cpqt5ChG7Nn+ChuiUwr8SJCeR+RhkGxcGSLppLA43lEoEMOGjUbYyT3tcRR9dMof
-b9Y3S16wOomEoyZvuMj78caRULHiiSjJyvhx0WS6mVcYsRUdUCZxlM0p5SmnAsoHyYNsxeEfCYBW
-uiSGaZEorMrZCAaLtK0RR5g8nwjzd0S7wcqYTqOUE3EDq3I+5UPKypAzg4KEUViphiUcYwBzqEQb
-TkVzsPobh4SioW9O03yke9eHgonHKG6JnU5xJ5lIYEe4zbOeutuTQY1YFN00UYAkfMoyhRfQz42C
-oEjM6HZ086GOPlGUDF3nR51CT9scrVaI0txueEdN6J1LbpXrn1QcdDNbTan+OBqSpgh36jQzqi91
-YtPbCKnnN8DhhgQljSlSnJC2mq5tQui8qCX/Z8aR/RSrGaQnl76Vxafm1Hmy7FpPtQbQspqwrFW9
-KgtflbakvaF/Xt3ojpQ6sLHCR6rCmyhVZprWWq01b229Jz5N1zzrVW94ddXeXYEalc75apO9eAQY
-DQrMnf0MsJRjWl6JkqPATktO4LInLAkFLZUJM47bipgJX1Y047QplE95RPvexSv6vPKGPMtVyZJm
-r8fellhWeYPBIjit2L3WoMn9oq3EUNpe6lFiuJWjxpwDAN86BbhZ45UEqGs/1iYyubQ1rW7LddB2
-ukmn0FLvN/eGXuy6bLv+nsxufKMLXtSqZ7xmXRWCE5ymsQ2EsE5pJkHsIqmBfDUqExZIhQnD4PxY
-ZcN4o8uFSZDhp4R4xIIpyPWogmK7QHggVmmxnhQs4xnTuMY2vjGOc6zjHfO4xz7+MZCDLOQhE7nI
-Rj4yp6YUFAm4iCP8Q5xURIIbqm1Eyhmq2udAgg0BD4XKVGscAORBNZGQx8pj/oh8O5JiTzbZyaN4
-AwD6eqWRVBkkafvdRm7Q0zbN7F5hjsqZP3LlOoekymu+8ke2fBQqd8SoGhkJbujcES0bjNFDuQEA
-3nYkj+AU0SDJEqWNEiSRiDnUSMYLCYqn56AECcpC+RCnkarmLlftzwL+xTJHLM1kLmf5ym94k60N
-HZRg5xrXJPj1rIeSB49EF5BpE4NWhT0UW88T2a9eWR7aDItHPLDV0nYznLVFFEsX+9vDPrSuoWsU
-RntkWYPmCLGJDe8UH/tE5HayR1bWOTLxD9n3drV/1L1oXFs6SLI+tVs4azcARDfbVfs3NqwEyCTJ
-+90V/ze56bNujVCNTuaO96HfPe9kC0XPq97XAzv3noqT/DbffMShBb6ie8kDziMPipze82akYrzW
-IW+5yPfzwFtXGVhXIjfIiZL0f28bG9wmzsqMxfSMD53Wvb45wuuCDf1kO4BbfziuD3T0sJ/b6kAP
-OsALbGIvZzrTH1/+88XDbuCKI4HhTLaZu7t2IpYTO72whZCr6j6igD0Cy/KWKNaJrni+oxvXvS0K
-u0F3KKTD/efxBg7TB8Xnhc9MDO+ZuuMNvPGrV9nEWXdLqgemN5iD/SgaL0rczZ322bN80FSOYdIT
-n3YSLKvid6+7wWrPeNLzUNlN/g/lJGr4nyNu7WSPvNIbL5TaR75z6aF82adN76mRffMRYzraac/8
-tBecoKd/i8LfMKLUMxr8/R6/SFxN5vDfm/oc10jAbJN7Qn+EPIGOs35U3Gpt06EIX0joBrHdGyVh
-S3rcwLKAjsjVHpPl3a19msUdoOzVH/NBX71hH7xh4KSBhI78m3n+bVuTgd//tV72QR7BiYSDnR9b
-BEgeCEzN2ZsKCgVo9YLpnR30KR7xPd643V/X/Nr+8SCujYLAyFvdhYQLUaAEYMjwxcrQ6dN+WImB
-tQio6V6GYAM2jB/9+Vz0+aDasaC0OYEp4VoRYp0EGNi/OUFIpMfm5ZptgB4hiR4ZlpvdvBkM0sUj
-6JmOjNqn/ZuRJEXsGaHZodzoWVqOFGEhyt+h+d3CZcwDAd/ZtZzH2Q0VahfyeVr/AV3NUWAQml0U
-4iEi3qGtdY63vV0Yjty9AeGKuMolbpP/kV3Qvd7okWL47WFbtIktKd69CZ5SFGIjkuKuJSKWtQgj
-hhy59WB2rMz+DTyIs73Hc9xMFFabr0iAg3EhKFqavDkBKIbi4lme9ImNzIkivXnEClbi0oWdbwQF
-aCHOI+TSG3weLaYbr4mhpc0TFeriWjhB1b3b//VCChqFMMZfQHKiohmjOzKiQYZeeogEA7hdrNRX
-tcWZRY0EFNpZhQVPUQRJhnFjoZHaHV4dRoagoAVaQprimrlhOpYksc0HJ0aE09VhpbkhAHRaCs5i
-ot0jPoYER/IjUAalUA4lURYlYCiXIYXF0ZSMyXTHUpbMC16FtzCl+SHGU/aMUWalVm4lV3alV34l
-WIalWI4lWZalWZ4lWqalcvwEW/qEF2JGCralXNLEW14GIM7+JV7ORGoAAJBchF/+JWA2xCjUnmZQ
-TUkFJmImJmIOZl1aRpAoJmRGZkVkxF5WZWZQTWNWBmaKxmaGRiqCxmeWRkRwJmFeZmnC5WnaJS1y
-RmiSxmiGRmeCRmx+xmx6Rmt2xm2KxmvCQgcwgm/+JnAGp3AOJ3EWp3EeJ3Imp29SQLFlJmXE5g/s
-gnROJ3VWp3VeJ3Zmp3ZuJ3d2p3T+QHOKRiqKgXKWp3meJ3oqZwdQzmqGxm5eQifEp3zOJ33Wp33e
-J37mp37uJ3/GJySEJ2wG2xMwAYEWqIEeKIImqIIuKIM2qIM+KIE+AYCCJpbJAz30J4ZmqIZuKH9e
-AntWJkf+wCeHjiiJlmh+/ifiOOdkxOaAQqiLviiMxqiDSmiKimeFXqiJ5qiOjqiH7kt7gsZ77qiQ
-Dul+ouiVqahksKiMLimTNmmD0uiR2miu4SiRVqmVdkKP7sePfkaQXqmXCqmR1mZnKKmTlqmZLimU
-iilr3uiXtmmOZmluuue9WMMg1Kmd3ime5qme7imf9qmf/img1qkCTChtBpsPvACiJqqiLiqjNqqj
-PiqkRqqkTiqi+gCh2iaWMYACBCqndqqnfiqgWsOHosZuLgA5nCqqpqqqriqrtqqrviqsxqqsnmoL
-XOqYBlsuxIKu7iqv9qqv/iqwBquwDiuxFquu5oKtrmn+rq3CrDarsz4rtMrqAozqaZRqtF4rtmYr
-rNZqjQZoiuWqsYaruI4ruRIrsnYrhS6rtq4ru2LrtPooiG6EqbYrvdbrtibrZsQmuJYrv/arvwbr
-uUapZ1Yos9qrwR7sqb6rlsYrLPjCKjwsxEasxE4sxVasxV4sxmasxj6sEeBrYQYbKYSCyI4syZas
-yZ4syqasyq4sy7asyJKCx2ZGKgqABWyszd4szuasxvoCtZrGbiKCFASt0A4t0Rat0R4t0iat0i4t
-0watDcQsaqZYNnwB1Vat1V4t1mat1m4t13at134t1WYD1KomRwgANTQt2qat2q4t0yJCz4rmvYio
-m87+7YaGaWpaBpmeqd7uLYOm6d1WRipaKN0ObobC6ZZ6RpcSruKe6NjirYDyLeRGboH6LZJGRuBS
-6eJmLn0aLsPKreZ+bifYbeVCRt5KrumaKeVKaddgLuhmLueS6r3IAgLMLu3Wru3eLu7mru7uLu/2
-ru/O7gQ0rmYGWx0EgfEeL/Imr/IuL/M2r/M+L/RGr/HWgfBSRioywO9mr/ZuL/f+riy8rWvey7wi
-LPm2K7cKrGzi6r+uL/v2a8Cq6XIQbPnO77oqbJwCqfjSr/5e6/nC78d+a/sGsACba/VORuAW7P4m
-8Kza7+F2hrUqMATfK7oWKgAPsAVf8LEWsGQccAT+d3CrMjDDjq8HjzA59O/fPqf6YrAKB/D7nrAB
-yy8JkzAIwy5HyG733jAO5/DuBu8Ee0ZsFq/0BrEQDzERQy/19jBuZqoOLzET5/D3wisNb4Tntu7i
-ii5ppliLnq4WN2nqDuyUUvHnvm61xi0Ya64VeytHZPEWrzGMdnG6rm4Zuy74jkbixvHgnnH6YjEb
-7/GLuvFnXK4dK64Y++y9AC3bHjIiJ3LSPi0Sc0ZsTi3YRrIkTzIle63YNnL8lu3ZKjInd/Ihuy0U
-jzFHOKzOlrIpn/LFdiwm/y9HhKzLvjIsx7IssyzMrrLMYhnNorIu77Ip82woEzJHiHAMR7AJj+7+
-Y+jrCifz+rawMTsGBw+zB8+wKMsrNHtwMV8xR+yrMm/zuDKz6mYIAlezAkszMFOzOEPwNaPxRmgz
-N7czAdsyZjzzOScwOcMtR0QDJ+SzPu8zP/ezP/8zQAe0QA80QedzImhwZMTmoVIqQze0Qz+0pFoq
-PJPtRjAALxQ0Rme0Rm80QUfDHOsmGQfyHSM06T4uH5/0k5L0YwCySNPtINuzFLc03eIxBacxSt+0
-gvoxpn6xTLvpS4dviPa0m9K0D5s0Th91hKq0M7OpUH/pT9NxSDf1lRL1reoxUiO1TicxT0u1lT41
-SHOEOmCBWI81WZe1WZ81Wqe1Wq81W7e1WO/+gFI3xg/PAl3XtV3fNV7ntV7vNV/3tV//NV0fMfr+
-MZbxgVsfNmIntmK7tTp8tJwG8zwrcDrncTa7s2W/82DvdNeEc2TPbz0DtTl3Nv1Odk2v82WfNrB6
-sxdvtmjr72dDNWS39vySdlFXMGrfdgZPtGPCsGyT72t/dWj39sHSdlVXNm7jtmq/MTgLt287Nv5y
-hDXkgHRPN3VXt3VfN3Znt3ZvN3d3t3RjQlwzRmzqQgOUt3mfN3qnt3qvN3u3t3u/N3yXty6E92Jc
-r3ffN37nt357t6j+MkzDwhRzNZjSt2KU7lWjdFYrKxwLeJV69WPHNIMTKVU7slEfOIITeGL+sHSE
-C6mDPzeEb/iOTni+VriF83GCZ/KCg7iOdjiXFrInvziMLy0jZ3ZxbwQkVzKO57iOb+0l07iCw4LZ
-xriQD7nQgvLCRjEsgAIvLzmTZ6wq+/iIp1gEzDKVV7mVr2wEYDhizGzNNrmXf/nDgoJzt3hsM7fB
-EjeF2/Zxn3ZyE7a6mrnB/vaDw4Iwwzm7onmUG/eas7mWH4Y823m7yrmH0zmg1yues7Jp7zmf6zbg
-8nah1++YI+694DNHV7qlX3pAHzSjo3CKLTREfzqoh/qjSjSUa8b1XjSmp7qqV7pH+zdoA7iKh3if
-G4aBlzgbn7ipM3WsmyiLS3pQ77qJijj+osOCGtv6rc96YWg4sPNopDtwVC87hwq7aVq1se8xrt/y
-VkP7hva6s/+6ttctshNGrVf76V57POv6txdus3PGbqJDCLw7vMe7vM87vde7vd87vue7vr87M4T7
-YMSmOyyDwA88wRe8wR88wie8wi88wze8wLuDv59YYe87xVe8xV/8vqPDum/GAz/6uh76tOu5ortz
-m2v2cns8pLs6bAc3yvNvxAcGMo+8ZZe8VrN2y2eroJM5y9/8s4J81Iq8zG8zzf+4PHA2zztrzvv6
-zh/9rPr8ZcR80HPz0KP4yTP9syZ9t2/EIHwA13e913892Ie92I892Ze92Z8914P3pq/+aLDJgNu/
-PdzHvdzPPd3Xvd3fPd7nPdy//FFmKtr/PeAHvuCj/SBsvGbUcbr3p7T//EYUO7mXO9//hbInfoca
-fmYgPuXr5+I/PYk/vumaO0VnCOtmfn5yO7s/O+kz7tonaed7fuSC/m5ne+rjp+lz/L2cAQvkvu7v
-Pu/3vu//PvAHv/APP/HnPgpEvl8APDIsP/M3v/M/P/RHv/RPP/VXv/UvP8SvvuXisjYUv/d/P/iH
-P/GfgeVjxm4qOZin/5I/uf+G/EZM+ZXHv/xTeZZrP2Rwufrnvy6LucoDN6FbPUCQEziQYEGBLWAl
-lAdAXkKHDyFGlDiRYkWLFzFaXNj+MGGuWB9BhhQ5kmRJkydRplT5MZfDjRlhxpQ5k2ZCEgBcrjK4
-k2dPnz+BBhU6cIHDmzWRJlWaFAAJhwuGRpU6lSpPhAoZLtW6devLjivBhhU7VmVLrBy5plUL86hC
-nVXhxpVrsKhNnGvx5s3Y9Olcv3+nXoXlVW/hvIQ9klW8mPFJs4OzGpastu3gt4AxZ95ZF1blyZ/X
-8k2ILkRp06dRp1a9mnVr169hl2bmMjJo2zUJu1u2m3dv37+BBxc+nHhx47vd0UZ7mznbu7D4xJY+
-nXr12OiMPm++faZoWJc6hRc/nnx58+fRp1e/nn14SMq5x69I+AkT+/fx59e/n3/+f///AQzQvifg
-k89AiCqTh572GGzQwQfZuyS7AymkyDvwIMxQww3Te++sCimkT8ARSSzRxAAJ/BBEAxNckMMXYcxQ
-QrtWrBGWC2PMUcf1PIRsORuZE/HEIYks0r8UfQSSuxZ3bNJJ8WbsTDsl5cPxyStz7JEwKm0T0sgv
-wTwRyS25/IxJLNHkMErPytzOO3Wsi1POOV1LpMA2PyNMl+P47NPPP43T5U48JauMAWboTFRROdWZ
-kFA3nUoIKs0opVQwMh89rLbEGuvUU7IewzTTtRK8rNJT/eKMzVEn825SVGGN69LaWMULsU9xzTWl
-UGmtlbLn5DE11mGjUnVKXwv+c5XYZaOa9Udku9pU12mpBYnXZ6FdqlRmuQXK2Gwlc3WVcckt19xz
-0U1X3XXZbdfdcY0YFNylCJMmlHvxzVffffnt199/AQ5Y4HulkXfepBK04N2FGW7YYXe/PTgv78SQ
-x+KLMc5Y44057tjjj0EO+WKDJaaJMJFRTlnllVEmuWSZKkOC5ZlprhlkMRx9OS3vdDa5155jEhVo
-jIQe2qJVjcYI6aRl4pnpi4p+OqKopX6I6qppxPqipbWuyOmuIboaa7GrJltqrsGWMm2YAGjb7bfh
-jlvuuemu2+678c4b27UXytvvvwEPXHC49077psERT1zxwNfOiITHIY9c8sn+Ka/c8ssxz1zzzaFp
-PCJoNg9d9NFJL33yzj232vTVWW+99NRhj1322Wmv3fbbcc9d9915793334EPXvjhiS/e+OORT175
-5Zlv3vnnoY9e+umpr97667HvXQwAUE9olBseygP1hZCK26ms+n7bKfIhgvuG7iVCHwAJHmLocMLT
-d7uh/AHoBecbsbU98D0ECaN4AwCwEakbwa0XCXEf/ML2QP61TYFGgeDUjkUR8rEvWrB4X/ZAmDQn
-POIhb6BfQrbHEQ46JA9OaNsokGChZ8lPIit0IEcK+IYYTkR+OnRIbVZoQ6w4BAk3aCAAJXK4HcIC
-CU4YRefk8QYSIjEikcn+4RIj6BBoOOGIN5zIFi8COpiQT4xc2WAXQ5jGkj3CCSwEwBJ7ERkbQkOK
-sNgiGts3w/1lUIi06kUF8wiZP/4QLUHko3bY9zNYmNCERkGjBLDhxSouZ5A11E4etKPIzgCSXhns
-ZEKw8T81jhJc0OCeTQbYmUfIcUpi6KIQCTlJyFhSlg6BpAwhs73/ARGRh7RaJKkYvjd+zyEjJCBH
-FEmrW9KShWjUJDYaIobHUZAEB1zfXaqJwP9lExv02+BdHoENBOahgf4TZzcTkodz5gGFccTGKO4y
-Ck6Skp6jMiYssMFOWIghkqysCAmAGT89zhKDtRwiD/fYmSPy0mq+TEj+AZH5LGJicoeaTOZyYElQ
-O5IAi4pEwikXMgpYYPIGSMCkxXCSQlg8ooHywEbnjvLNlb50pW27US86Z8DBvGGPnXNCSbcITjzW
-k6iEYuM+31DMhvhTIjkUZRXfttA9Ek6jsaQNLsmHBHQylDZww8rbQinJEuqzjsFsH9wiRauMTvCE
-Ym3oQanIEPJt7xFYnJBM0ZkQF97ohOSTp0NuQILtoU4Cd8loURELpI+CTqSdGSBTEfSGJ3ptoLDs
-43KWKVCCRvGjhewlM5l4g8b2CpNvayMs7mlBs1o1IZnN4kN1ytq3ajQycr0LOQHgBHaK4QZv6EUc
-Z0m+2sCTiuSLo/r+OMi+wyaWuSC6QTj1edy3VTUhN3DCUxEqS8sey4/z9CIHA8tVuM7WJlKFyCga
-O9JTAlSYMbzoQypZ0KvKdr4crC1KIYJJMbwhUjIlX15hAVx//vUhpiSsYT3ZXAUfCJJJraUN8+DD
-i/yMhvKtHw4NaNcLaxQJB/QseUFMAvMS8Q36TEgdtfpBeTghrdiyYoYnwsECpnK1P8SZfSNKvnBC
-kXt1hEYcZYYT8gG0c6vEiT+juD+eBhioe13pUBccZfl8NL0bhoz67uc2XAZygi1F6wLd9kGsameV
-H+6q+qoaxc7FTQIOdsgoTptDBCpQbg58m5gteeeO7k23tM0xTgr+2DZ0QnLOb+CpkLEpThYfWYV3
-IXRekRBHEx5xFFOU8qUxbbRHeJcrYuhem5fyhgtmmtSlRlYTDUNkO7JYKRKosqlhjaffznrWkxEx
-rX+L3ZfhutZJecSouYKEbPJXwzArdqyRnWxlL5vZzXb2s6EdbWlPm9rVtva1sZ1tbfOa29329rfB
-HW5xj5vcbYWdK8mdbnWvm93s1nXj0N1uec+b3urWHQLrnW997/trjVsIF/cdcIGn24WFA9u/B55w
-hXdbnPfmdNr6zTdNps1sT6s409AGu4ivbeMHn7jHDd61iyct46nrONhOrrWRG23lQ2s50EruOe+M
-QBI1t/nNcZ7+c53vnOc99/nPgW7z7qV8bLWJwSmQnnSlL53pTXf606EedalPHekxcBnFaxN0rW+d
-610POjBydjvvMCJNZc8QPdBC9LLVpj5hcvvb/zOmj4u8NpAw+90btKYEx27sePf7etD+w4fTHS1t
-h/vhEc8EuYdc5XX/++PPo3eHO4TskLe8eALvwME3vvCJ9/zbFz87wtj98peXfO76XnrLZ/5Gmy96
-5z8feyOFXnajV73lT48774jCBb33/e+BH3zhD5/4xTf+8ZHvez4IXvS1oQMHoB996U+f+tW3/vWx
-n33tbx/6dLg6yB0ChuSPn/zlNz/yTRF223knBdVyf65CkXb+168dLa/q1v0LwpmX94wwk3j//zvl
-MWKucdgPAA1QMeKP+WqvNuwP/xxQ/+aO8xzC/w6wAsFCAPdO4xSo/SywA1EiATWv+erPAUlQICCQ
-8V5vAj1wBUsCAycvITiQBWXwI0Cw9USwL0rwAb+P8FRwBmfQBVFPgUShFoiwCI3wCJEwCZVwCZmw
-CZ3wCYuQARQwdgijAjThCrEwC7VwC7mwC73wC8EwDMXwCitgByUwIbIACtVwDdmwDZ+wANSvdlLv
-9v6O9dROarxE9vSwRGiPCh2PDv8u98ROgSoPEPHODucPD9luDxmRRPoQdmzPEPFOENePECXxEOXv
-BhPC8Br+sRP74xFTJxIvsewoUQ4VqBKkIBVVcRVZsRVd8RVhMRZlcRZpMRWpQQCmEBJrIxu+oBd9
-8ReBMRiFcRiJsRiN8RiRsRezwQxTMCFsoBahMRqlcRppMRPikHa8QxkGZhu5sRu9UWBAABdDcAHR
-whAe5hzRMR3ZxRCYkf4cYgO+MR7lcR4BJgKucXYK0AdlsAbv0OIYMAd1UEX8EC0oUB9XEAh1bwMN
-kgX5MRH9cQQB8v5OUBNhoSAX0gIRchAdIgYvsgIbkiIbMCKJZSLJsQc7sgIzshIdAhWGoCVd8iVh
-MiZlciZpsiZt8iZxsiVfQQrHcSAdogxSISiFciiJsij+jfIokTIplXIpmTIoy6AdFREtjiEnqbIq
-rfIqcXId7lF25nAU0QQRKZITPXEs8QMUPUcUvRJLShEbLTEtvzITS3ITyXIuyxIqH9IhSM8tr2Qt
-8bEt9fJJwDIuYUEs6dITzdLf/vAvnYQvudIvFXNHAtMn5bIw5/IwJQ4t8vIxdYQx+U4Ix+EzQTM0
-RXM0SbM0TfM0UTM1VRM0l68ndREt6KAGZHM2abM2bfM2cTM3dXM3ebM3ZdP7BPI1w281ibM4jfM4
-VTP9siYhN/IkLfAjBTMkRTJWSFIyK9I5UXIrO7M5sdMAodM6pXM6UaU6hTMhLLI73S8lTZE70fP9
-vrP+PGEhPMWzUsgzFGvjPNtzWtSTLdkzP6nlPe0TIudzWOrzLO/TP9NTOzXQIY6gBBz0QSE0QiV0
-Qim0Qi30QjE0Qx+UJ21QMBXhAUA0REV0REm0RE30RFE0RVV0RUFUEeySaQijCDR0Rmm0Rm00Q+Fw
-OTUyIQpRM3MkMuGTMCmTES0T6zDTR3eEMxeUR5FUR4A0QB1CSIdUD4sU/BIiM5tUTRTU5BwzSzfk
-SQ0U9qa0E6uUB6/US2FESbnUIRrBEtz0TeE0TuV0Tum0Tu30TvE0T930BMSxQ60zDlghUAV1UAm1
-UA31UBE1URV1URk1UOPgRZOGME5ATym1Ui31UvP+lAi2VOYUSBvp8VNBNR7DMRehNCHMUR1RNVXP
-kR2Ds1RhAR5DNVZltR43lQAVEkH/Ey7Bc0BHElJZ7kBxVT9rleNuNVjhT1fhUz55FTMKFDEJ0lh1
-ZT/7sj+htVMANExxcFnH01ddDlir1VOktTFXkhvItVzN9VzRNV3VdV3ZtV3d9V3JdRw4tB9htDbK
-IAPwNV/1dV/5tV/99V8BNmAFdmDx9SlbFVsT4hjgdWEZtmEd9l3/YFghrkvRFELA1FmjdEwNk1uB
-Bi0rFkLUlFMp72O/FFldVUo11vPK9AxhAUtJNu8kFuUo9mXb42IvM2NTlkg5lv8Sk2ZhVkdVkkn+
-fdZBbNZIcTZnqXRndcZjh3Y9QtZWx/VhpXZqqZZd5ZVUERYW7pVgubZrvfZrBdZgk0QwFbZqzfZs
-pTZigXY9YfBbP+VaMVZStBVWmvVmzdNtwTVmuyYf8ZYx4NZu43Nut/Vg4/Y6+5YxwnU72/ZwF+Nv
-jVZuBZc+lfZl+o9xFyNxlxQWPHVWObdzQ2FUXdNVT1VVSbd014VVx9Y6YdVzWTdU7XFt+TMh2hRT
-abd2bddO+RRrCxdQG7V3ffd3gXdRH5VwAXdSb/d4kZd2NRV2p1Vom7ZmTTZrURZp4W5lm7Fln5dB
-npZYRzZ72aNorXQwqTdpifdxsdd7nVZvtab+K9H3PMDXTMV3fGPPet3xTNs3PbZ3Yh1iCN2wf/33
-f5twXh2yXtHCCsfwgBE4gRU4DMuwfMM3DQE4giW4f3NUbYKQWi0XLBw3fJU1cuOibs0XPzO4LNQX
-a/h2hDU4egu3gz24KkA4fEUYhR2jhKvmhGU4JTYYflm4hafiheE3hm+YJDB3TRc3iHFYhQF3h3m4
-WCa3ZCrXiHeFhqVm95Cziq34ilOzNf0UPmPTN734i8E4jHkTOFMXPsEAi9E4ja1YOS2YOZ33fs3j
-fVl2euUXTOg3KvESjtEjf2W2e/W4POT4eum4jmeviSWGaf+4E/h4b2f2jwO5fuOXkBHvju/+0n4T
-eTwWeX0bWY8fGY8nU5IPj5IJOI8vGZOl+Gm8gyWxcpVZuZVrcid1F3CBsilpuZZt+ZaXUmz3b2lr
-Yypd+ZeBeZW1knnFtYih2CRymGWVeImFwodZFoiPmSVOmWlsOJpFIpmvd5mZ2VsM+WCe2JqFeJqT
-pprBmQaR2Hy1eZt9wpmvF5qjeYhFNiE2t3XpWR5Bd4tF13T1eZ/JBXV3mXJrY3XreaC78XXbeEdh
-ARWpcaEZuqFj8RZj2Xx5MRkpuqIt+qKPcRkdGH6f0aE9+qMX2hqJWXFhoUdLuZMrOZJBGfS6eV4Q
-+Y8z2YQ3GY5RepQ/eaXdTpQjtWdLOab+a3im77emd1pMcTpMdPpXj7SUoUScjWb3JvipofoJBZgi
-DXiBrfqqsdoLG7iMXRWCo/qrwboWKngAudeYyxkksBmS01mdeYKdIdmdjxmeodaszzoW0tqTA5et
-5cKt8RquoViuyxoWOLKu7fqcOViv97qlweWbCTsWAFt/6fqs7zql1xqxCYKvU9qvjfix+zghliAF
-QDu0RXu0Sbu0Tfu0UTu1VXu1Q1uU6HWoHcIeZHu2abu2bfu2cTu3dXu3ebu3aVuxs4UwlIG1ibu4
-jfu4V9sVmHpoXnucBxi2BRM+YYesIbuYrVO6XXW6M5CIrRu7s9a7G4e6Ue6PXKe8zdv+vJu7W+Xp
-vNm7vUUHnlBw7dbbvem7vicHuFBvcfR7v/mbgpqvvwE8wAEnvhVRwA38wOdG2xR8wRm8wR38wSE8
-wiV8wim8wi38wjE8wzV8wzm8wz38w0E8xEV8xEm8xE38xFE8xVV8xVm8xV38xWE8sRrJltyMifpr
-uy2EgQgqbrwMg9wmnypC2A5IsioqbrTIgObs2MAsqvgHz2L8yZmDBGhMtB6iLYSIt9qmpLZstn5G
-iDiozUwsIuCsc6DBiNxKiySrc8TACU6LsuZr1aAMyuW8MLZnhz7KxCIMwSLinZCgieK8xhLpWbxc
-O9gruxLClHBGkXqBxrTK0gy9qjD+ac4l/TPyKsK0qJv0HCJ6YYcOq8vvwtMtzI5OSSKI3CXc61k+
-CruOys3Hi5wm/dULQ8q9R4F64RGUa+8KXbNeC9Rfi75oPLcEy9cH3SLEC3SUHNaRHSnqfJG2CXxu
-fSKEvHCMfMe/bNitLMZIwIVGS8etfcvZKtnBnSucQALUSSF86Nkj4hF8C9jOfMcF/VhWyMAwQr9q
-LNUhIpyI3cyYKLbCvd+R4hFEK1KyrG3wC0GgacLevd27vTMCqor2rMaYzCF6waUGT7yoy98xPiNM
-Kaxey4bsHeHli9fJC8wp4rc6p4BOS5HoaLJWScK8/TlmLONlPiacoOHri4EmaMv+56vO+MfLfjzM
-I0LO0tzOqMqOkLx/AOzRm/zYZ77pdUcMHN3ppX7qqR7Cbw3X3k0tJIDbzE0puq3qwT7sxX7syb7s
-zf7s0T7t1X7t2f7B7fvt4R5y2B1sQCfu7Z6+517k7n7v2fveEPzv/57A/RHwCV/ABR/jCj/x+/sF
-rzu7Hd9zxBvxGR+8AZfyDQfHsSbyNZkiLT98tZt2NF+mHaJibKb0TZ9mgBtaTub0Wb/1Qyb1kSVm
-XH/2aR9jRCn0f9ohLoEeeL/3ff/3gT/4hX/4ib/4jf/4eb8PYN9XCOMZquD5oT/6pX/6qb/6rf/6
-sT/7tf/5n2H5ayVBSgH5xX/+/Mm//I/fp6dYgTBEqTtBSyJQkIuapTdaa86E/dEfldWf/d3D+1kl
-D+O/kAECFix5AOQJPIgwocKFDBs6fAgx4kMSAA7Ko9cpo8aNHDt6/AgypMiRJDNeOkhRosqVLFu6
-bAiAxMFLJWvavImTJCSLBV/6/AlUJUGDAp8wOYo0qdKlTJs6fQo1qtSjT3gSDYo1a9CUAi/m/Ao2
-rMiTArlqPYv2Z8yDBzy4fQs3rty5dOvavYs3r9tFVtP6/ctw6MFw4AobPow4seLFjBs7fgy5cLi+
-gCsDNstgmN7NnDt7znsAZUXLpEmvFUhTrOrVX3d27Vk6NlbBRafavo07t9T+qq+vyv7t0qxX1sSL
-jxUNPDnW07BSG38OvZPrgbCVW4dIG5ZR3dy7e3/Km7rv6+QVCscYPT1xsrDMln/vkLlz9fTBTs8O
-H3727d/7+9cdHn75lXdefQZ+xZ57Ay4Ii3wHPmjTfdUxeN1+/12IYVQBTkihcgVCCOJxZY3W4YDM
-BfJZiiqueNcwlJWoXHbfhEFjjTbeiGOOOu7IY48+/kjjNy/CCJxZfLCIZJIrBoIckfA5GGKUHkk4
-npOlWZhhllpSNaSVpX0oZZgmNenldVCKGSaVZcqG5ZZu/rdhlWv+BSaaUSZI4pzAnWlniGrqaVmb
-bw7aXZyAWlZnnxDieej+njIJNA89kk5KaaWWXopppppuymmnkvbRZaNnZZfNF6aeimqqqq7Kaquu
-vgprrKZmE6qoWZklQCme7sprr752Og+ZtlrG3Dx3HItsssouy2yzzj4LbbTSHktMrcMClZ0WVWzL
-bbfefgtuuOKOS2655m6rhbXX+oQrIdO+C2+88kob7IjrEvtoc4pG+ee9s1XHH6EC42aov1gluq+B
-jBrsF58JG9gvwz4JOnDFGqorsUQIP6zewhlr5TDH6kX8MUsUW4wyUwWX3NLGIkPnMctAMXdAOzbf
-jHPOOu/Mc88+/wx00DbPgbHMgVUHhxxKL810004/DXXUUk9NddVKw1H+tNHmkcgAFEJ/DXbYYgcd
-mr1aq5XvfC+nR/LZDp2cctxc9ua2xiQOt3bHwta9Ush5G9c23wrBLXfKKwvOkMt/sxYz4hH5vThr
-gTtOd22FX87E4ZQjpHjkYjW+OUxpew7d5JQTjvnAmofe3t3okV4c6KwrdKKStt+Ol4uVz747YZH9
-Dnzwwj822e68G4l78srDxaTZvDMEOez2Zc036qkTunronUuPk+zPCxQ99ziZ7rj117+Z/ebbi1+T
-99+Hz35N5CNu/vlbpk/5+vGP5P7z8O8/kvkJrn72yxL+HKc/AIKkf7xjzjkGAMEISnCCFKygBS+I
-wQxqcIMQbAX16pb+HXN0YYQkLKEJT4jCFKpwhSxsoQtHaI4Pug0zzuCgDW+Iwxxu8Bx7+95B/qdA
-kAiwegArIMoOiLgEBrEjDJwdEJfYkSGCsIhGrBgSBadEKGqkiax7ohY1IkW3EbCKcJLh2bL4RS6G
-rli/aqMb37gpUBlvdqSSlR3viMc8xopWc2QdrnQFx0AKso31ap0PF8IcREhhkYxspCMfCclISnKS
-lKykJRdpAzNqLTvXOJcnPwnKUJrrGpo0Gq6occlUqnKVrLQkInp4SC9+UTqllNkYydifK/INjVpU
-4+Zk+cUwnu2WuPSOLuvGSyj6knLA1KIwN0nFYqKvlixL5hKX6Tj+B2pgm9zspje/Cc5winOc5Cyn
-ObfpwT6GLju6aIA73wnPeMpznvSspz3vic98ulMX1CwZDc8J0IAKdKDm5KHzDvnDfC2AHAxtqEMf
-CtGISnSiFK2oRS/K0Bb082PZyUUsPgrSkIp0pCQtqUlPitKUqvSjudhoxoSzCozKdKY0relFFwBL
-HzJnoTbtqU9/SlGNqnNzHV2pUY+K1KSqtKVDzd/dYgrUqEq1pzg9KEIbpNCpanWrFhWqeHxYVKWK
-daxkPSlTv/o9mHJ1rWxtaFUNedWEHoSnba3rVL0qINaFtax87atSz5pX7T3VroSN6lsVhFDm+MEN
-jG2sYx8L2cj+SnaylK2sZS/LWC+4VGLZiUIzPgva0Ip2tKQtrWlPi9rUqvazUdgsw4yE2djKdra0
-xawfcvq+rBZ2tzbFK4f0Wh2P+nW4xEUpYH8rWItAlbfMxehh83TVnTZ3ul11rcH2Wtzsave4clLf
-YKkL3og+N65yFQhdw4tecvi2u6cLrnbfm13u+lCt6U3veMmL1bnWN73rBat74Qvgvso3rd/dL3jv
-S17m8EIcDG6wgx8M4QhLeMIUrrCFL8zgT1jXX9lRwSQ+DOIQi3jEJC6xiU+M4hSr+MMq2PC9MLMC
-DMt4xjSu8YV5gVv/6dbA1O3v97Ab4CAndcDPoy+Pp4vguEr+98jT9fHzgCzkKC/VxesyMpN5m+To
-7vjKu3Uy76As5TCXlMjHKzCXC5vlxOaLADpos5vfDOc4y3nOdK6zne+M5zYbgMrXyo4QqADoQAt6
-0IQutKEPjehEK3rRgBYCn4eFKxrkedKUrrSl8UyAHDcwX6BYhac/DepQi3rUpC61qU+N6lR72giP
-tlV2IhCKWMt61rSuta1vjetc63rXvI51BFotKlxZQNXELraxj51qUGjaiVs+s129TMf/innaYwZ2
-o6zs7LqmOZbNzjZboQ3cqwiX2uQOKZlnh21vr3XbOu22urcK7nVKu9zlPrcfzfxurrI7twe5hSf+
-DfCAC3z+4AQvuMEPjvCEK/zfxbD2obIDhldIfOIUr7jFL47xjGt84xzvuMTB4HBAYSYBCy+5yU+O
-coXfYtlddHe+pRpvos6b3tS2d3K7styXb3XfOtavzrka8/aKm+b0trl3lftzfbN8jS5Pek+DXr6Z
-Ez3MRncq0p0+VZ5v2udYjyrU6Sf1qUe56gjEd9epuvRf5svfKW+7299+8IY3NepXcQAg7o73vOt9
-73zvu9//DvjAC/7uDgi5nkYO98Qr3u0rt6qauX52n359gGEXe5DJnkSzR56mWmc25Ddf08kTceiW
-FzPmsah50Ds37cxsuuorKvopkr70Uj79LlP/+op2vuX+B+k0sn8P/OCbmtVzB/tV1NCG5Ct/+cxv
-vvOfD/3oS3/61E++Ggw/J2ELf/vcB76yHc/tg7D50uQvv/nrvOfiU/4qQui1+98P//jz2tHqv/1B
-BCDp8+t//+TPNPjb/Xm5d1GxJ0aVR3vvZXvIhHsCKFG7x3QByIBBhX1rAmYHiIATWCbpFoET5YBq
-B4EbGFEEOEwGaIHFlYAztIAg6Fasl035Ug9eAIMxKIMzSIM1aIM3iIM5qIM7CIOJgIFekh3rEABD
-SIRFaIRHiIRJqIRLyIRN6IRDuA4/aCWYMQE8aIVXiIVZuIP1wIKIs2QqKIH1J3sHMW4lCGAneEYp
-CIb+Hdh6HwiGDSWC0DR7ZghfaKg1GviGK/h//GZeeThRcWg0FUiHw2WHpqSGKsiGLeiGeQiItkSC
-g8hXhSgzeOiHieiF+bIF9qCJm8iJneiJnwiKoSiKo0iKpaiJgiCFTpIdrpACreiKrwiLsSiLs0iL
-tWiLt4iLregKqUgkZiEGpgiMwSiMw2iKW9CFgsMcX4ZcMsdedDdf0IVu0Bh+P7aMQudfzZh5h4RY
-0/hk1eiM1IiNqKeN0qhTvUAC54iO6aiO68iO7eiO7wiP8SiP7zgK3gh2ozCP+aiP+8iP/XiO9RiO
-t+ePA0mQBamPvUCO7wMAC8mQDemQDwmRESmRE0kokRVpkRYZkFN0kRvJkR3pkR/pkBmJgiBJkiVp
-kh6JXympkivJkm4TEAA7
diff --git a/Documentation/DocBook/media/nv12mt.gif.b64 b/Documentation/DocBook/media/nv12mt.gif.b64
deleted file mode 100644 (file)
index 083a7c8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-R0lGODlhFgFnAMZnAAAAAAYCAgAASAwFBQAAdEgAACQODkgASCoQEEgAdHQAADATEjUVFHQASDsX
-F3QAdE0eHVMhIABISABInEhIAIM0Mok2NI84Nk9PT5o9O5xIAHRInFlZWaxEQbhJRgB0v75LSLhQ
-TbRTUcBRTrBXVatcWsJWVKdfXW9vb6VhX0h0v8RcWZhpaJJubpBwb8ZiX8ZiYI5zc4t1dYd4eMhn
-Zb90AIN8fH9/f8pracpta8ttasxzcM51dM52dM53dc94dkic39F+fNOEgpmZmdWJh9ePjdiTkt+c
-SNuamd2gnt6lo3S//5y/nOCqqeKwr+S1tOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0fHX
-1//fnPPd3fTe3vXj4vfo6Pnu7r////v09N////35+f//v///3///////////////////////////
-/////////////////////////////////////////////////////////////////////////yH+
-FE5WMTJNVCBtZW1vcnkgbGF5b3V0ACwAAAAAFgFnAAAH/oBngoOEhYaHiImKi4yNjo+QkZKTlJWW
-l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGmkM3ysvMzc7P
-0NHS0CjT1tfY19XZ3N3Y297h4sxDlQDj6OLn6ezZ6+3w0u/x9M0A5r/3vvq9/Lz+kQDqEpiLIC6D
-txAyUliLIS2HsyDKkniIIiyLrzC60tiKoyCPq0CqEpmKJCqQJk+lNLWyVEtSKPPJ3Ddz0stRN0Xl
-DLUTVEyaQPvVlNTzU1FPRzsl5fRTaNB/QwNGHTi1IL6nu5Zu0qqpKVSsVME+4pqJLCazl9Ba8oqp
-jAIA/gTCIOXkVsAVo52OAABgV6kmMxr2Cgbil9LLGh/OIJ6r6QgBLAfuMm48YYzPT1siF7a5qUyD
-u1HibtaUWfLoS55NT+a0+DSklqXPxK5EJkuhm7NdV8pMYW9i3YJsT8q99Wqm2MQn/cihZRBuzasv
-RenrdgnwM8uFQzpSOfrrTcihW5KyogiYM89VF9cUWq7i3+sRTVlB5Lyj6ngNd/58pn0mMUmY4ER6
-+R2nGWCEMbUIGQE2QUYj3Fnm3VibIPgeJ178kEFz4Imn4F8aEJbcWY18EcQLViziVoITOvLSFgXA
-5R4iVvxg44045oijByAU0QMIQAYppJAwPHhIFILx/qUeieDFCIB1igjBg45U4nhBlVSaAEIQYiTi
-2IzXLbTKF1mUaeaZaJr5RAc5aKeIFStw0RErVehARZp4mrlAnmlCscILU8yp3y5iILECBI7AKaeg
-q3DxQ5cuMgLgCg5uZBwuTpiAhBgQKZqRK45CKqYiftZ30aW1WEFDEF58xIinn4L6aCMIabHDDhye
-OqgtYgSRonOLwBqrrKImglAQUjyEalg0xjlRLKEuotayFIoliLC6whKtsVVFai222Wo7KyLT7kpU
-VeCGK26xhJTLmblZGZKuuutW1C2tUc1Lb7233TuqU9c6m9At2wJrLb68JEEGP/rG4u4iBaPnr7S8
-/ohhgsRnNOxwLgU/LJVh9YR8Qwsl3HCOCyHIIDI986yMjgwkzKBMyy63g1LN8JzAgskoq4wzOzT/
-3E0MIIiQggM2CG0ztbW88MUZDAgc7y5aFlHBCDsk4ebA8NryxQsZd7DoV7oIQcQKBpyhRRM/jOCE
-VV3X8kQRcKYtCBnsNsQLFHSLPQjecL+bi9lxApCFEjuM0ASzuXwNtdSMf5yLlkQEAcIOSmzN9S5O
-A6Dxs3HPogUIOSBhRQATy1LEE/d8vq+3t5BhhH0YA6zLFELo47qlocNChhC/unowLRYzDLnevbvy
-e/DC265LEqgPsntITCsPvCEef4fV9CVVz8ry/vYOjzwh3KvkvSrgh+985AGPDbrgvl9PbuoRNev+
-6wjHzzz29L8v7/G8g18r0sct8SkrEeXTyfkigaS9sIgRBCwge/bSlzBNAjAV/BACAXgIGAmmOxo8
-lybK8AC5TGdJh4igBAuhOUaUYQOWqQEIMVGb2jVGAh6iRA0N9iYOFmJE8RFhJ/CzIPn9qxDZoYR/
-NLEcBNClAUzIISWWw6FO+XAQQOzKAocjxUKoUBEImY+pIAEY+GhCCh0wT2OAkEVJkMc8EtGYB/cC
-pRBKjjVmTKER85fCBhlpEQ2c4SYGEKC3XWILCQhDGyUBIBNE4BG7O0IGtZg8SkRIEV+k2CJM/oSi
-R0gShWs5Q4aYY4kaiKiLlvDCBUjZCNcRMYh3zMSXFuEDHGAJS1e65Y20xKVGvPJNurTSjUbQox8N
-6ZhAosEf3ZIkADxQXsHU0QWI6SNkIrNIKlJAHSkpwEvIUEKK6AKfxrmncZbJT4BSxBZUIIgTlsic
-ZyrnE1bQJkws8gxkgieaIEDPFkaiBlCapR21dxwn7UWQTErEpCqlCMBQEJRrKdQKnkAaVFKiUB2g
-aEEPCk5YEpRshygV7VwRAU3lbRaZQsIA+qc+kBLCVriKhaos0CpcqIpVNpxaNwNXCGTJoldWyJ5C
-fcVDl35Up0blKVJjyT6lNvUgW/TfUp+6jzkhJhWqBqxfJQ+4Pqd6FXZXrepUv8rHsWK1q2e1qlnF
-SlVbsKWt4wurW6O6saxKFa5gZCn+5mrXiijNZn8FWmDTEbTBuqMSHDDsODCgWHEwtrHeeCxkucGB
-Y1j2spjNrGY3y9nOevazoA2taEdL2tKa9rSoTa1qV8va1rr2tbCNrWxnS9va2va2uM3tLQIBADs=
diff --git a/Documentation/DocBook/media/nv12mt_example.gif.b64 b/Documentation/DocBook/media/nv12mt_example.gif.b64
deleted file mode 100644 (file)
index a512078..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-R0lGODlhoAHkAOe1AAAAAAAASAAAdEgAAEgASEgAdBgYGHQAABoaGnQASHQAdC0eHigoKEIlJEYm
-JS4uLlssKzY2NgBISFIyMQBInEBAQEhBQUhIAFBBQVhCQkhISF5DQ2NDQmdDQ3NEQ05OToNGRHhJ
-SJxIAItHRY9HRXRInJdIRlpaWppLSaJJRqpJR7BIRa5KR2NfX7JKR2BgYGxdXWleXmZfX31ZWXJc
-XHpaWQB0v29dXLZKSHhbWolXVpVUU5JVU55SUJhUUqdQTrpLSK9OTKRRT6FSULRNS7hMSrVNSr5L
-SL9MSr1OS7xQTsBRTrtTUL5WU7lYVsJWVEh0v7deW4pqab5dW8RcWbdgXrZjYcZgXnd3d8ZiX8Zi
-YL9lY7RoZshnZb90ALJubLFwb8prabBzccpta79wbsttaqx6ecxzcKt8e4aGhr93dc10cs51dM52
-dImJib97ec53dc94dqiEhKeHhkic39F+fKeKiaWPj9OEgqSSkb6PjtWJh5qamqGamqCcnNePjZ+f
-n9iTkr6amtiUktmVk9+cSL6enduamb+jo92gnr+pqd6lo7Ozs7+wsHS//7W1tZy/nOCqqbm5ub+4
-uOKwr+S1tL+/v9+/dOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0d/fnPHX1+Dg4P/fnPPd
-3fTe3vXj4vfo6L//v+/v7/nu7r///9//v/v09N//39////35+f//v///3///////////////////
-////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBH
-SU1QACwAAAAAoAHkAAAI/gBrCRxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJ
-sqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtapV
-h6QkWdrKtavXr2DDih0rlpFWsmjTqkVrdq3bt27bwp1L16vcunjn3s3LNy2jVRU/MKhAuLDhw4gT
-K17MeDGCwY0jS54c+THly5gvW87MufPhzZ5DcwYturRkBGkqvgAEdPVP169Z+4Q9W3ZP2hJx89St
-k3dv27uBB4+tWvhO3ziRJzeeU/lN5zWhK5ROk7pM69eZL2+t/Xl3hthj/oZ/OZ789+jn0ROnWN5l
-e5bv4aefGX9l/ZTx7+Ofn537+tr/5cZffwAGeNyA4iFoXnH+FejgcAb+xmCEzSm44IMQ3mbhQPqh
-1KFJH4K4oXwNajghhhJSuJ2K3p1oIoopvgjjihOFWJKNI+GY44j28dgji+D5qJKOIRFZpJAeIpkk
-kAvZOMsBAAjQykdOHhDAJ1QqSVAhAABwpUcf0iJCl2TS0ZGNmZDpSJYcpekllmfyaKMXNtRCZ0av
-jEJQiIUIAAoBcMbJUSEUxHJkQa+wglEpgGKUJ4da1vLkmn1OiZEsoUC6USkDrJmJlIKyF+ksCWD5
-qaUWydJFHagIhCOj/oFyFCKpsYIp3CZPRCKLRXdeumqrs5Zay6kaxTGGniESS2uoNUYKay3PZhQJ
-FYnI8mqjtm5KwAVd1pltQangkYUnFEUrLbUtRGqnAKocsOZGmlDxRwyRZvLlpMwKqC2W5mLEyh5U
-zKAutNjme5G9WOJr8ECerJqKRIQautG/RsjRkRcAFNrRK4kUYQZHGHt5wbsb5edso/1mFEoQVrS6
-L5saEWunt7J+N221DyncUQ5OsJrRk2Z6AWpHN1RxbEc6a2TyRsvKjJAncUQt9dRUT/3DEUgcofXW
-XHc9CEMpK30ylmKaaRAebFSt9to/VLG21F0cQYUmDkXMENRvs13F/hFLXNH131wvgpCy7t6dt9pt
-L3HEH20ADrgWuyrktNguXlT2zAulEsrmnHfueec6KNEFuQt5QoUpYBdc80aXh11LJ2Vw8vnss+dg
-B+2cH3IEHg8zBHRDmuNOew5mPDE6RggTXOtBwQvveQ5oUDFGpnefvtCTNJcsp7qcRomqRq8Q4nFD
-pqMuOZlvLmxR9wCQbJApcbzSbEKoGEt9Q5V+9IoPSlCyEZddch/4dsCESjikfAl5UrdgNj+eUOIJ
-h5BBehB4oZTAT34R8c0rDvEEA8bkgTvog09AKELyWa8lS9NJw3wGHQpW0ILxy6BxHngIDL5khagw
-EkdwSB0XkkhU/jpBxRhIVwvn+NA9A4PIBSGiG0z4LCZCJJ0OwVcHKU7whEis3IEScsQstmSJDpmi
-+ipUOix6sYEz6uIZWQLGIDFJPVw04xplWCKCqHGOK2njdJJ4KBbd8UdAjNAfUchHiegRIWJcnYoG
-OaTt1bEWjPwhTA5pkERq75ECieR+tBgjSMqRPoWcCCX3FMpvoUiTmwykg1AJSJmM0lWlHCONMvnJ
-BHHyJtWCDStb6coYHsSSlPsJD/xgx1raUpU6ecUTisiaXfKylzYk5Rtn8ooi2MaZS0JmTjaBB2Zi
-s5E3McUaeifNGd1kE0OQzTdPEp8TYKEv8ByLGvRgCQ1IoQmK/oinPr+igXfuE56IOMIU3iCISWyl
-n/9M6EH9qdB9qiEE7zQEPhsKTw3woSIagIxpNqoYFmCgAg5YQQY4StLEGECjJTUNDo5AAhMAIQUg
-aABKU1rSk9L0pixYAAM44IKR3pSjBkiNNm+SiixA0gh3mCZL8AAw1I0iEj9Igv9ktJOivmAOxoQj
-GnNSiT+YjgaykUU0W4QTTHj1hC/ww1jJ2JOu1oAJ5quFWNm6VZww9XQvsMMizrCESGwRJ0X1JOqA
-mRHCXoSpSK1FKPbaV7rqaydPOMIe6nCEKCzifp20SRYeVj7DXsSzFYlsD6xwhDNc9q91tckojjCG
-Q3giXUpl/skfPPjVWCpyJ6sdww7mELkMPRYnsgiEomAZ25Vwk2GJNedMgqso0N6yIc51iCzwQERm
-FlclyiTIW+OKWuBSl7jKbZJtKTLd6lo3vDDBmauwyl3H2qS8mkJvQqK7EPgWhL6/1dA6s3kT+4KX
-qnSsiX/LCeAt7ldE3jUvfgOc2pcMmMC+hdCBSbJghDz4vAV+SIUJcuH4ZpiuExbJhgvS4RFD15Ey
-6bCHI9zdEIPExAJRMYzF+9yUqHjF3Y2wi00ZkxvPeI81PsmNcZzZHAvWJiYe8o/ni+KYlekhQyay
-QBIlETd9CXzIGpiYrkyRR1WSOc5kX8YkdkmMPInLChxa/n2/C2SEYPZ6VgrUmZcX5Db/TAFTSh5D
-oizlWuBKVzkrgaG8oLGMqKoONxhYISSgOokc2mV93qXrgmmRPv0pUHfqlUL4rBz7McTS2AI1nYeq
-YT4mzcJsPnFCwjWuKqtZWkYQQ2/NnABINHoiN+utclg56cJqKVpNe7VB+Izhg2yCCnsYrkL61ev8
-MpgjzZZrqlWtkBWSkyFiyp5GYsAFKmxCI4WgQ7Qd8i9v//cgqBSzAH2tkWg9q9fELvZBZJGIXM3a
-IMy+dZ2Z/BFNo9q8bmRIrhfipkLXLBS/ukgpCtCKcT8E4axqYVYRUgguU1rh2Hq3vqUNcH4zJBV1
-aDVC/vI96gaHMYl2UwgcwnA4xLmt5XGI29zwZ/GnwVxqbYsa1hwHOMEZxAtmmjTebj41vhGB53/z
-uUNOjZEPuRtlG1850eOQ85tHtg5rVR5BHH7yfUMkfws5hfOGd7uxh0J3vGsI0w3SPLPbLhQPPB5F
-FIg+s4HL7J+Lew1MXbjbYhxOwf4eQcSO98293eyYoEIWvn0QkpfZ5BQhNJl5jJD6TW8hpYCCQPRc
-sj4Q4glTzQjXGRI+0MubV+8C++P/LpDL+fuz6eEYFQA9ctWNPuCQl4iYxyzLWmywgw0RU5dqnpHQ
-1RDaG48IDTEYIvYZfPUUcdPw+TUA70HfIIlPdkKk/v8m7hM/9zRm0fJh0jAh5AEnOISwkYs8kFGc
-4Qx6Oib4tVoQJ0LaJVFcchS/fN0XFqQOdANKXkcgHzZL6+de7Nd1/UdImISACUhW81cd43VxLOaA
-FgiBznaAGFiBBqiBSNZkBfiBDdiBDyiCpHaBJihfBBiC9PdsHLiBHtiCMSiBAyh/LwiDKJiCNxh+
-KmiDO0iDCyhJGViCMkiEQNiDMJFCSOh/MyiAQfhMTDSBFGiER/iDVdiECOFOFPVPCLWF8dSFXlhR
-DBWGeQGGZFiGY3iGdGFRGDVTP7VRNvWGJBWHcghUbliHnkGHeFgaeriHeShUEeiELFiEJJiDVxiF
-/iOIg4YoiIPIiC6IhT4IiUkohey2hOoniUxIhStohZuIiE8ITp+YSpbIgCdYiIpoijrIiZFYaomY
-ipiIR5q4igo4ikKoipPYioRIbbQIhbF4i6HIX0O4iJ3Yi5kojLKoi404jMboi7sIioGojKcYjbko
-jYfIir/ITpTYdNloEUvmccn4S9vIjeFYitToiK9Iis94jK5IjLC4jMWIjLb4juUIjfOojjxoEXM2
-ENJnd9r4M3Gmj9M3hRORj5unJtc3kP9YkOlTiQfzZJICJcImjhmxjwJBkAwZjF/nJ9gyC3g2LN+X
-jhSnkYAnaHbyfDUYkpdWkYWjerCHEaImEJzi/ikRCZIHwZF59iWZpm0SeRE26ZGf8JICOYusVxBr
-R5O1tzyTc5IJAWzCkpRKeZSbByrL0o9M4y6BF5Rz13e3d4+PWC63tpXeOJQDkW1YGRHmIjTtsm5P
-2XjYkjxF2ZUVASsaV3Jw6ZVwApZhWZdmeWuvBxFedm7rUzAFN3k7uSiqgzEmWZhTpmwQcZbDNzJd
-Fn+nxyt1MpcVgSl9Fnk0g5eIBIKBWSspNxGPBphxeWsVR5fWaJiAdwBBM5N19Wf3ljrL85b1lXB8
-ojGWWRHGkmX/Y3CcCY5riW+qw5IUkWtOd2u0mZpDSThqmVqs1nFLeWtOCRE3A1sZAXZXaRHx/jIv
-WsKSv8l/5NiYBSN5GlFuAtNuGad5PnmRn7l5X/Kdl5hJDuMQKYM9/rIHFZMR5Nl6IhA0OjkRHDM+
-GLGfAwGf8SmU0Yc+V7J7iSkRK9MyDUkmVyJ8C0mVFuF9WAJA7XOQAzFw26egn0B3/0kRPPNE5VJ9
-ZFIo3eOaE1E0RxOXKNolFHAJIMqenqgSQzd1V5M1SMc1X4OOJoE2U0c1Vfc2MheAG5GjN9c2fOM3
-Pbo1SocRStpyibM4jfOkRwA5vIigJ9F2hRc6cldtE0dh2Qg7slN4nXN4uIN215YRXup2xROmKPGm
-zgM90vNmTzOmfWSUKxE+AlpG7eWMJ/FK/lxJEJaHp33KP6G3E69AQB5UPYGKjcGJEjQkQZDKjChB
-qHk5ZRz0qC9BQiP0BCF0QHoqYp5pE+kncZEqqJnqS8opEONHfr/SjXY0q/OxY8FJq7Wwf6RZTKvK
-qq2adXlpfzLBq7rqe1XUqwWBq7k6jqXIrC35Ra6Ke/Eoj0eGqXq5jtdKjyWhqQdaj+oIrc3agOIa
-rS7hrcoKrtjqq+b4qkZWruZ6rtPamdcoqehWqvbKp7UIr/Eqr8KamdpKgvwannZGVQOrmC+hqcf6
-rTB4sPq6sATmsJPqEYQKsem6gRKLkdSqE7mkTvhai5M0rwA7jTYxTOyqrgxLTcvkGhk7/rEfMUoW
-O5k4UU3X9LHA+hBaqIZ0IQhkUE9YIFH5pLNwYYZCKxaKsAWNwE9pWLRrQbRMqxaCgAL+BLRPmxZs
-SBEZ5YehQQIeUAEGMAE9pbV5eIdiqxgbcAQqMAIdYAGE0Ydlexlu+7aTQQIQMBg85VNyKxlB5bIl
-sVm1sF3NOBKR9Qd4sARnkAg54KwaWxNZAAOA0LLjWlVG5QnJ9Y0qcVdOBVVSFbhdmgVXZbNAmq0x
-0VW1FWP/yq0uYVYUlFanW4034VZwNRBzhYqFahOYm1eM5Vfs2LlHFrMWi1hJtVh8pbsoO7IxEVmT
-VVmnVa0o4bedpbiiKxOiRVqmhaiu/guPqsVarmWdlqsSs0VLYFWvI5FbuxWbtFuw7yVcxtuuM3Fc
-mVS5zGtj6uu7p7pc00a/ybRMAwG43asS9oW/BMsSDwbAOaFeRcRe/YsS/kXAiyvA03axJIsekBvA
-DlxdDBy9NvbAEHy9LTLBDVzB9wW9N/rBCqzBG8y+K+LBI2y/AHfBK+xgJnzCqHuEKsylMFFiIuyu
-OgzCm+qOL1TDG3vDMezCO+y/Mby+M+yIQIy+MAydMlu8MjwSnJbDNoyAS0yvKXbETxywQYyQFrdl
-qElsyEFlS5eQYtagD/EoHWKRtQBAH5kQfxmfrJSPFOqQ/ZqgXWI2FLlnWvzE1nsQ/ntsZahZxF0c
-EUApEIuWfBxXxbD5aSIJk4oMEYeWaC75yIiMxnuWcAeqSYdcoJFcxRDRkwgjym8cY338xJ52PR05
-yiRJoAj7wnY5EKRiayUXb0/8nA3xdINMnbFmvrq3kcJiER76xOnGlyNKwmXsPrQpxt9xbNqndn0X
-lYJHwcApegUTbpNmy1sMSfO5bBkXo80pEdxmbkPJKNwCAMfMEOXGeEZUqiljoFGcy7aXfPEGHfRm
-b7I5liKQzrAMynt5lwznOtq8zQIxzMK5PKfpaxB3f78MJ24ZzROx0Kqaz1uCyRjsEK/Xl7J7yusL
-ciKXEL0ymGVZuxMRLUCndQYh/nVDWqSHc6RQSZQQbUc6+nI7h6VHEKWQ7NBDo2lTenNGZ9M3jXmq
-k5z9PBGh2caYrNJL+nIwd3XCetRtXMqETNIN/ZDoAwD8KBCEh6ahoKbOw6YvTRBFSae483Zx58QU
-/SyXIxBk7Tx692vDadEXvRAsSZwFsdV459XCk3iLF5LTTNTYO9UP8c6fLNiH6s1w4gWpx6JM5Hmm
-15610DqFjRCl5z/HKWes6XcV4cqubKMGIXu093O+qZ6c98qCzRAY6sm77M+/56kGgaHOR5gVYXyt
-S3A1yj7hzBCxqh+pbdembZYxmjGiENxy7c+1kH2MWRAMCgtjUqF3fNooHKsu/lF+53cT6YfE9piL
-7gd/SVzNM0KsMJF/VFwQvJqyHBywAHjeTLy7IMveW3q+KFzI8N3d2R3fXBzBPezDoXuO7a3f/R3Y
-/v3eUCzg963e+T3f9W3fBq7gDI7FnJuvCfzfA36zxo3f9L2uAU7gC+7dEa7hG47hGS6KyJzgJF7i
-1mrhJm7eH37iK96OCA7iAP7iLN7gKe7iBX7gEy7i8evhNA7j8p3jwLjjFC7jNr4QOVu1buG0SD4W
-Sr7kYtHkTq60Ua4WUD7lXHG1E5G1eZsZcbvljNHlXr4YYB7miDHmZH4YZn7mbQuII+7jKF7jEn7j
-F67iPT7jc77f7j3kPy7n/nAe5y1e5H8ez24e6H5e53Y+6DjO54hu6Hge4kFe1EAO4UKu4/zN4xw+
-6Y+e55Su6Zle4YSu54p+6Ive5zFL0Ize6JEu6e5d6kTs6KrO6a/u6adu6X0O6m8u6nR+54U+67b+
-6Zsu67pO66M+7MQO6Il+68bO679O5Ki+58je7KGe7MHe6w5+E3F8rF62ZHGM3dglmab+Etk+3s5+
-7A2xx5EtAlK9aZrcIRR5xrINZbY6kXbsxqstu5rM7R+ax3Wcx6K57koSyAaZKvGOPA4pyCO93hFB
-ynCSyPWOEMaJJAoPzwVNBSbLk6v8JVAdEcOsHwq/dZN9EA9vZhcfoivJ/tgOMS0Vj48jH5PDYvLA
-Dp4agS+z/PEJYZ7qMikSLxCs0ANMwHj+6AhTaRHrLOhw5j4aDRE2zxGTkp0XsfM9X5WOoCzB/Nwv
-n8/YTPMK8aAM/ZnqpjR2cO9cvy0LZBESzT0FA89a/zJoGdPc+PUm+pkPndvQfekXcScL13D61tNU
-WtNYitM/p20JbRB6/zY516RA7fcCcSdxzzBDKjU/bdOI//cVLduDnzdX0zeHrxCahpjvnkkr7TaG
-D/kI0SshEwCQaaFtrhB2c9Ku09bCA6Zo/RBQvXauXzt2cNYXYTcyo2m1Tztv3ZtkRvtcvTmwf50a
-8ztCM81szdW2g/uV/maSgD3u1V5pUgkldeco4vMx1xmR0b8QMvAFj039lqLW/VkRlf3tjvw9GQ+g
-2Q9uQ8OcGvH94V8Rdj2dqY/vo5+YBlqpSkKgio3IACGgVS2CBQ0eRFiQUhEwrxI+hOiFQqyCtETQ
-qVWKwCeIHWtRenLIYa0XgDyeJCiRYsFZBzCi9AjykAyTMDuqLJgpAEeNHG1CXNjw50OcB1vaGAqx
-ZNKCS5kaLDUAwFQAEwn2fErQU5c6qEjWzJpRKlUKosZaDbu1zg2wWaNSrRrrLQBHTNV6bdr26dyp
-EwsJDFvr7tfAYuH6pVo3sFq2hflWdXVgKtLCBJ0yvVxZs0FUYzzl/t0cmrNnwqIrd/58MLPpwKhB
-sw7tejVszbNt2qZdGHfurLt5P/X9e2hw4T+JF0d5/KFy5B6ZN1+uF3rS59NVS7d+G3v2k9UNeude
-Orz28cO3l08Inrt66+zZtz+P/rp8mO+h278fn75l/R3xN/+vuAAF7I++AYU7kDf3CjSQQfQSVNDB
-8iDMjULYFtyvOwnHs/DCDcPrkLUQRcMwQ/8+XA/FFE1USsXsRgytRBbTc3E6GGOsMb8Zo9sRIRl7
-fA1I/oT8LkcAjTySyCGBQxK5G2trkkAlxSPyycp+FNJK3aJEkMsIp6QSSCzF9LLCMs2cUsst03RR
-zcDc7O1M2uBksRJMOjFz8QQsLOGzTz//BDRQQQcldFAN9iw0UUUXTfRQRh+F9FFHI6W00j8ntTRT
-SjHVtFNFNeAjKzciqKBUU09FNVVVV2W1VVYfINVVWWelVVZYa8U1V1xv1bVXX1Hl9Vdhew12WGNn
-feARMJdltllnn4U2WmmnpbZaa6/FNlttt+W2W2+/BTdcccclt1xzz0U3XXXXZbddd9+FN15556W3
-XnvvxTdfffflt19//+03IAA7
diff --git a/Documentation/DocBook/media/pipeline.png.b64 b/Documentation/DocBook/media/pipeline.png.b64
deleted file mode 100644 (file)
index 97d9ac0..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-iVBORw0KGgoAAAANSUhEUgAAAlgAAAEcCAMAAAAsmToJAAAAAXNSR0IArs4c6QAAAwBQTFRFAAEA
-EAEBAwUBCgMBCAUKAgkMHQIDCwYXFQYDBgkVDwgFCAsHChASJwkDFA4NEg4TDhANHgwHDg8aExAG
-DBEjBBUZERMQCBNRDxU0ExcZFRgVFRcgCRkzHBcUDRdCNRELIxYTAx4mLBUMEBwcEhsiDxwhExsu
-Dh8XJRkQByAtDCMUHx4bACk0DSsiGScsFCRcJSUiGSZCDiwqGCg1LyQbIycpVhsPDy0wNyQVECxA
-PSIfCS84ADJCEStWRiIULSwpADdHCDkgEy1/BjorEjhADDhXCzZvITNPUysQDzs8MjIvCj04BT1O
-PDEoQjEhMDU3LzY9KTdFTTMYNzk2GD6PAEpfEUVjBExFCEpPB1ArK0FjKEVZYTscdDYXG0d5SkA5
-FEiJQUNAOURPAFhCA1RpP0ZJVEMvYUAyBFtRWkYnDlR+QEleAF1jkTojHlV1AGB4PlN5YU87cUws
-SVRXAGaBWVJKUlRRRVZlAG1PWFNSBGt5AmqVAG+NAHNpK17BWl9ifFs9KWmnSGZ0YGFfp1IuCnWj
-AHuKbWBXoVNAdGBPDniWAHujTWmLk14rAH+ch19XX2aRX2t8AIeLiWgvAIeeAIaqa21rOnehdW1m
-AImspWJYj2tLW3C0AIyvWXaNAo6xb3Z5dXZzent4WIKiQojAen+CkX1pcoSWcYDOoH9fp4E+Y4ur
-hoWCXIvGb4mut3xpqYNYnYdUO5rDyXxdjY6LYJqk0IRGb5azXZnMjJGUgJWqpJB8l5aUyJN4kKK1
-rZ6IYqzge6Xho6GdnaWpgqy6yZ9zvaR0hqzMk6rN5Jxxw6mF26lbq7C2pLTGwrCbs7Owvb+8zcGc
-8rp42L2xsMbY3L+jtMfsz8W2nM/yx8jH0MfA7MWU78h/3crIyNTo4NLD6dK1z9bc1dbT3NXOv9vr
-/OKSwur8++Gw4uTh0ef78uPU+OPL3Ojz++bGyfH36evo/+3b6vT88vPw/feu1/v+//bb//nK/PnW
-5f/+//ro+fv49/7///37//71//3//v/8sZeTnQAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY4AABWO
-AUTUBDsAAAAHdElNRQfaCRQPAiJBEFMLAAAgAElEQVR42u2dD3wU5bX300nWws50shA4lyTGikRE
-Qy0aUChKvJZqTQGBFNurVo0FWq2VqhAq0hc0t1rAxtLLpu61cUl6gWtNe3vb7Z9IKm+Xqn2tkFih
-GmwFA9Xwpw1s/UOyCc97zvPM7L/sbjabXTLZPL/PhzA7O7M7s893zjnPmec5k8WkpNKgLPkTSEmw
-pCRYVlSjp5n/3+3xGGsONHt2vx1t04PNTbtP8aUujxAuHvN6XjHe721pbmqLsp/H021+crP5wce8
-Ta8Evi+wKMHKHKkwjf/vA+D/77SrAKDeeTRiO3/vcnzDoTzXgy/+CEKMbVdw5dh9tMGubAfuuMjf
-E7HnfgAf/X9yJn6Aupqv206fNfYdXHr/Aloc944EK7PBWg9QurVxlQ3s70Vs+FmAdQ0LAP6By1cA
-KCT2AsBqXKme7mEfajBr25MaTIjkSjPA0mHsVnz/G8jgzyBna4MGH/UzdgHYt9ZrMNovwcpksN4E
-eJpeHbLB5PDtelT4L/wP4Fr+95NirQa34d85cB1jX3eAsGVhiPRuR644WPjOafxgHXw9uD8axL/k
-3+gj3P4vLgJ0SrAyGaxzoFCsfpObJh8aJVMtzUSMA3JZTw/Ab8RKYcD+Rvu2ehsJJIBu9llFwdW3
-0l8N1B0CrDlgpz1K4OfIkRqgT4cOjNkkWBkLFiM4ejT4nXjVrcH/wb9G4BUUwOcZ+xCgtkh74Ci9
-9Iu1Jig/BjhDhmzCGUTzccaKNx9lAqwSUAVY17Kvw7U7S2wLn6fXRXCzn90P2dIVZhxYIlxSiCE0
-W+8F1l+GYDU0hG99P9/gVxiEKxiGvYPMoCMjT2a8fxyRQkQw9HpJg3EBGAmsr4PDz8Eaxz4F+UBf
-+DjtMZ0WJ/9ZBu8ZDlZwfX7fjTG0x9ibPTF93D52UEdELgD9LXYw19zteA7onMwLAHuI74SB9QGG
-b372DKAvLQF4xN/7FPlR/17gjD3H/BKszHWFYRbr6siEA7sL4Jbga4zG2Yd2sCuqaoC1H63YS3wJ
-nSW3RyFgsQ0coQLsNn4KdD/3gtcauG0HOCItVgYH78EYq4fHWOFaDLA6tMNHe3St0m0L3+Ixln+/
-BqP3ib0xGue2LRQstmu+vXjz13mMZYRbubhoFw7yXyRYmdwrHMN7hR/fgVGSdrovVzvEUpuXYPhn
-wG9+wJcOaTDZ3GcOpU/fiACLmb3CP5o0ncemCcamQY4EK+PzWD3zYayNYvcwYUj0UiCldTf+9yXQ
-2RNlKl+6Aw2YLRCtU/D+uBZgxQDr9iIkrauIeo067OOu8Cfs38Fxgi9+XoKVyWCx+wBKG5t1tDfU
-9ME81hlybtki3U59w9XNuOVL/r+IJbu/58yXwOgGdPd0aXAuwXU384eAdT7YtzXqPPO+HuybPRdA
-9hnW5YDR2zz41ntnJFiZDBbbbnfQvUI7OBaF5bF+ZdwehALCj+4n2n9qLDkK/8zxMdSNjlA/3UP4
-vRFqsf4+xhG4V8h3G0sB+/4ptJjzB5luyDDV1otUVXd9vbGmpXFr09td96mXha5kT9Yb4psfbKxv
-EgMdDjZuE2MTzPfru/9eX/8HsabWeMcY3eBtaHrL+LiDjVt3B75v224/k2CNFL3+D/kbSLCkJFhS
-EiwpKQmWlARLSoIlJSXBkpJgSUmwpKQkWFISLCkJlpSUBEtKgiUlwZKSkmBJSbCkJFhSUhIsKQmW
-leRP28f50/H5EizLSlHEDC9jCuGxJ6crtoU7TkVjxJxkuGu+XVvNp9t0bS9SFu4Ra1+/PTt/c+R+
-uFLbfMJYtNvMbRk7nq34JFiZrPB5hYdsoKqqA9Sjfbm61ZhkOAdwG1D3IVd2WhJFGp4CB+6Xw8Iq
-kD6j0QbZR3D3F/he8CPjHT1s3r0EK8PB6rHBLARmby7kRm538i4QYP2Jag4dmwkOKkU69gjbqcEb
-rOddgD1sL8DDofu8D/C4/9gCyPHTrNVZp3oXixpZjCCVYI0gsHy8Tihjf1Rt+Le7pSWw2U4bjBZg
-faUEkRJ1QETZte8ShefDT3CxtukV1tXSQm6yBXf+d7Nc0T9o2/d4SUjCyf8iTJZgjTCwng2+FVKG
-janqMn9o3UgDLOKmy1g83NrKQ6zzwc493+/YFFFKpoAqIuk03/5dmoCP1g/00xKsjAerpIWLYzMK
-oDTw9ACfqgY2w7A8rCDpHEETzZb+kPgCeIpqAz7HOD0PI2yXMfYpUcS2gGosLwf7bq8G1zNuwn7D
-JFgZD1ZAFBWdTxVBcjZHezJFKFhPAfyQwLqDu0LOGCysmi8qHS0G+Dg6wR4qJHKCVy4ajWtn0lec
-SzvfDzczCVbmg1VQxWVgs2E6oaY/HgcsP3FVKvB6pGUDCLCu53aMB+eE0E9E3y9ntxet4Gh6a/QD
-q3Qi62UYyyRYIyzdwPt/O2/Xg+X4+oJF1bNhEV/k1YgWCVdIXvGfIupCS6Xz9/8+xQGQOwddoXh8
-ABqv/8JNf9/a2goQ0jWQYGU2WH7W0cbJ6dL6lLYNsVi3AnzNWHfwyXV7WDCOZyI4p7ptRvW/XdVb
-T8/B4P1TZtnRccFCWqoEa6RYrCvUfHPt5JhgfTeQ5uxobz1DVd7HElH0rIq/cb5wAx3yCLTDbf4z
-It1gxPElMAE7mCQqFS/BGilgIRiXdeDyTkoWsO7W1ihgvYkheCuJPz7nBDumUTbrV5D3NvOdT2VI
-j2O8hRudxz/8YT97EXL9fnSFz/nZq4FnpbA+z7yQYGVyjLXcAXb+MIFFEXmsIFi5gU6kv0tFs6OK
-eGsBf1iF9g9yhLnMz0vh+u/npd3VN/j7/EEBpWcCYMngPaOlqCWhSatd84tUteDGHZF5LAKLv+xR
-TeGLQ/N1dcZm8faGEjV/4VF0hCoHaaaqnOIrtYXivuP2MlBnBOvEq6oESyq+QobC9ER7vydyq5Eq
-CZaUBEtKgiUlwZJKnyqmlXRLsKRSrhJlBI5KlmClX+USLKl0qFKCJZUO1UqwpNKhZkVtl2BJpVzt
-qtIswZJKvRSlUoIllQ6wFAmWVOqlKkq3BEsq5apWyzokWFIpV4eiVEiwpNISZHVLsKRSrlpFaZBg
-SaVeoCidEiyplKthZGYcJFhpV4FSPgIHZUmw0q8KtFkdEiypVKsbwVIafBIsqVSrhNCq7ZBgSaU8
-gie2ytq6JVhSqVWVSlZLbeiUYEmlVp4ChexWebsESyq16qzgZmtahwRLKg1mSylvlGBJpVotQLGW
-T4IllXKrpYyAjKkEaygEmU+WBGtINE3J9AmHEqwhIwskWFKpV4mi1EuwpFIvJbMHAEqwhkrNme0M
-+4Dl6+w4++rs7EnT+Q3R6SRysxm7hu3D5HQGC1Z3x7Kc8RNnX2XIds1VadXU8ebS7Ik2W+pHlfja
-Z+RMnBg4CVt6z+YqW+CHmzrRNr6x39PpUJQBPQjF10anY37HNek+nYkXm42Dp6N5O5MHy9eQs8Lt
-CqpufOirNGjtNaGv3POyWlOJVWeVbW3YCUysS+/pTHWGnc5VOYf7OcKCgSSzOm8cXxN6Au7x6T0b
-15IVoSy4LtYOJwlWs80Z/slnGSxaYUuZ1equ7XP0Zxcs1NJ+TqdNUaoSPZ2qyKM/u2DxCz/flwRY
-3fkrIz/57IPlqrumKjVcdUReJUMBlqtuam3co0y4sENn39M562DRV3oHDFZ7Tl+IhgAsl6smPxWD
-LFuiQXT2wXK5NtrinU5VGbQlcjreiX0/eQjAQhtcNUCwWi+OwtCQgOVy2gbPlWdetK8bCrBc7nh3
-broVpTyB09m6xGURsFxrywcE1oGov/nQgOVyOgadIVrisgxYSFb3IH1h41KXZcBybawcAFi+0VEJ
-GiKwXM6iwXHVNs9lIbCQrNiHWpFA9r09+q80RGC5VtYmDlZBdICGCizX2nWDSjPE+sWHCCyXszrm
-sbYqiqe/89FclgLLNa8lUbDqV7qsBZZr9mACeJvbYmC55nbEuWFY0s/pFNVYDCy3LUGwfBe7rAaW
-syR5rg6sdFkNLFdsZ+io6KesQ3uM5h06sFw1tYmB9aDTcmC5ViQ9Rao7x2U9sNYeiHW40/ob76e7
-LAeW62JfQmDFMlhDCZZzWrJgHV5pQbBim6zGfu7qdC+1IFg1iUwyyvKstCBYrquSBSvfZUWwlsS6
-xtv7id5vrLEgWHUTEwGr3G1FsNY2JTmgYbwlwaqrjToEprMdu4UFFQWxx89oLguC5Zp3IAGwprqs
-CFZNeXJgdaywJFiurOiDkwOKZdGWWBKstZ4EwFpiSbBcSSZJm93WBCvaLcP2ELBi5bnWWhIs94PD
-F6z85MCqqrMmWBdGM0mOAFexplU0bLQmWAn4k6yl1gRrYnJgLbMoWHN90buEhmL1DGstCtalIw6s
-iuEEFus3xFpnUbAulGBZGqwyg6uY4zkkWBKsZMDqNMDySLAkWKkEixcHiTdxVYIlwUoKrGYBVrcE
-S4KVUrBE+B77xqgES4KVHFj00ArFK8GSYKUYLF/cEEuCJcFKEiwevndLsCRYqQbLqyhx5r1IsCRY
-SYKF4XurBEuClXqwKuONTZZgSbCSBYvFe/yqBEuClTRYtRIsCVY6wGISLAmWBEuCJcGSYEmwMhGs
-JRIslFM3phzrOsQ54keHCViz9VFiI11fGe901kiLlW6wwOBJh/zYW10EwwUs0A2wIA5Yn4AVEixL
-gAUZBRa+KcE662A5UeZ7xrITN3I6hydYEafD/yewnBKsswqW8xOA0jfRms/RItxM9oo0HMF6lB95
-qVO4c+PM5vKVKyRYaQeLWyYOVo0uIIK7Xa5vGosPDTew6GwEWF8Vp6MjTuKK4WRJsM4SWKYQrEkA
-ZKwuIYwESxcu2TS8YqyAVrrcAJNx3RaACUZc9f1S8oEyxjrbYNUA3GEE658nyAqXOodd8B4C1hf0
-vG/Tyq/i/25yiStl8D40MVbIi0K60Emzhm+vcK7xoo5e3CA84b0SrKEBy2m8GId/vxgIroY3WFt4
-wPXo5fxs7pVgnX2wTFdYQ66Qa+MlwxgsdIWbTFco3l5TALl11gJr49xJ+Zfem+nphgIRvF9EXUWA
-q3HxWwZYzmEIVmjwjl1BKrl1OYyzFliXGB3Xh1IOVs0NULppoGD54oK1ZlL+TcmBZYby+sO8a8g1
-ziUyWYmCNQlqBgpWd1ywHr08/xpnUnksI91AOQZ3gVii1RTI5z2UIFg3wNI0gvUFgM9sqrkHD6wu
-xWBR5kindhwQWNOUKl9MsP7VyB0klXkX6Z6QBOksc22CYH0ZBg4WKNXdMcH6ajBlO/AEKcdpFh3f
-lot0I8Ry8UB+ZWJg3aOnE6y6POCPqXlUh9tSDNZFUOz8NBS6BwoWKoytIFiI6t14oNclBlYqFAoW
-IZgEWKgwtoJgoXn5TE0BfDIxsFKhULC+gDSmEyxdXLimq9ENr1in67xTXhxYC6V1Bueom/iuOl5y
-t8UC69FR8DDyqn87CbDC2AqC9W90OP8Gk4YELPScyYIVxlYQrG9SBP5lXXcOAVho9wrTChZ6F714
-ZRhXSNbdBJzQVdyaBVzHp43VpS6xSaQDDYK1ln6xLaH2ZUBgBdkKgnURXEgxd27dkIB1t2sQYAXZ
-CoJ1Azm37+uwaUjA+ow7ra6Qmp74mOcMmq8vQK4bF9H5110CY92uFaDjXl+dh32PFWi9hdm6jbbW
-H6qJ6QrX8r1CDeLEhgQU0hIGW0GwdAKrJhTmszuCNBys2fUJnI4adjrEVhCsKwks/BU3DokrdKUZ
-LIxkddMerRFm+fuj4A4836uIIKIDadJu4ZcVgja5Tti5c4m90jgxlgnW7CAFSjKq6gMWWAOsS5M6
-neogWJcSWO7MBQvbiiei5xFBhm5Caua6XIaxKuC92eJNLmMtIiiM2uwEwJo1OLCmtVvVYiUFVmXn
-yLFYwiNehE5vBeUHuOaGgeW6h/dt9W8PEKw+MVZ3vwqNsYgq68RYfcCa60vgdCCcKtbHFQ5RjJV2
-sJaCkWnCBfeaYA8lHCye7dRhXogrnFwXoCxGr1AfVK/QoCpar7DYZRGwBhS8V3b27RXqQ9Yr7B+s
-jsGB9X262y9uDlxWh/ZlFrbUo6VLnSFg1WFHG/faMgrj9jV83GUgeI8Hlisv+TxWkKrwPBbEymPp
-ISOv+tOWgn43ASMZmTKwKjti5rH08/rJY9WJzO7Fse8uzU00uz0QsMpaB515N8YifttMUgHkhoIV
-SEKQC7oE9JB0Q1ywRJbiNtfAwZrW3h098/7pWJl33XTi/YPljH/bmSs/pWBVdsTIvFOO0ribHBus
-uov4uYWl6Psm5VMPVr3SOLgYy8CmeFPwRbEz3BWKtYWbAglS/SZX/2Ald69wWjhVCd4r1EOzpmkD
-S9cHDJajsiPuvUK4qr97hV8QRIVb6tSApccDq7Vv+biBBu/OkPkewQkf5n9ha8OWnVHmtwx6dEN3
-UqMbQsCqyZ90zyTRFf3ipPzZnGy0clvmTip9iC+izSO79uiVBcaYjnxw3TPpwltMdC9cEgusCAd0
-dkY3mPcIL9dzuSOnkxK3mddcWZA/9aEgWFvmFly4xEDm0UmznP3dhA7/7gv7lo9THN0jfTxWKFim
-uzScfDF/W7y42ozGzFvSfMyMGZ/R3gVmZGAZsG7g8z8CSUdxeDRmRozug3NNsIzzXcvBmgR5mwYJ
-VjkFh+0SrFCw9E/y4VaFaylDV8xpKtxIMR+a2Ro+k/DLGDg715iDSOGmGgzfruW4Xc9XWwesOqLl
-QmO83Fd1KN1Y8zli7Vu6fq9z4yQaJcPBwrdmbdp4ER9IQxHZeXWDBKuWdzuaRzpYgU4hgkPjBWqM
-7u73aaSMDvS83G9yjJwGTNfxZbrhLpb58CyA8wSb1gHLmEEIGh6p8xJ+fM4r521y1XzxXpcxNpnA
-cn6Cj17EUP9eAuu8/mOs/sBqNe58jHSwzE5hjRhz5TSGXrnoRxYjsraEgeUU/bxP0p9NZorB2MlS
-YGEwdZHRwXZHDrZaczkYYLmN+YRz4bw6BOvewYNlPiGvRLpC0xWGdf4IKmMudBhYhgpNyAywnBYE
-ixz4F3XI+3ZY3Qa6HUJpCAOsQCpvVF3MAcoDA8t8Ql7gaQgSrOgWKxwspyFzPoVVLdaauWvNVPZa
-d8g0588BxlhiXrRpscwzShFYtYG7Bi0SrABYGGNNDomx+oJ1XUjeMwSsqy0GlrsAxvKFbyFYGGNN
-EIHUBMMrfisQY10iDt1IfaYCrNbgXc5aCZYJFvX7Jm+iXmGhKxKsux+l0fPXO7d8EfKvDgPrX83O
-oqXSDYUr+QCUUS7R9auhwArByuWnhwwFe4Wue4KT7gcNFgu5f14uwTLBMge7FrrCweKBvlGhxZyo
-E7RSYvVtVoqxPgGBCTmBPNb15tLkAozTRR7LeCt3U8rAKguC1T5SwQreJKwxK0TiVT5J55lpfJvW
-GbUjt1yuz+aZd9BmG+8Gt3GtmaSXbnLpVgret+B55M9+SBzKlhsgV9xOoCNd6/qEPoGqSNaJt/RL
-HxKZ95SAVRvuCeVM6NRpZBe3NYMsn5xiL8FKJVgs1A9KsCRYKQMLg6xpXkWpl2BJsFIKVi09H09R
-CiRYEqyUgtVBw2YqFaVj2IJVKcFyWfXJFM2K4hmuYHWoEizLguUz0qPDEawyRYJlWbBoGkL38ASr
-Q1HaJFiWBavBvAs97MAqD/ZoJVjWA6tNUaqHJVgdNONLgmXdx8opijoswaJR+yDBsi5YZsJhmIHV
-wW8bSLCsC5bHmFMxzMCqCBv+KsGyHljtxpSK4QWWMFhh04wkWNYCywyyhhdYFUbZDAmWdcEygqxh
-BVZnn0lGEizLgYVBlne4gWUYLEWVYFkXrHaRyRpOYHUGRlVLsKwLFgZZZRYGa3x0722oNdZJLbMo
-WLMzC6wZ/VQtI7CWWBOs/HgGyxyw31cPuq0J1vjkwGq0KFjl8Q66mo9PzppnTbCmxzNYsW/qtFnU
-YuUkN26xc601waqPd9Beng/Kml1nRbBqlvWtsuapClTYj3lTp3OpNcGakRxY7BpLgrXCy/qN3rNi
-O4+hBGtljKExtXjQVY7Y0Xu3zZpgtSQJlm5JsK7qZPGj9woEy7vUimCNj8GN6BF2x45YKtxWBGui
-L0mwqjZaECx3fvyDBsoHZbHxddYDa2NF9ENuDYx8jTkOcK4FwaorYMlqqgXBWtEc/5gr6erPYo0r
-rAfW1JhGVunv2tfc1gNrbmfSYE2rsRxYbls/x1xL3cIsxmLxM3RgbVwW02CV9NuRutJyYLnLWfKa
-aDmwlnr7OeRmuqmDYLXMsxpYWuwIq/9rv95pNbBs3YMAq3ajxcByl/V3yHj9NxBYrHqltcC6qj2G
-7y5XKhJoCsVtLbDmtrPBSK+xFFju/i8Tnm/I4jOqaqwE1opt0Y+3Je6g5JC5bTluK4G1opENTjZL
-gTW1td8D7qZ8AweL5TutA9bKZTGvg3gTv0J7hqPd1gFrRfUguWL+8RYC65rdifgMDIUFWKxko1XA
-WrouNleJtlFnVG84JGDNa2CDls9mFbDcF7+SyAFTIivLzMQtsQRYdeO9MQNCpXIATbHWEmC5x7ey
-FMinbbQEWHVKYuFiuaIEwGItORYAa60tRpqqakBcoZr6HvzZB2tFTgdLjWonuoccLPe8GxPs3lYq
-SndW8LJYN945pGDVrc2KYa7aoCDOUJkY7vDGqe4hBcu9IquNpUydkyJGC5xtsNxLshLu3aIZ6MwK
-Pfgm29SN7qDG/9ydVm28JuTFivHj26JfEB0l2B1UBu5TOmpzZteEfMPE9J6Ne6or5MXS8eMPs5Sq
-Y5ntGudZPJ0lK4LLdUtslw4gaVKtKB1ZEUd/eOvCS01pl6ZZ+ebC3GVN7TFSn94CGidTltxd3I7D
-62688mydTsjnL/O2d7LUq+PAA5eetdaZdKG5dOMDLe0DyvHSPZ0sZmV5y8IrpkoNC9VbGqz2anSB
-NLSvoE021fBSg6K0WROs1uoCY6xoWUOHbCgJVirUVlUgLBWG7M2SquEoC8ZYLWXGuPYSpT4t8a/U
-WVCUXuHQqkpV+FOrobHdJ5tnWIPVaSGwqvjseaVaQjXchS3pswxYbdwH1sugKgNUEXqvcIjlAap7
-JW1VRqjEOmB5MFwvl1hliGiqujXAokExHtkgmQNWpTXA6lQKlGbZHpmijsCYdwsEe9WyPTJGLYrS
-aAmwOhKcJSE1PNRIjz2xAlhV5YpXNkfmqIrK21oALF/ch5hIDTuBqN1ghS6hjLAySD5RxmjoD6Q2
-8LhXqUyQl2J3K4BVEO/hOFLDTtV8YvHQg9WtqOWyNTJIojje0IPV2W8xNanhpLYy/pSmoQfLfFyU
-VMZ4whargFUrmyPTPKEFwGqjMl1SGdQnrLYGWL7WVpltyByVG7NAs+RPIZVa/yNuo0iwpFKpShG6
-JwCWP4FPC27TM9AD6Ym+m182UUp0tn9HNFhGTftIsDyqkQZXVPEknu3zdVWbsbnvIR+7vUjVFu4j
-Jj7MUkm054YiNX/ZUbFnma6WrO6740Gb+IpD+MkzdoiVG0rU/DtPibWAn3B6xCNRFmwIUbniNfy9
-HTOWnYqGz1Pmxo9NdzhmPE1LO8t0rWQ1geXfH/JDB/puqiGyLxum68Ze2BB2beGJnqSP2jRYfcEC
-83yA+mpd04FmOQAUHo3Y8KAOqmID/Q90zhqQVNY7Exy4tUYb36/hnhpcH/ndvVOAPyH1VTtk4/tf
-o1XT+WcVcupwUaPFkR4Emw3hAA7WBgf+MPjL5L7Ul6tDYGy8gFoL4BvM/4wDf13gv/5+vuj4Qdg+
-KhhCDhabezF2K7afTbRfMmpWppkDVfoBaw7kPO9jPXtzYHLEht+FcSeYbw5chsu7wNbWimIvQu4R
-5ltM53PcBt/zs72a43fh++2fAhysro/Aom6210bv/xhmdLL9NvWHjH0JinFRgx9KsMLAegbgEew8
-Hz4f7H3syU4wwPp/GjzP2FOQd5RdADf72c+0vLcYmwn3+tkL2qi3Qvdp5VoOE/zsTQ2ew720vD/j
-Vnl7mG8B3JZkBz+kMFB8sF7TdHGBYFP/lEKzqsDQ9NunP0BZC8jhkF0mVl4BtPLvNvt77ECFfhoN
-cRasY69WVf2ZsWMPVG1lbL4KYzlYf9X0dxgxtYx15ehv0Lm+3clYNizjX75MghUG1vlGY6O9vxr/
-q68KFs6cDo5csfH2+dl+P+tVoY3RP8b//tNGdCFev2QfPFBFrbihqlLEXm/qo470sGa+F277CrsL
-rsPVv9Wy30s21RAYABUfrP+A85iJzE18ZUSS/H9hHP49Bx7Y+WATIyyqxb7/bYTk7+fA91jvR8je
-fRZGY3ygaM+3cbBahUNshQlo3EazXdVbT9DrL0EpWjObtFjhYP0JHCeE2/sOjMKlSgiOCFFK9wVf
-4m/+Tw3eRouFru9Nsli/EJgsh2sZ+wrkveV/hlsoxmF7OriXDfagg/olo0U0XkmoUVEcLDZYjuoq
-VLWDwPo4PBIgaAKdQ8SQvJOj4BbGPrBxb134FvsYt1hdWfC4scHPwP4Gt3dPvyhsXpvfQOqvoNP5
-vgpj0XgVLnAAOOgsj+fAwqrpUCxjLHBU8YYAAus7kG108Dg2vC6xqbfDOUN6sk+xF2z6sgd53PSE
-2HUVNWDXGDj3Q53bPGGZToXu9Q4bA1TGvZeM18DVGlYhry9YATWQBdpqrBc+L0IY2tuPoMO0QfHu
-XWSW/gPGYn/uZQ0M/l6wwSLGY8J8HS41D4CDhTHYN/hFo7EDALk7WpaDg8h7ir46SoQ68sAKCFur
-IkiOg8CKzB6FgLUe4EcijgcYi+A8KN6rogb0v4DRP2QbUdocvqHQUxpZL7sgKimwOsLnhvYFS21t
-QbUqkWCN7vNRJ6eA/izFbIep8uwhjNNP5kBh1e06YGBF9vUZJI5fEyfRpuW+EwYWGjO0TWXAwdJ/
-YnrB+0Hb0XKfpv9UgmU0BJbt7hUAAAvPSURBVAfr9gTB6mH3YVfQTxfs2N0tMyHnRBhYgrdfi23f
-tI06Yu613gGz/ATW7mTBosA9dJRK/BjrioAr/HEg2gro2BSw/zokjZAFm9mhMQ5wzLoCAys8WrwK
-ik+ZfUhhukLAIuwge7M2Dl2h6udeMZcds+m/YRTbTZZghcZYQVf4N97TiwFWD4ZScIuf+of2oxyj
-O4KukDfgnzQ0WGKn++BfTK7uEnsZrrCLwq2BclUWMayuv+D9XAqH9jGMnh6J5KoIcvaF5dyA0qgH
-WtrYKP13wrpeb/wax5AhnvEKBYsda209cQBmoVfkYB1AsA6I9w6AJsEKBetvGFmh/3qeneERVEyL
-tRx0Ho+vMs2UzQze74LPi3hdJKy4J/ylsTty9XjIqn/mDDh471SVaeGPkowP1n4bueHP2m/ZzoPw
-sPhqCow10J9TcgsPmvTfdXqf9NNSDv7FaP0b5hUxEwp1yPf7Q8HyNnq4Kfsa682B33CjeC6F9PQ9
-f8SQXoIVmm6YQhmdX6jFe3X4AYsJ1nrIEx2+JwR+y9FMYdeKTNwF8HsRwY4FnduDDwJ9P1z5U9OI
-kVn7Hy17gLeC2qgGY/cAwMIj1Vef6L0PIz5+U6eq2hsSIy6sRlVRj1HfwY4tQPd1yIbo49LX0Bzl
-QC69X+2hcEr/DfYMbw6zWN+F/CNsly33HT++n7+H4U/2DdaVQ51LXFwowQoD600NFu5hL4MOY6nR
-G6qrooCFG43lv3n7u7nwtVNsu07x1AIoPYHNRR7wXR1uRotAeR/yliLqfTPX2KsNwy7HDnZwSqBT
-n3DCXVGmRVSC7wcsdp8GqupA+5m/2R+ax3rfZnRZcPNetK+qCqOPUOxNS6V+sj+GqsgRLqLrwnCG
-Aiw/kqerDpVHaYtpEQr93EbS92knJFjht3RetuMPw2/E3HkkIr8QeLnA/M3bKIClrSkWOa7TIv+h
-MZo/RVc/XeL/CdmnTUcYuLuznpobxp0a0KFWRnvQUVbfJJcBliJuQr/+WJGiPdAyBfLeCM1jeRVT
-9GpXmZK/mTqxPTunKzOa6Jo6x3y/qmuMMprWzFFs7xn5DhFi3We33WkEorumK8U7uP099mQRLp4a
-6VyxacGGEMmhY9vLsm0Ln7/LQb6wPHzKXIV4+RHzN8de+sFVevaM53lO9dgG3XYnub/1ikJ5nKcU
-Bd3ig+ZHBPYib7R3fnb+5u6B3IRudSjRxgAnPGxm552Jf5c/ua3kWJlE9PpMS111vHJslEc8yIF+
-UoNQgwLoBqOVYpRgSSWtRipIDC1R35NgSSWn7lpR5zpG5VgJllQyaq0UPbOYTw+RYEkNWG314sE0
-1XHm7UmwpAYkX3MlUkUpBk/c8ukSLKmE1d5YaT7ur7q/h0hKsKT6V2erp7qiIJATr27t/0m+Eiyp
-aGrxNjd7GmurqyrLSxziOX9Clc2JPUdZgiUVTaBECFeU17Yk/nBuCZZUNBWEMFVQUe1paRvgY0kl
-WFJRXSEfFt3W3pHsY24lWFJpkQRLSoIlJcGSkmBJSUmwpCRYUhIsKak0g9Vab0zwqq3nQ057vQ1b
-m96OuuvL9XySoZ+1NG7b7RcTO7z1TebErdcbt/WtAHAwuPJg49am4LQA39Z62RgRqq8X2UmP0SYH
-Guu3RS+q8O5WsQW2RQNuwtuCWiV2U9TWG2o3WlDs5e/11jeeSAdYEfMKt9tpTqFaGuW7juXwSYb+
-Y9NVAIe2B49rfx5ubeNzvHuX22i/8FqiYmXhW+Yi2AKVMReb8+6lAnKAGEgnSs3sn0KzCtXRf4iy
-5QLRav69OpWDKj7Rw96fSa0yms95vs/GV4btEVIq0r+3iO91BFvwNWpB5fG0g/WyBouamh+zw8V9
-djw5EzhYvRdA/jbPdBj9Hk1MLW3aYHM820OgFDY9aaPqWSFaD7lbPTMh30+Tox2rmxeICfWMV0KU
-YMUF630dxm1tbiwC+9tnIjdcr4lWw20ubmoEGOdH1OybPUU0PxV/dftWXDw3bHaduAuoQd4+KpqF
-exXBuNO0iC2oOX6fbrCuAF71+GUtL6KSKNuZBwKs12xU1eGkDb7HvstrxPyWivy9puHJsf+dsSh0
-n+M2eBZJ/Bh87wz7GE2O7rIZ5R0O2SRY/YD1HbATGb1TqDJfmF6badYg/Y5qP2HU8RtFk+vf1ahg
-5Bh4iTO3L5qlQ+P0Pzaaa/+uLW8PewJoavEGXmQvrWBlGzVmmprbOOWBQpFesD+icrA6W71i82qE
-ZR1dNlRR9Me8tB93f3OU0afRrimj/X8FlVzji8TUOXyDLF40mfk+kvusBCs+WBVGISNvM9XkDJ0J
-rUDpjaLV2luahZtrYzq0MlGN9C/aqKN+ciE/YF15Ctqt9/lf0lNU25YdNveiGqQPMdbzF9uod9IM
-1q2Qu/lEyBkEAuzdq98KK0iKJucniOE6sdkP0dT98LEi28I96PePU6mAn4H+UmjZUVxRfITt0kQN
-m8Xw+AEJVhSwOoNg/QrgzmAEHlq7YeHz4aUcXgC0WAvgslOiEsh/CiKpGhYV9HuWikKKNv1wlB60
-Yi9Q1eSP8zJGH+bk/SENYBlDvHipyIPZ6KJmrDNOyNPcGuamg2D1ziS/fgUPqdArbkbzS1Xewf4c
-vy7053gditc0HlL9GHLxstgAdkXTnhMBVilrk2BFActsCsJmOjaFtszoSHubPaFbhoJ1vIjs0MkF
-oCowDsF5DLJp9SpeknEBZG/XzKJF60OK6Z2cQnvpyVf0GxhY7OAC6rw5tOei7BoEqxej8F9TKObY
-wU4uB/SK2aA/z3z3UUjPus7BjyhGJ9h7Dsw4wfbmIEPYl8TvUeFOvx+tXf5pCVa/YPVu4D05ZXWU
-EhchYCFXo45QTw93duAl7g+UiqSm/ruOH2E4wt4xwcJ9yNWofURUiwBrd7rTDeiBPbdnO0B9Lg5Y
-vpmgPm3UKcSzKcLTGWUaLyqrvV8Dx0uUJTmETClU8IhgW3SKvf4R3OzkmFw8pXYJVnxXSL+z97E8
-ozRRTLAO6ZCNsfoHOmz2U52xl9BiKUGLRUXW7EdEzvG3WraZDTpWJKp+ptVihYPFj2Hv+dH6CSZY
-vinC5VFfcboyY88V8N/oFY2C7xR1vaoB/Jp/0LFVDu2BV7QJ9PiAf/A4fhzaKsgm4wVKhWQpTh5L
-6PBiyDsRGyzkitfvNAKr5RhYhcRYIq+jG2DdBXeYNOZBDjdeIsb6IMk674mDdWDVFNE92AW2mGCh
-FdVCe7JdOXazV9ibRVVuu8ag+R0d7Ge8CnMpjqezfR00AstQpWQpNliPlf1cOLB4VZOP6/QgGhao
-wb0Kctifgr1CwxUaddXGmHYJvee4I0aamnqFf7LZ09wrxL7encYXxrZYiyHXeKbPX8vz3qFIazLF
-6WOPUoVu9Q1ebnKHqPf+lRL6Owc7kGixqMb4rTCZdXhI9eBo9kqWYoM1nUprM+pOx7FYRfBR4Sd/
-oelHeMD/eQLo14E8lgjeeWb9bwG7NF2Un2QskMc6L915rPsBCmsbn5wOKsVIEU8F52Cd2asZ4X41
-FRDN3/aY3f4Sz7xrW58cBbPQQFEW9Ble1f5F0Fc3zOePnVhMi7drjh8ZaWQZvPcD1ssOyFm3rWG5
-g9d5jKjoJ8A6Qw9fEBX9eqfg1g0XYBx/hjLv6xpE5v1n1CP8iqhua1RTZmeeMffyknOZsW2VI/2Z
-994N2fxeofZ8RB4raLG+ZDoyDKr2Z9P9Px5v9S7HqEmddYr6HsXcNo0+KlbaZ5GB66EbWJD9tPlh
-Eqz+YqxdOvUKHaJXGL0G6cxgDdJj/F5hDm+39XRfgyruoyO8mSfvP3oq8CgU8iDB24YH6bah8jRL
-PVhtnkax0OjhSavelmZPc1vYKlONnhb+1xC96PV6dpsjFl5vbqL9Xvd46Kazr8lDHY4DYiXpIG4b
-NOroECVJkRe5R/QKvUabHPB6ml45FbbKkPHSbApPB/+pPa8YHu5gcxMfvOD1eGj31zweDNNagi1t
-iM9GbfE0p2V0g5QUk2BJSbCkJFhSUoPW/wfr5tj8wgE+HwAAAABJRU5ErkJggg==
diff --git a/Documentation/DocBook/media/selection.png.b64 b/Documentation/DocBook/media/selection.png.b64
deleted file mode 100644 (file)
index 4161865..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-iVBORw0KGgoAAAANSUhEUgAABIsAAAHpCAYAAAACi7yYAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A
-/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBAiCLMGMtAAACAASURBVHja
-7d3rkds4FgZQaMohTBY7ObRCV+fgyWJy4P6wJavVIgmSAIjHOVWu3bElPkBSAj5dgpdpmqYAAAAA
-ACGEvzQBAAAAAHfCIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMDDD00A
-21wul9XXTNN0aHnP749Z39o2rK0jRzssLX/pvVve9+61S69Jdey2bn/sMTx6TAAA/cIW+oVb+2tb
-3p+izwioLIJsHYe9X+a979vae89ut6Pb1+txBwD0C3vZN0ERrFNZBAct/ZJxuVx2Vdg8v+/oLyEx
-69j7xbq2/1u2e0u75Th2Mevf8ytVzDkDAOgXjtYv3LquVP0nQRHEUVkEBTsJve/r0hfu2hdz7e0W
-27HQ4QAA9Avr7BcJiiCesAhO+GKK/YIt8SV+RscoNmippUPl1jIAQL/w3PUc7Y8JimAbYRGc9KVY
-Yu6b3OsYNUTRuQAA9AvL9AtT9LsERbCdOYsAX74ZOiVbO1M6LQCAfmH7/TzohcoiqOhLK+eXV4p1
-xP4y1krF0X1bn7dXBwIA0C+ss19oagAoR1gEJ4j9osv5iPq965imKUk59eidwNc/AIB+oX7h/HpK
-tzeMzm1oQJIv7Ra/eO/7sOWxtgAAtN0v1N+DdcIiyPQFlPP1JbZpTyehl19q1joQOhgAgH7hOf3C
-Pct9tz36c7DMbWhQwPMXUYkOQ6517P3Sj/216axJEdfWoyMBAOgXpukX5uqv7Xm/W9JgnsoiSGxr
-4FHiiyvlOu7v21pu/PqLzuuvOTHtlmIZW/bz+f1r6177ewBAv1C/8FwqjCCesAgSdwK2dAh63e+5
-fX8XuBxtt1SdkZhy6djt37vNOioAoF84Sr8wV39tzzIERvCd29Agg7knQ8T+unTk15mc64j5El17
-KsbRW75inrqR6glj79rELWsAgH5hmn7hmcckpt8HI7tMRjYAAAAA/KayCAAAAIAHYREAAAAAD8Ii
-AAAAAB6ERQAAAAA8CIsAAAAAeBAWAQAAAPAgLAIAAADgQVgEAAAAwIOwCAAAAIAHYREAAAAADz80
-AQAAqVwuF40AABWbpmn1NbvDIh0BAKDGzg3n0T8EgD7sCot0BAAAmDNNUwj6iwBQlS3fzIduQ7vd
-blobAMjuer1qhKZ6o4IiAGiZOYsAAMji0w+LAHC6jx0/unkaGgAAAAAPwiIAAAAAHoRFAAAAADwI
-iwAAAAB4EBYBAAAA8OBpaAAAFDf3ZJa5J6htef3za5eeyDb3urWnxsQuM/V7jmxX7Dr3HIMUbfj6
-+qXjurZ977Zja1vuaVOAnqgsAgCgqKWB+rt/2/r6s7Z/z3aesf0x+1fjdgFQjsoiALpyfRng3J5+
-Fb7/2+3NL8Xv/m1pWa/veX7t/XXXN4OtuWXs+fe59c/t45H2erd/Mdu/9XX0b63q5zWkWHr9/d8+
-rtfFapOY9byz9L7X5e7ZzqVKmT2VP3ts2cc966+1MmfuGKkkAvhFZREA3XgON94FNnMhzlJQNLes
-1/ffX/f62ue/fw1d3r3m9d/nlhu7/rX22rv8LW20d/voT8ztYbEBzNJrS4YMubbzzNCidLs+BzX3
-datsAjiXsAiALrwLfPYGE1uXtaVK5l2YNLes2OXurdI5svwtbaSKiFdbg5Cl18f821y1UupAZu92
-1njblwobgLG5DQ0AZqSofjkSnOSuvsmxf2fsB5SUMtT5vN2+LC82xNoziXaJNthyO11MBdHS7YUA
-5CUsAmAo91u97rdGLc1jdKQi5t08QiH8uSVrTcwcSkekWv7avuTeD1hzD2TuwcOWqqIS8wa9C01G
-nD/neV9fQzQAyhMWAUAma5NVA23KEeLMhUZHJ5g+e/9jXyscAqiLOYsA6MK7+XLW5gWK/fdnsYHP
-2uvWJtveu969ti5/bxsJzNgTDOx5JP2z1yAmNsC4T7j8+ifXdj6vs7VjlGsdQiSAc6gsAqAbz7eY
-Pf9dqmVtWd7cbWivE0LPbe/rv80tL1Vb7Vl+TBvl3g/a8nx70dIj7e9/v/b6mKer1bBfc9tZ65w8
-pdt1bh1zQdFaGwNw3GWapmnzmy6XQx1wAIAt7gHTjm4LJTuWv/uI084QYC482Pv6LfMSvXtc/Nag
-pNR+xb7+yLYeXX9MG669ZunYpN7mEeeJAsZx/4y7/P7vmP6U29AAAChq6yPm9z6S3n7t34/c648J
-Z97N49TKuQDQOpVFAED1VBY10rGMrCwCAMpRWQQAAADAIcIiAAAAAB48DQ0AADqSciJsAMYkLAIA
-gI4IgwA4SlgEAADAZh9/X9/+/ed/t8Ovf37t3PKWXje3rq3LTP2eI9sVs961969t59r2LbX16zJi
-t+Xzv1vyduE4YVHpD9SZsuDnX4COlA7HLD/Ferase2lZW7Zh6/a+vn6pDda27912rK0vVbsCAEB1
-45qFwf3H39dNIcm715fY/rWQKsV7Wj5me93Dn6VlxgZKnEdYVPLiXAgTPq7X6BBh7rWpln/kPWv7
-LigBAIDGxzUrVT+vocTS6+//thYs7A1plt73utw927kUeixt3xnhWEybzO13qe0VHtVDWFTq4nwK
-cmKDni2B0NLy7/82F/4srWdPYLRneVvWUWvgNNfuAjIAALoZ10TcHhYbwNz/LiYwStpvf3PbU47t
-zL0v727/WqvqijlmEEIIf2mCAh+oK0HR0UBhbflbbuVKsT1ry4vdhhRt/nm7PdZdYr0AADCCreHC
-0utj/m0u3EkdcuzdzntQ09MxS7Gud23iFrQ2qCwqeXFmrjBZWv7n7XZ6WFLDNgAAAGNLGeq8Vilt
-ndz53fKO7sMZc0DlPjaCpfKERTVfKBsmqy617hr2de21qeduAgAAzvM6YfKWypQS8wa9q6IpVT3z
-vPyYp4pBLGERu55i1sSXytO2q2oCAAAe44MMIc5caDQ3B1KSsVzF4dC7p6KthWgqiOohLKr5A2zj
-RNW511/LurY8NQ4AAEhv661OMY9RXxwDPAUP9/+OGjtsDB+ObufzOnMFOTHLnZvoWhhDLBNcl/xA
-PRherIUka7dfLS333Z/a9j/VOoRIAACwc0wy86SzL/3tmadvLU12/Pra2vZryz6V3OZ3f44eMwhB
-ZVGZi/jpFqi5qqAj1UJry495Gltupbdhbh1zQdFauwEAAL/72i+PkU/x+hoeRb93O/fMi1R6Iuet
-xyz1emNDQRNc10NYVOoieQl0jnoNN2KWXyoo2jMH0lnbfKTdzm5nAAA4bXyzMJnyXHVLC0FA7fsV
-cxveu7mCWjoG1EFYVPKDZ2GS5diAYW0ZtQYYJZ/gtrSuexs9h201txsAAFQ7vtkYMGx5/dHXHgk/
-atmvI+9PNYF0ioqvGqrG2O4yTdO0+U2XSwghhJuBNABQwPV3qL+j20LJjuXvPuL9KPnRBWCbtVvE
-hCrsOq9+96Muv/87pj+lsggAAKDFAeBLsCBIaJ9jSC2ERQAAAB0QHgGpCIuI++JZmZRbmTkAAFTW
-h98QHn1cPzQYFPR5+6x6+4RFRJ7IN40AAAA19dGfwp+Yx6HHPr4cQFgEAADQuNfwZy08inkEOzAu
-YREAAECjYiqKdvl50bg04Ujg+Xr7Ze5bw1q63VNYlPzgXzUCAP13zNyeDJB/bJErCAKKB0WtERYB
-AACcNWA9IRBy6xnDX3eColXCoowUbgLQk0kTAMQPRguFQItPOHuzDXuCoss/jieV9Ul+Hrg2TwqK
-WnvioLAIAABgy6CvgiBoz/apKGL4a1dQFE1YBAAA8DywK3hrWOoAJ1U1EXR3XQuKNhEWAQAAYwwW
-Gw6B9u6foAgERXsIiwAAgLYHgoUnia4tgBESwcL1UUlQ9Hn7bCo8EhYBAAB1DvJOenR860GLoAh+
-f4ZUFBS1RlgEAACUH8R5ZLx9hJyfMYKiQ4RFAABAuoGSEMj+w9mfQ4Kiw4RFAADA+iBICAS08Fkl
-KEpCWAQAACMPrMwLBPTyeSYoSkZYBAAAPQ6ahEDASJ95gqKkhEUAANDaoMgtYQB/PhMFRckJiwAA
-oJYBjxAIYNvnpqAoC2ERAADkHlQIgQDyf+4JipIRFgEAwN4Bg3mBAKogKEpLWAQAAK+DASEQQDME
-RekJiwAAGIpbwgD6ISjKQ1gEAEAXhEAAZPl+GSwoCkFYBABA7Z10IRAAZ30HDRgUhSAsAgDgrA64
-eYEAqPl7atCgKARhEQAAR/17CSGEMP186WSHa9HNEAIB70zTNMy+Xi4XBzyRkYOiEIRFAAAs+ff8
-gYcQCICSRg+KQhAWAQCMSQgE0J25KioVR/EERb8IiwAAenJGCPS/6ctgZHp0sG+OB0AFXkMk4dF7
-gqI/hEUAAC04qxLof5O2B6B7gqKvhEUAAGcSAgFQ2HOlkSojQdE7wiIAgFxOvCUMAFgnKHpPWAQA
-sJUQCIBOjFxlJCiaJywCALgTAgHAEARFy4RFAED/zAsEAKvuVUa9VxgJitYJi6DmD+uf7//+8s/6
-a969ds/yU6xn636uLWttu9e2dakdX5cRuy2Xf/K2ETBDCAQAbHBWUPS63toJi6BSS8HD9DM+eJh7
-barlH3nPme2y5h7+LC0zNlACdnaq/r5+v/Zzh0NCIADotsJIUBRPWAQ1fjg/BSKxQc+WQGhp+fd/
-mwtJltaTOzCKbZe5fSoV6giPYKXD9BQCFSMEAoCx+x+Cok2ERVCZtUBk6e9TLP/5dqrY8CfmFqy1
-7Xm+/evdenO3C5CgMyQEAoC+xibT1EV1kaBoO2ERVCp38LG0/CPhT+vt8q4dlsIrARVDdBTffB58
-hGv29X7+d3v8/+v1+ui0AgDEqiUo+rx9NhUeCYug48FcCOfPI7T3faXmQOrtWECJa/eo5xAIAKi8
-v9Dw/EU1BUWtERYByQaXe8OQ5/fVXNUEvVyruQiBAIBaCIqOERZBJ7ZOVJ17/bUParfs1+utaGu3
-oKkgIqczrpfHuf+l43NzMABgpD5IQ/MXCYqOExZBxQPCI6HDWoVOzCPhlwaNJQa8c3MFCWPo9Zov
-zbUEAPRGUJSGsAgqE/M0siOBydryY546VmKw+jpwzt0ukMtZlXOuBQAgeb+m8uoiQVE6wiKo0Gsw
-kmKwOjcvUEuTMadul63rjQ3STHA9SGdJCAQAUA1BUVrCIqjU0m1ksYPFtWWcFWrEPHZ+7rH1Z243
-43BLGADATD+pwuoiQVF6wiKoWMzgce01a4HMGQPZLWFXim3J3Y4G+w11boRAAABdERTlISwCoHlC
-IACAgn2v6dczUmurMBIUpSMsAqDejoh5gQAAiCAoSktYBBQf4BuIIwQCACAVQVF6wiLAgJyk3BIG
-AEApgqI8hEUARBECAQDwpX9Y4ZPRchgtKApBWATgS14IBAAAb40YFIUgLALolnmBAADI3ufsuLpo
-1KAoBGERQHtfyEIgAADIauSgKARhEUBV3BIGAEBzfdjOqotGD4pCEBYBlPkCFQIBAED1BEW/CIsA
-DhACAQCMpbYKmmmaqtmO1quLBEV/CIsA3n3ZmRcIAACGISj6SlgEDEUIBABAT16reWqpNGqJoOg7
-YRHQDbeEAQAAWwiK3hMWAdUTAgEAQGQ/9qnSqHSVUWvzFgmK5gmLgNMIgQAAgDMIipYJi4DkzAsE
-AADnu1f5mMfoK0HROmEREE0IBAAAtOysoOh1vbUTFgEhBLeEAQBAr0pWGNU8b5GgKJ6wCDonBAIA
-AEYnKNpGWASNEgIBAACb+vODzmEkKNpOWASVMS8QAABAGrUERZ+3z6bCI2ERFCIEAgAAanC5XLJW
-F9Uyb1FNQVFrhEWQ+oOxUCgkBAIAAHaPJzIHRmcTFB0jLILaPrSFQAAAALsJio4TFkEhQiAAAKCq
-MUqH1UWCojSERZD6A1coBAAAUJygKJ2/nE4AAABASqUrlgRFaaksghQfhD+1Af1QHQcAQEsERemp
-LAIAAIBB1fCI+yMERXkIiwAAAIDmCYrScRsaJOYWHlrkVkoAgIHHMB08FU1QlJbKIgAAAKBZgqL0
-hEUAAABAkwRFeQiLAAAAAGaMFhSFICwCAAAAeGvEoCgEYREAAADAN6MGRSEIiwAAAGB4l8sl+TJb
-fsLayEFRCCH8cEkAQJkOTo5OGAAAaY0eFIUgLAJgcCV/8VpalyAJAOB8gqJfhEUADKPmUuh32yZA
-AgAoR1D0h7CIrgduBlp9DqqdM4xyHj9vv3MTACAfQdFXwiKAmcH5K4P19o9hT/vlfAQASENQ9J2w
-iO4HjQZUGKyPeXxG2V/nIQCQyuVyGa5PJSh6T1iEgR0kOIcN2H2OOA8BANoiKJonLAIwYG+6vfne
-Ls5BAIBlgqJlf2kCeh/oGVRyxvntvNO22gkAoE6ConUqiwAyDthDUOWRsi1xDgIAHHFWUPS63tqp
-LAIoMGAXdhxrP5yDAABHCYriCYsYYuBnkIQBu/ZCmwIA4xIUbSMsAjhhwI42Ort9tTEAMApB0XbC
-IoYZABoY4Vpoo120jfMQACCVWoKi1ibRFhYBGKhrD+0OANAdQdF+wiKAkwfqBusCCwAA0hIUHSMs
-YqjBoAEp1Pe54LoEACAlQdFxP5xGAOebpilcLpfh9rkVKY6NUAwAID9BURrCIoBKjBQY1Rqc5Gz/
-uWULkQAA0hAUpSMsYriB4YgVHLR1rfR+ftb0eVBDW79ug/AIAGA7QVFawiJgqIH5O7UNznsOjGpo
-69rb9nn7BEcAAOsERekJixhuIN77YJxjg3OD9D4/C1q93gVHAADLBEV5CIsAKhyk9xZonhV09NSG
-giMAgGWConSERQCRg3QD9PaOmXMSAGAMgqJkHc0Qpin85ZQip5oHMgZZ7BmglwwhejlHS+/HSLeY
-lj4nAQBqJChK2nkPIQRhEW0NisAAvbXvmslxse8AgDFcNoKiPIRFGMhCxV9+LZ+jpYMitAMAQA6j
-BUUhCItoZKB4HwAZCGFwPt71v9b+joE2AQDa6sO1ZMSgKARhEUCSwTnaXfsAAPRl1KAoBGERmbSU
-SEvPcY62t72CkPh20lYAANuNHBSFICyikcGOQSKtnaejEhQ5PwEAWjd6UBSCsAjAgFwbD9N22g8A
-YJmg6BdhEcnlmNi6pW0G134egg7tCACQk6DoD2ERBjuAa157AgAMTVD0lbCIpFqu0FFdRM2D8NrP
-z5zbJ9jQrgBAe/25lvoagqLvhEU0O5Ax0IE+OxbU8zkLANA7QdF7wiIAqiXM0MYAALkIiuYJi0im
-xYmtc+4DBt+ue+0IAECdBEXLhEUYlAMAAAxstB/NBUXrhEUAVNepEAQDAJDDWUHR63prJyyiukHj
-1kFi6kGlW9HgXIIiAAD9uRwERfGERQAAAEDXBEXbCIs4rMdKHNVFcM41oqoIAMDYJzVB0XbCIqqy
-d6BogAkAAMCrWoKi1ibRFhYBsImqIgAA/boW+nSCov2ERVTz4VLbQNGtaAAAAG0SFB0jLKIbqhLA
-9QsAQJyefxwXFB0nLIJBP0BpSy1himsCAICaCYrSEBZRxaAx1UBYdQK9XRsAANBKf/Xs8ZigKB1h
-EQCnEvICAHCUoCgtYRG79Dyxdc59Bdc9AABn9ud67NMJitITFtEdVQoAAABjEBTl8cOpBZBOjl9q
-eg5AhbsAAG32UWvs1wmK0lFZxKkfNLk+UFIv1+03AAAA9RIUpaWyCCCRnkNFgSkAgD7cnLOrigRF
-6akswoDRvlMxt2kBAMA8QVEeKovodhB8uVwEPBTjXKvvMwAAQL9Uny6F0YKiEFQWAVT7hSxMAQCA
-c40YFIWgsoiTBsSlBsGpq4umaTKAJ9t1AQAALfVHex8bjRoUhaCyCKDKL+aavngFYgAAjGbkoCgE
-lUUAmwlPjlOhBwDoC+rP1Wr0oCgElUWc8IFY+kMl9fp8OYx9HZQ4/oIUAAA4h6DoF5VFACtKBoSC
-IgAAatdrn1VQ9IewiKID5V4+VEx07bz3pQsAAP0QFH0lLGIIqZ+KRl9qODcERQAAtDK26o2g6Dth
-EVCMwG6cL1wAAGiBoOg9E1xTbHB/9oDYRNfUSFAEAEAr/dbe+q6ConnCIoATv3BrJxQFAKBHgqJl
-bkMDKGz0aiLVVAAA+m5nEhStU1nErB6fguZWNM4+/wQlAABwnrOCotf11k5lEUBmAiIAAPRjzyco
-iqeyiLd6rCrKtT2qi5g7z1QSAQBAHQRF26gsAjhIIAQAgL5tvQRF26ksAjhomqYvfwAAgDrUEhS1
-Nom2yiLeDnxTqTWVvlwuBvUUuYZUHQEAUKve+6qCov2ERQAZCY4AAGihr9pbf1VQdIzb0Fj8sDjC
-wBi+X18q2gAAIC9B0XHCIoYlzOIsQiMAAGrup7bcVxUUpSEsAjjxyxgAAEhDUJSOsIgsA9dWqnZU
-F1HDdSc0AgBAP/UYQVFawiKASr6MAQCA7QRF6QmLACohMAIAoMY+as39VEFRHj+c+qQepLZ2a9fl
-ckm6/9M0ub2t4XPj7C9C5w8AAOwjKEpHWATw5F1QUzpAEhgBAFCbe5+41n6qoCgtt6ExdFVRru12
-O1FfLpfL40+L1yUAAPRMUJSesAhgg5LBkcAIAIDa1NZHFRTlISwC2KlEaCQwAgCAc40WFIUgLBqe
-W9Dybb9B/jgERgAAjDaOHKWPOmJQFIKwCCCJ0nMaAQAAeY0aFIUgLCLhQBnIdy2oLgIAoDY991FH
-DopCEBa5sMk60NfGzqPWz6cc++K6AACgZqMHRSEIiwCyUG0HAMAIevshUFD0i7DIBW1QnHl/VFHg
-fAIAgPoJiv744XQAyONyuQh3AIDmTdOkavqlj1fzsXKO7CMo+kplEUBjnQkBFAAApCMo+k5YNCC3
-oJXfL4N7AACgxDjm+U+r48ySBEXvCYsACnxp+zIGAIC6CIrmCYsGo6rovP0zuAfXAwD47qb0mKZk
-lVFL54mgaJkJrvGFAax2MlzvAAD0QlC0TmURQAGeIAIAwNn90RJVRrX/yHhWUPS63toJiwaiMsAx
-wPkEAACjEhTFExYBcAphFwDAOXJXGNXYzxMUbSMsAgAAALolKNpOWDQIv+A7Fpyv5XmLzLkEAOjH
-6p+2eL7UEhS1Nom2sAgAAADojqBoP2HRAPwC4JjgXLL9AAC8U+IJaWcQFB0jLAIAAAC6ISg6TlgE
-QBTzFgEA6OttcUYVuaAoDWFR59zi4diAawEAgBEIitIRFgEAABDFjzx9a7m6SFCUlrAIgFM7EAAA
-cISgKD1hUcek/o4RuBYAANiitR8HBUV5CIsAAACA5gmK0hEWdcqv9I4V5JLr1ybXAgDov+Kc2UtQ
-lJawCAAAAGiWoCi9H04rYpjU9iu/puAz4ZLlOpimyecNAECnfb0cBEV5qCzqkCDDMcNxBgAA0hgt
-KApBWEQEv/IDJQnVAACMA2sxYlAUgrDIIItqPjgdO1wHrgcAMO6AeowaFIUgLAJoml98AAAgvZGD
-ohCERRiIahuK6PXXN9VFAAD01rcbPSgKQVjk4sMxBNeENgYAIIQgKLoTFjFL5Qzgs6JvgiIAfI/A
-H4KiP4RFYJCMjpT2064AAEMTFH0lLNLpx7GkUTWFlbm3xXWhPQEAchEUfScsovpBKBiU+9wYrS21
-IwBAGYKi94RFOv5UOEB2TF2baNMcbaf9AICzxzo1ERTNExYB+OJuarsEHtoMAOAoQdEyYRHNDELB
-4NxniPbVVgD4nsH5cpSgaJ2wyMWGY4tjp507bR9tBADw1VlB0et6aycsAkg8QM+theq/UtsoENEm
-AACxBEXxhEU0NwgFA3SfJ+/aH+0AADBHULSNsMigAMeYho5Ta4Fu6cBo1GtGWAkAME9QtJ2wiGYH
-oWCA7rNl7rg4BwEACKGeoKi1SbSFRQ0PEHCsOW9wfsZxEehuP072DwD0Vxm3Dyoo2u+HUx+g/g5Q
-60HR5XI5pR3v6+whaNMRBwCIJyg6RlhENwMpMCCv/3PmrPZ9Xm9rn3fOSQCAbQRFxwmLDGZpYEA8
-TZPKiMHPKddHnvOwxrZ1nQAA7CcoSkNYBFCxHqv+agiM7l6344z2Fg4B0INeftyk7XNFUJSOsAgf
-6uDaPGXfagxJ5rYpxbEQCgEA5CMoSktY1BiDjXEHwn6tGe8ccp347AUAYJ2gKL2/nFYGpIDr8sx9
-9TkEAMBegqI8hEUN8cu2Ab9zwHljv9H2AADvCYrSERYBGLTbf20OANA0QVFa5iwySABci1W1hQo6
-5xwAwBaCovRUFjXC4MmAzLngHBmpTbSLcw4AIIagKA+VRQAG7FW3kYDUOQcAcKbRgqIQVBY1IcdA
-yaDBOcF5A3bXn88r5xwAQBtGDIpCUFkERQZqwh0M1tO0n2vJOQcAUMqoQVEIwiIAA/YG21No5JwD
-AMhp5KAoBLehVc8taAZvJc8N0h1vt/6UaWO0CQB9j13gDKMHRSGoLAJINlDn3HYfsYPqvAMASEtQ
-9IuwyMACcB11dVxGCI2cgwAA6QmK/hAWVUwZZ3+Du9THdJomg0aDcRaOXS+fo85HAIC8BEVfCYsM
-DnBMnX8Mc821FB65BgFokR8zaZGg6DthEaT+gvypDaBW7zqvNQRIOtUAAOcQFL0nLAJgaEtBTcog
-SSAEAFAXQdE8YREAzBDwAAD0SVC0TFgEKQaU//z637lb0O7/DgAAwLkEReuERVBAzDxGAiUAAIC8
-zgqKXtdbO2ERVGItUBImAQDQRL/WE9G6O569EBTFExZBQnOBToonpKlOAgAA2EdQtI2wCAqICXEE
-SgAAAOkJirYTFkEl1kKcFGFS7HIESgAAHOpzuhWNStQSFH3ePpsKj4RF0IhS1UkxyxEmAQAAtasp
-KGqNsAg64nY3AACg6jFLoYozQdExwiIY7cPZ7W4AAEDHBEXHCYuAL2q63S12ewAAgPSmaWpumwVF
-aQiLgM3MnwQAANRGUJSOsAjIwvxJAABj80Q0ShIUpSUsAk5j/iQA8i3Z/QAADThJREFUAOAoQVF6
-wiKgWm53AwAAlgiK8hAWAU1zuxsAABCCoCglYRHQPYESAAD0TVCUlrAIIJg/CQAAWiUoSk9YBBDB
-/EkAADv6NZ6IxnM/NsO5ICjKQ1gEkOrLz+1uAADQndGCohCERQBFCZQAAGjBNE0aIYwZFIUgLAKo
-jvmTAADgfKMGRSEIiwCaY/4kAKAl5i1q85iNbuSgKARhEUCX3O4GAAD7jB4UhSAsAhiW290AACjW
-92ykukxQ9IuwCID3X+gV3e4Wuz0AALCXoOgPYREAu5k/CQCgL6POVyQo+kpYBEBW5k8CAKBmgqLv
-hEUAnM78SQDQN09Ea+c4jUZQ9J6wCIDqmT8JAIDUBEXzhEUAdMH8SQAAB/o3g1UVCYqWCYsAGIb5
-kwAAEBStExYBwBPzJwEAI1FR9HnKemsnLAKADdzuBgDQJkFRPGERACTmdjcAePO95YloVR6TIn2j
-Co67oGgbYREAnECgBABQhqBoO2ERAFTK/EkAQA4jzVNUS1D0eftsKjwSFgFAo86cP+kjXL92gP67
-OSAAQFVqCopaIywCgI6VCpQ+/r6uvkagBIB5i85t+1P6Iicdb0HRMcIiABhcqdvdBEoAQAmCouOE
-RQDAonuYNH3p/Ny+do4igqCoTtbMch6B1b+XEP43OSgAEOHsuYnOqCoSFKUhLAIADoupCEoVKIV/
-VzqewiQAGJKgKB1hEQBQRLFA6d+IXzEFSgB0aKSnnH3rQwiKkhIWAQDVmAuUrtfrr05wovmTBEoA
-0A9BUXrCIgCgHTEBzr+J5kcQKAGEEH7NO5OyYqX1J6KNXL2z9bwpQVCUh7AIAOhLTYGSMAkAihEU
-pSMsAgDGUypQUp0EwIDOqBwTFKUlLAIAeGctxHG7GwBUQVCUnrAIAGAPt7sBwDelq4oERXkIiwAA
-cnG7G9BRAGCSa2LOkx6NFhSFICwCADiXQAkAqjViUBSCsAgAoH7mTwKgcj1WFY0aFIUgLAIAaF8l
-8ydNP0O4/ONwANC+kYOiEIRFAABjKBQoTT+fOtrhGvWez/9ujg80wLxFLJ0bPRk9KApBWAQAwF2p
-291eO+V/X1dfI1ACoARB0S/CIgAA4qyESZfL5UtlUdLOu0AJoEo9VRUJiv4QFgEAkG7Q8E8I06OT
-fYvrnEcEQSmWI0wCYPY7RFD0hbAIAIBTxYQ4KQIl1UkA6ago6puwCACA6q2FOKWqk2K2BYB2CIre
-ExYBANC8UtVJscsRKNErT0Tjfh70QFA0T1gEAMAQagqUhEkA5xIULRMWAQDAfbBg/iSAWSqKxiEs
-AgCADcyfBNCus4Ki1/XWTlgEAAAJud0NtjFvUf1UFKVdbwuERQAAUJjb3QDKEhRtIywCAIAKCZSo
-VeonolH3se6BoGg7YREAADTK/EkAK59flQRFn7fPpsIjYREAAHTK/EnAXj1UFdUUFLVGWAQAAANz
-uxvQI0HRMcIiAABgkUCJV6nnLfJEtHqOaw8ERccJiwAAgMPMnwTUQFCUhrAIAADIzvxJUKeeKroE
-RekIiwAAgCq43S3xAPZpPwVk9E5QlJawCAAAaEYNt7u1GLx8/H0VGNHtvFCCovSERQAAQDdKVCe1
-WpkkMKJHgqI8hEUAAMBQSlQn1TBv0ud/t2/bkTIw8kS0Oo3choKidIRFAAAAzwO/CsKkmO2I3Zec
-gRFUc90KipISFgEAAGwZlJ44b9KekCdnYNRCFYtqpQGuSUFRcsIiAACAlAPXjPMm7b29TYUR3V5v
-gqIshEUAAAClB7iZAqWt74kJjKafjhdjGy0oCkFYBAAAUKV3IU6qW9y+L3PS4PDu+hgwKApBWAQA
-ANCMUvMlAeMGRSEIiwAAALqR6va2PXMZnTWwtl7r7Wm9tRAWAQAADCBn1ZEgwXqtty/Coozc9QsA
-AJwt5glqHwb01mu9p663NsIiAACAzsQERAb01mu9day3RsIiAACATpQKiUYc0Fuv9Y5EWJTY5+2m
-EQAAgHrGKAkDolEH9NZrvaMRFgEAAHQoR0g04oDeeq13RMIiAACATuQKiEYd0Fuv9Y7qL00AAACA
-Ab31Wi93wiIAAAAM6K3XenkQFgEAAGBAb73WW3C9tRMWAQAAYEBvvdZbaL0tEBYBAABgQG+91ltg
-va0QFgEAAGBAb73Wm3m9LREWAQAAMEuQYL3W2856UxEWAQAA8JYBvfVabzvrTekyTdO0+U2XSwgh
-hNvt5tMTAMjuer2GEELY0W2hZMfydx9xenSO9RWhFS3fLgMtKhkgffzuR11+/3dMf0plEQAAAAAP
-wiIAAAAAHn5oAgAAgLG1OKcKkI/KIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwYIJrAAAAivq4
-frz9+7mJtre8/vm1SxN3z71ubl1bl5n6PUe2K3adW4/DWvsfPb5737PlmJrc/T2VRQAAABSzNHB/
-929bX3/W9u/ZzjO2/+gxOrrcrcve856alt8qlUUAAAAUsVb18zpoX3r9/d8+rh+L1Sdbq19itu91
-uXu28/73qapz9tiyjyWWneo9Z+xvb1QWAQAAkF3M7WGxAczSa3Pac9vbnu08M7RYu+3r8/b5eM3W
-dj/aFjmO8xnnUQuERQAAABSzNQhZen3Mv81VK6UOZPZu52i3Qe1p99zhmYqi79yGBgAAABFShjqf
-t88vy4sNsfZMon10H9fmYzozbMndHqMSFgEAANCleyBzDzS2VBWVmDfoXfVTrsqnFPv4/HevYRd9
-ERYBAABApBwhzlxodHRC59T7WGM4pIIoD2ERAAAAxWy9bWntaWdrnquL7v8dY2sIcXQ7n9d55oTd
-e7Z9yzHds2+520OF1HcmuAYAACC7mKdOzT1ZbG0enVqeHrZlO1sLKO5PQXv9s8WeY5b7ONdyHtVG
-ZREAAABFPM9zs6UqaOn1MQP8Ek/T2rOde+ZFamVC55T7lqo9SsxD1QuVRQAAABSz9RHzex9Jb7+O
-i7l1b8utc3uqkfa8p6blt+oyTdO0+U2XSwghhNvtpgUBgOyu12sIIYQd3RZKdix/9xGnRwdcXxEA
-zvbxux91+f3fMf0plUUAAAAAPJizCACA09yrxl7NVbBvef3za5cq4udeN7eurctM/Z4j2xW7ztT7
-eH/t2nGda//YZS7tz1q77DlmAL1SWQQAwCmWBvbv/m3r68/a/j3becb2x+5jDccixTLn9qXm9oc9
-Pq4fi38gRrHKopikvvQvG3vWs+fLxS8yfpEBAOb7DDH9taXX3//ter0u9pP29AvXtu91uXu2c6mP
-d6RftsWWdR89FiXsOWZ7zw+ojcmaSaFIZVGqXx5S/nqzd3v37r9fZAAA1sOGd3+/9votPz6msue2
-tz3bWWvgcsaxOLq81tof4EzZK4u2/mq05XVry1/7ZWPLLw4pvlBTbXcNHQS/yAAAOfoae19/u90W
-K5zvP3jN9V9S9lf2budaFXlpe6uacrRnquW11P4AZ8paWbT1V6PUy6/h1wO/yPjCBQD6kzNcWqrk
-fve61z9792duOTX05e7bkONHyL3tD9CzIreh5f6CWftlo9aORMntzn1Puy9XAKBmr2HDliqSEkHK
-7XYTWpx8fmh/gD9+1LhRZ06SfOQLodQEhEe+BN+VYKdc9mtbqCoCAHqVo5/zroJmy5QKqfclV9+x
-tr7snvYH6NmPkXe+9nCn1Q6T0AgAiO2LbekjrD3tLKav8lwtErvuPU/KPbKdc/2qVo5diW0+crtd
-D+0PkNtfNW7UvQz0tRz0zKdb7Nnu5+2v5YumxPbMlfECALz2tbY+DGTtCbO1PBxky3a21E86eiy2
-PiE4VT+9l/YHKKVIZdHR0s21JyDs/WWjhvmM/CIDAIzouX+3pSpo6fUxfbsSc2nu2c49fdaUUzds
-DWy27mOq45dif1K1P0DPslYWbf3VKPXya3uKQ6rt9osMANCDrQ/7qPmhJr3u17uK8b3bnGo/j94F
-0Op5BVDSZZqmafObLpdNH55rQcJrBcrWx83HLv/19ak+/Pc+Qn7rdqfc19flbA1+UuwLAGz9rt3R
-baFkx/J3H/F+lD59/wPA6T5+96Muv/87pj9VZM6iFGn93mXU8uQGv8gAAAAALShSWQQAcITKokY6
-liqLAKA6eyqLfmg2AADoj2kCANhLWAQAAB0SBgGwl7BohV9kAAAAgJEIi1YIgwAAAICRCIsAAMji
-Y6VCGwCo01+aAAAAAIA7lUUAACR10QQA0PZ3+TRN0+Y3XXQBAIDydnRbKNmx1EcEgC76UyqLAAAo
-1vkEAOq3KyzSEQAAAADokwmuAQAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
-AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
-AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA
-AA/CIgAAAAAe/g/10lQlA3JSSwAAAABJRU5ErkJggg==
diff --git a/Documentation/DocBook/media/typical_media_device.svg b/Documentation/DocBook/media/typical_media_device.svg
deleted file mode 100644 (file)
index f0c82f7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg stroke-linejoin="round" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" clip-path="url(#a)" xml:space="preserve" fill-rule="evenodd" height="178.78mm" viewBox="0 0 24285.662 17877.829" width="251.99mm" version="1.2" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" preserveAspectRatio="xMidYMid" stroke-width="28.222"><defs><clipPath id="a" clipPathUnits="userSpaceOnUse"><rect y="0" x="0" width="28000" height="21000"/></clipPath></defs><g transform="matrix(1.004 0 0 1 -2185.6 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#fcf" d="m12231 4800c-516 0-1031 515-1031 1031v4124c0 516 515 1032 1031 1032h8538c516 0 1032-516 1032-1032v-4124c0-516-516-1031-1032-1031h-8538z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ffc" d="m3595 15607c-293 0-585 292-585 585v2340c0 293 292 586 585 586h3275c293 0 586-293 586-586v-2340c0-293-293-585-586-585h-3275z"/></g><g transform="translate(-2197.3 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#e6e6e6" d="m2663 2186c-461 0-922 461-922 922v11169c0 461 461 923 922 923h3692c461 0 922-462 922-923v-11169c0-461-461-922-922-922h-3692z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4461 8602h-2260v-1086h4520v1086h-2260z"/><path fill="none" d="m4461 8602h-2260v-1086h4520v1086h-2260z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="8275" x="2579" class="TextPosition"><tspan fill="#000000">Audio decoder</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4461 11772h-2260v-1270h4520v1270h-2260z"/><path fill="none" d="m4461 11772h-2260v-1270h4520v1270h-2260z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="11353" x="2617" class="TextPosition"><tspan fill="#000000">Video decoder</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4453 10217h-2269v-1224h4537v1224h-2268z"/><path fill="none" d="m4453 10217h-2269v-1224h4537v1224h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="9821" x="2571" class="TextPosition"><tspan fill="#000000">Audio encoder</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.RectangleShape"><path fill="#cfc" d="m15711 12832h-3810v-1281h7620v1281h-3810z"/><path fill="none" d="m15711 12832h-3810v-1281h7620v1281h-3810z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="12407" x="12377" class="TextPosition"><tspan fill="#000000">Button Key/IR input logic</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2411.8)" class="com.sun.star.drawing.RectangleShape"><path fill="#cfe7f5" d="m14169 14572h-2268v-1412h4536v1412h-2268z"/><path fill="none" d="m14169 14572h-2268v-1412h4536v1412h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14082" x="12882" class="TextPosition"><tspan fill="#000000">EEPROM</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#fc9" d="m5140 17662h-1563v-1715h3126v1715h-1563z"/><path fill="none" d="m5140 17662h-1563v-1715h3126v1715h-1563z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="17020" x="4276" class="TextPosition"><tspan fill="#000000">Sensor</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 8030 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 8030 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 9612 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 9612 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6721 11100 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m6721 11100 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2411.8)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 13854 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 13854 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 12163 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 12163 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 17158 670-353v176h2028v-176l671 353-671 354v-177h-2028v177l-670-354z"/><path fill="none" d="m9962 17158 670-353v176h2028v-176l671 353-671 354v-177h-2028v177l-670-354z" stroke="#3465af"/></g><g transform="matrix(0 .83339 -1.0005 0 30268 -5276.3)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m23229 12779 1009-978 1009 978h-505v2959h505l-1009 979-1009-979h504v-2959h-504z"/><path fill="none" d="m23229 12779 1009-978 1009 978h-505v2959h505l-1009 979-1009-979h504v-2959h-504z" stroke="#3465af"/></g><g transform="translate(-9973.6 -666.6)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="706px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15832" x="24341" class="TextPosition" transform="matrix(0,-1,1,0,8509,40173)"><tspan fill="#000000">System Bus</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m13151 9262h-1250v-875h2499v875h-1249z"/><path fill="none" d="m13151 9262h-1250v-875h2499v875h-1249z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="9040" x="12215" class="TextPosition"><tspan fill="#000000">Demux</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9996 8765 373-357v178h1130v-178l374 357-374 358v-179h-1130v179l-373-358z"/><path fill="none" d="m9996 8765 373-357v178h1130v-178l374 357-374 358v-179h-1130v179l-373-358z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9996 7378 373-358v179h1130v-179l374 358-374 358v-179h-1130v179l-373-358z"/><path fill="none" d="m9996 7378 373-358v179h1130v-179l374 358-374 358v-179h-1130v179l-373-358z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m16322 7992h-4421v-1270h8841v1270h-4420z"/><path fill="none" d="m16322 7992h-4421v-1270h8841v1270h-4420z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="7573" x="12786" class="TextPosition"><tspan fill="#000000">Conditional Access Module</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m4445 13287h-2269v-1224h4537v1224h-2268z"/><path fill="none" d="m4445 13287h-2269v-1224h4537v1224h-2268z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="12891" x="2601" class="TextPosition"><tspan fill="#000000">Video encoder</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6721 12634 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m6721 12634 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m20791 7545 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m20791 7545 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2028 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14478" x="1990" class="TextPosition"><tspan fill="#000000">Radio / Analog TV</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="700" class="TextParagraph"><tspan y="10724" x="14956" class="TextPosition"><tspan fill="#000000">Digital TV</tspan></tspan></tspan></text>
-</g><g transform="translate(-8970.5 -1395.8)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="494px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="19167" x="14724" class="TextPosition"><tspan fill="#000000">PS.: picture is not complete: other blocks may be present</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="18561" x="4199" class="TextPosition"><tspan fill="#000000">Webcam</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.RectangleShape"><path fill="#f90" d="m14552 16372h-2650v-1412h5299v1412h-2649z"/><path fill="none" d="m14552 16372h-2650v-1412h5299v1412h-2649z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15882" x="12265" class="TextPosition"><tspan fill="#000000">Processing blocks</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2468.2)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9962 15654 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z"/><path fill="none" d="m9962 15654 385-353v176h1166v-176l386 353-386 354v-177h-1166v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6702 16954 397-353v176h1201v-176l398 353-398 354v-177h-1201v177l-397-354z"/><path fill="none" d="m6702 16954 397-353v176h1201v-176l398 353-398 354v-177h-1201v177l-397-354z" stroke="#3465af"/></g><g transform="translate(-2479.5 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="8792" x="22850" class="TextPosition"><tspan fill="#000000">Smartcard</tspan></tspan></tspan></text>
-</g><g transform="matrix(1.0048 0 0 1 -2207.4 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#fcf" d="m2766 2600c-333 0-666 333-666 666v2668c0 333 333 666 666 666h18368c333 0 667-333 667-666v-2668c0-333-334-666-667-666h-18368z"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#ff8080" d="m5121 5155h-1614v-1816h3227v1816h-1613z"/><path fill="none" d="m5121 5155h-1614v-1816h3227v1816h-1613z" stroke="#3465af"/><text font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextShape"><tspan class="TextParagraph"><tspan y="4111" x="4374" class="TextPosition"><tspan fill="#000000">Tuner</tspan></tspan></tspan><tspan class="TextParagraph"><tspan y="4814" x="4151" class="TextPosition"><tspan fill="#000000">FM/TV</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ff8080" d="m2902 3702c0 111 40 202 88 202h530c48 0 89-91 89-202 0-110-41-202-89-202h-530c-48 0-88 92-88 202z"/><path fill="none" d="m2902 3702c0 111 40 202 88 202h530c48 0 89-91 89-202 0-110-41-202-89-202h-530c-48 0-88 92-88 202z" stroke="#3465af"/><path fill="#ffb3b3" d="m2902 3702c0 111 40 202 88 202s88-91 88-202c0-110-40-202-88-202s-88 92-88 202z"/><path fill="none" d="m2902 3702c0 111 40 202 88 202s88-91 88-202c0-110-40-202-88-202s-88 92-88 202z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#ff8080" d="m2903 4267c0 110 40 202 88 202h530c48 0 89-92 89-202s-41-203-89-203h-530c-48 0-88 93-88 203z"/><path fill="none" d="m2903 4267c0 110 40 202 88 202h530c48 0 89-92 89-202s-41-203-89-203h-530c-48 0-88 93-88 203z" stroke="#3465af"/><path fill="#ffb3b3" d="m2903 4267c0 110 40 202 88 202s88-92 88-202-40-203-88-203-88 93-88 203z"/><path fill="none" d="m2903 4267c0 110 40 202 88 202s88-92 88-202-40-203-88-203-88 93-88 203z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m6719 4196 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z"/><path fill="none" d="m6719 4196 385-353v176h1167v-176l386 353-386 354v-177h-1167v177l-385-354z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9979 4150 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z"/><path fill="none" d="m9979 4150 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z" stroke="#3465af"/></g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.RectangleShape"><path fill="#cff" d="m16500 6189h-4500v-1389h9e3v1389h-4500z"/><path fill="none" d="m16500 6189h-4500v-1389h9e3v1389h-4500z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="5710" x="12051" class="TextPosition"><tspan fill="#000000">Satellite Equipment Control (SEC)</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#cff" d="m13400 4600h-1400v-1e3h2800v1e3h-1400z"/><path fill="none" d="m13400 4600h-1400v-1e3h2800v1e3h-1400z" stroke="#3465af"/><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="4316" x="12465" class="TextPosition"><tspan fill="#000000">Demod</tspan></tspan></tspan></text>
-</g><g transform="translate(-2140.9 -2186)" class="com.sun.star.drawing.CustomShape"><path fill="#729fcf" d="m9979 5451 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z"/><path fill="none" d="m9979 5451 402-368v184h1217v-184l403 368-403 369v-185h-1217v185l-402-369z" stroke="#3465af"/></g><path fill="#ff9" d="m7855.1 9099v7302h-1270v-14605h1270v7303z"/><path fill="none" d="m7855.1 9099v7302h-1270v-14605h1270v7303z" stroke="#3465af"/><text y="-6640.4663" x="-20770.572" transform="rotate(-90)" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="7409.5396" x="-11193.634" class="TextPosition" transform="matrix(0,-1,1,0,-4473,23627)"><tspan fill="#000000">I2C Bus (control bus)</tspan></tspan></tspan></text>
-<g transform="translate(-2197.3 -2186)" class="com.sun.star.drawing.TextShape"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="3278" x="9391" class="TextPosition"><tspan fill="#000000">Digital TV Frontend</tspan></tspan></tspan></text>
-</g><g transform="matrix(1.015 0 0 .99994 -2233.3 -2185.7)" class="com.sun.star.drawing.CustomShape"><g stroke="#3465af" fill="none"><path d="m3e3 2800c-18 0-35 1-53 3"/><path d="m2915 2808c-17 3-35 7-52 12"/><path d="m2832 2830c-16 6-33 12-49 20"/><path d="m2754 2864c-15 8-31 17-46 27"/><path d="m2681 2909c-14 10-28 21-42 32"/><path d="m2614 2962c-13 12-26 24-38 37"/><path d="m2554 3023c-11 13-22 27-33 41"/><path d="m2502 3091c-10 14-19 29-28 45"/><path d="m2459 3164c-8 16-15 32-22 49"/><path d="m2426 3243c-5 17-10 34-14 51"/><path d="m2406 3326c-3 18-5 35-6 53"/><path d="m2400 3411v53"/><path d="m2400 3497v53"/><path d="m2400 3582v53"/><path d="m2400 3668v53"/><path d="m2400 3753v53"/><path d="m2400 3839v53"/><path d="m2400 3924v53"/><path d="m2400 4009v54"/><path d="m2400 4095v53"/><path d="m2400 4180v53"/><path d="m2400 4266v53"/><path d="m2400 4351v53"/><path d="m2400 4437v53"/><path d="m2400 4522v53"/><path d="m2400 4607v54"/><path d="m2400 4693v53"/><path d="m2400 4778v53"/><path d="m2400 4864v53"/><path d="m2400 4949v53"/><path d="m2400 5035v53"/><path d="m2400 5120v53"/><path d="m2400 5205v54"/><path d="m2400 5291v53"/><path d="m2400 5376v53"/><path d="m2400 5462v53"/><path d="m2400 5547v53"/><path d="m2400 5633v53"/><path d="m2400 5718v53"/><path d="m2400 5803c0 18 1 36 3 53"/><path d="m2408 5888c4 18 8 35 13 52"/><path d="m2431 5971c6 16 13 33 20 49"/><path d="m2466 6049c8 15 17 31 27 46"/><path d="m2511 6122c10 14 21 28 32 42"/><path d="m2564 6188c12 13 25 26 38 38"/><path d="m2626 6248c13 11 27 23 41 33"/><path d="m2694 6300c14 10 29 19 45 27"/><path d="m2768 6343c15 7 32 15 48 21"/><path d="m2847 6375c17 5 34 10 51 14"/><path d="m2930 6395c17 2 35 4 53 5"/><path d="m3015 6400h53"/><path d="m3100 6400h53"/><path d="m3186 6400h53"/><path d="m3271 6400h53"/><path d="m3357 6400h53"/><path d="m3442 6400h53"/><path d="m3527 6400h54"/><path d="m3613 6400h53"/><path d="m3698 6400h53"/><path d="m3784 6400h53"/><path d="m3869 6400h53"/><path d="m3955 6400h53"/><path d="m4040 6400h53"/><path d="m4125 6400h54"/><path d="m4211 6400h53"/><path d="m4296 6400h53"/><path d="m4382 6400h53"/><path d="m4467 6400h53"/><path d="m4553 6400h53"/><path d="m4638 6400h53"/><path d="m4723 6400h54"/><path d="m4809 6400h53"/><path d="m4894 6400h53"/><path d="m4980 6400h53"/><path d="m5065 6400h53"/><path d="m5151 6400h53"/><path d="m5236 6400h53"/><path d="m5322 6400h53"/><path d="m5407 6400h53"/><path d="m5492 6400h53"/><path d="m5578 6400h53"/><path d="m5663 6400h53"/><path d="m5749 6400h53"/><path d="m5834 6400h53"/><path d="m5920 6400h53"/><path d="m6005 6400h53"/><path d="m6090 6400h53"/><path d="m6176 6400h53"/><path d="m6261 6400h53"/><path d="m6347 6400h53"/><path d="m6432 6400h53"/><path d="m6518 6400h53"/><path d="m6603 6400h53"/><path d="m6688 6400h54"/><path d="m6774 6400h53"/><path d="m6859 6400h53"/><path d="m6945 6400h53"/><path d="m7030 6400h53"/><path d="m7116 6400h53"/><path d="m7201 6400h53"/><path d="m7286 6400h54"/><path d="m7372 6400h53"/><path d="m7457 6400h53"/><path d="m7543 6400h53"/><path d="m7628 6400h53"/><path d="m7714 6400h53"/><path d="m7799 6400h53"/><path d="m7884 6400h54"/><path d="m7970 6400h53"/><path d="m8055 6400h53"/><path d="m8141 6400h53"/><path d="m8226 6400h53"/><path d="m8312 6400h53"/><path d="m8397 6400h53"/><path d="m8482 6400h54"/><path d="m8568 6400h53"/><path d="m8653 6400h53"/><path d="m8739 6400h53"/><path d="m8824 6400h53"/><path d="m8910 6400h53"/><path d="m8995 6400h53"/><path d="m9081 6400h53"/><path d="m9166 6400h53"/><path d="m9251 6400h53"/><path d="m9337 6400h53"/><path d="m9422 6400h53"/><path d="m9508 6400h53"/><path d="m9593 6400h53"/><path d="m9679 6400h53"/><path d="m9764 6400h53"/><path d="m9849 6400h53"/><path d="m9935 6400h53"/><path d="m10020 6400h53"/><path d="m10106 6400h53"/><path d="m10191 6400h53"/><path d="m10277 6400h53"/><path d="m10362 6400h53"/><path d="m10447 6400h53"/><path d="m10533 6400h53"/><path d="m10618 6400h53"/><path d="m10704 6400h53"/><path d="m10789 6400h53"/><path d="m10875 6400h53"/><path d="m10960 6400h53"/><path d="m11045 6400h54"/><path d="m11131 6400h53"/><path d="m11216 6400h53"/><path d="m11302 6400h53"/><path d="m11387 6400h53"/><path d="m11473 6400h53"/><path d="m11558 6400h53"/><path d="m11643 6400h54"/><path d="m11729 6400h53"/><path d="m11814 6400h53"/><path d="m11900 6400h53"/><path d="m11985 6400h53"/><path d="m12071 6400h53"/><path d="m12156 6400h53"/><path d="m12241 6400h54"/><path d="m12327 6400h53"/><path d="m12412 6400h53"/><path d="m12498 6400h53"/><path d="m12583 6400h53"/><path d="m12669 6400h53"/><path d="m12754 6400h53"/><path d="m12839 6400h54"/><path d="m12925 6400h53"/><path d="m13010 6400h53"/><path d="m13096 6400h53"/><path d="m13181 6400h53"/><path d="m13267 6400h53"/><path d="m13352 6400h53"/><path d="m13438 6400h53"/><path d="m13523 6400h53"/><path d="m13608 6400h53"/><path d="m13694 6400h53"/><path d="m13779 6400h53"/><path d="m13865 6400h53"/><path d="m13950 6400h53"/><path d="m14036 6400h53"/><path d="m14121 6400h53"/><path d="m14206 6400h53"/><path d="m14292 6400h53"/><path d="m14377 6400h53"/><path d="m14463 6400h53"/><path d="m14548 6400h53"/><path d="m14634 6400h53"/><path d="m14719 6400h53"/><path d="m14804 6400h54"/><path d="m14890 6400h53"/><path d="m14975 6400h53"/><path d="m15061 6400h53"/><path d="m15146 6400h53"/><path d="m15232 6400h53"/><path d="m15317 6400h53"/><path d="m15402 6400h54"/><path d="m15488 6400h53"/><path d="m15573 6400h53"/><path d="m15659 6400h53"/><path d="m15744 6400h53"/><path d="m15830 6400h53"/><path d="m15915 6400h53"/><path d="m16000 6400h54"/><path d="m16086 6400h53"/><path d="m16171 6400h53"/><path d="m16257 6400h53"/><path d="m16342 6400h53"/><path d="m16428 6400h53"/><path d="m16513 6400h53"/><path d="m16598 6400h54"/><path d="m16684 6400h53"/><path d="m16769 6400h53"/><path d="m16855 6400h53"/><path d="m16940 6400h53"/><path d="m17026 6400h53"/><path d="m17111 6400h53"/><path d="m17196 6400h54"/><path d="m17282 6400h53"/><path d="m17367 6400h53"/><path d="m17453 6400h53"/><path d="m17538 6400h53"/><path d="m17624 6400h53"/><path d="m17709 6400h53"/><path d="m17795 6400h53"/><path d="m17880 6400h53"/><path d="m17965 6400h53"/><path d="m18051 6400h53"/><path d="m18136 6400h53"/><path d="m18222 6400h53"/><path d="m18307 6400h53"/><path d="m18393 6400h53"/><path d="m18478 6400h53"/><path d="m18563 6400h53"/><path d="m18649 6400h53"/><path d="m18734 6400h53"/><path d="m18820 6400h53"/><path d="m18905 6400h53"/><path d="m18991 6400h53"/><path d="m19076 6400h53"/><path d="m19161 6400h54"/><path d="m19247 6400h53"/><path d="m19332 6400h53"/><path d="m19418 6400h53"/><path d="m19503 6400h53"/><path d="m19589 6400h53"/><path d="m19674 6400h53"/><path d="m19759 6400h54"/><path d="m19845 6400h53"/><path d="m19930 6400h53"/><path d="m20016 6400h53"/><path d="m20101 6400h53"/><path d="m20187 6400h53"/><path d="m20272 6400h53"/><path d="m20357 6400h54"/><path d="m20443 6400h53"/><path d="m20528 6400h53"/><path d="m20614 6400c17-1 35-2 53-5"/><path d="m20699 6390c17-4 34-9 51-14"/><path d="m20781 6365c16-6 32-13 48-21"/><path d="m20858 6329c15-8 31-17 45-27"/><path d="m20930 6283c14-10 28-21 42-32"/><path d="m20996 6229c13-12 25-25 37-38"/><path d="m21055 6167c11-14 22-28 33-42"/><path d="m21106 6098c10-15 19-30 27-45"/><path d="m21148 6024c7-16 14-33 20-49"/><path d="m21179 5944c5-17 9-34 13-51"/><path d="m21197 5861c2-18 4-35 4-53"/><path d="m21201 5776v-54"/><path d="m21201 5690v-53"/><path d="m21201 5605v-53"/><path d="m21201 5519v-53"/><path d="m21201 5434v-53"/><path d="m21201 5348v-53"/><path d="m21201 5263v-53"/><path d="m21201 5178v-54"/><path d="m21201 5092v-53"/><path d="m21201 5007v-53"/><path d="m21201 4921v-53"/><path d="m21201 4836v-53"/><path d="m21201 4750v-53"/><path d="m21201 4665v-53"/><path d="m21201 4579v-53"/><path d="m21201 4494v-53"/><path d="m21201 4409v-53"/><path d="m21201 4323v-53"/><path d="m21201 4238v-53"/><path d="m21201 4152v-53"/><path d="m21201 4067v-53"/><path d="m21201 3981v-53"/><path d="m21201 3896v-53"/><path d="m21201 3811v-53"/><path d="m21201 3725v-53"/><path d="m21201 3640v-53"/><path d="m21201 3554v-53"/><path d="m21201 3469v-53"/><path d="m21201 3383c-1-17-3-35-5-52"/><path d="m21190 3299c-4-17-8-35-14-51"/><path d="m21165 3217c-6-16-13-33-21-49"/><path d="m21129 3140c-9-16-18-31-28-46"/><path d="m21082 3068c-10-14-21-28-33-42"/><path d="m21027 3002c-12-13-24-25-37-37"/><path d="m20965 2944c-14-12-28-22-42-33"/><path d="m20896 2893c-15-9-30-18-46-27"/><path d="m20821 2852c-16-8-32-14-49-20"/><path d="m20741 2821c-17-5-34-9-51-12"/><path d="m20658 2804c-18-3-35-4-53-4"/><path d="m20573 2800h-53"/><path d="m20487 2800h-53"/><path d="m20402 2800h-53"/><path d="m20316 2800h-53"/><path d="m20231 2800h-53"/><path d="m20146 2800h-54"/><path d="m20060 2800h-53"/><path d="m19975 2800h-53"/><path d="m19889 2800h-53"/><path d="m19804 2800h-53"/><path d="m19718 2800h-53"/><path d="m19633 2800h-53"/><path d="m19548 2800h-54"/><path d="m19462 2800h-53"/><path d="m19377 2800h-53"/><path d="m19291 2800h-53"/><path d="m19206 2800h-53"/><path d="m19120 2800h-53"/><path d="m19035 2800h-53"/><path d="m18950 2800h-54"/><path d="m18864 2800h-53"/><path d="m18779 2800h-53"/><path d="m18693 2800h-53"/><path d="m18608 2800h-53"/><path d="m18522 2800h-53"/><path d="m18437 2800h-53"/><path d="m18352 2800h-54"/><path d="m18266 2800h-53"/><path d="m18181 2800h-53"/><path d="m18095 2800h-53"/><path d="m18010 2800h-53"/><path d="m17924 2800h-53"/><path d="m17839 2800h-53"/><path d="m17753 2800h-53"/><path d="m17668 2800h-53"/><path d="m17583 2800h-53"/><path d="m17497 2800h-53"/><path d="m17412 2800h-53"/><path d="m17326 2800h-53"/><path d="m17241 2800h-53"/><path d="m17155 2800h-53"/><path d="m17070 2800h-53"/><path d="m16985 2800h-53"/><path d="m16899 2800h-53"/><path d="m16814 2800h-53"/><path d="m16728 2800h-53"/><path d="m16643 2800h-53"/><path d="m16557 2800h-53"/><path d="m16472 2800h-53"/><path d="m16387 2800h-54"/><path d="m16301 2800h-53"/><path d="m16216 2800h-53"/><path d="m16130 2800h-53"/><path d="m16045 2800h-53"/><path d="m15959 2800h-53"/><path d="m15874 2800h-53"/><path d="m15789 2800h-54"/><path d="m15703 2800h-53"/><path d="m15618 2800h-53"/><path d="m15532 2800h-53"/><path d="m15447 2800h-53"/><path d="m15361 2800h-53"/><path d="m15276 2800h-53"/><path d="m15191 2800h-54"/><path d="m15105 2800h-53"/><path d="m15020 2800h-53"/><path d="m14934 2800h-53"/><path d="m14849 2800h-53"/><path d="m14763 2800h-53"/><path d="m14678 2800h-53"/><path d="m14593 2800h-54"/><path d="m14507 2800h-53"/><path d="m14422 2800h-53"/><path d="m14336 2800h-53"/><path d="m14251 2800h-53"/><path d="m14165 2800h-53"/><path d="m14080 2800h-53"/><path d="m13994 2800h-53"/><path d="m13909 2800h-53"/><path d="m13824 2800h-53"/><path d="m13738 2800h-53"/><path d="m13653 2800h-53"/><path d="m13567 2800h-53"/><path d="m13482 2800h-53"/><path d="m13396 2800h-53"/><path d="m13311 2800h-53"/><path d="m13226 2800h-53"/><path d="m13140 2800h-53"/><path d="m13055 2800h-53"/><path d="m12969 2800h-53"/><path d="m12884 2800h-53"/><path d="m12798 2800h-53"/><path d="m12713 2800h-53"/><path d="m12628 2800h-53"/><path d="m12542 2800h-53"/><path d="m12457 2800h-53"/><path d="m12371 2800h-53"/><path d="m12286 2800h-53"/><path d="m12200 2800h-53"/><path d="m12115 2800h-53"/><path d="m12030 2800h-54"/><path d="m11944 2800h-53"/><path d="m11859 2800h-53"/><path d="m11773 2800h-53"/><path d="m11688 2800h-53"/><path d="m11602 2800h-53"/><path d="m11517 2800h-53"/><path d="m11432 2800h-54"/><path d="m11346 2800h-53"/><path d="m11261 2800h-53"/><path d="m11175 2800h-53"/><path d="m11090 2800h-53"/><path d="m11004 2800h-53"/><path d="m10919 2800h-53"/><path d="m10834 2800h-54"/><path d="m10748 2800h-53"/><path d="m10663 2800h-53"/><path d="m10577 2800h-53"/><path d="m10492 2800h-53"/><path d="m10406 2800h-53"/><path d="m10321 2800h-53"/><path d="m10236 2800h-54"/><path d="m10150 2800h-53"/><path d="m10065 2800h-53"/><path d="m9979 2800h-53"/><path d="m9894 2800h-53"/><path d="m9808 2800h-53"/><path d="m9723 2800h-53"/><path d="m9637 2800h-53"/><path d="m9552 2800h-53"/><path d="m9467 2800h-53"/><path d="m9381 2800h-53"/><path d="m9296 2800h-53"/><path d="m9210 2800h-53"/><path d="m9125 2800h-53"/><path d="m9039 2800h-53"/><path d="m8954 2800h-53"/><path d="m8869 2800h-53"/><path d="m8783 2800h-53"/><path d="m8698 2800h-53"/><path d="m8612 2800h-53"/><path d="m8527 2800h-53"/><path d="m8441 2800h-53"/><path d="m8356 2800h-53"/><path d="m8271 2800h-54"/><path d="m8185 2800h-53"/><path d="m8100 2800h-53"/><path d="m8014 2800h-53"/><path d="m7929 2800h-53"/><path d="m7843 2800h-53"/><path d="m7758 2800h-53"/><path d="m7673 2800h-54"/><path d="m7587 2800h-53"/><path d="m7502 2800h-53"/><path d="m7416 2800h-53"/><path d="m7331 2800h-53"/><path d="m7245 2800h-53"/><path d="m7160 2800h-53"/><path d="m7075 2800h-54"/><path d="m6989 2800h-53"/><path d="m6904 2800h-53"/><path d="m6818 2800h-53"/><path d="m6733 2800h-53"/><path d="m6647 2800h-53"/><path d="m6562 2800h-53"/><path d="m6477 2800h-54"/><path d="m6391 2800h-53"/><path d="m6306 2800h-53"/><path d="m6220 2800h-53"/><path d="m6135 2800h-53"/><path d="m6049 2800h-53"/><path d="m5964 2800h-53"/><path d="m5879 2800h-54"/><path d="m5793 2800h-53"/><path d="m5708 2800h-53"/><path d="m5622 2800h-53"/><path d="m5537 2800h-53"/><path d="m5451 2800h-53"/><path d="m5366 2800h-53"/><path d="m5280 2800h-53"/><path d="m5195 2800h-53"/><path d="m5110 2800h-53"/><path d="m5024 2800h-53"/><path d="m4939 2800h-53"/><path d="m4853 2800h-53"/><path d="m4768 2800h-53"/><path d="m4682 2800h-53"/><path d="m4597 2800h-53"/><path d="m4512 2800h-53"/><path d="m4426 2800h-53"/><path d="m4341 2800h-53"/><path d="m4255 2800h-53"/><path d="m4170 2800h-53"/><path d="m4084 2800h-53"/><path d="m3999 2800h-53"/><path d="m3914 2800h-54"/><path d="m3828 2800h-53"/><path d="m3743 2800h-53"/><path d="m3657 2800h-53"/><path d="m3572 2800h-53"/><path d="m3486 2800h-53"/><path d="m3401 2800h-53"/><path d="m3316 2800h-54"/><path d="m3230 2800h-53"/><path d="m3145 2800h-53"/><path d="m3059 2800h-53"/></g></g><g transform="translate(-2197.3 -2186)"><rect height="1100.7" width="1213.6" y="6917.1" x="23255" fill="#f3e777"/><path fill="#ca4677" d="m22802 7700.4v-405.46l150.7-169.16c82.886-93.039 170.53-186.62 194.77-207.96l44.069-38.798 783.23-0.086 783.23-0.086v613.5 613.5h-978-978v-405.46zm1027.7 136.98v-78.372l-169.91 4.925-169.91 4.9249-5.09 45.854c-8.249 74.303 46.711 101.04 207.69 101.04h137.21v-78.372zm235.86-262.94 4.495-341.31 207.2-8.6408 207.2-8.6408 5.144-46.443c9.596-86.615-41.863-102.05-322.02-96.607l-246.71 4.7956-4.438 419.08-4.439 419.08h74.537 74.538l4.494-341.31zm391.3 313.72c26.41-19.286 36.255-41.399 32.697-73.447l-5.09-45.854h-174.05-174.05l-5.38 48.984c-9.97 90.771 0.993 97.91 150.36 97.91 99.305 0 148.27-7.6982 175.52-27.594zm-627.16-274.84v-77.768h-174.05-174.05v66.246c0 36.436 4.973 71.431 11.051 77.768 6.078 6.3366 84.401 11.521 174.05 11.521h163v-77.768zm659.89-4.9154 5.125-74.042-179.18 4.9155-179.18 4.9155-5.38 48.984c-10.473 95.348-2.259 99.57 183.28 94.197l170.2-4.9284 5.125-74.042zm-659.89-237.63v-78.372l-169.91 4.925-169.91 4.925-5.097 73.447-5.097 73.447h175 175v-78.372zm659.86 4.925-5.097-73.447h-174.05-174.05l-5.38 48.984c-10.289 93.673-2.146 97.91 188.15 97.91h175.52l-5.097-73.447zm-659.86-228.98v-77.768h-137.21c-97.358 0-147.91 7.8138-174.05 26.902-34.952 25.523-49.645 92.242-25.79 117.11 6.078 6.3366 84.401 11.521 174.05 11.521h163v-77.768z"/></g><g transform="matrix(.84874 0 0 .76147 2408.1 3615.3)"><rect height="3076.2" width="2734.3" y="13264" x="19249" fill="#6076b3"/><g stroke-linejoin="round" fill-rule="evenodd" stroke-width="28.222" fill="#e0ee2c"><rect y="13369" width="356.65" x="18937" height="180.95"/><rect y="13708" width="356.65" x="18937" height="180.95"/><rect y="14048" width="356.65" x="18937" height="180.95"/><rect y="14387" width="356.65" x="18937" height="180.95"/><rect y="14726" width="356.65" x="18937" height="180.95"/><rect y="15066" width="356.65" x="18937" height="180.95"/><rect y="15405" width="356.65" x="18937" height="180.95"/><rect y="15744" width="356.65" x="18937" height="180.95"/><rect y="16083" width="356.65" x="18937" height="180.95"/><rect y="13324" width="356.65" x="21939" height="180.95"/><rect y="13663" width="356.65" x="21939" height="180.95"/><rect y="14002" width="356.65" x="21939" height="180.95"/><rect y="14342" width="356.65" x="21939" height="180.95"/><rect y="14681" width="356.65" x="21939" height="180.95"/><rect y="15020" width="356.65" x="21939" height="180.95"/><rect y="15360" width="356.65" x="21939" height="180.95"/><rect y="15699" width="356.65" x="21939" height="180.95"/><rect y="16038" width="356.65" x="21939" height="180.95"/></g><g stroke-linejoin="round" fill-rule="evenodd" transform="matrix(.98702 0 0 .90336 -2675 7020.8)" class="com.sun.star.drawing.TextShape" stroke-width="28.222"><text class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"/></text>
-<text style="word-spacing:0px;letter-spacing:0px" xml:space="preserve" font-size="1128.9px" y="9042.0264" x="22439.668" font-family="Sans" line-height="125%" fill="#000000"><tspan y="9042.0264" x="22439.668">CPU</tspan></text>
-</g></g><g stroke-linejoin="round" fill-rule="evenodd" transform="translate(-11752 543.6)" class="com.sun.star.drawing.TextShape" stroke-width="28.222"><text class="TextShape"><tspan font-size="706px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="15832" x="24341" class="TextPosition" transform="matrix(0,-1,1,0,8509,40173)"><tspan fill="#000000">PCI, USB, SPI, I2C, ...</tspan></tspan></tspan></text>
-</g><g stroke-linejoin="round" fill-rule="evenodd" transform="translate(-655.31 963.83)" class="com.sun.star.drawing.RectangleShape" stroke-width="28.222"><g transform="matrix(.49166 0 0 1.0059 6045.6 -82.24)"><path fill="#cfe7f5" d="m14169 14572h-2268v-1412h4536v1412h-2268z"/><path fill="none" d="m14169 14572h-2268v-1412h4536v1412h-2268z" stroke="#3465af"/></g><text y="-395.11282" x="-790.22229" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="13686.9" x="12091.779" class="TextPosition"><tspan fill="#000000">Bridge</tspan></tspan></tspan></text>
-<text y="338.66486" x="-846.66675" class="TextShape"><tspan font-size="635px" font-family="&apos;Times New Roman&apos;, serif" font-weight="400" class="TextParagraph"><tspan y="14420.677" x="12035.335" class="TextPosition"><tspan fill="#000000"> DMA</tspan></tspan></tspan></text>
-</g></svg>
diff --git a/Documentation/DocBook/media/v4l/.gitignore b/Documentation/DocBook/media/v4l/.gitignore
deleted file mode 100644 (file)
index d7ec32e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!*.xml
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
deleted file mode 100644 (file)
index 87f1d24..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-  <bibliography>
-    <title>References</title>
-
-    <biblioentry id="cea608">
-      <abbrev>CEA&nbsp;608-E</abbrev>
-      <authorgroup>
-       <corpauthor>Consumer Electronics Association (<ulink
-url="http://www.ce.org">http://www.ce.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>CEA-608-E R-2014 "Line 21 Data Services"</title>
-    </biblioentry>
-
-    <biblioentry id="en300294">
-      <abbrev>EN&nbsp;300&nbsp;294</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>EN 300 294 "625-line television Wide Screen Signalling
-(WSS)"</title>
-    </biblioentry>
-
-    <biblioentry id="ets300231">
-      <abbrev>ETS&nbsp;300&nbsp;231</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink
-url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ETS 300 231 "Specification of the domestic video
-Programme Delivery Control system (PDC)"</title>
-    </biblioentry>
-
-    <biblioentry id="ets300706">
-      <abbrev>ETS&nbsp;300&nbsp;706</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ETS 300 706 "Enhanced Teletext specification"</title>
-    </biblioentry>
-
-    <biblioentry id="mpeg2part1">
-      <abbrev>ISO&nbsp;13818-1</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>), International
-Organisation for Standardisation (<ulink
-url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information
-technology &mdash; Generic coding of moving pictures and associated
-audio information: Systems"</title>
-    </biblioentry>
-
-    <biblioentry id="mpeg2part2">
-      <abbrev>ISO&nbsp;13818-2</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>), International
-Organisation for Standardisation (<ulink
-url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information
-technology &mdash; Generic coding of moving pictures and associated
-audio information: Video"</title>
-    </biblioentry>
-
-    <biblioentry id="itu470">
-      <abbrev>ITU&nbsp;BT.470</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.470-6 "Conventional Television
-Systems"</title>
-    </biblioentry>
-
-    <biblioentry id="itu601">
-      <abbrev>ITU&nbsp;BT.601</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.601-5 "Studio Encoding Parameters
-of Digital Television for Standard 4:3 and Wide-Screen 16:9 Aspect
-Ratios"</title>
-    </biblioentry>
-
-    <biblioentry id="itu653">
-      <abbrev>ITU&nbsp;BT.653</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.653-3 "Teletext systems"</title>
-    </biblioentry>
-
-    <biblioentry id="itu709">
-      <abbrev>ITU&nbsp;BT.709</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.709-5 "Parameter values for the
-HDTV standards for production and international programme
-exchange"</title>
-    </biblioentry>
-
-    <biblioentry id="itu1119">
-      <abbrev>ITU&nbsp;BT.1119</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.1119 "625-line
-television Wide Screen Signalling (WSS)"</title>
-    </biblioentry>
-
-    <biblioentry id="jfif">
-      <abbrev>JFIF</abbrev>
-      <authorgroup>
-       <corpauthor>Independent JPEG Group (<ulink
-url="http://www.ijg.org">http://www.ijg.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>JPEG File Interchange Format</title>
-      <subtitle>Version 1.02</subtitle>
-    </biblioentry>
-
-    <biblioentry id="itu-t81">
-      <abbrev>ITU-T.81</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union
-(<ulink url="http://www.itu.int">http://www.itu.int</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-T Recommendation T.81
-"Information Technology &mdash; Digital Compression and Coding of Continous-Tone
-Still Images &mdash; Requirements and Guidelines"</title>
-    </biblioentry>
-
-    <biblioentry id="w3c-jpeg-jfif">
-      <abbrev>W3C JPEG JFIF</abbrev>
-      <authorgroup>
-       <corpauthor>The World Wide Web Consortium (<ulink
-url="http://www.w3.org/Graphics/JPEG">http://www.w3.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>JPEG JFIF</title>
-    </biblioentry>
-
-    <biblioentry id="smpte12m">
-      <abbrev>SMPTE&nbsp;12M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 12M-1999 "Television, Audio and Film - Time and
-Control Code"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte170m">
-      <abbrev>SMPTE&nbsp;170M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 170M-1999 "Television - Composite Analog Video
-Signal - NTSC for Studio Applications"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte240m">
-      <abbrev>SMPTE&nbsp;240M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 240M-1999 "Television - Signal Parameters -
-1125-Line High-Definition Production"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte431">
-      <abbrev>SMPTE&nbsp;RP&nbsp;431-2</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE RP 431-2:2011 "D-Cinema Quality - Reference Projector and Environment"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte2084">
-      <abbrev>SMPTE&nbsp;ST&nbsp;2084</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE ST 2084:2014 "High Dynamic Range Electro-Optical Transfer Function of Master Reference Displays"</title>
-    </biblioentry>
-
-    <biblioentry id="srgb">
-      <abbrev>sRGB</abbrev>
-      <authorgroup>
-       <corpauthor>International Electrotechnical Commission
-(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>IEC 61966-2-1 ed1.0 "Multimedia systems and equipment - Colour measurement
-and management - Part 2-1: Colour management - Default RGB colour space - sRGB"</title>
-    </biblioentry>
-
-    <biblioentry id="sycc">
-      <abbrev>sYCC</abbrev>
-      <authorgroup>
-       <corpauthor>International Electrotechnical Commission
-(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>IEC 61966-2-1-am1 ed1.0 "Amendment 1 - Multimedia systems and equipment - Colour measurement
-and management - Part 2-1: Colour management - Default RGB colour space - sRGB"</title>
-    </biblioentry>
-
-    <biblioentry id="xvycc">
-      <abbrev>xvYCC</abbrev>
-      <authorgroup>
-       <corpauthor>International Electrotechnical Commission
-(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>IEC 61966-2-4 ed1.0 "Multimedia systems and equipment - Colour measurement
-and management - Part 2-4: Colour management - Extended-gamut YCC colour space for video
-applications - xvYCC"</title>
-    </biblioentry>
-
-    <biblioentry id="adobergb">
-      <abbrev>AdobeRGB</abbrev>
-      <authorgroup>
-       <corpauthor>Adobe Systems Incorporated (<ulink url="http://www.adobe.com">http://www.adobe.com</ulink>)</corpauthor>
-      </authorgroup>
-      <title>Adobe&copy; RGB (1998) Color Image Encoding Version 2005-05</title>
-    </biblioentry>
-
-    <biblioentry id="oprgb">
-      <abbrev>opRGB</abbrev>
-      <authorgroup>
-       <corpauthor>International Electrotechnical Commission
-(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>IEC 61966-2-5 "Multimedia systems and equipment - Colour measurement
-and management - Part 2-5: Colour management - Optional RGB colour space - opRGB"</title>
-    </biblioentry>
-
-    <biblioentry id="itu2020">
-      <abbrev>ITU&nbsp;BT.2020</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.2020 (08/2012) "Parameter values for ultra-high
-definition television systems for production and international programme exchange"
-</title>
-    </biblioentry>
-
-    <biblioentry id="tech3213">
-      <abbrev>EBU&nbsp;Tech&nbsp;3213</abbrev>
-      <authorgroup>
-       <corpauthor>European Broadcast Union (<ulink
-url="http://www.ebu.ch">http://www.ebu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>E.B.U. Standard for Chromaticity Tolerances for Studio Monitors"</title>
-    </biblioentry>
-
-    <biblioentry id="iec62106">
-      <abbrev>IEC&nbsp;62106</abbrev>
-      <authorgroup>
-       <corpauthor>International Electrotechnical Commission
-(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>Specification of the radio data system (RDS) for VHF/FM sound broadcasting
-in the frequency range from 87,5 to 108,0 MHz</title>
-    </biblioentry>
-
-    <biblioentry id="nrsc4">
-      <abbrev>NRSC-4-B</abbrev>
-      <authorgroup>
-       <corpauthor>National Radio Systems Committee
-(<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>NRSC-4-B: United States RBDS Standard</title>
-    </biblioentry>
-
-    <biblioentry id="iso12232">
-      <abbrev>ISO&nbsp;12232:2006</abbrev>
-      <authorgroup>
-       <corpauthor>International Organization for Standardization
-(<ulink url="http://www.iso.org">http://www.iso.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>Photography &mdash; Digital still cameras &mdash; Determination
-      of exposure index, ISO speed ratings, standard output sensitivity, and
-      recommended exposure index</title>
-    </biblioentry>
-
-    <biblioentry id="cea861">
-      <abbrev>CEA-861-E</abbrev>
-      <authorgroup>
-       <corpauthor>Consumer Electronics Association
-(<ulink url="http://www.ce.org">http://www.ce.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>A DTV Profile for Uncompressed High Speed Digital Interfaces</title>
-    </biblioentry>
-
-    <biblioentry id="vesadmt">
-      <abbrev>VESA&nbsp;DMT</abbrev>
-      <authorgroup>
-       <corpauthor>Video Electronics Standards Association
-(<ulink url="http://www.vesa.org">http://www.vesa.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT)</title>
-    </biblioentry>
-
-    <biblioentry id="vesaedid">
-      <abbrev>EDID</abbrev>
-      <authorgroup>
-       <corpauthor>Video Electronics Standards Association
-(<ulink url="http://www.vesa.org">http://www.vesa.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>VESA Enhanced Extended Display Identification Data Standard</title>
-      <subtitle>Release A, Revision 2</subtitle>
-    </biblioentry>
-
-    <biblioentry id="hdcp">
-      <abbrev>HDCP</abbrev>
-      <authorgroup>
-       <corpauthor>Digital Content Protection LLC
-(<ulink url="http://www.digital-cp.com">http://www.digital-cp.com</ulink>)</corpauthor>
-      </authorgroup>
-      <title>High-bandwidth Digital Content Protection System</title>
-      <subtitle>Revision 1.3</subtitle>
-    </biblioentry>
-
-    <biblioentry id="hdmi">
-      <abbrev>HDMI</abbrev>
-      <authorgroup>
-       <corpauthor>HDMI Licensing LLC
-(<ulink url="http://www.hdmi.org">http://www.hdmi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>High-Definition Multimedia Interface</title>
-      <subtitle>Specification Version 1.4a</subtitle>
-    </biblioentry>
-
-    <biblioentry id="hdmi2">
-      <abbrev>HDMI2</abbrev>
-      <authorgroup>
-       <corpauthor>HDMI Licensing LLC
-(<ulink url="http://www.hdmi.org">http://www.hdmi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>High-Definition Multimedia Interface</title>
-      <subtitle>Specification Version 2.0</subtitle>
-    </biblioentry>
-
-    <biblioentry id="dp">
-      <abbrev>DP</abbrev>
-      <authorgroup>
-       <corpauthor>Video Electronics Standards Association
-(<ulink url="http://www.vesa.org">http://www.vesa.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>VESA DisplayPort Standard</title>
-      <subtitle>Version 1, Revision 2</subtitle>
-    </biblioentry>
-
-    <biblioentry id="poynton">
-      <abbrev>poynton</abbrev>
-      <authorgroup>
-       <corpauthor>Charles Poynton</corpauthor>
-      </authorgroup>
-      <title>Digital Video and HDTV, Algorithms and Interfaces</title>
-    </biblioentry>
-
-    <biblioentry id="colimg">
-      <abbrev>colimg</abbrev>
-      <authorgroup>
-       <corpauthor>Erik Reinhard et al.</corpauthor>
-      </authorgroup>
-      <title>Color Imaging: Fundamentals and Applications</title>
-    </biblioentry>
-
-  </bibliography>
diff --git a/Documentation/DocBook/media/v4l/capture.c.xml b/Documentation/DocBook/media/v4l/capture.c.xml
deleted file mode 100644 (file)
index 22126a9..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-<programlisting>
-/*
- *  V4L2 video capture example
- *
- *  This program can be used and distributed without restrictions.
- *
- *      This program is provided with the V4L2 API
- * see https://linuxtv.org/docs.php for more information
- */
-
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;assert.h&gt;
-
-#include &lt;getopt.h&gt;             /* getopt_long() */
-
-#include &lt;fcntl.h&gt;              /* low-level i/o */
-#include &lt;unistd.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;sys/stat.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;sys/time.h&gt;
-#include &lt;sys/mman.h&gt;
-#include &lt;sys/ioctl.h&gt;
-
-#include &lt;linux/videodev2.h&gt;
-
-#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
-
-enum io_method {
-        IO_METHOD_READ,
-        IO_METHOD_MMAP,
-        IO_METHOD_USERPTR,
-};
-
-struct buffer {
-        void   *start;
-        size_t  length;
-};
-
-static char            *dev_name;
-static enum io_method   io = IO_METHOD_MMAP;
-static int              fd = -1;
-struct buffer          *buffers;
-static unsigned int     n_buffers;
-static int              out_buf;
-static int              force_format;
-static int              frame_count = 70;
-
-static void errno_exit(const char *s)
-{
-        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
-        exit(EXIT_FAILURE);
-}
-
-static int xioctl(int fh, int request, void *arg)
-{
-        int r;
-
-        do {
-                r = ioctl(fh, request, arg);
-        } while (-1 == r &amp;&amp; EINTR == errno);
-
-        return r;
-}
-
-static void process_image(const void *p, int size)
-{
-        if (out_buf)
-                fwrite(p, size, 1, stdout);
-
-        fflush(stderr);
-        fprintf(stderr, ".");
-        fflush(stdout);
-}
-
-static int read_frame(void)
-{
-        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-        unsigned int i;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("read");
-                        }
-                }
-
-                process_image(buffers[0].start, buffers[0].length);
-                break;
-
-        case IO_METHOD_MMAP:
-                CLEAR(buf);
-
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-
-                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("VIDIOC_DQBUF");
-                        }
-                }
-
-                assert(buf.index &lt; n_buffers);
-
-                process_image(buffers[buf.index].start, buf.bytesused);
-
-                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                        errno_exit("VIDIOC_QBUF");
-                break;
-
-        case IO_METHOD_USERPTR:
-                CLEAR(buf);
-
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_USERPTR;
-
-                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("VIDIOC_DQBUF");
-                        }
-                }
-
-                for (i = 0; i &lt; n_buffers; ++i)
-                        if (buf.m.userptr == (unsigned long)buffers[i].start
-                            &amp;&amp; buf.length == buffers[i].length)
-                                break;
-
-                assert(i &lt; n_buffers);
-
-                process_image((void *)buf.m.userptr, buf.bytesused);
-
-                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                        errno_exit("VIDIOC_QBUF");
-                break;
-        }
-
-        return 1;
-}
-
-static void mainloop(void)
-{
-        unsigned int count;
-
-        count = frame_count;
-
-        while (count-- &gt; 0) {
-                for (;;) {
-                        fd_set fds;
-                        struct timeval tv;
-                        int r;
-
-                        FD_ZERO(&amp;fds);
-                        FD_SET(fd, &amp;fds);
-
-                        /* Timeout. */
-                        tv.tv_sec = 2;
-                        tv.tv_usec = 0;
-
-                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
-
-                        if (-1 == r) {
-                                if (EINTR == errno)
-                                        continue;
-                                errno_exit("select");
-                        }
-
-                        if (0 == r) {
-                                fprintf(stderr, "select timeout\n");
-                                exit(EXIT_FAILURE);
-                        }
-
-                        if (read_frame())
-                                break;
-                        /* EAGAIN - continue select loop. */
-                }
-        }
-}
-
-static void stop_capturing(void)
-{
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                /* Nothing to do. */
-                break;
-
-        case IO_METHOD_MMAP:
-        case IO_METHOD_USERPTR:
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &amp;type))
-                        errno_exit("VIDIOC_STREAMOFF");
-                break;
-        }
-}
-
-static void start_capturing(void)
-{
-        unsigned int i;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                /* Nothing to do. */
-                break;
-
-        case IO_METHOD_MMAP:
-                for (i = 0; i &lt; n_buffers; ++i) {
-                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                        CLEAR(buf);
-                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                        buf.memory = V4L2_MEMORY_MMAP;
-                        buf.index = i;
-
-                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                                errno_exit("VIDIOC_QBUF");
-                }
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
-                        errno_exit("VIDIOC_STREAMON");
-                break;
-
-        case IO_METHOD_USERPTR:
-                for (i = 0; i &lt; n_buffers; ++i) {
-                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                        CLEAR(buf);
-                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                        buf.memory = V4L2_MEMORY_USERPTR;
-                        buf.index = i;
-                        buf.m.userptr = (unsigned long)buffers[i].start;
-                        buf.length = buffers[i].length;
-
-                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                                errno_exit("VIDIOC_QBUF");
-                }
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
-                        errno_exit("VIDIOC_STREAMON");
-                break;
-        }
-}
-
-static void uninit_device(void)
-{
-        unsigned int i;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                free(buffers[0].start);
-                break;
-
-        case IO_METHOD_MMAP:
-                for (i = 0; i &lt; n_buffers; ++i)
-                        if (-1 == munmap(buffers[i].start, buffers[i].length))
-                                errno_exit("munmap");
-                break;
-
-        case IO_METHOD_USERPTR:
-                for (i = 0; i &lt; n_buffers; ++i)
-                        free(buffers[i].start);
-                break;
-        }
-
-        free(buffers);
-}
-
-static void init_read(unsigned int buffer_size)
-{
-        buffers = calloc(1, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        buffers[0].length = buffer_size;
-        buffers[0].start = malloc(buffer_size);
-
-        if (!buffers[0].start) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-}
-
-static void init_mmap(void)
-{
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
-
-        CLEAR(req);
-
-        req.count = 4;
-        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_MMAP;
-
-        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s does not support "
-                                 "memory mapping\n", dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_REQBUFS");
-                }
-        }
-
-        if (req.count &lt; 2) {
-                fprintf(stderr, "Insufficient buffer memory on %s\n",
-                         dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        buffers = calloc(req.count, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
-                struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                CLEAR(buf);
-
-                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory      = V4L2_MEMORY_MMAP;
-                buf.index       = n_buffers;
-
-                if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &amp;buf))
-                        errno_exit("VIDIOC_QUERYBUF");
-
-                buffers[n_buffers].length = buf.length;
-                buffers[n_buffers].start =
-                        mmap(NULL /* start anywhere */,
-                              buf.length,
-                              PROT_READ | PROT_WRITE /* required */,
-                              MAP_SHARED /* recommended */,
-                              fd, buf.m.offset);
-
-                if (MAP_FAILED == buffers[n_buffers].start)
-                        errno_exit("mmap");
-        }
-}
-
-static void init_userp(unsigned int buffer_size)
-{
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
-
-        CLEAR(req);
-
-        req.count  = 4;
-        req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_USERPTR;
-
-        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s does not support "
-                                 "user pointer i/o\n", dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_REQBUFS");
-                }
-        }
-
-        buffers = calloc(4, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        for (n_buffers = 0; n_buffers &lt; 4; ++n_buffers) {
-                buffers[n_buffers].length = buffer_size;
-                buffers[n_buffers].start = malloc(buffer_size);
-
-                if (!buffers[n_buffers].start) {
-                        fprintf(stderr, "Out of memory\n");
-                        exit(EXIT_FAILURE);
-                }
-        }
-}
-
-static void init_device(void)
-{
-        struct <link linkend="v4l2-capability">v4l2_capability</link> cap;
-        struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> cropcap;
-        struct <link linkend="v4l2-crop">v4l2_crop</link> crop;
-        struct <link linkend="v4l2-format">v4l2_format</link> fmt;
-        unsigned int min;
-
-        if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &amp;cap)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s is no V4L2 device\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_QUERYCAP");
-                }
-        }
-
-        if (!(cap.capabilities &amp; V4L2_CAP_VIDEO_CAPTURE)) {
-                fprintf(stderr, "%s is no video capture device\n",
-                         dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        switch (io) {
-        case IO_METHOD_READ:
-                if (!(cap.capabilities &amp; V4L2_CAP_READWRITE)) {
-                        fprintf(stderr, "%s does not support read i/o\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                }
-                break;
-
-        case IO_METHOD_MMAP:
-        case IO_METHOD_USERPTR:
-                if (!(cap.capabilities &amp; V4L2_CAP_STREAMING)) {
-                        fprintf(stderr, "%s does not support streaming i/o\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                }
-                break;
-        }
-
-
-        /* Select video input, video standard and tune here. */
-
-
-        CLEAR(cropcap);
-
-        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-        if (0 == xioctl(fd, VIDIOC_CROPCAP, &amp;cropcap)) {
-                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                crop.c = cropcap.defrect; /* reset to default */
-
-                if (-1 == xioctl(fd, VIDIOC_S_CROP, &amp;crop)) {
-                        switch (errno) {
-                        case EINVAL:
-                                /* Cropping not supported. */
-                                break;
-                        default:
-                                /* Errors ignored. */
-                                break;
-                        }
-                }
-        } else {
-                /* Errors ignored. */
-        }
-
-
-        CLEAR(fmt);
-
-        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        if (force_format) {
-                fmt.fmt.pix.width       = 640;
-                fmt.fmt.pix.height      = 480;
-                fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-                fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
-
-                if (-1 == xioctl(fd, VIDIOC_S_FMT, &amp;fmt))
-                        errno_exit("VIDIOC_S_FMT");
-
-                /* Note VIDIOC_S_FMT may change width and height. */
-        } else {
-                /* Preserve original settings as set by v4l2-ctl for example */
-                if (-1 == xioctl(fd, VIDIOC_G_FMT, &amp;fmt))
-                        errno_exit("VIDIOC_G_FMT");
-        }
-
-        /* Buggy driver paranoia. */
-        min = fmt.fmt.pix.width * 2;
-        if (fmt.fmt.pix.bytesperline &lt; min)
-                fmt.fmt.pix.bytesperline = min;
-        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
-        if (fmt.fmt.pix.sizeimage &lt; min)
-                fmt.fmt.pix.sizeimage = min;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                init_read(fmt.fmt.pix.sizeimage);
-                break;
-
-        case IO_METHOD_MMAP:
-                init_mmap();
-                break;
-
-        case IO_METHOD_USERPTR:
-                init_userp(fmt.fmt.pix.sizeimage);
-                break;
-        }
-}
-
-static void close_device(void)
-{
-        if (-1 == close(fd))
-                errno_exit("close");
-
-        fd = -1;
-}
-
-static void open_device(void)
-{
-        struct stat st;
-
-        if (-1 == stat(dev_name, &amp;st)) {
-                fprintf(stderr, "Cannot identify '%s': %d, %s\n",
-                         dev_name, errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-
-        if (!S_ISCHR(st.st_mode)) {
-                fprintf(stderr, "%s is no device\n", dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
-
-        if (-1 == fd) {
-                fprintf(stderr, "Cannot open '%s': %d, %s\n",
-                         dev_name, errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-}
-
-static void usage(FILE *fp, int argc, char **argv)
-{
-        fprintf(fp,
-                 "Usage: %s [options]\n\n"
-                 "Version 1.3\n"
-                 "Options:\n"
-                 "-d | --device name   Video device name [%s]\n"
-                 "-h | --help          Print this message\n"
-                 "-m | --mmap          Use memory mapped buffers [default]\n"
-                 "-r | --read          Use read() calls\n"
-                 "-u | --userp         Use application allocated buffers\n"
-                 "-o | --output        Outputs stream to stdout\n"
-                 "-f | --format        Force format to 640x480 YUYV\n"
-                 "-c | --count         Number of frames to grab [%i]\n"
-                 "",
-                 argv[0], dev_name, frame_count);
-}
-
-static const char short_options[] = "d:hmruofc:";
-
-static const struct option
-long_options[] = {
-        { "device", required_argument, NULL, 'd' },
-        { "help",   no_argument,       NULL, 'h' },
-        { "mmap",   no_argument,       NULL, 'm' },
-        { "read",   no_argument,       NULL, 'r' },
-        { "userp",  no_argument,       NULL, 'u' },
-        { "output", no_argument,       NULL, 'o' },
-        { "format", no_argument,       NULL, 'f' },
-        { "count",  required_argument, NULL, 'c' },
-        { 0, 0, 0, 0 }
-};
-
-int main(int argc, char **argv)
-{
-        dev_name = "/dev/video0";
-
-        for (;;) {
-                int idx;
-                int c;
-
-                c = getopt_long(argc, argv,
-                                short_options, long_options, &amp;idx);
-
-                if (-1 == c)
-                        break;
-
-                switch (c) {
-                case 0: /* getopt_long() flag */
-                        break;
-
-                case 'd':
-                        dev_name = optarg;
-                        break;
-
-                case 'h':
-                        usage(stdout, argc, argv);
-                        exit(EXIT_SUCCESS);
-
-                case 'm':
-                        io = IO_METHOD_MMAP;
-                        break;
-
-                case 'r':
-                        io = IO_METHOD_READ;
-                        break;
-
-                case 'u':
-                        io = IO_METHOD_USERPTR;
-                        break;
-
-                case 'o':
-                        out_buf++;
-                        break;
-
-                case 'f':
-                        force_format++;
-                        break;
-
-                case 'c':
-                        errno = 0;
-                        frame_count = strtol(optarg, NULL, 0);
-                        if (errno)
-                                errno_exit(optarg);
-                        break;
-
-                default:
-                        usage(stderr, argc, argv);
-                        exit(EXIT_FAILURE);
-                }
-        }
-
-        open_device();
-        init_device();
-        start_capturing();
-        mainloop();
-        stop_capturing();
-        uninit_device();
-        close_device();
-        fprintf(stderr, "\n");
-        return 0;
-}
-</programlisting>
diff --git a/Documentation/DocBook/media/v4l/cec-api.xml b/Documentation/DocBook/media/v4l/cec-api.xml
deleted file mode 100644 (file)
index 7062c1f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<partinfo>
-  <authorgroup>
-    <author>
-      <firstname>Hans</firstname>
-      <surname>Verkuil</surname>
-      <affiliation><address><email>hans.verkuil@cisco.com</email></address></affiliation>
-      <contrib>Initial version.</contrib>
-    </author>
-  </authorgroup>
-  <copyright>
-    <year>2016</year>
-    <holder>Hans Verkuil</holder>
-  </copyright>
-
-  <revhistory>
-    <!-- Put document revisions here, newest first. -->
-    <revision>
-      <revnumber>1.0.0</revnumber>
-      <date>2016-03-17</date>
-      <authorinitials>hv</authorinitials>
-      <revremark>Initial revision</revremark>
-    </revision>
-  </revhistory>
-</partinfo>
-
-<title>CEC API</title>
-
-<chapter id="cec-api">
-  <title>CEC: Consumer Electronics Control</title>
-
-  <section id="cec-intro">
-    <title>Introduction</title>
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-    <para>HDMI connectors provide a single pin for use by the Consumer Electronics
-    Control protocol. This protocol allows different devices connected by an HDMI cable
-    to communicate. The protocol for CEC version 1.4 is defined in supplements 1 (CEC)
-    and 2 (HEAC or HDMI Ethernet and Audio Return Channel) of the HDMI 1.4a
-    (<xref linkend="hdmi" />) specification and the extensions added to CEC version 2.0
-    are defined in chapter 11 of the HDMI 2.0 (<xref linkend="hdmi2" />) specification.
-    </para>
-
-    <para>The bitrate is very slow (effectively no more than 36 bytes per second) and
-    is based on the ancient AV.link protocol used in old SCART connectors. The protocol
-    closely resembles a crazy Rube Goldberg contraption and is an unholy mix of low and
-    high level messages. Some messages, especially those part of the HEAC protocol layered
-    on top of CEC, need to be handled by the kernel, others can be handled either by the
-    kernel or by userspace.</para>
-
-    <para>In addition, CEC can be implemented in HDMI receivers, transmitters and in USB
-    devices that have an HDMI input and an HDMI output and that control just the CEC pin.</para>
-
-    <para>Drivers that support CEC will create a CEC device node (/dev/cecX)
-    to give userspace access to the CEC adapter. The &CEC-ADAP-G-CAPS; ioctl will tell userspace
-    what it is allowed to do.</para>
-  </section>
-</chapter>
-
-<appendix id="cec-user-func">
-  <title>Function Reference</title>
-  <!-- Keep this alphabetically sorted. -->
-  &sub-cec-func-open;
-  &sub-cec-func-close;
-  &sub-cec-func-ioctl;
-  &sub-cec-func-poll;
-  <!-- All ioctls go here. -->
-  &sub-cec-ioc-adap-g-caps;
-  &sub-cec-ioc-adap-g-log-addrs;
-  &sub-cec-ioc-adap-g-phys-addr;
-  &sub-cec-ioc-dqevent;
-  &sub-cec-ioc-g-mode;
-  &sub-cec-ioc-receive;
-</appendix>
diff --git a/Documentation/DocBook/media/v4l/cec-func-close.xml b/Documentation/DocBook/media/v4l/cec-func-close.xml
deleted file mode 100644 (file)
index 0812c8c..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<refentry id="cec-func-close">
-  <refmeta>
-    <refentrytitle>cec close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>cec-close</refname>
-    <refpurpose>Close a cec device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>Closes the cec device. Resources associated with the file descriptor
-    are freed. The device configuration remain unchanged.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>close</function> returns 0 on success. On error, -1 is
-    returned, and <varname>errno</varname> is set appropriately. Possible error
-    codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file descriptor.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-func-ioctl.xml b/Documentation/DocBook/media/v4l/cec-func-ioctl.xml
deleted file mode 100644 (file)
index f92817a..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<refentry id="cec-func-ioctl">
-  <refmeta>
-    <refentrytitle>cec ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>cec-ioctl</refname>
-    <refpurpose>Control a cec device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<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>CEC ioctl request code as defined in the cec.h header file,
-         for example CEC_ADAP_G_CAPS.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a request-specific structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>The <function>ioctl()</function> function manipulates cec device
-    parameters. The argument <parameter>fd</parameter> must be an open file
-    descriptor.</para>
-    <para>The ioctl <parameter>request</parameter> code specifies the cec
-    function to be called. It has encoded in it whether the argument is an
-    input, output or read/write parameter, and the size of the argument
-    <parameter>argp</parameter> in bytes.</para>
-    <para>Macros and structures definitions specifying cec ioctl requests and
-    their parameters are located in the cec.h header file. All cec ioctl
-    requests, their respective function and parameters are specified in
-    <xref linkend="cec-user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <para>Request-specific error codes are listed in the
-    individual requests descriptions.</para>
-    <para>When an ioctl that takes an output or read/write parameter fails,
-    the parameter remains unmodified.</para>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-func-open.xml b/Documentation/DocBook/media/v4l/cec-func-open.xml
deleted file mode 100644 (file)
index 2edc555..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-<refentry id="cec-func-open">
-  <refmeta>
-    <refentrytitle>cec open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>cec-open</refname>
-    <refpurpose>Open a cec device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access mode must be <constant>O_RDWR</constant>.
-         </para>
-         <para>When the <constant>O_NONBLOCK</constant> flag is
-given, the &CEC-RECEIVE; ioctl will return &EAGAIN; when no message is
-available, and the &CEC-TRANSMIT;, &CEC-ADAP-S-PHYS-ADDR; and
-&CEC-ADAP-S-LOG-ADDRS; ioctls all act in non-blocking mode.</para>
-         <para>Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>To open a cec device applications call <function>open()</function>
-    with the desired device name. The function has no side effects; the device
-    configuration remain unchanged.</para>
-    <para>When the device is opened in read-only mode, attempts to modify its
-    configuration will result in an error, and <varname>errno</varname> will be
-    set to <errorcode>EBADF</errorcode>.</para>
-  </refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>open</function> returns the new file descriptor on success.
-    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
-    Possible error codes include:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The requested access to the file is not allowed.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of files open.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The system limit on the total number of open files has been
-         reached.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Insufficient kernel memory was available.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file exists.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-func-poll.xml b/Documentation/DocBook/media/v4l/cec-func-poll.xml
deleted file mode 100644 (file)
index 1bddbde..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<refentry id="cec-func-poll">
-  <refmeta>
-    <refentrytitle>cec poll()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>cec-poll</refname>
-    <refpurpose>Wait for some event on a file descriptor</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/poll.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>poll</function></funcdef>
-       <paramdef>struct pollfd *<parameter>ufds</parameter></paramdef>
-       <paramdef>unsigned int <parameter>nfds</parameter></paramdef>
-       <paramdef>int <parameter>timeout</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>With the <function>poll()</function> function applications
-can wait for CEC events.</para>
-
-    <para>On success <function>poll()</function> returns the number of
-file descriptors that have been selected (that is, file descriptors
-for which the <structfield>revents</structfield> field of the
-respective <structname>pollfd</structname> structure is non-zero).
-CEC devices set the <constant>POLLIN</constant> and
-<constant>POLLRDNORM</constant> flags in the
-<structfield>revents</structfield> field if there are messages in the
-receive queue. If the transmit queue has room for new messages, the
-<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant>
-flags are set. If there are events in the event queue, then the
-<constant>POLLPRI</constant> flag is set.
-When the function timed out it returns a value of zero, on
-failure it returns <returnvalue>-1</returnvalue> and the
-<varname>errno</varname> variable is set appropriately.
-</para>
-
-    <para>For more details see the
-<function>poll()</function> manual page.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, <function>poll()</function> returns the number
-structures which have non-zero <structfield>revents</structfield>
-fields, or zero if the call timed out. On error
-<returnvalue>-1</returnvalue> is returned, and the
-<varname>errno</varname> variable is set appropriately:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para>One or more of the <parameter>ufds</parameter> members
-specify an invalid file descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>ufds</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>nfds</parameter> argument is greater
-than <constant>OPEN_MAX</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml b/Documentation/DocBook/media/v4l/cec-ioc-adap-g-caps.xml
deleted file mode 100644 (file)
index 3523ef2..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<refentry id="cec-ioc-adap-g-caps">
-  <refmeta>
-    <refentrytitle>ioctl CEC_ADAP_G_CAPS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_ADAP_G_CAPS</refname>
-    <refpurpose>Query device capabilities</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 cec_caps *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_ADAP_G_CAPS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>All cec devices must support the <constant>CEC_ADAP_G_CAPS</constant>
-    ioctl. To query device information, applications call the ioctl with a
-    pointer to a &cec-caps;. The driver fills the structure and returns
-    the information to the application.
-    The ioctl never fails.</para>
-
-    <table pgwide="1" frame="none" id="cec-caps">
-      <title>struct <structname>cec_caps</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>char</entry>
-           <entry><structfield>driver[32]</structfield></entry>
-           <entry>The name of the cec adapter driver.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name[32]</structfield></entry>
-           <entry>The name of this CEC adapter. The combination <structfield>driver</structfield>
-           and <structfield>name</structfield> must be unique.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>The capabilities of the CEC adapter, see <xref
-               linkend="cec-capabilities" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>version</structfield></entry>
-           <entry>CEC Framework API version, formatted with the
-           <constant>KERNEL_VERSION()</constant> macro.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-capabilities">
-      <title>CEC Capabilities Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_CAP_PHYS_ADDR</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>Userspace has to configure the physical address by
-           calling &CEC-ADAP-S-PHYS-ADDR;. If this capability isn't set,
-           then setting the physical address is handled by the kernel
-           whenever the EDID is set (for an HDMI receiver) or read (for
-           an HDMI transmitter).</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_CAP_LOG_ADDRS</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>Userspace has to configure the logical addresses by
-           calling &CEC-ADAP-S-LOG-ADDRS;. If this capability isn't set,
-           then the kernel will have configured this.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_CAP_TRANSMIT</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>Userspace can transmit CEC messages by calling &CEC-TRANSMIT;. This
-           implies that userspace can be a follower as well, since being able to
-           transmit messages is a prerequisite of becoming a follower. If this
-           capability isn't set, then the kernel will handle all CEC transmits
-           and process all CEC messages it receives.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>CEC_CAP_PASSTHROUGH</constant></entry>
-           <entry>0x00000008</entry>
-           <entry>Userspace can use the passthrough mode by
-           calling &CEC-S-MODE;.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_CAP_RC</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>This adapter supports the remote control protocol.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_CAP_MONITOR_ALL</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>The CEC hardware can monitor all messages, not just directed and
-           broadcast messages.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml b/Documentation/DocBook/media/v4l/cec-ioc-adap-g-log-addrs.xml
deleted file mode 100644 (file)
index 302b829..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-<refentry id="cec-ioc-adap-g-log-addrs">
-  <refmeta>
-    <refentrytitle>ioctl CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_ADAP_G_LOG_ADDRS</refname>
-    <refname>CEC_ADAP_S_LOG_ADDRS</refname>
-    <refpurpose>Get or set the logical addresses</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 cec_log_addrs *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>To query the current CEC logical addresses, applications call the
-<constant>CEC_ADAP_G_LOG_ADDRS</constant> ioctl with a pointer to a
-<structname>cec_log_addrs</structname> structure where the drivers stores the
-logical addresses.</para>
-
-    <para>To set new logical addresses, applications fill in struct <structname>cec_log_addrs</structname>
-and call the <constant>CEC_ADAP_S_LOG_ADDRS</constant> ioctl with a pointer to this struct.
-The <constant>CEC_ADAP_S_LOG_ADDRS</constant> ioctl is only available if
-<constant>CEC_CAP_LOG_ADDRS</constant> is set (&ENOTTY; is returned otherwise). This ioctl will block until all
-requested logical addresses have been claimed. <constant>CEC_ADAP_S_LOG_ADDRS</constant>
-can only be called by a file handle in initiator mode (see &CEC-S-MODE;).</para>
-
-    <table pgwide="1" frame="none" id="cec-log-addrs">
-      <title>struct <structname>cec_log_addrs</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>log_addr</structfield>[CEC_MAX_LOG_ADDRS]</entry>
-           <entry>The actual logical addresses that were claimed. This is set by the
-           driver. If no logical address could be claimed, then it is set to
-           <constant>CEC_LOG_ADDR_INVALID</constant>. If this adapter is Unregistered,
-           then <structfield>log_addr[0]</structfield> is set to 0xf and all others to
-           <constant>CEC_LOG_ADDR_INVALID</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>log_addr_mask</structfield></entry>
-           <entry>The bitmask of all logical addresses this adapter has claimed.
-           If this adapter is Unregistered then <structfield>log_addr_mask</structfield>
-           sets bit 15 and clears all other bits. If this adapter is not configured at all, then
-           <structfield>log_addr_mask</structfield> is set to 0. Set by the driver.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>cec_version</structfield></entry>
-           <entry>The CEC version that this adapter shall use. See
-           <xref linkend="cec-versions" />.
-           Used to implement the <constant>CEC_MSG_CEC_VERSION</constant> and
-           <constant>CEC_MSG_REPORT_FEATURES</constant> messages. Note that
-           <constant>CEC_OP_CEC_VERSION_1_3A</constant> is not allowed
-           by the CEC framework.
-           </entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>num_log_addrs</structfield></entry>
-           <entry>Number of logical addresses to set up. Must be &le;
-           <structfield>available_log_addrs</structfield> as returned by
-           &CEC-ADAP-G-CAPS;. All arrays in this structure are only filled up to
-           index <structfield>available_log_addrs</structfield>-1. The remaining
-           array elements will be ignored. Note that the CEC 2.0 standard allows
-           for a maximum of 2 logical addresses, although some hardware has support
-           for more. <constant>CEC_MAX_LOG_ADDRS</constant> is 4. The driver will
-           return the actual number of logical addresses it could claim, which may
-           be less than what was requested. If this field is set to 0, then the
-           CEC adapter shall clear all claimed logical addresses and all other
-           fields will be ignored.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vendor_id</structfield></entry>
-           <entry>The vendor ID is a 24-bit number that identifies the specific
-           vendor or entity. Based on this ID vendor specific commands may be
-           defined. If you do not want a vendor ID then set it to
-           <constant>CEC_VENDOR_ID_NONE</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags. No flags are defined yet, so set this to 0.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>osd_name</structfield>[15]</entry>
-           <entry>The On-Screen Display name as is returned by the
-           <constant>CEC_MSG_SET_OSD_NAME</constant> message.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>primary_device_type</structfield>[CEC_MAX_LOG_ADDRS]</entry>
-           <entry>Primary device type for each logical address. See
-           <xref linkend="cec-prim-dev-types" /> for possible types.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>log_addr_type</structfield>[CEC_MAX_LOG_ADDRS]</entry>
-           <entry>Logical address types. See <xref linkend="cec-log-addr-types" /> for
-           possible types. The driver will update this with the actual logical address
-           type that it claimed (e.g. it may have to fallback to
-           <constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant>).</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>all_device_types</structfield>[CEC_MAX_LOG_ADDRS]</entry>
-           <entry>CEC 2.0 specific: all device types. See <xref linkend="cec-all-dev-types-flags" />.
-           Used to implement the <constant>CEC_MSG_REPORT_FEATURES</constant> message.
-           This field is ignored if <structfield>cec_version</structfield> &lt;
-           <constant>CEC_OP_CEC_VERSION_2_0</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>features</structfield>[CEC_MAX_LOG_ADDRS][12]</entry>
-           <entry>Features for each logical address. Used to implement the
-           <constant>CEC_MSG_REPORT_FEATURES</constant> message. The 12 bytes include
-           both the RC Profile and the Device Features.
-           This field is ignored if <structfield>cec_version</structfield> &lt;
-           <constant>CEC_OP_CEC_VERSION_2_0</constant>.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-versions">
-      <title>CEC Versions</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_OP_CEC_VERSION_1_3A</constant></entry>
-           <entry>4</entry>
-           <entry>CEC version according to the HDMI 1.3a standard.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_CEC_VERSION_1_4B</constant></entry>
-           <entry>5</entry>
-           <entry>CEC version according to the HDMI 1.4b standard.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_CEC_VERSION_2_0</constant></entry>
-           <entry>6</entry>
-           <entry>CEC version according to the HDMI 2.0 standard.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-prim-dev-types">
-      <title>CEC Primary Device Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_TV</constant></entry>
-           <entry>0</entry>
-           <entry>Use for a TV.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_RECORD</constant></entry>
-           <entry>1</entry>
-           <entry>Use for a recording device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_TUNER</constant></entry>
-           <entry>3</entry>
-           <entry>Use for a device with a tuner.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_PLAYBACK</constant></entry>
-           <entry>4</entry>
-           <entry>Use for a playback device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM</constant></entry>
-           <entry>5</entry>
-           <entry>Use for an audio system (e.g. an audio/video receiver).</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_SWITCH</constant></entry>
-           <entry>6</entry>
-           <entry>Use for a CEC switch.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_PRIM_DEVTYPE_VIDEOPROC</constant></entry>
-           <entry>7</entry>
-           <entry>Use for a video processor device.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-log-addr-types">
-      <title>CEC Logical Address Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_TV</constant></entry>
-           <entry>0</entry>
-           <entry>Use for a TV.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_RECORD</constant></entry>
-           <entry>1</entry>
-           <entry>Use for a recording device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_TUNER</constant></entry>
-           <entry>2</entry>
-           <entry>Use for a tuner device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_PLAYBACK</constant></entry>
-           <entry>3</entry>
-           <entry>Use for a playback device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_AUDIOSYSTEM</constant></entry>
-           <entry>4</entry>
-           <entry>Use for an audio system device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_SPECIFIC</constant></entry>
-           <entry>5</entry>
-           <entry>Use for a second TV or for a video processor device.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant></entry>
-           <entry>6</entry>
-           <entry>Use this if you just want to remain unregistered.
-           Used for pure CEC switches or CDC-only devices (CDC:
-           Capability Discovery and Control).</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-all-dev-types-flags">
-      <title>CEC All Device Types Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_TV</constant></entry>
-           <entry>0x80</entry>
-           <entry>This supports the TV type.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_RECORD</constant></entry>
-           <entry>0x40</entry>
-           <entry>This supports the Recording type.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_TUNER</constant></entry>
-           <entry>0x20</entry>
-           <entry>This supports the Tuner type.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_PLAYBACK</constant></entry>
-           <entry>0x10</entry>
-           <entry>This supports the Playback type.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM</constant></entry>
-           <entry>0x08</entry>
-           <entry>This supports the Audio System type.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_OP_ALL_DEVTYPE_SWITCH</constant></entry>
-           <entry>0x04</entry>
-           <entry>This supports the CEC Switch or Video Processing type.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml b/Documentation/DocBook/media/v4l/cec-ioc-adap-g-phys-addr.xml
deleted file mode 100644 (file)
index d95f178..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<refentry id="cec-ioc-adap-g-phys-addr">
-  <refmeta>
-    <refentrytitle>ioctl CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_ADAP_G_PHYS_ADDR</refname>
-    <refname>CEC_ADAP_S_PHYS_ADDR</refname>
-    <refpurpose>Get or set the physical address</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>__u16 *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>To query the current physical address applications call the
-<constant>CEC_ADAP_G_PHYS_ADDR</constant> ioctl with a pointer to an __u16
-where the driver stores the physical address.</para>
-
-    <para>To set a new physical address applications store the physical address in
-an __u16 and call the <constant>CEC_ADAP_S_PHYS_ADDR</constant> ioctl with a
-pointer to this integer. <constant>CEC_ADAP_S_PHYS_ADDR</constant> is only
-available if <constant>CEC_CAP_PHYS_ADDR</constant> is set (&ENOTTY; will be returned
-otherwise). <constant>CEC_ADAP_S_PHYS_ADDR</constant>
-can only be called by a file handle in initiator mode (see &CEC-S-MODE;), if not
-&EBUSY; will be returned.</para>
-
-    <para>The physical address is a 16-bit number where each group of 4 bits
-represent a digit of the physical address a.b.c.d where the most significant
-4 bits represent 'a'. The CEC root device (usually the TV) has address 0.0.0.0.
-Every device that is hooked up to an input of the TV has address a.0.0.0 (where
-'a' is &ge; 1), devices hooked up to those in turn have addresses a.b.0.0, etc.
-So a topology of up to 5 devices deep is supported. The physical address a
-device shall use is stored in the EDID of the sink.</para>
-
-<para>For example, the EDID for each HDMI input of the TV will have a different
-physical address of the form a.0.0.0 that the sources will read out and use as
-their physical address.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml b/Documentation/DocBook/media/v4l/cec-ioc-dqevent.xml
deleted file mode 100644 (file)
index 697dde5..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-<refentry id="cec-ioc-g-event">
-  <refmeta>
-    <refentrytitle>ioctl CEC_DQEVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_DQEVENT</refname>
-    <refpurpose>Dequeue a CEC event</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 cec_event *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_DQEVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>CEC devices can send asynchronous events. These can be retrieved by calling
-    the <constant>CEC_DQEVENT</constant> ioctl. If the file descriptor is in non-blocking
-    mode and no event is pending, then it will return -1 and set errno to the &EAGAIN;.</para>
-
-    <para>The internal event queues are per-filehandle and per-event type. If there is
-    no more room in a queue then the last event is overwritten with the new one. This
-    means that intermediate results can be thrown away but that the latest event is always
-    available. This also means that is it possible to read two successive events that have
-    the same value (e.g. two CEC_EVENT_STATE_CHANGE events with the same state). In that
-    case the intermediate state changes were lost but it is guaranteed that the state
-    did change in between the two events.</para>
-
-    <table pgwide="1" frame="none" id="cec-event-state-change">
-      <title>struct <structname>cec_event_state_change</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>phys_addr</structfield></entry>
-           <entry>The current physical address.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>log_addr_mask</structfield></entry>
-           <entry>The current set of claimed logical addresses.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-event-lost-msgs">
-      <title>struct <structname>cec_event_lost_msgs</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>lost_msgs</structfield></entry>
-           <entry>Set to the number of lost messages since the filehandle
-           was opened or since the last time this event was dequeued for
-           this filehandle. The messages lost are the oldest messages. So
-           when a new message arrives and there is no more room, then the
-           oldest message is discarded to make room for the new one. The
-           internal size of the message queue guarantees that all messages
-           received in the last two seconds will be stored. Since messages
-           should be replied to within a second according to the CEC
-           specification, this is more than enough.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-event">
-      <title>struct <structname>cec_event</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ts</structfield></entry>
-           <entry>Timestamp of the event in ns.</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>event</structfield></entry>
-           <entry>The CEC event type, see <xref linkend="cec-events" />.</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Event flags, see <xref linkend="cec-event-flags" />.</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct cec_event_state_change</entry>
-           <entry><structfield>state_change</structfield></entry>
-           <entry>The new adapter state as sent by the <constant>CEC_EVENT_STATE_CHANGE</constant>
-           event.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct cec_event_lost_msgs</entry>
-           <entry><structfield>lost_msgs</structfield></entry>
-           <entry>The number of lost messages as sent by the <constant>CEC_EVENT_LOST_MSGS</constant>
-           event.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-events">
-      <title>CEC Events Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_EVENT_STATE_CHANGE</constant></entry>
-           <entry>1</entry>
-           <entry>Generated when the CEC Adapter's state changes. When open() is
-           called an initial event will be generated for that filehandle with the
-           CEC Adapter's state at that time.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>CEC_EVENT_LOST_MSGS</constant></entry>
-           <entry>2</entry>
-           <entry>Generated if one or more CEC messages were lost because the
-           application didn't dequeue CEC messages fast enough.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-event-flags">
-      <title>CEC Event Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_EVENT_FL_INITIAL_VALUE</constant></entry>
-           <entry>1</entry>
-           <entry>Set for the initial events that are generated when the device is
-           opened. See the table above for which events do this. This allows
-           applications to learn the initial state of the CEC adapter at open()
-           time.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-mode.xml
deleted file mode 100644 (file)
index 26b4282..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-<refentry id="cec-ioc-g-mode">
-  <refmeta>
-    <refentrytitle>ioctl CEC_G_MODE, CEC_S_MODE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_G_MODE</refname>
-    <refname>CEC_S_MODE</refname>
-    <refpurpose>Get or set exclusive use of the CEC adapter</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>__u32 *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_G_MODE, CEC_S_MODE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>By default any filehandle can use &CEC-TRANSMIT; and &CEC-RECEIVE;, but
-in order to prevent applications from stepping on each others toes it must be possible
-to obtain exclusive access to the CEC adapter. This ioctl sets the filehandle
-to initiator and/or follower mode which can be exclusive depending on the chosen
-mode. The initiator is the filehandle that is used
-to initiate messages, i.e. it commands other CEC devices. The follower is the filehandle
-that receives messages sent to the CEC adapter and processes them. The same filehandle
-can be both initiator and follower, or this role can be taken by two different
-filehandles.</para>
-
-    <para>When a CEC message is received, then the CEC framework will decide how
-it will be processed. If the message is a reply to an earlier transmitted message,
-then the reply is sent back to the filehandle that is waiting for it. In addition
-the CEC framework will process it.</para>
-
-    <para>If the message is not a reply, then the CEC framework will process it
-first. If there is no follower, then the message is just discarded and a feature
-abort is sent back to the initiator if the framework couldn't process it. If there
-is a follower, then the message is passed on to the follower who will use
-&CEC-RECEIVE; to dequeue the new message. The framework expects the follower to
-make the right decisions.</para>
-
-    <para>The CEC framework will process core messages unless requested otherwise
-by the follower. The follower can enable the passthrough mode. In that case, the
-CEC framework will pass on most core messages without processing them and
-the follower will have to implement those messages. There are some messages
-that the core will always process, regardless of the passthrough mode. See
-<xref linkend="cec-core-processing" /> for details.</para>
-
-    <para>If there is no initiator, then any CEC filehandle can use &CEC-TRANSMIT;.
-If there is an exclusive initiator then only that initiator can call &CEC-TRANSMIT;.
-The follower can of course always call &CEC-TRANSMIT;.</para>
-
-    <para>Available initiator modes are:</para>
-
-    <table pgwide="1" frame="none" id="cec-mode-initiator">
-      <title>Initiator Modes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_MODE_NO_INITIATOR</constant></entry>
-           <entry>0x0</entry>
-           <entry>This is not an initiator, i.e. it cannot transmit CEC messages
-           or make any other changes to the CEC adapter.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_INITIATOR</constant></entry>
-           <entry>0x1</entry>
-           <entry>This is an initiator (the default when the device is opened) and it
-           can transmit CEC messages and make changes to the CEC adapter, unless there
-           is an exclusive initiator.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_EXCL_INITIATOR</constant></entry>
-           <entry>0x2</entry>
-           <entry>This is an exclusive initiator and this file descriptor is the only one
-           that can transmit CEC messages and make changes to the CEC adapter. If someone
-           else is already the exclusive initiator then an attempt to become one will return
-           the &EBUSY; error.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Available follower modes are:</para>
-
-    <table pgwide="1" frame="none" id="cec-mode-follower">
-      <title>Follower Modes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_MODE_NO_FOLLOWER</constant></entry>
-           <entry>0x00</entry>
-           <entry>This is not a follower (the default when the device is opened).</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_FOLLOWER</constant></entry>
-           <entry>0x10</entry>
-           <entry>This is a follower and it will receive CEC messages unless there is
-           an exclusive follower. You cannot become a follower if <constant>CEC_CAP_TRANSMIT</constant>
-           is not set or if <constant>CEC_MODE_NO_INITIATOR</constant> was specified,
-           &EINVAL; is returned in that case.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_EXCL_FOLLOWER</constant></entry>
-           <entry>0x20</entry>
-           <entry>This is an exclusive follower and only this file descriptor will receive
-           CEC messages for processing. If someone else is already the exclusive follower
-           then an attempt to become one will return the &EBUSY; error. You cannot become
-           a follower if <constant>CEC_CAP_TRANSMIT</constant> is not set or if
-           <constant>CEC_MODE_NO_INITIATOR</constant> was specified, &EINVAL; is returned
-           in that case.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_EXCL_FOLLOWER_PASSTHRU</constant></entry>
-           <entry>0x30</entry>
-           <entry>This is an exclusive follower and only this file descriptor will receive
-           CEC messages for processing. In addition it will put the CEC device into
-           passthrough mode, allowing the exclusive follower to handle most core messages
-           instead of relying on the CEC framework for that. If someone else is already the
-           exclusive follower then an attempt to become one will return the &EBUSY; error.
-           You cannot become a follower if <constant>CEC_CAP_TRANSMIT</constant>
-            is not set or if <constant>CEC_MODE_NO_INITIATOR</constant> was specified,
-            &EINVAL; is returned in that case.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_MONITOR</constant></entry>
-           <entry>0xe0</entry>
-           <entry>Put the file descriptor into monitor mode. Can only be used in combination
-           with <constant>CEC_MODE_NO_INITIATOR</constant>, otherwise &EINVAL; will be
-           returned. In monitor mode all messages this CEC device transmits and all messages
-           it receives (both broadcast messages and directed messages for one its logical
-           addresses) will be reported. This is very useful for debugging. This is only
-           allowed if the process has the <constant>CAP_NET_ADMIN</constant>
-           capability. If that is not set, then &EPERM; is returned.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MODE_MONITOR_ALL</constant></entry>
-           <entry>0xf0</entry>
-           <entry>Put the file descriptor into 'monitor all' mode. Can only be used in combination
-            with <constant>CEC_MODE_NO_INITIATOR</constant>, otherwise &EINVAL; will be
-            returned. In 'monitor all' mode all messages this CEC device transmits and all messages
-            it receives, including directed messages for other CEC devices will be reported. This
-           is very useful for debugging, but not all devices support this. This mode requires that
-           the <constant>CEC_CAP_MONITOR_ALL</constant> capability is set, otherwise &EINVAL; is
-           returned. This is only allowed if the process has the <constant>CAP_NET_ADMIN</constant>
-           capability. If that is not set, then &EPERM; is returned.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Core message processing details:</para>
-
-    <table pgwide="1" frame="none" id="cec-core-processing">
-      <title>Core Message Processing</title>
-      <tgroup cols="2">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_MSG_GET_CEC_VERSION</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will return the CEC version that was set with &CEC-ADAP-S-LOG-ADDRS;.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_GIVE_DEVICE_VENDOR_ID</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will return the vendor ID that was set with &CEC-ADAP-S-LOG-ADDRS;.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_ABORT</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will return a feature refused message as per the specification.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_GIVE_PHYSICAL_ADDR</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will report the current physical address.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_GIVE_OSD_NAME</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will report the current OSD name as was set with
-           &CEC-ADAP-S-LOG-ADDRS;.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_GIVE_FEATURES</constant></entry>
-           <entry>When in passthrough mode this message has to be handled by userspace,
-           otherwise the core will report the current features as was set with
-           &CEC-ADAP-S-LOG-ADDRS; or the message is ignore if the CEC version was
-           older than 2.0.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_USER_CONTROL_PRESSED</constant></entry>
-           <entry>If <constant>CEC_CAP_RC</constant> is set, then generate a remote control
-           key press. This message is always passed on to userspace.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_USER_CONTROL_RELEASED</constant></entry>
-           <entry>If <constant>CEC_CAP_RC</constant> is set, then generate a remote control
-           key release. This message is always passed on to userspace.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_MSG_REPORT_PHYSICAL_ADDR</constant></entry>
-           <entry>The CEC framework will make note of the reported physical address
-           and then just pass the message on to userspace.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-receive.xml b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
deleted file mode 100644 (file)
index fde9f86..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-<refentry id="cec-ioc-receive">
-  <refmeta>
-    <refentrytitle>ioctl CEC_RECEIVE, CEC_TRANSMIT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>CEC_RECEIVE</refname>
-    <refname>CEC_TRANSMIT</refname>
-    <refpurpose>Receive or transmit a CEC message</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 cec_msg *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='cec-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>CEC_RECEIVE, CEC_TRANSMIT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      Note: this documents the proposed CEC API. This API is not yet finalized and
-      is currently only available as a staging kernel module.
-    </para>
-
-    <para>To receive a CEC message the application has to fill in the
-    <structname>cec_msg</structname> structure and pass it to the
-    <constant>CEC_RECEIVE</constant> ioctl. <constant>CEC_RECEIVE</constant> is
-    only available if <constant>CEC_CAP_RECEIVE</constant> is set. If the
-    file descriptor is in non-blocking mode and there are no received
-    messages pending, then it will return -1 and set errno to the &EAGAIN;.
-    If the file descriptor is in blocking mode and <structfield>timeout</structfield>
-    is non-zero and no message arrived within <structfield>timeout</structfield>
-    milliseconds, then it will return -1 and set errno to the &ETIMEDOUT;.</para>
-
-    <para>To send a CEC message the application has to fill in the
-    <structname>cec_msg</structname> structure and pass it to the
-    <constant>CEC_TRANSMIT</constant> ioctl. <constant>CEC_TRANSMIT</constant> is
-    only available if <constant>CEC_CAP_TRANSMIT</constant> is set.
-    If there is no more room in the transmit queue, then it will return
-    -1 and set errno to the &EBUSY;.</para>
-
-    <table pgwide="1" frame="none" id="cec-msg">
-      <title>struct <structname>cec_msg</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ts</structfield></entry>
-           <entry>Timestamp of when the message was transmitted in ns in the case
-           of <constant>CEC_TRANSMIT</constant> with <structfield>reply</structfield>
-           set to 0, or the timestamp of the received message in all other cases.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>len</structfield></entry>
-           <entry>The length of the message. For <constant>CEC_TRANSMIT</constant> this
-           is filled in by the application. The driver will fill this in for
-           <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant>
-           it will be filled in with the length of the reply message if
-           <structfield>reply</structfield> was set.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>timeout</structfield></entry>
-           <entry>The timeout in milliseconds. This is the time the device will wait for a message to
-           be received before timing out. If it is set to 0, then it will wait indefinitely when it
-           is called by <constant>CEC_RECEIVE</constant>. If it is 0 and it is called by
-           <constant>CEC_TRANSMIT</constant>, then it will be replaced by 1000 if the
-           <structfield>reply</structfield> is non-zero or ignored if <structfield>reply</structfield>
-           is 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sequence</structfield></entry>
-           <entry>The sequence number is automatically assigned by the CEC
-           framework for all transmitted messages. It can be later used by the
-           framework to generate an event if a reply for a message was
-           requested and the message was transmitted in a non-blocking mode.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags. No flags are defined yet, so set this to 0.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>rx_status</structfield></entry>
-           <entry>The status bits of the received message. See <xref linkend="cec-rx-status" />
-           for the possible status values. It is 0 if this message was transmitted, not
-           received, unless this is the reply to a transmitted message. In that case both
-           <structfield>rx_status</structfield> and <structfield>tx_status</structfield>
-           are set.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>tx_status</structfield></entry>
-           <entry>The status bits of the transmitted message. See <xref linkend="cec-tx-status" />
-           for the possible status values. It is 0 if this messages was received, not
-           transmitted.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>msg</structfield>[16]</entry>
-           <entry>The message payload. For <constant>CEC_TRANSMIT</constant> this
-           is filled in by the application. The driver will fill this in for
-           <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant>
-           it will be filled in with the payload of the reply message if
-           <structfield>reply</structfield> was set.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>reply</structfield></entry>
-           <entry>Wait until this message is replied. If <structfield>reply</structfield>
-           is 0 and the <structfield>timeout</structfield> is 0, then don't wait for a reply but
-           return after transmitting the message. If there was an error as indicated by a non-zero
-           <structfield>tx_status</structfield> field, then <structfield>reply</structfield> and
-           <structfield>timeout</structfield> are both set to 0 by the driver. Ignored by
-           <constant>CEC_RECEIVE</constant>. The case where <structfield>reply</structfield> is 0
-           (this is the opcode for the Feature Abort message) and <structfield>timeout</structfield>
-           is non-zero is specifically allowed to send a message and wait up to <structfield>timeout</structfield>
-           milliseconds for a Feature Abort reply. In this case <structfield>rx_status</structfield>
-           will either be set to <constant>CEC_RX_STATUS_TIMEOUT</constant> or
-           <constant>CEC_RX_STATUS_FEATURE_ABORT</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>tx_arb_lost_cnt</structfield></entry>
-           <entry>A counter of the number of transmit attempts that resulted in the
-           Arbitration Lost error. This is only set if the hardware supports this, otherwise
-           it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_ARB_LOST</constant>
-           status bit is set.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>tx_nack_cnt</structfield></entry>
-           <entry>A counter of the number of transmit attempts that resulted in the
-           Not Acknowledged error. This is only set if the hardware supports this, otherwise
-           it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_NACK</constant>
-            status bit is set.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>tx_low_drive_cnt</structfield></entry>
-           <entry>A counter of the number of transmit attempts that resulted in the
-           Arbitration Lost error. This is only set if the hardware supports this, otherwise
-           it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_LOW_DRIVE</constant>
-            status bit is set.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>tx_error_cnt</structfield></entry>
-           <entry>A counter of the number of transmit errors other than Arbitration Lost
-           or Not Acknowledged. This is only set if the hardware supports this, otherwise
-           it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_ERROR</constant>
-           status bit is set.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-tx-status">
-      <title>CEC Transmit Status</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_TX_STATUS_OK</constant></entry>
-           <entry>0x01</entry>
-           <entry>The message was transmitted successfully. This is mutually exclusive with
-           <constant>CEC_TX_STATUS_MAX_RETRIES</constant>. Other bits can still be set if
-           earlier attempts met with failure before the transmit was eventually successful.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_TX_STATUS_ARB_LOST</constant></entry>
-           <entry>0x02</entry>
-           <entry>CEC line arbitration was lost.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_TX_STATUS_NACK</constant></entry>
-           <entry>0x04</entry>
-           <entry>Message was not acknowledged.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_TX_STATUS_LOW_DRIVE</constant></entry>
-           <entry>0x08</entry>
-           <entry>Low drive was detected on the CEC bus. This indicates that a follower
-           detected an error on the bus and requests a retransmission.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_TX_STATUS_ERROR</constant></entry>
-           <entry>0x10</entry>
-           <entry>Some error occurred. This is used for any errors that do not
-           fit the previous two, either because the hardware could not tell
-           which error occurred, or because the hardware tested for other conditions
-           besides those two.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_TX_STATUS_MAX_RETRIES</constant></entry>
-           <entry>0x20</entry>
-           <entry>The transmit failed after one or more retries. This status bit is mutually
-           exclusive with <constant>CEC_TX_STATUS_OK</constant>. Other bits can still be set
-           to explain which failures were seen.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="cec-rx-status">
-      <title>CEC Receive Status</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>CEC_RX_STATUS_OK</constant></entry>
-           <entry>0x01</entry>
-           <entry>The message was received successfully.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_RX_STATUS_TIMEOUT</constant></entry>
-           <entry>0x02</entry>
-           <entry>The reply to an earlier transmitted message timed out.</entry>
-         </row>
-         <row>
-           <entry><constant>CEC_RX_STATUS_FEATURE_ABORT</constant></entry>
-           <entry>0x04</entry>
-           <entry>The message was received successfully but the reply was
-           <constant>CEC_MSG_FEATURE_ABORT</constant>. This status is only
-           set if this message was the reply to an earlier transmitted
-           message.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
deleted file mode 100644 (file)
index 8b5e014..0000000
+++ /dev/null
@@ -1,1102 +0,0 @@
-  <title>Common API Elements</title>
-
-  <para>Programming a V4L2 device consists of these
-steps:</para>
-
-  <itemizedlist>
-    <listitem>
-      <para>Opening the device</para>
-    </listitem>
-    <listitem>
-      <para>Changing device properties, selecting a video and audio
-input, video standard, picture brightness a.&nbsp;o.</para>
-    </listitem>
-    <listitem>
-      <para>Negotiating a data format</para>
-    </listitem>
-    <listitem>
-      <para>Negotiating an input/output method</para>
-    </listitem>
-    <listitem>
-      <para>The actual input/output loop</para>
-    </listitem>
-    <listitem>
-      <para>Closing the device</para>
-    </listitem>
-  </itemizedlist>
-
-  <para>In practice most steps are optional and can be executed out of
-order. It depends on the V4L2 device type, you can read about the
-details in <xref linkend="devices" />. In this chapter we will discuss
-the basic concepts applicable to all devices.</para>
-
-  <section id="open">
-    <title>Opening and Closing Devices</title>
-
-    <section>
-      <title>Device Naming</title>
-
-      <para>V4L2 drivers are implemented as kernel modules, loaded
-manually by the system administrator or automatically when a device is
-first discovered. The driver modules plug into the "videodev" kernel
-module. It provides helper functions and a common application
-interface specified in this document.</para>
-
-      <para>Each driver thus loaded registers one or more device nodes
-with major number 81 and a minor number between 0 and 255. Minor numbers
-are allocated dynamically unless the kernel is compiled with the kernel
-option CONFIG_VIDEO_FIXED_MINOR_RANGES. In that case minor numbers are
-allocated in ranges depending on the device node type (video, radio, etc.).</para>
-
-      <para>Many drivers support "video_nr", "radio_nr" or "vbi_nr"
-module options to select specific video/radio/vbi node numbers. This allows
-the user to request that the device node is named e.g. /dev/video5 instead
-of leaving it to chance. When the driver supports multiple devices of the same
-type more than one device node number can be assigned, separated by commas:
-       <informalexample>
-         <screen>
-&gt; modprobe mydriver video_nr=0,1 radio_nr=0,1</screen>
-       </informalexample></para>
-
-      <para>In <filename>/etc/modules.conf</filename> this may be
-written as: <informalexample>
-         <screen>
-options mydriver video_nr=0,1 radio_nr=0,1
-         </screen>
-       </informalexample> When no device node number is given as module
-option the driver supplies a default.</para>
-
-      <para>Normally udev will create the device nodes in /dev automatically
-for you. If udev is not installed, then you need to enable the
-CONFIG_VIDEO_FIXED_MINOR_RANGES kernel option in order to be able to correctly
-relate a minor number to a device node number. I.e., you need to be certain
-that minor number 5 maps to device node name video5. With this kernel option
-different device types have different minor number ranges. These ranges are
-listed in <xref linkend="devices" />.
-</para>
-
-      <para>The creation of character special files (with
-<application>mknod</application>) is a privileged operation and
-devices cannot be opened by major and minor number. That means
-applications cannot <emphasis>reliable</emphasis> scan for loaded or
-installed drivers. The user must enter a device name, or the
-application can try the conventional device names.</para>
-    </section>
-
-    <section id="related">
-      <title>Related Devices</title>
-
-      <para>Devices can support several functions. For example
-video capturing, VBI capturing and radio support.</para>
-
-      <para>The V4L2 API creates different nodes for each of these functions.</para>
-
-      <para>The V4L2 API was designed with the idea that one device node could support
-all functions. However, in practice this never worked: this 'feature'
-was never used by applications and many drivers did not support it and if
-they did it was certainly never tested. In addition, switching a device
-node between different functions only works when using the streaming I/O
-API, not with the read()/write() API.</para>
-
-      <para>Today each device node supports just one function.</para>
-
-      <para>Besides video input or output the hardware may also
-support audio sampling or playback. If so, these functions are
-implemented as ALSA PCM devices with optional ALSA audio mixer
-devices.</para>
-
-      <para>One problem with all these devices is that the V4L2 API
-makes no provisions to find these related devices. Some really
-complex devices use the Media Controller (see <xref linkend="media_controller" />)
-which can be used for this purpose. But most drivers do not use it,
-and while some code exists that uses sysfs to discover related devices
-(see libmedia_dev in the <ulink url="http://git.linuxtv.org/cgit.cgi/v4l-utils.git/">v4l-utils</ulink>
-git repository), there is no library yet that can provide a single API towards
-both Media Controller-based devices and devices that do not use the Media Controller.
-If you want to work on this please write to the linux-media mailing list: &v4l-ml;.</para>
-    </section>
-
-    <section>
-      <title>Multiple Opens</title>
-
-      <para>V4L2 devices can be opened more than once.<footnote><para>
-There are still some old and obscure drivers that have not been updated to
-allow for multiple opens. This implies that for such drivers &func-open; can
-return an &EBUSY; when the device is already in use.</para></footnote>
-When this is supported by the driver, users can for example start a
-"panel" application to change controls like brightness or audio
-volume, while another application captures video and audio. In other words, panel
-applications are comparable to an ALSA audio mixer application.
-Just opening a V4L2 device should not change the state of the device.<footnote>
-<para>Unfortunately, opening a radio device often switches the state of the
-device to radio mode in many drivers. This behavior should be fixed eventually
-as it violates the V4L2 specification.</para></footnote></para>
-
-      <para>Once an application has allocated the memory buffers needed for
-streaming data (by calling the &VIDIOC-REQBUFS; or &VIDIOC-CREATE-BUFS; ioctls,
-or implicitly by calling the &func-read; or &func-write; functions) that
-application (filehandle) becomes the owner of the device. It is no longer
-allowed to make changes that would affect the buffer sizes (e.g. by calling
-the &VIDIOC-S-FMT; ioctl) and other applications are no longer allowed to allocate
-buffers or start or stop streaming. The &EBUSY; will be returned instead.</para>
-
-      <para>Merely opening a V4L2 device does not grant exclusive
-access.<footnote>
-         <para>Drivers could recognize the
-<constant>O_EXCL</constant> open flag. Presently this is not required,
-so applications cannot know if it really works.</para>
-       </footnote> Initiating data exchange however assigns the right
-to read or write the requested type of data, and to change related
-properties, to this file descriptor. Applications can request
-additional access privileges using the priority mechanism described in
-<xref linkend="app-pri" />.</para>
-    </section>
-
-    <section>
-      <title>Shared Data Streams</title>
-
-      <para>V4L2 drivers should not support multiple applications
-reading or writing the same data stream on a device by copying
-buffers, time multiplexing or similar means. This is better handled by
-a proxy application in user space.</para>
-    </section>
-
-    <section>
-      <title>Functions</title>
-
-    <para>To open and close V4L2 devices applications use the
-&func-open; and &func-close; function, respectively. Devices are
-programmed using the &func-ioctl; function as explained in the
-following sections.</para>
-    </section>
-  </section>
-
-  <section id="querycap">
-    <title>Querying Capabilities</title>
-
-    <para>Because V4L2 covers a wide variety of devices not all
-aspects of the API are equally applicable to all types of devices.
-Furthermore devices of the same type have different capabilities and
-this specification permits the omission of a few complicated and less
-important parts of the API.</para>
-
-    <para>The &VIDIOC-QUERYCAP; ioctl is available to check if the kernel
-device is compatible with this specification, and to query the <link
-linkend="devices">functions</link> and <link linkend="io">I/O
-methods</link> supported by the device.</para>
-
-    <para>Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the
-V4L2 API version used by the driver, with generally matches the Kernel version.
-There's no need of using &VIDIOC-QUERYCAP; to check if a specific ioctl is
-supported, the V4L2 core now returns ENOTTY if a driver doesn't provide
-support for an ioctl.</para>
-
-    <para>Other features can be queried
-by calling the respective ioctl, for example &VIDIOC-ENUMINPUT;
-to learn about the number, types and names of video connectors on the
-device. Although abstraction is a major objective of this API, the
-&VIDIOC-QUERYCAP; ioctl also allows driver specific applications to reliably identify
-the driver.</para>
-
-    <para>All V4L2 drivers must support
-<constant>VIDIOC_QUERYCAP</constant>. Applications should always call
-this ioctl after opening the device.</para>
-  </section>
-
-  <section id="app-pri">
-    <title>Application Priority</title>
-
-    <para>When multiple applications share a device it may be
-desirable to assign them different priorities. Contrary to the
-traditional "rm -rf /" school of thought a video recording application
-could for example block other applications from changing video
-controls or switching the current TV channel. Another objective is to
-permit low priority applications working in background, which can be
-preempted by user controlled applications and automatically regain
-control of the device at a later time.</para>
-
-    <para>Since these features cannot be implemented entirely in user
-space V4L2 defines the &VIDIOC-G-PRIORITY; and &VIDIOC-S-PRIORITY;
-ioctls to request and query the access priority associate with a file
-descriptor. Opening a device assigns a medium priority, compatible
-with earlier versions of V4L2 and drivers not supporting these ioctls.
-Applications requiring a different priority will usually call
-<constant>VIDIOC_S_PRIORITY</constant> after verifying the device with
-the &VIDIOC-QUERYCAP; ioctl.</para>
-
-    <para>Ioctls changing driver properties, such as &VIDIOC-S-INPUT;,
-return an &EBUSY; after another application obtained higher priority.</para>
-  </section>
-
-  <section id="video">
-    <title>Video Inputs and Outputs</title>
-
-    <para>Video inputs and outputs are physical connectors of a
-device. These can be for example RF connectors (antenna/cable), CVBS
-a.k.a. Composite Video, S-Video or RGB connectors. Video and VBI
-capture devices have inputs. Video and VBI output devices have outputs,
-at least one each. Radio devices have no video inputs or outputs.</para>
-
-    <para>To learn about the number and attributes of the
-available inputs and outputs applications can enumerate them with the
-&VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; ioctl, respectively. The
-&v4l2-input; returned by the <constant>VIDIOC_ENUMINPUT</constant>
-ioctl also contains signal status information applicable when the
-current video input is queried.</para>
-
-    <para>The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctls return the
-index of the current video input or output. To select a different
-input or output applications call the &VIDIOC-S-INPUT; and
-&VIDIOC-S-OUTPUT; ioctls. Drivers must implement all the input ioctls
-when the device has one or more inputs, all the output ioctls when the
-device has one or more outputs.</para>
-
-    <example>
-      <title>Information about the current video input</title>
-
-      <programlisting>
-&v4l2-input; input;
-int index;
-
-if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;index)) {
-       perror("VIDIOC_G_INPUT");
-       exit(EXIT_FAILURE);
-}
-
-memset(&amp;input, 0, sizeof(input));
-input.index = index;
-
-if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror("VIDIOC_ENUMINPUT");
-       exit(EXIT_FAILURE);
-}
-
-printf("Current input: %s\n", input.name);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Switching to the first video input</title>
-
-      <programlisting>
-int index;
-
-index = 0;
-
-if (-1 == ioctl(fd, &VIDIOC-S-INPUT;, &amp;index)) {
-       perror("VIDIOC_S_INPUT");
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  </section>
-
-  <section id="audio">
-    <title>Audio Inputs and Outputs</title>
-
-    <para>Audio inputs and outputs are physical connectors of a
-device. Video capture devices have inputs, output devices have
-outputs, zero or more each. Radio devices have no audio inputs or
-outputs. They have exactly one tuner which in fact
-<emphasis>is</emphasis> an audio source, but this API associates
-tuners with video inputs or outputs only, and radio devices have
-none of these.<footnote>
-       <para>Actually &v4l2-audio; ought to have a
-<structfield>tuner</structfield> field like &v4l2-input;, not only
-making the API more consistent but also permitting radio devices with
-multiple tuners.</para>
-      </footnote> A connector on a TV card to loop back the received
-audio signal to a sound card is not considered an audio output.</para>
-
-    <para>Audio and video inputs and outputs are associated. Selecting
-a video source also selects an audio source. This is most evident when
-the video and audio source is a tuner. Further audio connectors can
-combine with more than one video input or output. Assumed two
-composite video inputs and two audio inputs exist, there may be up to
-four valid combinations. The relation of video and audio connectors
-is defined in the <structfield>audioset</structfield> field of the
-respective &v4l2-input; or &v4l2-output;, where each bit represents
-the index number, starting at zero, of one audio input or output.</para>
-
-    <para>To learn about the number and attributes of the
-available inputs and outputs applications can enumerate them with the
-&VIDIOC-ENUMAUDIO; and &VIDIOC-ENUMAUDOUT; ioctl, respectively. The
-&v4l2-audio; returned by the <constant>VIDIOC_ENUMAUDIO</constant> ioctl
-also contains signal status information applicable when the current
-audio input is queried.</para>
-
-    <para>The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctls report
-the current audio input and output, respectively. Note that, unlike
-&VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; these ioctls return a structure
-as <constant>VIDIOC_ENUMAUDIO</constant> and
-<constant>VIDIOC_ENUMAUDOUT</constant> do, not just an index.</para>
-
-    <para>To select an audio input and change its properties
-applications call the &VIDIOC-S-AUDIO; ioctl. To select an audio
-output (which presently has no changeable properties) applications
-call the &VIDIOC-S-AUDOUT; ioctl.</para>
-
-    <para>Drivers must implement all audio input ioctls when the device
-has multiple selectable audio inputs, all audio output ioctls when the
-device has multiple selectable audio outputs. When the device has any
-audio inputs or outputs the driver must set the <constant>V4L2_CAP_AUDIO</constant>
-flag in the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl.</para>
-
-    <example>
-      <title>Information about the current audio input</title>
-
-      <programlisting>
-&v4l2-audio; audio;
-
-memset(&amp;audio, 0, sizeof(audio));
-
-if (-1 == ioctl(fd, &VIDIOC-G-AUDIO;, &amp;audio)) {
-       perror("VIDIOC_G_AUDIO");
-       exit(EXIT_FAILURE);
-}
-
-printf("Current input: %s\n", audio.name);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Switching to the first audio input</title>
-
-      <programlisting>
-&v4l2-audio; audio;
-
-memset(&amp;audio, 0, sizeof(audio)); /* clear audio.mode, audio.reserved */
-
-audio.index = 0;
-
-if (-1 == ioctl(fd, &VIDIOC-S-AUDIO;, &amp;audio)) {
-       perror("VIDIOC_S_AUDIO");
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  </section>
-
-  <section id="tuner">
-    <title>Tuners and Modulators</title>
-
-    <section>
-      <title>Tuners</title>
-
-      <para>Video input devices can have one or more tuners
-demodulating a RF signal. Each tuner is associated with one or more
-video inputs, depending on the number of RF connectors on the tuner.
-The <structfield>type</structfield> field of the respective
-&v4l2-input; returned by the &VIDIOC-ENUMINPUT; ioctl is set to
-<constant>V4L2_INPUT_TYPE_TUNER</constant> and its
-<structfield>tuner</structfield> field contains the index number of
-the tuner.</para>
-
-      <para>Radio input devices have exactly one tuner with index zero, no
-video inputs.</para>
-
-      <para>To query and change tuner properties applications use the
-&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctls, respectively. The
-&v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
-contains signal status information applicable when the tuner of the
-current video or radio input is queried. Note that
-<constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
-when there is more than one at all. The tuner is solely determined by
-the current video input. Drivers must support both ioctls and set the
-<constant>V4L2_CAP_TUNER</constant> flag in the &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl when the device has one or
-more tuners.</para>
-    </section>
-
-    <section>
-      <title>Modulators</title>
-
-      <para>Video output devices can have one or more modulators, uh,
-modulating a video signal for radiation or connection to the antenna
-input of a TV set or video recorder. Each modulator is associated with
-one or more video outputs, depending on the number of RF connectors on
-the modulator. The <structfield>type</structfield> field of the
-respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
-set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
-<structfield>modulator</structfield> field contains the index number
-of the modulator.</para>
-
-      <para>Radio output devices have exactly one modulator with index
-zero, no video outputs.</para>
-
-      <para>A video or radio device cannot support both a tuner and a
-modulator. Two separate device nodes will have to be used for such
-hardware, one that supports the tuner functionality and one that supports
-the modulator functionality. The reason is a limitation with the
-&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
-is for a tuner or a modulator.</para>
-
-      <para>To query and change modulator properties applications use
-the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
-<constant>VIDIOC_S_MODULATOR</constant> does not switch the current
-modulator, when there is more than one at all. The modulator is solely
-determined by the current video output. Drivers must support both
-ioctls and set the <constant>V4L2_CAP_MODULATOR</constant> flag in
-the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl when the
-device has one or more modulators.</para>
-    </section>
-
-    <section>
-      <title>Radio Frequency</title>
-
-      <para>To get and set the tuner or modulator radio frequency
-applications use the &VIDIOC-G-FREQUENCY; and &VIDIOC-S-FREQUENCY;
-ioctl which both take a pointer to a &v4l2-frequency;. These ioctls
-are used for TV and radio devices alike. Drivers must support both
-ioctls when the tuner or modulator ioctls are supported, or
-when the device is a radio device.</para>
-    </section>
-  </section>
-
-  <section id="standard">
-    <title>Video Standards</title>
-
-    <para>Video devices typically support one or more different video
-standards or variations of standards. Each video input and output may
-support another set of standards. This set is reported by the
-<structfield>std</structfield> field of &v4l2-input; and
-&v4l2-output; returned by the &VIDIOC-ENUMINPUT; and
-&VIDIOC-ENUMOUTPUT; ioctls, respectively.</para>
-
-    <para>V4L2 defines one bit for each analog video standard
-currently in use worldwide, and sets aside bits for driver defined
-standards, &eg; hybrid standards to watch NTSC video tapes on PAL TVs
-and vice versa. Applications can use the predefined bits to select a
-particular standard, although presenting the user a menu of supported
-standards is preferred. To enumerate and query the attributes of the
-supported standards applications use the &VIDIOC-ENUMSTD; ioctl.</para>
-
-    <para>Many of the defined standards are actually just variations
-of a few major standards. The hardware may in fact not distinguish
-between them, or do so internal and switch automatically. Therefore
-enumerated standards also contain sets of one or more standard
-bits.</para>
-
-    <para>Assume a hypothetic tuner capable of demodulating B/PAL,
-G/PAL and I/PAL signals. The first enumerated standard is a set of B
-and G/PAL, switched automatically depending on the selected radio
-frequency in UHF or VHF band. Enumeration gives a "PAL-B/G" or "PAL-I"
-choice. Similar a Composite input may collapse standards, enumerating
-"PAL-B/G/H/I", "NTSC-M" and "SECAM-D/K".<footnote>
-       <para>Some users are already confused by technical terms PAL,
-NTSC and SECAM. There is no point asking them to distinguish between
-B, G, D, or K when the software or hardware can do that
-automatically.</para>
-    </footnote></para>
-
-    <para>To query and select the standard used by the current video
-input or output applications call the &VIDIOC-G-STD; and
-&VIDIOC-S-STD; ioctl, respectively. The <emphasis>received</emphasis>
-standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note that the
-parameter of all these ioctls is a pointer to a &v4l2-std-id; type
-(a standard set), <emphasis>not</emphasis> an index into the standard
-enumeration. Drivers must implement all video standard ioctls
-when the device has one or more video inputs or outputs.</para>
-
-    <para>Special rules apply to devices such as USB cameras where the notion of video
-standards makes little sense. More generally for any capture or output device
-which is: <itemizedlist>
-       <listitem>
-         <para>incapable of capturing fields or frames at the nominal
-rate of the video standard, or</para>
-       </listitem>
-       <listitem>
-         <para>that does not support the video standard formats at all.</para>
-       </listitem>
-      </itemizedlist> Here the driver shall set the
-<structfield>std</structfield> field of &v4l2-input; and &v4l2-output;
-to zero and the <constant>VIDIOC_G_STD</constant>,
-<constant>VIDIOC_S_STD</constant>,
-<constant>VIDIOC_QUERYSTD</constant> and
-<constant>VIDIOC_ENUMSTD</constant> ioctls shall return the
-&ENOTTY; or the &EINVAL;.</para>
-       <para>Applications can make use of the <xref linkend="input-capabilities" /> and
-<xref linkend="output-capabilities"/> flags to determine whether the video standard ioctls
-can be used with the given input or output.</para>
-
-    <example>
-      <title>Information about the current video standard</title>
-
-      <programlisting>
-&v4l2-std-id; std_id;
-&v4l2-standard; standard;
-
-if (-1 == ioctl(fd, &VIDIOC-G-STD;, &amp;std_id)) {
-       /* Note when VIDIOC_ENUMSTD always returns ENOTTY this
-          is no video device or it falls under the USB exception,
-          and VIDIOC_G_STD returning ENOTTY is no error. */
-
-       perror("VIDIOC_G_STD");
-       exit(EXIT_FAILURE);
-}
-
-memset(&amp;standard, 0, sizeof(standard));
-standard.index = 0;
-
-while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
-       if (standard.id &amp; std_id) {
-              printf("Current video standard: %s\n", standard.name);
-              exit(EXIT_SUCCESS);
-       }
-
-       standard.index++;
-}
-
-/* EINVAL indicates the end of the enumeration, which cannot be
-   empty unless this device falls under the USB exception. */
-
-if (errno == EINVAL || standard.index == 0) {
-       perror("VIDIOC_ENUMSTD");
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Listing the video standards supported by the current
-input</title>
-
-      <programlisting>
-&v4l2-input; input;
-&v4l2-standard; standard;
-
-memset(&amp;input, 0, sizeof(input));
-
-if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
-       perror("VIDIOC_G_INPUT");
-       exit(EXIT_FAILURE);
-}
-
-if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror("VIDIOC_ENUM_INPUT");
-       exit(EXIT_FAILURE);
-}
-
-printf("Current input %s supports:\n", input.name);
-
-memset(&amp;standard, 0, sizeof(standard));
-standard.index = 0;
-
-while (0 == ioctl(fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
-       if (standard.id &amp; input.std)
-               printf("%s\n", standard.name);
-
-       standard.index++;
-}
-
-/* EINVAL indicates the end of the enumeration, which cannot be
-   empty unless this device falls under the USB exception. */
-
-if (errno != EINVAL || standard.index == 0) {
-       perror("VIDIOC_ENUMSTD");
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Selecting a new video standard</title>
-
-      <programlisting>
-&v4l2-input; input;
-&v4l2-std-id; std_id;
-
-memset(&amp;input, 0, sizeof(input));
-
-if (-1 == ioctl(fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
-       perror("VIDIOC_G_INPUT");
-       exit(EXIT_FAILURE);
-}
-
-if (-1 == ioctl(fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror("VIDIOC_ENUM_INPUT");
-       exit(EXIT_FAILURE);
-}
-
-if (0 == (input.std &amp; V4L2_STD_PAL_BG)) {
-       fprintf(stderr, "Oops. B/G PAL is not supported.\n");
-       exit(EXIT_FAILURE);
-}
-
-/* Note this is also supposed to work when only B
-   <emphasis>or</emphasis> G/PAL is supported. */
-
-std_id = V4L2_STD_PAL_BG;
-
-if (-1 == ioctl(fd, &VIDIOC-S-STD;, &amp;std_id)) {
-       perror("VIDIOC_S_STD");
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  </section>
-  <section id="dv-timings">
-       <title>Digital Video (DV) Timings</title>
-       <para>
-       The video standards discussed so far have been dealing with Analog TV and the
-corresponding video timings. Today there are many more different hardware interfaces
-such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
-video signals and there is a need to extend the API to select the video timings
-for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
-the limited bits available, a new set of ioctls was added to set/get video timings at
-the input and output.</para>
-
-       <para>These ioctls deal with the detailed digital video timings that define
-each video format. This includes parameters such as the active video width and height,
-signal polarities, frontporches, backporches, sync widths etc. The <filename>linux/v4l2-dv-timings.h</filename>
-header can be used to get the timings of the formats in the <xref linkend="cea861" /> and
-<xref linkend="vesadmt" /> standards.
-       </para>
-
-       <para>To enumerate and query the attributes of the DV timings supported by a device
-       applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls.
-       To set DV timings for the device applications use the
-&VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the
-&VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications
-use the &VIDIOC-QUERY-DV-TIMINGS; ioctl.</para>
-       <para>Applications can make use of the <xref linkend="input-capabilities" /> and
-<xref linkend="output-capabilities"/> flags to determine whether the digital video ioctls
-can be used with the given input or output.</para>
-  </section>
-
-  &sub-controls;
-
-  <section id="format">
-    <title>Data Formats</title>
-
-    <section>
-      <title>Data Format Negotiation</title>
-
-      <para>Different devices exchange different kinds of data with
-applications, for example video images, raw or sliced VBI data, RDS
-datagrams. Even within one kind many different formats are possible,
-in particular an abundance of image formats. Although drivers must
-provide a default and the selection persists across closing and
-reopening a device, applications should always negotiate a data format
-before engaging in data exchange. Negotiation means the application
-asks for a particular format and the driver selects and reports the
-best the hardware can do to satisfy the request. Of course
-applications can also just query the current selection.</para>
-
-      <para>A single mechanism exists to negotiate all data formats
-using the aggregate &v4l2-format; and the &VIDIOC-G-FMT; and
-&VIDIOC-S-FMT; ioctls. Additionally the &VIDIOC-TRY-FMT; ioctl can be
-used to examine what the hardware <emphasis>could</emphasis> do,
-without actually selecting a new data format. The data formats
-supported by the V4L2 API are covered in the respective device section
-in <xref linkend="devices" />. For a closer look at image formats see
-<xref linkend="pixfmt" />.</para>
-
-      <para>The <constant>VIDIOC_S_FMT</constant> ioctl is a major
-turning-point in the initialization sequence. Prior to this point
-multiple panel applications can access the same device concurrently to
-select the current input, change controls or modify other properties.
-The first <constant>VIDIOC_S_FMT</constant> assigns a logical stream
-(video data, VBI data etc.) exclusively to one file descriptor.</para>
-
-      <para>Exclusive means no other application, more precisely no
-other file descriptor, can grab this stream or change device
-properties inconsistent with the negotiated parameters. A video
-standard change for example, when the new standard uses a different
-number of scan lines, can invalidate the selected image format.
-Therefore only the file descriptor owning the stream can make
-invalidating changes. Accordingly multiple file descriptors which
-grabbed different logical streams prevent each other from interfering
-with their settings. When for example video overlay is about to start
-or already in progress, simultaneous video capturing may be restricted
-to the same cropping and image size.</para>
-
-      <para>When applications omit the
-<constant>VIDIOC_S_FMT</constant> ioctl its locking side effects are
-implied by the next step, the selection of an I/O method with the
-&VIDIOC-REQBUFS; ioctl or implicit with the first &func-read; or
-&func-write; call.</para>
-
-      <para>Generally only one logical stream can be assigned to a
-file descriptor, the exception being drivers permitting simultaneous
-video capturing and overlay using the same file descriptor for
-compatibility with V4L and earlier versions of V4L2. Switching the
-logical stream or returning into "panel mode" is possible by closing
-and reopening the device. Drivers <emphasis>may</emphasis> support a
-switch using <constant>VIDIOC_S_FMT</constant>.</para>
-
-      <para>All drivers exchanging data with
-applications must support the <constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl. Implementation of the
-<constant>VIDIOC_TRY_FMT</constant> is highly recommended but
-optional.</para>
-    </section>
-
-    <section>
-      <title>Image Format Enumeration</title>
-
-      <para>Apart of the generic format negotiation functions
-a special ioctl to enumerate all image formats supported by video
-capture, overlay or output devices is available.<footnote>
-         <para>Enumerating formats an application has no a-priori
-knowledge of (otherwise it could explicitly ask for them and need not
-enumerate) seems useless, but there are applications serving as proxy
-between drivers and the actual video applications for which this is
-useful.</para>
-       </footnote></para>
-
-      <para>The &VIDIOC-ENUM-FMT; ioctl must be supported
-by all drivers exchanging image data with applications.</para>
-
-      <important>
-       <para>Drivers are not supposed to convert image formats in
-kernel space. They must enumerate only formats directly supported by
-the hardware. If necessary driver writers should publish an example
-conversion routine or library for integration into applications.</para>
-      </important>
-    </section>
-  </section>
-
-  &sub-planar-apis;
-
-  <section id="crop">
-    <title>Image Cropping, Insertion and Scaling</title>
-
-    <para>Some video capture devices can sample a subsection of the
-picture and shrink or enlarge it to an image of arbitrary size. We
-call these abilities cropping and scaling. Some video output devices
-can scale an image up or down and insert it at an arbitrary scan line
-and horizontal offset into a video signal.</para>
-
-    <para>Applications can use the following API to select an area in
-the video signal, query the default area and the hardware limits.
-<emphasis>Despite their name, the &VIDIOC-CROPCAP;, &VIDIOC-G-CROP;
-and &VIDIOC-S-CROP; ioctls apply to input as well as output
-devices.</emphasis></para>
-
-    <para>Scaling requires a source and a target. On a video capture
-or overlay device the source is the video signal, and the cropping
-ioctls determine the area actually sampled. The target are images
-read by the application or overlaid onto the graphics screen. Their
-size (and position for an overlay) is negotiated with the
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls.</para>
-
-    <para>On a video output device the source are the images passed in
-by the application, and their size is again negotiated with the
-<constant>VIDIOC_G/S_FMT</constant> ioctls, or may be encoded in a
-compressed video stream. The target is the video signal, and the
-cropping ioctls determine the area where the images are
-inserted.</para>
-
-    <para>Source and target rectangles are defined even if the device
-does not support scaling or the <constant>VIDIOC_G/S_CROP</constant>
-ioctls. Their size (and position where applicable) will be fixed in
-this case. <emphasis>All capture and output device must support the
-<constant>VIDIOC_CROPCAP</constant> ioctl such that applications can
-determine if scaling takes place.</emphasis></para>
-
-    <section>
-      <title>Cropping Structures</title>
-
-      <figure id="crop-scale">
-       <title>Image Cropping, Insertion and Scaling</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="crop.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="crop.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>The cropping, insertion and scaling process</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <para>For capture devices the coordinates of the top left
-corner, width and height of the area which can be sampled is given by
-the <structfield>bounds</structfield> substructure of the
-&v4l2-cropcap; returned by the <constant>VIDIOC_CROPCAP</constant>
-ioctl. To support a wide range of hardware this specification does not
-define an origin or units. However by convention drivers should
-horizontally count unscaled samples relative to 0H (the leading edge
-of the horizontal sync pulse, see <xref linkend="vbi-hsync" />).
-Vertically ITU-R line
-numbers of the first field (<xref linkend="vbi-525" />, <xref
-linkend="vbi-625" />), multiplied by two if the driver can capture both
-fields.</para>
-
-      <para>The top left corner, width and height of the source
-rectangle, that is the area actually sampled, is given by &v4l2-crop;
-using the same coordinate system as &v4l2-cropcap;. Applications can
-use the <constant>VIDIOC_G_CROP</constant> and
-<constant>VIDIOC_S_CROP</constant> ioctls to get and set this
-rectangle. It must lie completely within the capture boundaries and
-the driver may further adjust the requested size and/or position
-according to hardware limitations.</para>
-
-      <para>Each capture device has a default source rectangle, given
-by the <structfield>defrect</structfield> substructure of
-&v4l2-cropcap;. The center of this rectangle shall align with the
-center of the active picture area of the video signal, and cover what
-the driver writer considers the complete picture. Drivers shall reset
-the source rectangle to the default when the driver is first loaded,
-but not later.</para>
-
-      <para>For output devices these structures and ioctls are used
-accordingly, defining the <emphasis>target</emphasis> rectangle where
-the images will be inserted into the video signal.</para>
-
-    </section>
-
-    <section>
-      <title>Scaling Adjustments</title>
-
-      <para>Video hardware can have various cropping, insertion and
-scaling limitations. It may only scale up or down, support only
-discrete scaling factors, or have different scaling abilities in
-horizontal and vertical direction. Also it may not support scaling at
-all. At the same time the &v4l2-crop; rectangle may have to be
-aligned, and both the source and target rectangles may have arbitrary
-upper and lower size limits. In particular the maximum
-<structfield>width</structfield> and <structfield>height</structfield>
-in &v4l2-crop; may be smaller than the
-&v4l2-cropcap;.<structfield>bounds</structfield> area. Therefore, as
-usual, drivers are expected to adjust the requested parameters and
-return the actual values selected.</para>
-
-      <para>Applications can change the source or the target rectangle
-first, as they may prefer a particular image size or a certain area in
-the video signal. If the driver has to adjust both to satisfy hardware
-limitations, the last requested rectangle shall take priority, and the
-driver should preferably adjust the opposite one. The &VIDIOC-TRY-FMT;
-ioctl however shall not change the driver state and therefore only
-adjust the requested rectangle.</para>
-
-      <para>Suppose scaling on a video capture device is restricted to
-a factor 1:1 or 2:1 in either direction and the target image size must
-be a multiple of 16&nbsp;&times;&nbsp;16 pixels. The source cropping
-rectangle is set to defaults, which are also the upper limit in this
-example, of 640&nbsp;&times;&nbsp;400 pixels at offset 0,&nbsp;0. An
-application requests an image size of 300&nbsp;&times;&nbsp;225
-pixels, assuming video will be scaled down from the "full picture"
-accordingly. The driver sets the image size to the closest possible
-values 304&nbsp;&times;&nbsp;224, then chooses the cropping rectangle
-closest to the requested size, that is 608&nbsp;&times;&nbsp;224
-(224&nbsp;&times;&nbsp;2:1 would exceed the limit 400). The offset
-0,&nbsp;0 is still valid, thus unmodified. Given the default cropping
-rectangle reported by <constant>VIDIOC_CROPCAP</constant> the
-application can easily propose another offset to center the cropping
-rectangle.</para>
-
-      <para>Now the application may insist on covering an area using a
-picture aspect ratio closer to the original request, so it asks for a
-cropping rectangle of 608&nbsp;&times;&nbsp;456 pixels. The present
-scaling factors limit cropping to 640&nbsp;&times;&nbsp;384, so the
-driver returns the cropping size 608&nbsp;&times;&nbsp;384 and adjusts
-the image size to closest possible 304&nbsp;&times;&nbsp;192.</para>
-
-    </section>
-
-    <section>
-      <title>Examples</title>
-
-      <para>Source and target rectangles shall remain unchanged across
-closing and reopening a device, such that piping data into or out of a
-device will work without special preparations. More advanced
-applications should ensure the parameters are suitable before starting
-I/O.</para>
-
-      <example>
-       <title>Resetting the cropping parameters</title>
-
-       <para>(A video capture device is assumed; change
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> for other
-devices.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-crop.c = cropcap.defrect;
-
-/* Ignore if cropping is not supported (EINVAL). */
-
-if (-1 == ioctl (fd, &VIDIOC-S-CROP;, &amp;crop)
-    &amp;&amp; errno != EINVAL) {
-       perror ("VIDIOC_S_CROP");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-      </example>
-
-      <example>
-       <title>Simple downscaling</title>
-
-       <para>(A video capture device is assumed.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-format; format;
-
-reset_cropping_parameters ();
-
-/* Scale down to 1/4 size of full picture. */
-
-memset (&amp;format, 0, sizeof (format)); /* defaults */
-
-format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-format.fmt.pix.width = cropcap.defrect.width &gt;&gt; 1;
-format.fmt.pix.height = cropcap.defrect.height &gt;&gt; 1;
-format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-
-if (-1 == ioctl (fd, &VIDIOC-S-FMT;, &amp;format)) {
-       perror ("VIDIOC_S_FORMAT");
-       exit (EXIT_FAILURE);
-}
-
-/* We could check the actual image size now, the actual scaling factor
-   or if the driver can scale at all. */
-       </programlisting>
-      </example>
-
-      <example>
-       <title>Selecting an output area</title>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
-if (-1 == ioctl (fd, VIDIOC_CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-
-crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-crop.c = cropcap.defrect;
-
-/* Scale the width and height to 50 % of their original size
-   and center the output. */
-
-crop.c.width /= 2;
-crop.c.height /= 2;
-crop.c.left += crop.c.width / 2;
-crop.c.top += crop.c.height / 2;
-
-/* Ignore if cropping is not supported (EINVAL). */
-
-if (-1 == ioctl (fd, VIDIOC_S_CROP, &amp;crop)
-    &amp;&amp; errno != EINVAL) {
-       perror ("VIDIOC_S_CROP");
-       exit (EXIT_FAILURE);
-}
-</programlisting>
-      </example>
-
-      <example>
-       <title>Current scaling factor and pixel aspect</title>
-
-       <para>(A video capture device is assumed.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-&v4l2-format; format;
-double hscale, vscale;
-double aspect;
-int dwidth, dheight;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-G-CROP;, &amp;crop)) {
-       if (errno != EINVAL) {
-               perror ("VIDIOC_G_CROP");
-               exit (EXIT_FAILURE);
-       }
-
-       /* Cropping not supported. */
-       crop.c = cropcap.defrect;
-}
-
-memset (&amp;format, 0, sizeof (format));
-format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-G-FMT;, &amp;format)) {
-       perror ("VIDIOC_G_FMT");
-       exit (EXIT_FAILURE);
-}
-
-/* The scaling applied by the driver. */
-
-hscale = format.fmt.pix.width / (double) crop.c.width;
-vscale = format.fmt.pix.height / (double) crop.c.height;
-
-aspect = cropcap.pixelaspect.numerator /
-        (double) cropcap.pixelaspect.denominator;
-aspect = aspect * hscale / vscale;
-
-/* Devices following ITU-R BT.601 do not capture
-   square pixels. For playback on a computer monitor
-   we should scale the images to this size. */
-
-dwidth = format.fmt.pix.width / aspect;
-dheight = format.fmt.pix.height;
-       </programlisting>
-      </example>
-    </section>
-  </section>
-
-  &sub-selection-api;
-
-  <section id="streaming-par">
-    <title>Streaming Parameters</title>
-
-    <para>Streaming parameters are intended to optimize the video
-capture process as well as I/O. Presently applications can request a
-high quality capture mode with the &VIDIOC-S-PARM; ioctl.</para>
-
-    <para>The current video standard determines a nominal number of
-frames per second. If less than this number of frames is to be
-captured or output, applications can request frame skipping or
-duplicating on the driver side. This is especially useful when using
-the &func-read; or &func-write;, which are not augmented by timestamps
-or sequence counters, and to avoid unnecessary data copying.</para>
-
-    <para>Finally these ioctls can be used to determine the number of
-buffers used internally by a driver in read/write mode. For
-implications see the section discussing the &func-read;
-function.</para>
-
-    <para>To get and set the streaming parameters applications call
-the &VIDIOC-G-PARM; and &VIDIOC-S-PARM; ioctl, respectively. They take
-a pointer to a &v4l2-streamparm;, which contains a union holding
-separate parameters for input and output devices.</para>
-
-    <para>These ioctls are optional, drivers need not implement
-them. If so, they return the &EINVAL;.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
deleted file mode 100644 (file)
index 82fa328..0000000
+++ /dev/null
@@ -1,2723 +0,0 @@
-  <title>Changes</title>
-
-  <para>The following chapters document the evolution of the V4L2 API,
-errata or extensions. They are also intended to help application and
-driver writers to port or update their code.</para>
-
-  <section id="diff-v4l">
-    <title>Differences between V4L and V4L2</title>
-
-    <para>The Video For Linux API was first introduced in Linux 2.1 to
-unify and replace various TV and radio device related interfaces,
-developed independently by driver writers in prior years. Starting
-with Linux 2.5 the much improved V4L2 API replaces the V4L API.
-The support for the old V4L calls were removed from Kernel, but the
-library <xref linkend="libv4l" /> supports the conversion of a V4L
-API system call into a V4L2 one.</para>
-
-    <section>
-      <title>Opening and Closing Devices</title>
-
-      <para>For compatibility reasons the character device file names
-recommended for V4L2 video capture, overlay, radio and raw
-vbi capture devices did not change from those used by V4L. They are
-listed in <xref linkend="devices" /> and below in <xref
-         linkend="v4l-dev" />.</para>
-
-      <para>The teletext devices (minor range 192-223) have been removed in
-V4L2 and no longer exist. There is no hardware available anymore for handling
-pure teletext. Instead raw or sliced VBI is used.</para>
-
-      <para>The V4L <filename>videodev</filename> module automatically
-assigns minor numbers to drivers in load order, depending on the
-registered device type. We recommend that V4L2 drivers by default
-register devices with the same numbers, but the system administrator
-can assign arbitrary minor numbers using driver module options. The
-major device number remains 81.</para>
-
-      <table id="v4l-dev">
-       <title>V4L Device Types, Names and Numbers</title>
-       <tgroup cols="3">
-         <thead>
-           <row>
-             <entry>Device Type</entry>
-             <entry>File Name</entry>
-             <entry>Minor Numbers</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row>
-             <entry>Video capture and overlay</entry>
-             <entry><para><filename>/dev/video</filename> and
-<filename>/dev/bttv0</filename><footnote> <para>According to
-Documentation/devices.txt these should be symbolic links to
-<filename>/dev/video0</filename>. Note the original bttv interface is
-not compatible with V4L or V4L2.</para> </footnote>,
-<filename>/dev/video0</filename> to
-<filename>/dev/video63</filename></para></entry>
-             <entry>0-63</entry>
-           </row>
-           <row>
-             <entry>Radio receiver</entry>
-             <entry><para><filename>/dev/radio</filename><footnote>
-                   <para>According to
-<filename>Documentation/devices.txt</filename> a symbolic link to
-<filename>/dev/radio0</filename>.</para>
-                 </footnote>, <filename>/dev/radio0</filename> to
-<filename>/dev/radio63</filename></para></entry>
-             <entry>64-127</entry>
-           </row>
-           <row>
-             <entry>Raw VBI capture</entry>
-             <entry><para><filename>/dev/vbi</filename>,
-<filename>/dev/vbi0</filename> to
-<filename>/dev/vbi31</filename></para></entry>
-             <entry>224-255</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <para>V4L prohibits (or used to prohibit) multiple opens of a
-device file. V4L2 drivers <emphasis>may</emphasis> support multiple
-opens, see <xref linkend="open" /> for details and consequences.</para>
-
-      <para>V4L drivers respond to V4L2 ioctls with an &EINVAL;.</para>
-    </section>
-
-    <section>
-      <title>Querying Capabilities</title>
-
-      <para>The V4L <constant>VIDIOCGCAP</constant> ioctl is
-equivalent to V4L2's &VIDIOC-QUERYCAP;.</para>
-
-      <para>The <structfield>name</structfield> field in struct
-<structname>video_capability</structname> became
-<structfield>card</structfield> in &v4l2-capability;,
-<structfield>type</structfield> was replaced by
-<structfield>capabilities</structfield>. Note V4L2 does not
-distinguish between device types like this, better think of basic
-video input, video output and radio devices supporting a set of
-related functions like video capturing, video overlay and VBI
-capturing. See <xref linkend="open" /> for an
-introduction.<informaltable>
-         <tgroup cols="3">
-           <thead>
-             <row>
-               <entry>struct
-<structname>video_capability</structname>
-<structfield>type</structfield></entry>
-               <entry>&v4l2-capability;
-<structfield>capabilities</structfield> flags</entry>
-               <entry>Purpose</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VID_TYPE_CAPTURE</constant></entry>
-               <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
-               <entry>The <link linkend="capture">video
-capture</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_TUNER</constant></entry>
-               <entry><constant>V4L2_CAP_TUNER</constant></entry>
-               <entry>The device has a <link linkend="tuner">tuner or
-modulator</link>.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_TELETEXT</constant></entry>
-               <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
-               <entry>The <link linkend="raw-vbi">raw VBI
-capture</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_OVERLAY</constant></entry>
-               <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
-               <entry>The <link linkend="overlay">video
-overlay</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_CHROMAKEY</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant> in
-field <structfield>capability</structfield> of
-&v4l2-framebuffer;</entry>
-               <entry>Whether chromakey overlay is supported. For
-more information on overlay see
-<xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_CLIPPING</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant>
-and <constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant> in field
-<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
-               <entry>Whether clipping the overlaid image is
-supported, see <xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_FRAMERAM</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant>
-<emphasis>not set</emphasis> in field
-<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
-               <entry>Whether overlay overwrites frame buffer memory,
-see <xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_SCALES</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>This flag indicates if the hardware can scale
-images. The V4L2 API implies the scale factor by setting the cropping
-dimensions and image size with the &VIDIOC-S-CROP; and &VIDIOC-S-FMT;
-ioctl, respectively. The driver returns the closest sizes possible.
-For more information on cropping and scaling see <xref
-                   linkend="crop" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MONOCHROME</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can enumerate the supported image
-formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
-supports grey scale capturing only. For more information on image
-formats see <xref linkend="pixfmt" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_SUBCAPTURE</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can call the &VIDIOC-G-CROP; ioctl
-to determine if the device supports capturing a subsection of the full
-picture ("cropping" in V4L2). If not, the ioctl returns the &EINVAL;.
-For more information on cropping and scaling see <xref
-                   linkend="crop" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MPEG_DECODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can enumerate the supported image
-formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
-supports MPEG streams.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MPEG_ENCODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MJPEG_DECODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MJPEG_ENCODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>The <structfield>audios</structfield> field was replaced
-by <structfield>capabilities</structfield> flag
-<constant>V4L2_CAP_AUDIO</constant>, indicating
-<emphasis>if</emphasis> the device has any audio inputs or outputs. To
-determine their number applications can enumerate audio inputs with
-the &VIDIOC-G-AUDIO; ioctl. The audio ioctls are described in <xref
-         linkend="audio" />.</para>
-
-      <para>The <structfield>maxwidth</structfield>,
-<structfield>maxheight</structfield>,
-<structfield>minwidth</structfield> and
-<structfield>minheight</structfield> fields were removed. Calling the
-&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT; ioctl with the desired dimensions
-returns the closest size possible, taking into account the current
-video standard, cropping and scaling limitations.</para>
-    </section>
-
-    <section>
-      <title>Video Sources</title>
-
-      <para>V4L provides the <constant>VIDIOCGCHAN</constant> and
-<constant>VIDIOCSCHAN</constant> ioctl using struct
-<structname>video_channel</structname> to enumerate
-the video inputs of a V4L device. The equivalent V4L2 ioctls
-are &VIDIOC-ENUMINPUT;, &VIDIOC-G-INPUT; and &VIDIOC-S-INPUT;
-using &v4l2-input; as discussed in <xref linkend="video" />.</para>
-
-      <para>The <structfield>channel</structfield> field counting
-inputs was renamed to <structfield>index</structfield>, the video
-input types were renamed as follows: <informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_channel</structname>
-<structfield>type</structfield></entry>
-               <entry>&v4l2-input;
-<structfield>type</structfield></entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VIDEO_TYPE_TV</constant></entry>
-               <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_TYPE_CAMERA</constant></entry>
-               <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>Unlike the <structfield>tuners</structfield> field
-expressing the number of tuners of this input, V4L2 assumes each video
-input is connected to at most one tuner. However a tuner can have more
-than one input, &ie; RF connectors, and a device can have multiple
-tuners. The index number of the tuner associated with the input, if
-any, is stored in field <structfield>tuner</structfield> of
-&v4l2-input;. Enumeration of tuners is discussed in <xref
-         linkend="tuner" />.</para>
-
-      <para>The redundant <constant>VIDEO_VC_TUNER</constant> flag was
-dropped. Video inputs associated with a tuner are of type
-<constant>V4L2_INPUT_TYPE_TUNER</constant>. The
-<constant>VIDEO_VC_AUDIO</constant> flag was replaced by the
-<structfield>audioset</structfield> field. V4L2 considers devices with
-up to 32 audio inputs. Each set bit in the
-<structfield>audioset</structfield> field represents one audio input
-this video input combines with. For information about audio inputs and
-how to switch between them see <xref linkend="audio" />.</para>
-
-      <para>The <structfield>norm</structfield> field describing the
-supported video standards was replaced by
-<structfield>std</structfield>. The V4L specification mentions a flag
-<constant>VIDEO_VC_NORM</constant> indicating whether the standard can
-be changed. This flag was a later addition together with the
-<structfield>norm</structfield> field and has been removed in the
-meantime. V4L2 has a similar, albeit more comprehensive approach
-to video standards, see <xref linkend="standard" /> for more
-information.</para>
-    </section>
-
-    <section>
-      <title>Tuning</title>
-
-      <para>The V4L <constant>VIDIOCGTUNER</constant> and
-<constant>VIDIOCSTUNER</constant> ioctl and struct
-<structname>video_tuner</structname> can be used to enumerate the
-tuners of a V4L TV or radio device. The equivalent V4L2 ioctls are
-&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; using &v4l2-tuner;. Tuners are
-covered in <xref linkend="tuner" />.</para>
-
-      <para>The <structfield>tuner</structfield> field counting tuners
-was renamed to <structfield>index</structfield>. The fields
-<structfield>name</structfield>, <structfield>rangelow</structfield>
-and <structfield>rangehigh</structfield> remained unchanged.</para>
-
-      <para>The <constant>VIDEO_TUNER_PAL</constant>,
-<constant>VIDEO_TUNER_NTSC</constant> and
-<constant>VIDEO_TUNER_SECAM</constant> flags indicating the supported
-video standards were dropped. This information is now contained in the
-associated &v4l2-input;. No replacement exists for the
-<constant>VIDEO_TUNER_NORM</constant> flag indicating whether the
-video standard can be switched. The <structfield>mode</structfield>
-field to select a different video standard was replaced by a whole new
-set of ioctls and structures described in <xref linkend="standard" />.
-Due to its ubiquity it should be mentioned the BTTV driver supports
-several standards in addition to the regular
-<constant>VIDEO_MODE_PAL</constant> (0),
-<constant>VIDEO_MODE_NTSC</constant>,
-<constant>VIDEO_MODE_SECAM</constant> and
-<constant>VIDEO_MODE_AUTO</constant> (3). Namely N/PAL Argentina,
-M/PAL, N/PAL, and NTSC Japan with numbers 3-6 (sic).</para>
-
-      <para>The <constant>VIDEO_TUNER_STEREO_ON</constant> flag
-indicating stereo reception became
-<constant>V4L2_TUNER_SUB_STEREO</constant> in field
-<structfield>rxsubchans</structfield>. This field also permits the
-detection of monaural and bilingual audio, see the definition of
-&v4l2-tuner; for details. Presently no replacement exists for the
-<constant>VIDEO_TUNER_RDS_ON</constant> and
-<constant>VIDEO_TUNER_MBS_ON</constant> flags.</para>
-
-      <para> The <constant>VIDEO_TUNER_LOW</constant> flag was renamed
-to <constant>V4L2_TUNER_CAP_LOW</constant> in the &v4l2-tuner;
-<structfield>capability</structfield> field.</para>
-
-      <para>The <constant>VIDIOCGFREQ</constant> and
-<constant>VIDIOCSFREQ</constant> ioctl to change the tuner frequency
-where renamed to &VIDIOC-G-FREQUENCY; and  &VIDIOC-S-FREQUENCY;. They
-take a pointer to a &v4l2-frequency; instead of an unsigned long
-integer.</para>
-    </section>
-
-    <section id="v4l-image-properties">
-      <title>Image Properties</title>
-
-      <para>V4L2 has no equivalent of the
-<constant>VIDIOCGPICT</constant> and <constant>VIDIOCSPICT</constant>
-ioctl and struct <structname>video_picture</structname>. The following
-fields where replaced by V4L2 controls accessible with the
-&VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_picture</structname></entry>
-               <entry>V4L2 Control ID</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><structfield>brightness</structfield></entry>
-               <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>hue</structfield></entry>
-               <entry><constant>V4L2_CID_HUE</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>colour</structfield></entry>
-               <entry><constant>V4L2_CID_SATURATION</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>contrast</structfield></entry>
-               <entry><constant>V4L2_CID_CONTRAST</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>whiteness</structfield></entry>
-               <entry><constant>V4L2_CID_WHITENESS</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>The V4L picture controls are assumed to range from 0 to
-65535 with no particular reset value. The V4L2 API permits arbitrary
-limits and defaults which can be queried with the &VIDIOC-QUERYCTRL;
-ioctl. For general information about controls see <xref
-linkend="control" />.</para>
-
-      <para>The <structfield>depth</structfield> (average number of
-bits per pixel) of a video image is implied by the selected image
-format. V4L2 does not explicitly provide such information assuming
-applications recognizing the format are aware of the image depth and
-others need not know. The <structfield>palette</structfield> field
-moved into the &v4l2-pix-format;:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_picture</structname>
-<structfield>palette</structfield></entry>
-               <entry>&v4l2-pix-format;
-<structfield>pixfmt</structfield></entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VIDEO_PALETTE_GREY</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-GREY"><constant>V4L2_PIX_FMT_GREY</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_HI240</constant></entry>
-               <entry><para><link
-linkend="pixfmt-reserved"><constant>V4L2_PIX_FMT_HI240</constant></link><footnote>
-                     <para>This is a custom format used by the BTTV
-driver, not one of the V4L2 standard formats.</para>
-                   </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB565</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB565</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB555</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB555</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB24</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR24</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB32</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR32</constant></link><footnote>
-                     <para>Presumably all V4L RGB formats are
-little-endian, although some drivers might interpret them according to machine endianness. V4L2 defines little-endian, big-endian and red/blue
-swapped variants. For details see <xref linkend="pixfmt-rgb" />.</para>
-                   </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV422</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><para><constant>VIDEO_PALETTE_YUYV</constant><footnote>
-                     <para><constant>VIDEO_PALETTE_YUV422</constant>
-and <constant>VIDEO_PALETTE_YUYV</constant> are the same formats. Some
-V4L drivers respond to one, some to the other.</para>
-                   </footnote></para></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_UYVY</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV420</constant></entry>
-               <entry>None</entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV411</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-Y41P"><constant>V4L2_PIX_FMT_Y41P</constant></link><footnote>
-                     <para>Not to be confused with
-<constant>V4L2_PIX_FMT_YUV411P</constant>, which is a planar
-format.</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RAW</constant></entry>
-               <entry><para>None<footnote> <para>V4L explains this
-as: "RAW capture (BT848)"</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV422P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUV422P"><constant>V4L2_PIX_FMT_YUV422P</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV411P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link><footnote>
-                     <para>Not to be confused with
-<constant>V4L2_PIX_FMT_Y41P</constant>, which is a packed
-format.</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV420P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV410P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></link></para></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>V4L2 image formats are defined in <xref
-linkend="pixfmt" />. The image format can be selected with the
-&VIDIOC-S-FMT; ioctl.</para>
-    </section>
-
-    <section>
-      <title>Audio</title>
-
-      <para>The <constant>VIDIOCGAUDIO</constant> and
-<constant>VIDIOCSAUDIO</constant> ioctl and struct
-<structname>video_audio</structname> are used to enumerate the
-audio inputs of a V4L device. The equivalent V4L2 ioctls are
-&VIDIOC-G-AUDIO; and &VIDIOC-S-AUDIO; using &v4l2-audio; as
-discussed in <xref linkend="audio" />.</para>
-
-      <para>The <structfield>audio</structfield> "channel number"
-field counting audio inputs was renamed to
-<structfield>index</structfield>.</para>
-
-      <para>On <constant>VIDIOCSAUDIO</constant> the
-<structfield>mode</structfield> field selects <emphasis>one</emphasis>
-of the <constant>VIDEO_SOUND_MONO</constant>,
-<constant>VIDEO_SOUND_STEREO</constant>,
-<constant>VIDEO_SOUND_LANG1</constant> or
-<constant>VIDEO_SOUND_LANG2</constant> audio demodulation modes. When
-the current audio standard is BTSC
-<constant>VIDEO_SOUND_LANG2</constant> refers to SAP and
-<constant>VIDEO_SOUND_LANG1</constant> is meaningless. Also
-undocumented in the V4L specification, there is no way to query the
-selected mode. On <constant>VIDIOCGAUDIO</constant> the driver returns
-the <emphasis>actually received</emphasis> audio programmes in this
-field. In the V4L2 API this information is stored in the &v4l2-tuner;
-<structfield>rxsubchans</structfield> and
-<structfield>audmode</structfield> fields, respectively. See <xref
-linkend="tuner" /> for more information on tuners. Related to audio
-modes &v4l2-audio; also reports if this is a mono or stereo
-input, regardless if the source is a tuner.</para>
-
-      <para>The following fields where replaced by V4L2 controls
-accessible with the &VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and
-&VIDIOC-S-CTRL; ioctls:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct
-<structname>video_audio</structname></entry>
-               <entry>V4L2 Control ID</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><structfield>volume</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>bass</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>treble</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>balance</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>To determine which of these controls are supported by a
-driver V4L provides the <structfield>flags</structfield>
-<constant>VIDEO_AUDIO_VOLUME</constant>,
-<constant>VIDEO_AUDIO_BASS</constant>,
-<constant>VIDEO_AUDIO_TREBLE</constant> and
-<constant>VIDEO_AUDIO_BALANCE</constant>. In the V4L2 API the
-&VIDIOC-QUERYCTRL; ioctl reports if the respective control is
-supported. Accordingly the <constant>VIDEO_AUDIO_MUTABLE</constant>
-and <constant>VIDEO_AUDIO_MUTE</constant> flags where replaced by the
-boolean <constant>V4L2_CID_AUDIO_MUTE</constant> control.</para>
-
-      <para>All V4L2 controls have a <structfield>step</structfield>
-attribute replacing the struct <structname>video_audio</structname>
-<structfield>step</structfield> field. The V4L audio controls are
-assumed to range from 0 to 65535 with no particular reset value. The
-V4L2 API permits arbitrary limits and defaults which can be queried
-with the &VIDIOC-QUERYCTRL; ioctl. For general information about
-controls see <xref linkend="control" />.</para>
-    </section>
-
-    <section>
-      <title>Frame Buffer Overlay</title>
-
-      <para>The V4L2 ioctls equivalent to
-<constant>VIDIOCGFBUF</constant> and <constant>VIDIOCSFBUF</constant>
-are &VIDIOC-G-FBUF; and &VIDIOC-S-FBUF;. The
-<structfield>base</structfield> field of struct
-<structname>video_buffer</structname> remained unchanged, except V4L2
-defines a flag to indicate non-destructive overlays instead of a
-<constant>NULL</constant> pointer. All other fields moved into the
-&v4l2-pix-format; <structfield>fmt</structfield> substructure of
-&v4l2-framebuffer;. The <structfield>depth</structfield> field was
-replaced by <structfield>pixelformat</structfield>. See <xref
-         linkend="pixfmt-rgb" /> for a list of RGB formats and their
-respective color depths.</para>
-
-      <para>Instead of the special ioctls
-<constant>VIDIOCGWIN</constant> and <constant>VIDIOCSWIN</constant>
-V4L2 uses the general-purpose data format negotiation ioctls
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
-&v4l2-format; as argument. Here the <structfield>win</structfield>
-member of the <structfield>fmt</structfield> union is used, a
-&v4l2-window;.</para>
-
-      <para>The <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> fields of struct
-<structname>video_window</structname> moved into &v4l2-rect;
-substructure <structfield>w</structfield> of struct
-<structname>v4l2_window</structname>. The
-<structfield>chromakey</structfield>,
-<structfield>clips</structfield>, and
-<structfield>clipcount</structfield> fields remained unchanged. Struct
-<structname>video_clip</structname> was renamed to &v4l2-clip;, also
-containing a struct <structname>v4l2_rect</structname>, but the
-semantics are still the same.</para>
-
-      <para>The <constant>VIDEO_WINDOW_INTERLACE</constant> flag was
-dropped. Instead applications must set the
-<structfield>field</structfield> field to
-<constant>V4L2_FIELD_ANY</constant> or
-<constant>V4L2_FIELD_INTERLACED</constant>. The
-<constant>VIDEO_WINDOW_CHROMAKEY</constant> flag moved into
-&v4l2-framebuffer;, under the new name
-<constant>V4L2_FBUF_FLAG_CHROMAKEY</constant>.</para>
-
-      <para>In V4L, storing a bitmap pointer in
-<structfield>clips</structfield> and setting
-<structfield>clipcount</structfield> to
-<constant>VIDEO_CLIP_BITMAP</constant> (-1) requests bitmap
-clipping, using a fixed size bitmap of 1024 &times; 625 bits. Struct
-<structname>v4l2_window</structname> has a separate
-<structfield>bitmap</structfield> pointer field for this purpose and
-the bitmap size is determined by <structfield>w.width</structfield> and
-<structfield>w.height</structfield>.</para>
-
-      <para>The <constant>VIDIOCCAPTURE</constant> ioctl to enable or
-disable overlay was renamed to &VIDIOC-OVERLAY;.</para>
-    </section>
-
-    <section>
-      <title>Cropping</title>
-
-      <para>To capture only a subsection of the full picture V4L
-defines the <constant>VIDIOCGCAPTURE</constant> and
-<constant>VIDIOCSCAPTURE</constant> ioctls using struct
-<structname>video_capture</structname>. The equivalent V4L2 ioctls are
-&VIDIOC-G-CROP; and &VIDIOC-S-CROP; using &v4l2-crop;, and the related
-&VIDIOC-CROPCAP; ioctl. This is a rather complex matter, see
-<xref linkend="crop" /> for details.</para>
-
-      <para>The <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> fields moved into &v4l2-rect;
-substructure <structfield>c</structfield> of struct
-<structname>v4l2_crop</structname>. The
-<structfield>decimation</structfield> field was dropped. In the V4L2
-API the scaling factor is implied by the size of the cropping
-rectangle and the size of the captured or overlaid image.</para>
-
-      <para>The <constant>VIDEO_CAPTURE_ODD</constant>
-and <constant>VIDEO_CAPTURE_EVEN</constant> flags to capture only the
-odd or even field, respectively, were replaced by
-<constant>V4L2_FIELD_TOP</constant> and
-<constant>V4L2_FIELD_BOTTOM</constant> in the field named
-<structfield>field</structfield> of &v4l2-pix-format; and
-&v4l2-window;. These structures are used to select a capture or
-overlay format with the &VIDIOC-S-FMT; ioctl.</para>
-    </section>
-
-    <section>
-      <title>Reading Images, Memory Mapping</title>
-
-      <section>
-       <title>Capturing using the read method</title>
-
-       <para>There is no essential difference between reading images
-from a V4L or V4L2 device using the &func-read; function, however V4L2
-drivers are not required to support this I/O method. Applications can
-determine if the function is available with the &VIDIOC-QUERYCAP;
-ioctl. All V4L2 devices exchanging data with applications must support
-the &func-select; and &func-poll; functions.</para>
-
-       <para>To select an image format and size, V4L provides the
-<constant>VIDIOCSPICT</constant> and <constant>VIDIOCSWIN</constant>
-ioctls. V4L2 uses the general-purpose data format negotiation ioctls
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
-&v4l2-format; as argument, here the &v4l2-pix-format; named
-<structfield>pix</structfield> of its <structfield>fmt</structfield>
-union is used.</para>
-
-       <para>For more information about the V4L2 read interface see
-<xref linkend="rw" />.</para>
-      </section>
-      <section>
-       <title>Capturing using memory mapping</title>
-
-       <para>Applications can read from V4L devices by mapping
-buffers in device memory, or more often just buffers allocated in
-DMA-able system memory, into their address space. This avoids the data
-copying overhead of the read method. V4L2 supports memory mapping as
-well, with a few differences.</para>
-
-       <informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>V4L</entry>
-               <entry>V4L2</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry></entry>
-               <entry>The image format must be selected before
-buffers are allocated, with the &VIDIOC-S-FMT; ioctl. When no format
-is selected the driver may use the last, possibly by another
-application requested format.</entry>
-             </row>
-             <row>
-               <entry><para>Applications cannot change the number of
-buffers. The it is built into the driver, unless it has a module
-option to change the number when the driver module is
-loaded.</para></entry>
-               <entry><para>The &VIDIOC-REQBUFS; ioctl allocates the
-desired number of buffers, this is a required step in the initialization
-sequence.</para></entry>
-             </row>
-             <row>
-               <entry><para>Drivers map all buffers as one contiguous
-range of memory. The <constant>VIDIOCGMBUF</constant> ioctl is
-available to query the number of buffers, the offset of each buffer
-from the start of the virtual file, and the overall amount of memory
-used, which can be used as arguments for the &func-mmap;
-function.</para></entry>
-               <entry><para>Buffers are individually mapped. The
-offset and size of each buffer can be determined with the
-&VIDIOC-QUERYBUF; ioctl.</para></entry>
-             </row>
-             <row>
-               <entry><para>The <constant>VIDIOCMCAPTURE</constant>
-ioctl prepares a buffer for capturing. It also determines the image
-format for this buffer. The ioctl returns immediately, eventually with
-an &EAGAIN; if no video signal had been detected. When the driver
-supports more than one buffer applications can call the ioctl multiple
-times and thus have multiple outstanding capture
-requests.</para><para>The <constant>VIDIOCSYNC</constant> ioctl
-suspends execution until a particular buffer has been
-filled.</para></entry>
-               <entry><para>Drivers maintain an incoming and outgoing
-queue. &VIDIOC-QBUF; enqueues any empty buffer into the incoming
-queue. Filled buffers are dequeued from the outgoing queue with the
-&VIDIOC-DQBUF; ioctl. To wait until filled buffers become available this
-function, &func-select; or &func-poll; can be used. The
-&VIDIOC-STREAMON; ioctl must be called once after enqueuing one or
-more buffers to start capturing. Its counterpart
-&VIDIOC-STREAMOFF; stops capturing and dequeues all buffers from both
-queues. Applications can query the signal status, if known, with the
-&VIDIOC-ENUMINPUT; ioctl.</para></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable>
-
-       <para>For a more in-depth discussion of memory mapping and
-examples, see <xref linkend="mmap" />.</para>
-      </section>
-    </section>
-
-    <section>
-      <title>Reading Raw VBI Data</title>
-
-      <para>Originally the V4L API did not specify a raw VBI capture
-interface, only the device file <filename>/dev/vbi</filename> was
-reserved for this purpose. The only driver supporting this interface
-was the BTTV driver, de-facto defining the V4L VBI interface. Reading
-from the device yields a raw VBI image with the following
-parameters:<informaltable>
-           <tgroup cols="2">
-             <thead>
-               <row>
-                 <entry>&v4l2-vbi-format;</entry>
-                 <entry>V4L, BTTV driver</entry>
-               </row>
-             </thead>
-             <tbody valign="top">
-               <row>
-                 <entry>sampling_rate</entry>
-                 <entry>28636363&nbsp;Hz NTSC (or any other 525-line
-standard); 35468950&nbsp;Hz PAL and SECAM (625-line standards)</entry>
-               </row>
-               <row>
-                 <entry>offset</entry>
-                 <entry>?</entry>
-               </row>
-               <row>
-                 <entry>samples_per_line</entry>
-                 <entry>2048</entry>
-               </row>
-               <row>
-                 <entry>sample_format</entry>
-                 <entry>V4L2_PIX_FMT_GREY. The last four bytes (a
-machine endianness integer) contain a frame counter.</entry>
-               </row>
-               <row>
-                 <entry>start[]</entry>
-                 <entry>10, 273 NTSC; 22, 335 PAL and SECAM</entry>
-               </row>
-               <row>
-                 <entry>count[]</entry>
-                 <entry><para>16, 16<footnote><para>Old driver
-versions used different values, eventually the custom
-<constant>BTTV_VBISIZE</constant> ioctl was added to query the
-correct values.</para></footnote></para></entry>
-               </row>
-               <row>
-                 <entry>flags</entry>
-                 <entry>0</entry>
-               </row>
-             </tbody>
-           </tgroup>
-       </informaltable></para>
-
-      <para>Undocumented in the V4L specification, in Linux 2.3 the
-<constant>VIDIOCGVBIFMT</constant> and
-<constant>VIDIOCSVBIFMT</constant> ioctls using struct
-<structname>vbi_format</structname> were added to determine the VBI
-image parameters. These ioctls are only partially compatible with the
-V4L2 VBI interface specified in <xref linkend="raw-vbi" />.</para>
-
-      <para>An <structfield>offset</structfield> field does not
-exist, <structfield>sample_format</structfield> is supposed to be
-<constant>VIDEO_PALETTE_RAW</constant>, equivalent to
-<constant>V4L2_PIX_FMT_GREY</constant>. The remaining fields are
-probably equivalent to &v4l2-vbi-format;.</para>
-
-      <para>Apparently only the Zoran (ZR 36120) driver implements
-these ioctls. The semantics differ from those specified for V4L2 in two
-ways. The parameters are reset on &func-open; and
-<constant>VIDIOCSVBIFMT</constant> always returns an &EINVAL; if the
-parameters are invalid.</para>
-    </section>
-
-    <section>
-      <title>Miscellaneous</title>
-
-      <para>V4L2 has no equivalent of the
-<constant>VIDIOCGUNIT</constant> ioctl. Applications can find the VBI
-device associated with a video capture device (or vice versa) by
-reopening the device and requesting VBI data. For details see
-<xref linkend="open" />.</para>
-
-      <para>No replacement exists for <constant>VIDIOCKEY</constant>,
-and the V4L functions for microcode programming. A new interface for
-MPEG compression and playback devices is documented in <xref
-         linkend="extended-controls" />.</para>
-    </section>
-
-  </section>
-
-  <section id="hist-v4l2">
-    <title>Changes of the V4L2 API</title>
-
-    <para>Soon after the V4L API was added to the kernel it was
-criticised as too inflexible. In August 1998 Bill Dirks proposed a
-number of improvements and began to work on documentation, example
-drivers and applications. With the help of other volunteers this
-eventually became the V4L2 API, not just an extension but a
-replacement for the V4L API. However it took another four years and
-two stable kernel releases until the new API was finally accepted for
-inclusion into the kernel in its present form.</para>
-
-    <section>
-      <title>Early Versions</title>
-      <para>1998-08-20: First version.</para>
-
-      <para>1998-08-27: The &func-select; function was introduced.</para>
-
-      <para>1998-09-10: New video standard interface.</para>
-
-      <para>1998-09-18: The <constant>VIDIOC_NONCAP</constant> ioctl
-was replaced by the otherwise meaningless <constant>O_TRUNC</constant>
-&func-open; flag, and the aliases <constant>O_NONCAP</constant> and
-<constant>O_NOIO</constant> were defined. Applications can set this
-flag if they intend to access controls only, as opposed to capture
-applications which need exclusive access. The
-<constant>VIDEO_STD_XXX</constant> identifiers are now ordinals
-instead of flags, and the <function>video_std_construct()</function>
-helper function takes id and transmission arguments.</para>
-
-      <para>1998-09-28: Revamped video standard. Made video controls
-individually enumerable.</para>
-
-      <para>1998-10-02: The <structfield>id</structfield> field was
-removed from struct <structname>video_standard</structname> and the
-color subcarrier fields were renamed. The &VIDIOC-QUERYSTD; ioctl was
-renamed to &VIDIOC-ENUMSTD;, &VIDIOC-G-INPUT; to &VIDIOC-ENUMINPUT;. A
-first draft of the Codec API was released.</para>
-
-      <para>1998-11-08: Many minor changes. Most symbols have been
-renamed. Some material changes to &v4l2-capability;.</para>
-
-      <para>1998-11-12: The read/write directon of some ioctls was misdefined.</para>
-
-      <para>1998-11-14: <constant>V4L2_PIX_FMT_RGB24</constant>
-changed to <constant>V4L2_PIX_FMT_BGR24</constant>, and
-<constant>V4L2_PIX_FMT_RGB32</constant> changed to
-<constant>V4L2_PIX_FMT_BGR32</constant>. Audio controls are now
-accessible with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls under
-names starting with <constant>V4L2_CID_AUDIO</constant>. The
-<constant>V4L2_MAJOR</constant> define was removed from
-<filename>videodev.h</filename> since it was only used once in the
-<filename>videodev</filename> kernel module. The
-<constant>YUV422</constant> and <constant>YUV411</constant> planar
-image formats were added.</para>
-
-      <para>1998-11-28: A few ioctl symbols changed. Interfaces for codecs and
-video output devices were added.</para>
-
-      <para>1999-01-14: A raw VBI capture interface was added.</para>
-
-      <para>1999-01-19: The <constant>VIDIOC_NEXTBUF</constant> ioctl
-      was removed.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.16 1999-01-31</title>
-      <para>1999-01-27: There is now one QBUF ioctl, VIDIOC_QWBUF and VIDIOC_QRBUF
-are gone. VIDIOC_QBUF takes a v4l2_buffer as a parameter. Added
-digital zoom (cropping) controls.</para>
-    </section>
-
-    <!-- Where's 0.17? mhs couldn't find that videodev.h, perhaps Bill
-        forgot to bump the version number or never released it. -->
-
-    <section>
-      <title>V4L2 Version 0.18 1999-03-16</title>
-      <para>Added a v4l to V4L2 ioctl compatibility layer to
-videodev.c. Driver writers, this changes how you implement your ioctl
-handler. See the Driver Writer's Guide. Added some more control id
-codes.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.19 1999-06-05</title>
-      <para>1999-03-18: Fill in the category and catname fields of
-v4l2_queryctrl objects before passing them to the driver. Required a
-minor change to the VIDIOC_QUERYCTRL handlers in the sample
-drivers.</para>
-      <para>1999-03-31: Better compatibility for v4l memory capture
-ioctls. Requires changes to drivers to fully support new compatibility
-features, see Driver Writer's Guide and v4l2cap.c. Added new control
-IDs: V4L2_CID_HFLIP, _VFLIP. Changed V4L2_PIX_FMT_YUV422P to _YUV422P,
-and _YUV411P to _YUV411P.</para>
-      <para>1999-04-04: Added a few more control IDs.</para>
-      <para>1999-04-07: Added the button control type.</para>
-      <para>1999-05-02: Fixed a typo in videodev.h, and added the
-V4L2_CTRL_FLAG_GRAYED (later V4L2_CTRL_FLAG_GRABBED) flag.</para>
-      <para>1999-05-20: Definition of VIDIOC_G_CTRL was wrong causing
-a malfunction of this ioctl.</para>
-      <para>1999-06-05: Changed the value of
-V4L2_CID_WHITENESS.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 (1999-09-10)</title>
-
-      <para>Version 0.20 introduced a number of changes which were
-<emphasis>not backward compatible</emphasis> with 0.19 and earlier
-versions. Purpose of these changes was to simplify the API, while
-making it more extensible and following common Linux driver API
-conventions.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>Some typos in <constant>V4L2_FMT_FLAG</constant>
-symbols were fixed. &v4l2-clip; was changed for compatibility with
-v4l. (1999-08-30)</para>
-       </listitem>
-
-       <listitem>
-         <para><constant>V4L2_TUNER_SUB_LANG1</constant> was added.
-(1999-09-05)</para>
-       </listitem>
-
-       <listitem>
-         <para>All ioctl() commands that used an integer argument now
-take a pointer to an integer. Where it makes sense, ioctls will return
-the actual new value in the integer pointed to by the argument, a
-common convention in the V4L2 API. The affected ioctls are:
-VIDIOC_PREVIEW, VIDIOC_STREAMON, VIDIOC_STREAMOFF, VIDIOC_S_FREQ,
-VIDIOC_S_INPUT, VIDIOC_S_OUTPUT, VIDIOC_S_EFFECT. For example
-<programlisting>
-err = ioctl (fd, VIDIOC_XXX, V4L2_XXX);
-</programlisting> becomes <programlisting>
-int a = V4L2_XXX; err = ioctl(fd, VIDIOC_XXX, &amp;a);
-</programlisting>
-         </para>
-       </listitem>
-
-       <listitem>
-         <para>All the different get- and set-format commands were
-swept into one &VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctl taking a union
-and a type field selecting the union member as parameter. Purpose is to
-simplify the API by eliminating several ioctls and to allow new and
-driver private data streams without adding new ioctls.</para>
-
-         <para>This change obsoletes the following ioctls:
-<constant>VIDIOC_S_INFMT</constant>,
-<constant>VIDIOC_G_INFMT</constant>,
-<constant>VIDIOC_S_OUTFMT</constant>,
-<constant>VIDIOC_G_OUTFMT</constant>,
-<constant>VIDIOC_S_VBIFMT</constant> and
-<constant>VIDIOC_G_VBIFMT</constant>. The image format structure
-<structname>v4l2_format</structname> was renamed to &v4l2-pix-format;,
-while &v4l2-format; is now the envelopping structure for all format
-negotiations.</para>
-       </listitem>
-
-       <listitem>
-         <para>Similar to the changes above, the
-<constant>VIDIOC_G_PARM</constant> and
-<constant>VIDIOC_S_PARM</constant> ioctls were merged with
-<constant>VIDIOC_G_OUTPARM</constant> and
-<constant>VIDIOC_S_OUTPARM</constant>. A
-<structfield>type</structfield> field in the new &v4l2-streamparm;
-selects the respective union member.</para>
-
-         <para>This change obsoletes the
-<constant>VIDIOC_G_OUTPARM</constant> and
-<constant>VIDIOC_S_OUTPARM</constant> ioctls.</para>
-       </listitem>
-
-       <listitem>
-         <para>Control enumeration was simplified, and two new
-control flags were introduced and one dropped. The
-<structfield>catname</structfield> field was replaced by a
-<structfield>group</structfield> field.</para>
-
-         <para>Drivers can now flag unsupported and temporarily
-unavailable controls with <constant>V4L2_CTRL_FLAG_DISABLED</constant>
-and <constant>V4L2_CTRL_FLAG_GRABBED</constant> respectively. The
-<structfield>group</structfield> name indicates a possibly narrower
-classification than the <structfield>category</structfield>. In other
-words, there may be multiple groups within a category. Controls within
-a group would typically be drawn within a group box. Controls in
-different categories might have a greater separation, or may even
-appear in separate windows.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-buffer; <structfield>timestamp</structfield>
-was changed to a 64 bit integer, containing the sampling or output
-time of the frame in nanoseconds. Additionally timestamps will be in
-absolute system time, not starting from zero at the beginning of a
-stream. The data type name for timestamps is stamp_t, defined as a
-signed 64-bit integer. Output devices should not send a buffer out
-until the time in the timestamp field has arrived. I would like to
-follow SGI's lead, and adopt a multimedia timestamping system like
-their UST (Unadjusted System Time). See
-http://web.archive.org/web/*/http://reality.sgi.com
-/cpirazzi_engr/lg/time/intro.html.
-UST uses timestamps that are 64-bit signed integers
-(not struct timeval's) and given in nanosecond units. The UST clock
-starts at zero when the system is booted and runs continuously and
-uniformly. It takes a little over 292 years for UST to overflow. There
-is no way to set the UST clock. The regular Linux time-of-day clock
-can be changed periodically, which would cause errors if it were being
-used for timestamping a multimedia stream. A real UST style clock will
-require some support in the kernel that is not there yet. But in
-anticipation, I will change the timestamp field to a 64-bit integer,
-and I will change the v4l2_masterclock_gettime() function (used only
-by drivers) to return a 64-bit integer.</para>
-       </listitem>
-
-       <listitem>
-         <para>A <structfield>sequence</structfield> field was added
-to &v4l2-buffer;. The <structfield>sequence</structfield> field counts
-captured frames, it is ignored by output devices. When a capture
-driver drops a frame, the sequence number of that frame is
-skipped.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 incremental changes</title>
-      <!-- Version number didn't change anymore, reason unknown. -->
-
-      <para>1999-12-23: In &v4l2-vbi-format; the
-<structfield>reserved1</structfield> field became
-<structfield>offset</structfield>. Previously drivers were required to
-clear the <structfield>reserved1</structfield> field.</para>
-
-      <para>2000-01-13: The
-      <constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant> flag was added.</para>
-
-      <para>2000-07-31: The <filename>linux/poll.h</filename> header
-is now included by <filename>videodev.h</filename> for compatibility
-with the original <filename>videodev.h</filename> file.</para>
-
-      <para>2000-11-20: <constant>V4L2_TYPE_VBI_OUTPUT</constant> and
-<constant>V4L2_PIX_FMT_Y41P</constant> were added.</para>
-
-      <para>2000-11-25: <constant>V4L2_TYPE_VBI_INPUT</constant> was
-added.</para>
-
-      <para>2000-12-04: A couple typos in symbol names were fixed.</para>
-
-      <para>2001-01-18: To avoid namespace conflicts the
-<constant>fourcc</constant> macro defined in the
-<filename>videodev.h</filename> header file was renamed to
-<constant>v4l2_fourcc</constant>.</para>
-
-      <para>2001-01-25: A possible driver-level compatibility problem
-between the <filename>videodev.h</filename> file in Linux 2.4.0 and
-the <filename>videodev.h</filename> file included in the
-<filename>videodevX</filename> patch was fixed. Users of an earlier
-version of <filename>videodevX</filename> on Linux 2.4.0 should
-recompile their V4L and V4L2 drivers.</para>
-
-      <para>2001-01-26: A possible kernel-level incompatibility
-between the <filename>videodev.h</filename> file in the
-<filename>videodevX</filename> patch and the
-<filename>videodev.h</filename> file in Linux 2.2.x with devfs patches
-applied was fixed.</para>
-
-      <para>2001-03-02: Certain V4L ioctls which pass data in both
-direction although they are defined with read-only parameter, did not
-work correctly through the backward compatibility layer.
-[Solution?]</para>
-
-      <para>2001-04-13: Big endian 16-bit RGB formats were added.</para>
-
-      <para>2001-09-17: New YUV formats and the &VIDIOC-G-FREQUENCY; and
-&VIDIOC-S-FREQUENCY; ioctls were added. (The old
-<constant>VIDIOC_G_FREQ</constant> and
-<constant>VIDIOC_S_FREQ</constant> ioctls did not take multiple tuners
-into account.)</para>
-
-      <para>2000-09-18: <constant>V4L2_BUF_TYPE_VBI</constant> was
-added. This may <emphasis>break compatibility</emphasis> as the
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls may fail now if the struct
-<structname>v4l2_fmt</structname> <structfield>type</structfield>
-field does not contain <constant>V4L2_BUF_TYPE_VBI</constant>. In the
-documentation of the &v4l2-vbi-format;
-<structfield>offset</structfield> field the ambiguous phrase "rising
-edge" was changed to "leading edge".</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 2000-11-23</title>
-
-      <para>A number of changes were made to the raw VBI
-interface.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>Figures clarifying the line numbering scheme were
-added to the V4L2 API specification. The
-<structfield>start</structfield>[0] and
-<structfield>start</structfield>[1] fields no longer count line
-numbers beginning at zero. Rationale: a) The previous definition was
-unclear. b) The <structfield>start</structfield>[] values are ordinal
-numbers. c) There is no point in inventing a new line numbering
-scheme. We now use line number as defined by ITU-R, period.
-Compatibility: Add one to the start values. Applications depending on
-the previous semantics may not function correctly.</para>
-       </listitem>
-
-       <listitem>
-         <para>The restriction "count[0] &gt; 0 and count[1] &gt; 0"
-has been relaxed  to "(count[0] + count[1]) &gt; 0". Rationale:
-Drivers may allocate resources at scan line granularity and some data
-services are transmitted only on the first field. The comment that
-both <structfield>count</structfield> values will usually be equal is
-misleading and pointless and has been removed. This change
-<emphasis>breaks compatibility</emphasis> with earlier versions:
-Drivers may return EINVAL, applications may not function
-correctly.</para>
-       </listitem>
-
-       <listitem>
-         <para>Drivers are again permitted to return negative
-(unknown) start values as proposed earlier. Why this feature was
-dropped is unclear. This change may <emphasis>break
-compatibility</emphasis> with applications depending on the start
-values being positive. The use of <constant>EBUSY</constant> and
-<constant>EINVAL</constant> error codes with the &VIDIOC-S-FMT; ioctl
-was clarified. The &EBUSY; was finally documented, and the
-<structfield>reserved2</structfield> field which was previously
-mentioned only in the <filename>videodev.h</filename> header
-file.</para>
-       </listitem>
-
-       <listitem>
-         <para>New buffer types
-<constant>V4L2_TYPE_VBI_INPUT</constant> and
-<constant>V4L2_TYPE_VBI_OUTPUT</constant> were added. The former is an
-alias for the old <constant>V4L2_TYPE_VBI</constant>, the latter was
-missing in the <filename>videodev.h</filename> file.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 2002-07-25</title>
-      <para>Added sliced VBI interface proposal.</para>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.5.46, 2002-10</title>
-
-      <para>Around October-November 2002, prior to an announced
-feature freeze of Linux 2.5, the API was revised, drawing from
-experience with V4L2 0.20. This unnamed version was finally merged
-into Linux 2.5.46.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>As specified in <xref linkend="related" />, drivers
-must make related device functions available under all minor device
-numbers.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &func-open; function requires access mode
-<constant>O_RDWR</constant> regardless of the device type. All V4L2
-drivers exchanging data with applications must support the
-<constant>O_NONBLOCK</constant> flag. The <constant>O_NOIO</constant>
-flag, a V4L2 symbol which aliased the meaningless
-<constant>O_TRUNC</constant> to indicate accesses without data
-exchange (panel applications) was dropped. Drivers must stay in "panel
-mode" until the application attempts to initiate a data exchange, see
-<xref linkend="open" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-capability; changed dramatically. Note that
-also the size of the structure changed, which is encoded in the ioctl
-request code, thus older V4L2 devices will respond with an &EINVAL; to
-the new &VIDIOC-QUERYCAP; ioctl.</para>
-
-         <para>There are new fields to identify the driver, a new RDS
-device function <constant>V4L2_CAP_RDS_CAPTURE</constant>, the
-<constant>V4L2_CAP_AUDIO</constant> flag indicates if the device has
-any audio connectors, another I/O capability
-<constant>V4L2_CAP_ASYNCIO</constant> can be flagged. In response to
-these changes the <structfield>type</structfield> field became a bit
-set and was merged into the <structfield>flags</structfield> field.
-<constant>V4L2_FLAG_TUNER</constant> was renamed to
-<constant>V4L2_CAP_TUNER</constant>,
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> replaced
-<constant>V4L2_FLAG_PREVIEW</constant> and
-<constant>V4L2_CAP_VBI_CAPTURE</constant> and
-<constant>V4L2_CAP_VBI_OUTPUT</constant> replaced
-<constant>V4L2_FLAG_DATA_SERVICE</constant>.
-<constant>V4L2_FLAG_READ</constant> and
-<constant>V4L2_FLAG_WRITE</constant> were merged into
-<constant>V4L2_CAP_READWRITE</constant>.</para>
-
-         <para>The redundant fields
-<structfield>inputs</structfield>, <structfield>outputs</structfield>
-and <structfield>audios</structfield> were removed. These properties
-can be determined as described in <xref linkend="video" /> and <xref
-linkend="audio" />.</para>
-
-         <para>The somewhat volatile and therefore barely useful
-fields <structfield>maxwidth</structfield>,
-<structfield>maxheight</structfield>,
-<structfield>minwidth</structfield>,
-<structfield>minheight</structfield>,
-<structfield>maxframerate</structfield> were removed. This information
-is available as described in <xref linkend="format" /> and
-<xref linkend="standard" />.</para>
-
-         <para><constant>V4L2_FLAG_SELECT</constant> was removed. We
-believe the select() function is important enough to require support
-of it in all V4L2 drivers exchanging data with applications. The
-redundant <constant>V4L2_FLAG_MONOCHROME</constant> flag was removed,
-this information is available as described in <xref
-             linkend="format" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-input; the
-<structfield>assoc_audio</structfield> field and the
-<structfield>capability</structfield> field and its only flag
-<constant>V4L2_INPUT_CAP_AUDIO</constant> was replaced by the new
-<structfield>audioset</structfield> field. Instead of linking one
-video input to one audio input this field reports all audio inputs
-this video input combines with.</para>
-
-         <para>New fields are <structfield>tuner</structfield>
-(reversing the former link from tuners to video inputs),
-<structfield>std</structfield> and
-<structfield>status</structfield>.</para>
-
-         <para>Accordingly &v4l2-output; lost its
-<structfield>capability</structfield> and
-<structfield>assoc_audio</structfield> fields.
-<structfield>audioset</structfield>,
-<structfield>modulator</structfield> and
-<structfield>std</structfield> where added instead.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-audio; field
-<structfield>audio</structfield> was renamed to
-<structfield>index</structfield>, for consistency with other
-structures. A new capability flag
-<constant>V4L2_AUDCAP_STEREO</constant> was added to indicated if the
-audio input in question supports stereo sound.
-<constant>V4L2_AUDCAP_EFFECTS</constant> and the corresponding
-<constant>V4L2_AUDMODE</constant> flags where removed. This can be
-easily implemented using controls. (However the same applies to AVL
-which is still there.)</para>
-
-         <para>Again for consistency the &v4l2-audioout; field
-<structfield>audio</structfield> was renamed to
-<structfield>index</structfield>.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-tuner;
-<structfield>input</structfield> field was replaced by an
-<structfield>index</structfield> field, permitting devices with
-multiple tuners. The link between video inputs and tuners is now
-reversed, inputs point to their tuner. The
-<structfield>std</structfield> substructure became a
-simple set (more about this below) and moved into &v4l2-input;. A
-<structfield>type</structfield> field was added.</para>
-
-         <para>Accordingly in &v4l2-modulator; the
-<structfield>output</structfield> was replaced by an
-<structfield>index</structfield> field.</para>
-
-         <para>In &v4l2-frequency; the
-<structfield>port</structfield> field was replaced by a
-<structfield>tuner</structfield> field containing the respective tuner
-or modulator index number. A tuner <structfield>type</structfield>
-field was added and the <structfield>reserved</structfield> field
-became larger for future extensions (satellite tuners in
-particular).</para>
-       </listitem>
-
-       <listitem>
-         <para>The idea of completely transparent video standards was
-dropped. Experience showed that applications must be able to work with
-video standards beyond presenting the user a menu. Instead of
-enumerating supported standards with an ioctl applications can now
-refer to standards by &v4l2-std-id; and symbols defined in the
-<filename>videodev2.h</filename> header file. For details see <xref
-             linkend="standard" />. The &VIDIOC-G-STD; and
-&VIDIOC-S-STD; now take a pointer to this type as argument.
-&VIDIOC-QUERYSTD; was added to autodetect the received standard, if
-the hardware has this capability. In &v4l2-standard; an
-<structfield>index</structfield> field was added for &VIDIOC-ENUMSTD;.
-A &v4l2-std-id; field named <structfield>id</structfield> was added as
-machine readable identifier, also replacing the
-<structfield>transmission</structfield> field. The misleading
-<structfield>framerate</structfield> field was renamed
-to <structfield>frameperiod</structfield>. The now obsolete
-<structfield>colorstandard</structfield> information, originally
-needed to distguish between variations of standards, were
-removed.</para>
-
-         <para>Struct <structname>v4l2_enumstd</structname> ceased to
-be. &VIDIOC-ENUMSTD; now takes a pointer to a &v4l2-standard;
-directly. The information which standards are supported by a
-particular video input or output moved into &v4l2-input; and
-&v4l2-output; fields named <structfield>std</structfield>,
-respectively.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-queryctrl; fields
-<structfield>category</structfield> and
-<structfield>group</structfield> did not catch on and/or were not
-implemented as expected and therefore removed.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-TRY-FMT; ioctl was added to negotiate data
-formats as with &VIDIOC-S-FMT;, but without the overhead of
-programming the hardware and regardless of I/O in progress.</para>
-
-         <para>In &v4l2-format; the <structfield>fmt</structfield>
-union was extended to contain &v4l2-window;. All image format
-negotiations are now possible with <constant>VIDIOC_G_FMT</constant>,
-<constant>VIDIOC_S_FMT</constant> and
-<constant>VIDIOC_TRY_FMT</constant>; ioctl. The
-<constant>VIDIOC_G_WIN</constant> and
-<constant>VIDIOC_S_WIN</constant> ioctls to prepare for a video
-overlay were removed. The <structfield>type</structfield> field
-changed to type &v4l2-buf-type; and the buffer type names changed as
-follows.<informaltable>
-             <tgroup cols="2">
-               <thead>
-                 <row>
-                   <entry>Old defines</entry>
-                   <entry>&v4l2-buf-type;</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CAPTURE</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CODECIN</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CODECOUT</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN2</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSOUT</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEOOUT</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_PRIVATE_BASE</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_PRIVATE</constant> (but this is deprecated)</entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable></para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-fmtdesc; a &v4l2-buf-type; field named
-<structfield>type</structfield> was added as in &v4l2-format;. The
-<constant>VIDIOC_ENUM_FBUFFMT</constant> ioctl is no longer needed and
-was removed. These calls can be replaced by &VIDIOC-ENUM-FMT; with
-type <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-pix-format; the
-<structfield>depth</structfield> field was removed, assuming
-applications which recognize the format by its four-character-code
-already know the color depth, and others do not care about it. The
-same rationale lead to the removal of the
-<constant>V4L2_FMT_FLAG_COMPRESSED</constant> flag. The
-<constant>V4L2_FMT_FLAG_SWCONVECOMPRESSED</constant> flag was removed
-because drivers are not supposed to convert images in kernel space. A
-user library of conversion functions should be provided instead. The
-<constant>V4L2_FMT_FLAG_BYTESPERLINE</constant> flag was redundant.
-Applications can set the <structfield>bytesperline</structfield> field
-to zero to get a reasonable default. Since the remaining flags were
-replaced as well, the <structfield>flags</structfield> field itself
-was removed.</para>
-         <para>The interlace flags were replaced by a &v4l2-field;
-value in a newly added <structfield>field</structfield>
-field.<informaltable>
-             <tgroup cols="2">
-               <thead>
-                 <row>
-                   <entry>Old flag</entry>
-                   <entry>&v4l2-field;</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant></entry>
-                   <entry>?</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_INTERLACED</constant>
-= <constant>V4L2_FMT_FLAG_COMBINED</constant></entry>
-                   <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_TOPFIELD</constant>
-= <constant>V4L2_FMT_FLAG_ODDFIELD</constant></entry>
-                   <entry><constant>V4L2_FIELD_TOP</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_BOTFIELD</constant>
-= <constant>V4L2_FMT_FLAG_EVENFIELD</constant></entry>
-                   <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable></para>
-
-         <para>The color space flags were replaced by a
-&v4l2-colorspace; value in a newly added
-<structfield>colorspace</structfield> field, where one of
-<constant>V4L2_COLORSPACE_SMPTE170M</constant>,
-<constant>V4L2_COLORSPACE_BT878</constant>,
-<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant> or
-<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant> replaces
-<constant>V4L2_FMT_CS_601YUV</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-requestbuffers; the
-<structfield>type</structfield> field was properly defined as
-&v4l2-buf-type;. Buffer types changed as mentioned above. A new
-<structfield>memory</structfield> field of type &v4l2-memory; was
-added to distinguish between I/O methods using buffers allocated
-by the driver or the application. See <xref linkend="io" /> for
-details.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-buffer; the <structfield>type</structfield>
-field was properly defined as &v4l2-buf-type;. Buffer types changed as
-mentioned above. A <structfield>field</structfield> field of type
-&v4l2-field; was added to indicate if a buffer contains a top or
-bottom field. The old field flags were removed. Since no unadjusted
-system time clock was added to the kernel as planned, the
-<structfield>timestamp</structfield> field changed back from type
-stamp_t, an unsigned 64 bit integer expressing the sample time in
-nanoseconds, to struct <structname>timeval</structname>. With the
-addition of a second memory mapping method the
-<structfield>offset</structfield> field moved into union
-<structfield>m</structfield>, and a new
-<structfield>memory</structfield> field of type &v4l2-memory; was
-added to distinguish between I/O methods. See <xref linkend="io" />
-for details.</para>
-
-         <para>The <constant>V4L2_BUF_REQ_CONTIG</constant>
-flag was used by the V4L compatibility layer, after changes to this
-code it was no longer needed. The
-<constant>V4L2_BUF_ATTR_DEVICEMEM</constant> flag would indicate if
-the buffer was indeed allocated in device memory rather than DMA-able
-system memory. It was barely useful and so was removed.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-framebuffer; the
-<structfield>base[3]</structfield> array anticipating double- and
-triple-buffering in off-screen video memory, however without defining
-a synchronization mechanism, was replaced by a single pointer. The
-<constant>V4L2_FBUF_CAP_SCALEUP</constant> and
-<constant>V4L2_FBUF_CAP_SCALEDOWN</constant> flags were removed.
-Applications can determine this capability more accurately using the
-new cropping and scaling interface. The
-<constant>V4L2_FBUF_CAP_CLIPPING</constant> flag was replaced by
-<constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant> and
-<constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-clip; the <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> field moved into a
-<structfield>c</structfield> substructure of type &v4l2-rect;. The
-<structfield>x</structfield> and <structfield>y</structfield> fields
-were renamed to <structfield>left</structfield> and
-<structfield>top</structfield>, &ie; offsets to a context dependent
-origin.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-window; the <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> field moved into a
-<structfield>w</structfield> substructure as above. A
-<structfield>field</structfield> field of type %v4l2-field; was added
-to distinguish between field and frame (interlaced) overlay.</para>
-       </listitem>
-
-       <listitem>
-         <para>The digital zoom interface, including struct
-<structname>v4l2_zoomcap</structname>, struct
-<structname>v4l2_zoom</structname>,
-<constant>V4L2_ZOOM_NONCAP</constant> and
-<constant>V4L2_ZOOM_WHILESTREAMING</constant> was replaced by a new
-cropping and scaling interface. The previously unused struct
-<structname>v4l2_cropcap</structname> and
-<structname>v4l2_crop</structname> where redefined for this purpose.
-See <xref linkend="crop" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-vbi-format; the
-<structfield>SAMPLE_FORMAT</structfield> field now contains a
-four-character-code as used to identify video image formats and
-<constant>V4L2_PIX_FMT_GREY</constant> replaces the
-<constant>V4L2_VBI_SF_UBYTE</constant> define. The
-<structfield>reserved</structfield> field was extended.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-captureparm; the type of the
-<structfield>timeperframe</structfield> field changed from unsigned
-long to &v4l2-fract;. This allows the accurate expression of multiples
-of the NTSC-M frame rate 30000 / 1001. A new field
-<structfield>readbuffers</structfield> was added to control the driver
-behaviour in read I/O mode.</para>
-
-         <para>Similar changes were made to &v4l2-outputparm;.</para>
-       </listitem>
-
-       <listitem>
-         <para>The struct <structname>v4l2_performance</structname>
-and <constant>VIDIOC_G_PERF</constant> ioctl were dropped. Except when
-using the <link linkend="rw">read/write I/O method</link>, which is
-limited anyway, this information is already available to
-applications.</para>
-       </listitem>
-
-       <listitem>
-         <para>The example transformation from RGB to YCbCr color
-space in the old V4L2 documentation was inaccurate, this has been
-corrected in <xref linkend="pixfmt" />.<!-- 0.5670G should be
-0.587, and 127/112 != 255/224 --></para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 2003-06-19</title>
-
-      <orderedlist>
-       <listitem>
-         <para>A new capability flag
-<constant>V4L2_CAP_RADIO</constant> was added for radio devices. Prior
-to this change radio devices would identify solely by having exactly one
-tuner whose type field reads <constant>V4L2_TUNER_RADIO</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>An optional driver access priority mechanism was
-added, see <xref linkend="app-pri" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>The audio input and output interface was found to be
-incomplete.</para>
-         <para>Previously the &VIDIOC-G-AUDIO;
-ioctl would enumerate the available audio inputs. An ioctl to
-determine the current audio input, if more than one combines with the
-current video input, did not exist. So
-<constant>VIDIOC_G_AUDIO</constant> was renamed to
-<constant>VIDIOC_G_AUDIO_OLD</constant>, this ioctl was removed on
-Kernel 2.6.39. The &VIDIOC-ENUMAUDIO; ioctl was added to enumerate
-audio inputs, while &VIDIOC-G-AUDIO; now reports the current audio
-input.</para>
-         <para>The same changes were made to &VIDIOC-G-AUDOUT; and
-&VIDIOC-ENUMAUDOUT;.</para>
-         <para>Until further the "videodev" module will automatically
-translate between the old and new ioctls, but drivers and applications
-must be updated to successfully compile again.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-OVERLAY; ioctl was incorrectly defined with
-write-read parameter. It was changed to write-only, while the write-read
-version was renamed to <constant>VIDIOC_OVERLAY_OLD</constant>. The old
-ioctl was removed on Kernel 2.6.39. Until further the "videodev"
-kernel module will automatically translate to the new version, so drivers
-must be recompiled, but not applications.</para>
-       </listitem>
-
-       <listitem>
-         <para><xref linkend="overlay" /> incorrectly stated that
-clipping rectangles define regions where the video can be seen.
-Correct is that clipping rectangles define regions where
-<emphasis>no</emphasis> video shall be displayed and so the graphics
-surface can be seen.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-S-PARM; and &VIDIOC-S-CTRL; ioctls were
-defined with write-only parameter, inconsistent with other ioctls
-modifying their argument. They were changed to write-read, while a
-<constant>_OLD</constant> suffix was added to the write-only versions.
-The old ioctls were removed on Kernel 2.6.39. Drivers and
-applications assuming a constant parameter need an update.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 2003-11-05</title>
-      <orderedlist>
-       <listitem>
-         <para>In <xref linkend="pixfmt-rgb" /> the following pixel
-formats were incorrectly transferred from Bill Dirks' V4L2
-specification. Descriptions below refer to bytes in memory, in
-ascending address order.<informaltable>
-             <tgroup cols="3">
-               <thead>
-                 <row>
-                   <entry>Symbol</entry>
-                   <entry>In this document prior to revision
-0.5</entry>
-                   <entry>Corrected</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
-                   <entry>B, G, R</entry>
-                   <entry>R, G, B</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
-                   <entry>R, G, B</entry>
-                   <entry>B, G, R</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-                   <entry>B, G, R, X</entry>
-                   <entry>R, G, B, X</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-                   <entry>R, G, B, X</entry>
-                   <entry>B, G, R, X</entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable> The
-<constant>V4L2_PIX_FMT_BGR24</constant> example was always
-correct.</para>
-         <para>In <xref linkend="v4l-image-properties" /> the mapping
-of the V4L <constant>VIDEO_PALETTE_RGB24</constant> and
-<constant>VIDEO_PALETTE_RGB32</constant> formats to V4L2 pixel formats
-was accordingly corrected.</para>
-       </listitem>
-
-       <listitem>
-         <para>Unrelated to the fixes above, drivers may still
-interpret some V4L2 RGB pixel formats differently. These issues have
-yet to be addressed, for details see <xref
-             linkend="pixfmt-rgb" />.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.6, 2004-05-09</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-CROPCAP; ioctl was incorrectly defined
-with read-only parameter. It is now defined as write-read ioctl, while
-the read-only version was renamed to
-<constant>VIDIOC_CROPCAP_OLD</constant>. The old ioctl was removed
-on Kernel 2.6.39.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.8</title>
-      <orderedlist>
-       <listitem>
-         <para>A new field <structfield>input</structfield> (former
-<structfield>reserved[0]</structfield>) was added to the &v4l2-buffer;
-structure. Purpose of this field is to alternate between video inputs
-(&eg; cameras) in step with the video capturing process. This function
-must be enabled with the new <constant>V4L2_BUF_FLAG_INPUT</constant>
-flag. The <structfield>flags</structfield> field is no longer
-read-only.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2004-08-01</title>
-
-      <orderedlist>
-       <listitem>
-         <para>The return value of the
-<xref linkend="func-open" /> function was incorrectly documented.</para>
-       </listitem>
-
-       <listitem>
-         <para>Audio output ioctls end in -AUDOUT, not -AUDIOOUT.</para>
-       </listitem>
-
-       <listitem>
-         <para>In the Current Audio Input example the
-<constant>VIDIOC_G_AUDIO</constant> ioctl took the wrong
-argument.</para>
-       </listitem>
-
-       <listitem>
-         <para>The documentation of the &VIDIOC-QBUF; and
-&VIDIOC-DQBUF; ioctls did not mention the &v4l2-buffer;
-<structfield>memory</structfield> field. It was also missing from
-examples. Also on the <constant>VIDIOC_DQBUF</constant> page the &EIO;
-was not documented.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.14</title>
-      <orderedlist>
-       <listitem>
-         <para>A new sliced VBI interface was added. It is documented
-in <xref linkend="sliced" /> and replaces the interface first
-proposed in V4L2 specification 0.8.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.15</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-LOG-STATUS; ioctl was added.</para>
-       </listitem>
-
-       <listitem>
-         <para>New video standards
-<constant>V4L2_STD_NTSC_443</constant>,
-<constant>V4L2_STD_SECAM_LC</constant>,
-<constant>V4L2_STD_SECAM_DK</constant> (a set of SECAM D, K and K1),
-and <constant>V4L2_STD_ATSC</constant> (a set of
-<constant>V4L2_STD_ATSC_8_VSB</constant> and
-<constant>V4L2_STD_ATSC_16_VSB</constant>) were defined. Note the
-<constant>V4L2_STD_525_60</constant> set now includes
-<constant>V4L2_STD_NTSC_443</constant>. See also <xref
-             linkend="v4l2-std-id" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>The <constant>VIDIOC_G_COMP</constant> and
-<constant>VIDIOC_S_COMP</constant> ioctl were renamed to
-<constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> respectively. Their argument
-was replaced by a struct
-<structname>v4l2_mpeg_compression</structname> pointer. (The
-<constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls where removed in Linux
-2.6.25.)</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2005-11-27</title>
-      <para>The capture example in <xref linkend="capture-example" />
-called the &VIDIOC-S-CROP; ioctl without checking if cropping is
-supported. In the video standard selection example in
-<xref linkend="standard" /> the &VIDIOC-S-STD; call used the wrong
-argument type.</para>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-01-10</title>
-      <orderedlist>
-       <listitem>
-         <para>The <constant>V4L2_IN_ST_COLOR_KILL</constant> flag in
-&v4l2-input; not only indicates if the color killer is enabled, but
-also if it is active. (The color killer disables color decoding when
-it detects no color in the video signal to improve the image
-quality.)</para>
-       </listitem>
-
-       <listitem>
-         <para>&VIDIOC-S-PARM; is a write-read ioctl, not write-only as
-stated on its reference page. The ioctl changed in 2003 as noted above.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-02-03</title>
-      <orderedlist>
-       <listitem>
-         <para>In &v4l2-captureparm; and &v4l2-outputparm; the
-<structfield>timeperframe</structfield> field gives the time in
-seconds, not microseconds.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-02-04</title>
-      <orderedlist>
-       <listitem>
-         <para>The <structfield>clips</structfield> field in
-&v4l2-window; must point to an array of &v4l2-clip;, not a linked
-list, because drivers ignore the struct
-<structname>v4l2_clip</structname>.<structfield>next</structfield>
-pointer.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.17</title>
-      <orderedlist>
-       <listitem>
-         <para>New video standard macros were added:
-<constant>V4L2_STD_NTSC_M_KR</constant> (NTSC M South Korea), and the
-sets <constant>V4L2_STD_MN</constant>,
-<constant>V4L2_STD_B</constant>, <constant>V4L2_STD_GH</constant> and
-<constant>V4L2_STD_DK</constant>. The
-<constant>V4L2_STD_NTSC</constant> and
-<constant>V4L2_STD_SECAM</constant> sets now include
-<constant>V4L2_STD_NTSC_M_KR</constant> and
-<constant>V4L2_STD_SECAM_LC</constant> respectively.</para>
-       </listitem>
-
-       <listitem>
-         <para>A new <constant>V4L2_TUNER_MODE_LANG1_LANG2</constant>
-was defined to record both languages of a bilingual program. The
-use of <constant>V4L2_TUNER_MODE_STEREO</constant> for this purpose
-is deprecated now. See the &VIDIOC-G-TUNER; section for
-details.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-09-23 (Draft 0.15)</title>
-      <orderedlist>
-       <listitem>
-         <para>In various places
-<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> and
-<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant> of the sliced VBI
-interface were not mentioned along with other buffer types.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="vidioc-g-audio" /> it was clarified
-that the &v4l2-audio; <structfield>mode</structfield> field is a flags
-field.</para>
-       </listitem>
-
-       <listitem>
-         <para><xref linkend="vidioc-querycap" /> did not mention the
-sliced VBI and radio capability flags.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="vidioc-g-frequency" /> it was
-clarified that applications must initialize the tuner
-<structfield>type</structfield> field of &v4l2-frequency; before
-calling &VIDIOC-S-FREQUENCY;.</para>
-       </listitem>
-
-       <listitem>
-         <para>The <structfield>reserved</structfield> array
-in &v4l2-requestbuffers; has 2 elements, not 32.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="output" /> and <xref
-             linkend="raw-vbi" /> the device file names
-<filename>/dev/vout</filename> which never caught on were replaced
-by <filename>/dev/video</filename>.</para>
-       </listitem>
-
-       <listitem>
-         <para>With Linux 2.6.15 the possible range for VBI device minor
-numbers was extended from 224-239 to 224-255. Accordingly device file names
-<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> are
-possible now.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.18</title>
-      <orderedlist>
-       <listitem>
-         <para>New ioctls &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS;
-and &VIDIOC-TRY-EXT-CTRLS; were added, a flag to skip unsupported
-controls with &VIDIOC-QUERYCTRL;, new control types
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
-<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant> (<xref
-             linkend="v4l2-ctrl-type" />), and new control flags
-<constant>V4L2_CTRL_FLAG_READ_ONLY</constant>,
-<constant>V4L2_CTRL_FLAG_UPDATE</constant>,
-<constant>V4L2_CTRL_FLAG_INACTIVE</constant> and
-<constant>V4L2_CTRL_FLAG_SLIDER</constant> (<xref
-             linkend="control-flags" />). See <xref
-             linkend="extended-controls" /> for details.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.19</title>
-      <orderedlist>
-       <listitem>
-         <para>In &v4l2-sliced-vbi-cap; a buffer type field was added
-replacing a reserved field. Note on architectures where the size of
-enum types differs from int types the size of the structure changed.
-The &VIDIOC-G-SLICED-VBI-CAP; ioctl was redefined from being read-only
-to write-read. Applications must initialize the type field and clear
-the reserved fields now. These changes may <emphasis>break the
-compatibility</emphasis> with older drivers and applications.</para>
-       </listitem>
-
-       <listitem>
-         <para>The ioctls &VIDIOC-ENUM-FRAMESIZES; and
-&VIDIOC-ENUM-FRAMEINTERVALS; were added.</para>
-       </listitem>
-
-       <listitem>
-         <para>A new pixel format <constant>V4L2_PIX_FMT_RGB444</constant> (<xref
-linkend="rgb-formats" />) was added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-10-12 (Draft 0.17)</title>
-      <orderedlist>
-       <listitem>
-         <para><constant>V4L2_PIX_FMT_HM12</constant> (<xref
-linkend="reserved-formats" />) is a YUV 4:2:0, not 4:2:2 format.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.21</title>
-      <orderedlist>
-       <listitem>
-         <para>The <filename>videodev2.h</filename> header file is
-now dual licensed under GNU General Public License version two or
-later, and under a 3-clause BSD-style license.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.22</title>
-      <orderedlist>
-       <listitem>
-         <para>Two new field orders
-         <constant>V4L2_FIELD_INTERLACED_TB</constant> and
-         <constant>V4L2_FIELD_INTERLACED_BT</constant> were
-         added. See <xref linkend="v4l2-field" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>Three new clipping/blending methods with a global or
-straight or inverted local alpha value were added to the video overlay
-interface. See the description of the &VIDIOC-G-FBUF; and
-&VIDIOC-S-FBUF; ioctls for details.</para>
-         <para>A new <structfield>global_alpha</structfield> field
-was added to <link
-linkend="v4l2-window"><structname>v4l2_window</structname></link>,
-extending the structure. This may <emphasis>break
-compatibility</emphasis> with applications using a struct
-<structname>v4l2_window</structname> directly. However the <link
-linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls, which take a
-pointer to a <link linkend="v4l2-format">v4l2_format</link> parent
-structure with padding bytes at the end, are not affected.</para>
-       </listitem>
-
-       <listitem>
-         <para>The format of the <structfield>chromakey</structfield>
-field in &v4l2-window; changed from "host order RGB32" to a pixel
-value in the same format as the framebuffer. This may <emphasis>break
-compatibility</emphasis> with existing applications. Drivers
-supporting the "host order RGB32" format are not known.</para>
-       </listitem>
-
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.24</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_PAL8</constant>,
-<constant>V4L2_PIX_FMT_YUV444</constant>,
-<constant>V4L2_PIX_FMT_YUV555</constant>,
-<constant>V4L2_PIX_FMT_YUV565</constant> and
-<constant>V4L2_PIX_FMT_YUV32</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.25</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats <link linkend="V4L2-PIX-FMT-Y16">
-<constant>V4L2_PIX_FMT_Y16</constant></link> and <link
-linkend="V4L2-PIX-FMT-SBGGR16">
-<constant>V4L2_PIX_FMT_SBGGR16</constant></link> were added.</para>
-       </listitem>
-       <listitem>
-         <para>New <link linkend="control">controls</link>
-<constant>V4L2_CID_POWER_LINE_FREQUENCY</constant>,
-<constant>V4L2_CID_HUE_AUTO</constant>,
-<constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant>,
-<constant>V4L2_CID_SHARPNESS</constant> and
-<constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant> were added. The
-controls <constant>V4L2_CID_BLACK_LEVEL</constant>,
-<constant>V4L2_CID_WHITENESS</constant>,
-<constant>V4L2_CID_HCENTER</constant> and
-<constant>V4L2_CID_VCENTER</constant> were deprecated.
-</para>
-       </listitem>
-       <listitem>
-         <para>A <link linkend="camera-controls">Camera controls
-class</link> was added, with the new controls
-<constant>V4L2_CID_EXPOSURE_AUTO</constant>,
-<constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>,
-<constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>,
-<constant>V4L2_CID_PAN_RELATIVE</constant>,
-<constant>V4L2_CID_TILT_RELATIVE</constant>,
-<constant>V4L2_CID_PAN_RESET</constant>,
-<constant>V4L2_CID_TILT_RESET</constant>,
-<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
-<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
-<constant>V4L2_CID_FOCUS_ABSOLUTE</constant>,
-<constant>V4L2_CID_FOCUS_RELATIVE</constant> and
-<constant>V4L2_CID_FOCUS_AUTO</constant>.</para>
-       </listitem>
-       <listitem>
-         <para>The <constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls, which were superseded
-by the <link linkend="extended-controls">extended controls</link>
-interface in Linux 2.6.18, where finally removed from the
-<filename>videodev2.h</filename> header file.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.26</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_Y16</constant> and
-<constant>V4L2_PIX_FMT_SBGGR16</constant> were added.</para>
-       </listitem>
-       <listitem>
-         <para>Added user controls
-<constant>V4L2_CID_CHROMA_AGC</constant> and
-<constant>V4L2_CID_COLOR_KILLER</constant>.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.27</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-S-HW-FREQ-SEEK; ioctl and the
-<constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability were added.</para>
-       </listitem>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_YVYU</constant>,
-<constant>V4L2_PIX_FMT_PCA501</constant>,
-<constant>V4L2_PIX_FMT_PCA505</constant>,
-<constant>V4L2_PIX_FMT_PCA508</constant>,
-<constant>V4L2_PIX_FMT_PCA561</constant>,
-<constant>V4L2_PIX_FMT_SGBRG8</constant>,
-<constant>V4L2_PIX_FMT_PAC207</constant> and
-<constant>V4L2_PIX_FMT_PJPG</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.28</title>
-      <orderedlist>
-       <listitem>
-         <para>Added <constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant> and
-<constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant> MPEG audio encodings.</para>
-       </listitem>
-       <listitem>
-         <para>Added <constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant> MPEG
-video encoding.</para>
-       </listitem>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_SGRBG10</constant> and
-<constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.29</title>
-      <orderedlist>
-       <listitem>
-         <para>The <constant>VIDIOC_G_CHIP_IDENT</constant> ioctl was renamed
-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>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_VYUY</constant>,
-<constant>V4L2_PIX_FMT_NV16</constant> and
-<constant>V4L2_PIX_FMT_NV61</constant> were added.</para>
-       </listitem>
-       <listitem>
-         <para>Added camera controls
-<constant>V4L2_CID_ZOOM_ABSOLUTE</constant>,
-<constant>V4L2_CID_ZOOM_RELATIVE</constant>,
-<constant>V4L2_CID_ZOOM_CONTINUOUS</constant> and
-<constant>V4L2_CID_PRIVACY</constant>.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.30</title>
-      <orderedlist>
-       <listitem>
-         <para>New control flag <constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant> was added.</para>
-       </listitem>
-       <listitem>
-         <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.32</title>
-      <orderedlist>
-       <listitem>
-         <para>In order to be easier to compare a V4L2 API and a kernel
-version, now V4L2 API is numbered using the Linux Kernel version numeration.</para>
-       </listitem>
-       <listitem>
-         <para>Finalized the RDS capture API. See <xref linkend="rds" /> for
-more information.</para>
-       </listitem>
-       <listitem>
-         <para>Added new capabilities for modulators and RDS encoders.</para>
-       </listitem>
-       <listitem>
-         <para>Add description for libv4l API.</para>
-       </listitem>
-       <listitem>
-         <para>Added support for string controls via new type <constant>V4L2_CTRL_TYPE_STRING</constant>.</para>
-       </listitem>
-       <listitem>
-         <para>Added <constant>V4L2_CID_BAND_STOP_FILTER</constant> documentation.</para>
-       </listitem>
-       <listitem>
-         <para>Added FM Modulator (FM TX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_TX</constant> and their Control IDs.</para>
-       </listitem>
-<listitem>
-         <para>Added FM Receiver (FM RX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_RX</constant> and their Control IDs.</para>
-       </listitem>
-       <listitem>
-         <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.33</title>
-      <orderedlist>
-       <listitem>
-         <para>Added support for Digital Video timings in order to support HDTV receivers and transmitters.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.34</title>
-      <orderedlist>
-       <listitem>
-         <para>Added
-<constant>V4L2_CID_IRIS_ABSOLUTE</constant> and
-<constant>V4L2_CID_IRIS_RELATIVE</constant> controls to the
-           <link linkend="camera-controls">Camera controls class</link>.
-         </para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.37</title>
-      <orderedlist>
-       <listitem>
-         <para>Remove the vtx (videotext/teletext) API. This API was no longer
-used and no hardware exists to verify the API. Nor were any userspace applications found
-that used it. It was originally scheduled for removal in 2.6.35.
-         </para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.39</title>
-      <orderedlist>
-        <listitem>
-          <para>The old VIDIOC_*_OLD symbols and V4L1 support were removed.</para>
-        </listitem>
-        <listitem>
-          <para>Multi-planar API added. Does not affect the compatibility of
-          current drivers and applications. See
-          <link linkend="planar-apis">multi-planar API</link>
-          for details.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 3.1</title>
-      <orderedlist>
-        <listitem>
-         <para>VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.</para>
-         <para>Standardize an error code for invalid ioctl.</para>
-          <para>Added V4L2_CTRL_TYPE_BITMASK.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 3.2</title>
-      <orderedlist>
-        <listitem>
-         <para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para>
-        </listitem>
-        <listitem>
-         <para>Add selection API for extended control over cropping
-         and composing. Does not affect the compatibility of current
-         drivers and applications. See <link
-         linkend="selection-api"> selection API </link> for
-         details.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.3</title>
-      <orderedlist>
-        <listitem>
-         <para>Added <constant>V4L2_CID_ALPHA_COMPONENT</constant> control
-           to the <link linkend="control">User controls class</link>.
-         </para>
-        </listitem>
-        <listitem>
-         <para>Added the device_caps field to struct v4l2_capabilities and added the new
-         V4L2_CAP_DEVICE_CAPS capability.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.4</title>
-      <orderedlist>
-        <listitem>
-         <para>Added <link linkend="jpeg-controls">JPEG compression control
-         class</link>.</para>
-        </listitem>
-        <listitem>
-         <para>Extended the DV Timings API:
-         &VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
-         &VIDIOC-DV-TIMINGS-CAP;.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.5</title>
-      <orderedlist>
-        <listitem>
-         <para>Added integer menus, the new type will be
-         V4L2_CTRL_TYPE_INTEGER_MENU.</para>
-        </listitem>
-        <listitem>
-         <para>Added selection API for V4L2 subdev interface:
-         &VIDIOC-SUBDEV-G-SELECTION; and
-         &VIDIOC-SUBDEV-S-SELECTION;.</para>
-        </listitem>
-        <listitem>
-         <para> Added <constant>V4L2_COLORFX_ANTIQUE</constant>,
-         <constant>V4L2_COLORFX_ART_FREEZE</constant>,
-         <constant>V4L2_COLORFX_AQUA</constant>,
-         <constant>V4L2_COLORFX_SILHOUETTE</constant>,
-         <constant>V4L2_COLORFX_SOLARIZATION</constant>,
-         <constant>V4L2_COLORFX_VIVID</constant> and
-         <constant>V4L2_COLORFX_ARBITRARY_CBCR</constant> menu items
-         to the <constant>V4L2_CID_COLORFX</constant> control.</para>
-        </listitem>
-        <listitem>
-         <para> Added <constant>V4L2_CID_COLORFX_CBCR</constant> control.</para>
-        </listitem>
-        <listitem>
-         <para> Added camera controls <constant>V4L2_CID_AUTO_EXPOSURE_BIAS</constant>,
-         <constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>,
-         <constant>V4L2_CID_IMAGE_STABILIZATION</constant>,
-         <constant>V4L2_CID_ISO_SENSITIVITY</constant>,
-         <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>,
-         <constant>V4L2_CID_EXPOSURE_METERING</constant>,
-         <constant>V4L2_CID_SCENE_MODE</constant>,
-         <constant>V4L2_CID_3A_LOCK</constant>,
-         <constant>V4L2_CID_AUTO_FOCUS_START</constant>,
-         <constant>V4L2_CID_AUTO_FOCUS_STOP</constant>,
-         <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant> and
-         <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>.
-         </para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.6</title>
-      <orderedlist>
-       <listitem>
-         <para>Replaced <structfield>input</structfield> in
-         <structname>v4l2_buffer</structname> by
-         <structfield>reserved2</structfield> and removed
-         <constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
-       </listitem>
-        <listitem>
-         <para>Added V4L2_CAP_VIDEO_M2M and V4L2_CAP_VIDEO_M2M_MPLANE capabilities.</para>
-        </listitem>
-        <listitem>
-         <para>Added support for frequency band enumerations: &VIDIOC-ENUM-FREQ-BANDS;.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.9</title>
-      <orderedlist>
-        <listitem>
-         <para>Added timestamp types to
-         <structfield>flags</structfield> field in
-         <structname>v4l2_buffer</structname>. See <xref
-         linkend="buffer-flags" />.</para>
-        </listitem>
-        <listitem>
-         <para>Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control event
-         changes flag. See <xref linkend="ctrl-changes-flags"/>.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.10</title>
-      <orderedlist>
-        <listitem>
-         <para>Removed obsolete and unused DV_PRESET ioctls
-         VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and
-         VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability
-         flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS.
-         </para>
-        </listitem>
-        <listitem>
-         <para>Added new debugging ioctl &VIDIOC-DBG-G-CHIP-INFO;.
-         </para>
-        </listitem>
-      </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>
-      <title>V4L2 in Linux 3.14</title>
-      <orderedlist>
-        <listitem>
-               <para> In struct <structname>v4l2_rect</structname>, the type
-of <structfield>width</structfield> and <structfield>height</structfield>
-fields changed from _s32 to _u32.
-         </para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.15</title>
-      <orderedlist>
-        <listitem>
-         <para>Added Software Defined Radio (SDR) Interface.
-         </para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.16</title>
-      <orderedlist>
-        <listitem>
-         <para>Added event V4L2_EVENT_SOURCE_CHANGE.
-         </para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.17</title>
-      <orderedlist>
-        <listitem>
-         <para>Extended &v4l2-pix-format;. Added format flags.
-         </para>
-        </listitem>
-        <listitem>
-         <para>Added compound control types and &VIDIOC-QUERY-EXT-CTRL;.
-         </para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.18</title>
-      <orderedlist>
-       <listitem>
-         <para>Added <constant>V4L2_CID_PAN_SPEED</constant> and
- <constant>V4L2_CID_TILT_SPEED</constant> camera controls.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.19</title>
-      <orderedlist>
-       <listitem>
-         <para>Rewrote Colorspace chapter, added new &v4l2-ycbcr-encoding;
-and &v4l2-quantization; fields to &v4l2-pix-format;, &v4l2-pix-format-mplane;
-and &v4l2-mbus-framefmt;.
-         </para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 4.4</title>
-      <orderedlist>
-       <listitem>
-         <para>Renamed <constant>V4L2_TUNER_ADC</constant> to
-<constant>V4L2_TUNER_SDR</constant>. The use of
-<constant>V4L2_TUNER_ADC</constant> is deprecated now.
-         </para>
-       </listitem>
-       <listitem>
-         <para>Added <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>
-RF Tuner control.</para>
-       </listitem>
-       <listitem>
-         <para>Added transmitter support for Software Defined Radio (SDR)
-Interface.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section id="other">
-      <title>Relation of V4L2 to other Linux multimedia APIs</title>
-
-      <section id="xvideo">
-        <title>X Video Extension</title>
-
-        <para>The X Video Extension (abbreviated XVideo or just Xv) is
-an extension of the X Window system, implemented for example by the
-XFree86 project. Its scope is similar to V4L2, an API to video capture
-and output devices for X clients. Xv allows applications to display
-live video in a window, send window contents to a TV output, and
-capture or output still images in XPixmaps<footnote>
-         <para>This is not implemented in XFree86.</para>
-       </footnote>. With their implementation XFree86 makes the
-extension available across many operating systems and
-architectures.</para>
-
-        <para>Because the driver is embedded into the X server Xv has a
-number of advantages over the V4L2 <link linkend="overlay">video
-overlay interface</link>. The driver can easily determine the overlay
-target, &ie; visible graphics memory or off-screen buffers for a
-destructive overlay. It can program the RAMDAC for a non-destructive
-overlay, scaling or color-keying, or the clipping functions of the
-video capture hardware, always in sync with drawing operations or
-windows moving or changing their stacking order.</para>
-
-        <para>To combine the advantages of Xv and V4L a special Xv
-driver exists in XFree86 and XOrg, just programming any overlay capable
-Video4Linux device it finds. To enable it
-<filename>/etc/X11/XF86Config</filename> must contain these lines:</para>
-        <para><screen>
-Section "Module"
-    Load "v4l"
-EndSection</screen></para>
-
-        <para>As of XFree86 4.2 this driver still supports only V4L
-ioctls, however it should work just fine with all V4L2 devices through
-the V4L2 backward-compatibility layer. Since V4L2 permits multiple
-opens it is possible (if supported by the V4L2 driver) to capture
-video while an X client requested video overlay. Restrictions of
-simultaneous capturing and overlay are discussed in <xref
-         linkend="overlay" /> apply.</para>
-
-        <para>Only marginally related to V4L2, XFree86 extended Xv to
-support hardware YUV to RGB conversion and scaling for faster video
-playback, and added an interface to MPEG-2 decoding hardware. This API
-is useful to display images captured with V4L2 devices.</para>
-      </section>
-
-      <section>
-        <title>Digital Video</title>
-
-        <para>V4L2 does not support digital terrestrial, cable or
-satellite broadcast. A separate project aiming at digital receivers
-exists. You can find its homepage at <ulink
-url="https://linuxtv.org">https://linuxtv.org</ulink>. The Linux DVB API
-has no connection to the V4L2 API except that drivers for hybrid
-hardware may support both.</para>
-      </section>
-
-      <section>
-        <title>Audio Interfaces</title>
-
-        <para>[to do - OSS/ALSA]</para>
-      </section>
-    </section>
-
-    <section id="experimental">
-      <title>Experimental API Elements</title>
-
-      <para>The following V4L2 API elements are currently experimental
-and may change in the future.</para>
-
-      <itemizedlist>
-        <listitem>
-         <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
-ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
-        </listitem>
-      </itemizedlist>
-    </section>
-
-    <section id="obsolete">
-      <title>Obsolete API Elements</title>
-
-      <para>The following V4L2 API elements were superseded by new
-interfaces and should not be implemented in new drivers.</para>
-
-      <itemizedlist>
-        <listitem>
-         <para><constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
-<xref linkend="extended-controls" />.</para>
-        </listitem>
-        <listitem>
-         <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_ENUM_DV_PRESETS and
-         VIDIOC_QUERY_DV_PRESET ioctls. Use the DV Timings API (<xref linkend="dv-timings" />).</para>
-        </listitem>
-        <listitem>
-         <para><constant>VIDIOC_SUBDEV_G_CROP</constant> and
-         <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctls. Use
-         <constant>VIDIOC_SUBDEV_G_SELECTION</constant> and
-         <constant>VIDIOC_SUBDEV_S_SELECTION</constant>, <xref
-         linkend="vidioc-subdev-g-selection" />.</para>
-        </listitem>
-      </itemizedlist>
-    </section>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
deleted file mode 100644 (file)
index e2e5484..0000000
+++ /dev/null
@@ -1,5505 +0,0 @@
-  <section id="control">
-    <title>User Controls</title>
-
-    <para>Devices typically have a number of user-settable controls
-such as brightness, saturation and so on, which would be presented to
-the user on a graphical user interface. But, different devices
-will have different controls available, and furthermore, the range of
-possible values, and the default value will vary from device to
-device. The control ioctls provide the information and a mechanism to
-create a nice user interface for these controls that will work
-correctly with any device.</para>
-
-    <para>All controls are accessed using an ID value. V4L2 defines
-several IDs for specific purposes. Drivers can also implement their
-own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
-<footnote><para>The use of <constant>V4L2_CID_PRIVATE_BASE</constant>
-is problematic because different drivers may use the same
-<constant>V4L2_CID_PRIVATE_BASE</constant> ID for different controls.
-This makes it hard to programatically set such controls since the meaning
-of the control with that ID is driver dependent. In order to resolve this
-drivers use unique IDs and the <constant>V4L2_CID_PRIVATE_BASE</constant>
-IDs are mapped to those unique IDs by the kernel. Consider these
-<constant>V4L2_CID_PRIVATE_BASE</constant> IDs as aliases to the real
-IDs.</para>
-<para>Many applications today still use the <constant>V4L2_CID_PRIVATE_BASE</constant>
-IDs instead of using &VIDIOC-QUERYCTRL; with the <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>
-flag to enumerate all IDs, so support for <constant>V4L2_CID_PRIVATE_BASE</constant>
-is still around.</para></footnote>
-and higher values. The pre-defined control IDs have the prefix
-<constant>V4L2_CID_</constant>, and are listed in <xref
-linkend="control-id" />. The ID is used when querying the attributes of
-a control, and when getting or setting the current value.</para>
-
-    <para>Generally applications should present controls to the user
-without assumptions about their purpose. Each control comes with a
-name string the user is supposed to understand. When the purpose is
-non-intuitive the driver writer should provide a user manual, a user
-interface plug-in or a driver specific panel application. Predefined
-IDs were introduced to change a few controls programmatically, for
-example to mute a device during a channel switch.</para>
-
-    <para>Drivers may enumerate different controls after switching
-the current video input or output, tuner or modulator, or audio input
-or output. Different in the sense of other bounds, another default and
-current value, step size or other menu items. A control with a certain
-<emphasis>custom</emphasis> ID can also change name and
-type.</para>
-
-    <para>If a control is not applicable to the current configuration
-of the device (for example, it doesn't apply to the current video input)
-drivers set the <constant>V4L2_CTRL_FLAG_INACTIVE</constant> flag.</para>
-
-    <para>Control values are stored globally, they do not
-change when switching except to stay within the reported bounds. They
-also do not change &eg; when the device is opened or closed, when the
-tuner radio frequency is changed or generally never without
-application request.</para>
-
-    <para>V4L2 specifies an event mechanism to notify applications
-when controls change value (see &VIDIOC-SUBSCRIBE-EVENT;, event
-<constant>V4L2_EVENT_CTRL</constant>), panel applications might want to make
-use of that in order to always reflect the correct control value.</para>
-
-    <para>
-      All controls use machine endianness.
-    </para>
-
-    <table pgwide="1" frame="none" id="control-id">
-      <title>Control IDs</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>ID</entry>
-           <entry>Type</entry>
-           <entry>Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CID_BASE</constant></entry>
-           <entry></entry>
-           <entry>First predefined ID, equal to
-<constant>V4L2_CID_BRIGHTNESS</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_USER_BASE</constant></entry>
-           <entry></entry>
-           <entry>Synonym of <constant>V4L2_CID_BASE</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture brightness, or more precisely, the black
-level.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CONTRAST</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture contrast or luma gain.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_SATURATION</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture color saturation or chroma gain.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HUE</constant></entry>
-           <entry>integer</entry>
-           <entry>Hue or color balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
-           <entry>integer</entry>
-           <entry>Overall audio volume. Note some drivers also
-provide an OSS or ALSA mixer interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio stereo balance. Minimum corresponds to all
-the way left, maximum to right.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio bass adjustment.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio treble adjustment.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_MUTE</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mute audio, &ie; set the volume to zero, however
-without affecting <constant>V4L2_CID_AUDIO_VOLUME</constant>. Like
-ALSA drivers, V4L2 drivers must mute at load time to avoid excessive
-noise. Actually the entire device should be reset to a low power
-consumption state.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_LOUDNESS</constant></entry>
-           <entry>boolean</entry>
-           <entry>Loudness mode (bass boost).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BLACK_LEVEL</constant></entry>
-           <entry>integer</entry>
-           <entry>Another name for brightness (not a synonym of
-<constant>V4L2_CID_BRIGHTNESS</constant>). This control is deprecated
-and should not be used in new drivers and applications.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUTO_WHITE_BALANCE</constant></entry>
-           <entry>boolean</entry>
-           <entry>Automatic white balance (cameras).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_DO_WHITE_BALANCE</constant></entry>
-           <entry>button</entry>
-           <entry>This is an action control. When set (the value is
-ignored), the device will do a white balance and then hold the current
-setting. Contrast this with the boolean
-<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant>, which, when
-activated, keeps adjusting the white balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_RED_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Red chroma balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BLUE_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Blue chroma balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_GAMMA</constant></entry>
-           <entry>integer</entry>
-           <entry>Gamma adjust.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_WHITENESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Whiteness for grey-scale devices. This is a synonym
-for <constant>V4L2_CID_GAMMA</constant>. This control is deprecated
-and should not be used in new drivers and applications.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_EXPOSURE</constant></entry>
-           <entry>integer</entry>
-           <entry>Exposure (cameras). [Unit?]</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUTOGAIN</constant></entry>
-           <entry>boolean</entry>
-           <entry>Automatic gain/exposure control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_GAIN</constant></entry>
-           <entry>integer</entry>
-           <entry>Gain control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HFLIP</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mirror the picture horizontally.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_VFLIP</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mirror the picture vertically.</entry>
-         </row>
-         <row id="v4l2-power-line-frequency">
-           <entry><constant>V4L2_CID_POWER_LINE_FREQUENCY</constant></entry>
-           <entry>enum</entry>
-           <entry>Enables a power line frequency filter to avoid
-flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are:
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0),
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1),
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2) and
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_AUTO</constant> (3).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HUE_AUTO</constant></entry>
-           <entry>boolean</entry>
-           <entry>Enables automatic hue control by the device. The
-effect of setting <constant>V4L2_CID_HUE</constant> while automatic
-hue control is enabled is undefined, drivers should ignore such
-request.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant></entry>
-           <entry>integer</entry>
-           <entry>This control specifies the white balance settings
-as a color temperature in Kelvin. A driver should have a minimum of
-2800 (incandescent) to 6500 (daylight). For more information about
-color temperature see <ulink
-url="http://en.wikipedia.org/wiki/Color_temperature">Wikipedia</ulink>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_SHARPNESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the sharpness filters in a camera. The
-minimum value disables the filters, higher values give a sharper
-picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the backlight compensation in a camera. The
-minimum value disables backlight compensation.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CHROMA_AGC</constant></entry>
-           <entry>boolean</entry>
-           <entry>Chroma automatic gain control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the Chroma gain control (for use when chroma AGC
-           is disabled).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
-           <entry>boolean</entry>
-           <entry>Enable the color killer (&ie; force a black &amp; white image in case of a weak video signal).</entry>
-         </row>
-         <row id="v4l2-colorfx">
-           <entry><constant>V4L2_CID_COLORFX</constant></entry>
-           <entry>enum</entry>
-           <entry>Selects a color effect. The following values are defined:
-           </entry>
-         </row><row>
-         <entry></entry>
-         <entry></entry>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_COLORFX_NONE</constant>&nbsp;</entry>
-                 <entry>Color effect is disabled.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_ANTIQUE</constant>&nbsp;</entry>
-                 <entry>An aging (old photo) effect.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_ART_FREEZE</constant>&nbsp;</entry>
-                 <entry>Frost color effect.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_AQUA</constant>&nbsp;</entry>
-                 <entry>Water color, cool tone.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_BW</constant>&nbsp;</entry>
-                 <entry>Black and white.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_EMBOSS</constant>&nbsp;</entry>
-                 <entry>Emboss, the highlights and shadows replace light/dark boundaries
-                 and low contrast areas are set to a gray background.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_GRASS_GREEN</constant>&nbsp;</entry>
-                 <entry>Grass green.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_NEGATIVE</constant>&nbsp;</entry>
-                 <entry>Negative.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SEPIA</constant>&nbsp;</entry>
-                 <entry>Sepia tone.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SKETCH</constant>&nbsp;</entry>
-                 <entry>Sketch.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SKIN_WHITEN</constant>&nbsp;</entry>
-                 <entry>Skin whiten.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SKY_BLUE</constant>&nbsp;</entry>
-                 <entry>Sky blue.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SOLARIZATION</constant>&nbsp;</entry>
-                 <entry>Solarization, the image is partially reversed in tone,
-                 only color values above or below a certain threshold are inverted.
-                 </entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SILHOUETTE</constant>&nbsp;</entry>
-                 <entry>Silhouette (outline).</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_VIVID</constant>&nbsp;</entry>
-                 <entry>Vivid colors.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_COLORFX_SET_CBCR</constant>&nbsp;</entry>
-                 <entry>The Cb and Cr chroma components are replaced by fixed
-                 coefficients determined by <constant>V4L2_CID_COLORFX_CBCR</constant>
-                 control.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_COLORFX_CBCR</constant></entry>
-           <entry>integer</entry>
-           <entry>Determines the Cb and Cr coefficients for <constant>V4L2_COLORFX_SET_CBCR</constant>
-           color effect. Bits [7:0] of the supplied 32 bit value are interpreted as
-           Cr component, bits [15:8] as Cb component and bits [31:16] must be zero.
-         </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUTOBRIGHTNESS</constant></entry>
-           <entry>boolean</entry>
-           <entry>Enable Automatic Brightness.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_ROTATE</constant></entry>
-           <entry>integer</entry>
-           <entry>Rotates the image by specified angle. Common angles are 90,
-           270 and 180. Rotating the image to 90 and 270 will reverse the height
-           and width of the display window. It is necessary to set the new height and
-           width of the picture using the &VIDIOC-S-FMT; ioctl according to
-           the rotation angle selected.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BG_COLOR</constant></entry>
-           <entry>integer</entry>
-           <entry>Sets the background color on the current output device.
-           Background color needs to be specified in the RGB24 format. The
-           supplied 32 bit value is interpreted as bits 0-7 Red color information,
-           bits 8-15 Green color information, bits 16-23 Blue color
-           information and bits 24-31 must be zero.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
-               <constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
-           <entry>boolean</entry>
-           <entry>Switch on or off the illuminator 1 or 2 of the device
-               (usually a microscope).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry>
-           <entry>integer</entry>
-           <entry>This is a read-only control that can be read by the application
-and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS.
-The value is the minimum number of CAPTURE buffers that is necessary for hardware
-to work.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_OUTPUT</constant></entry>
-           <entry>integer</entry>
-           <entry>This is a read-only control that can be read by the application
-and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
-The value is the minimum number of OUTPUT buffers that is necessary for hardware
-to work.</entry>
-         </row>
-         <row id="v4l2-alpha-component">
-           <entry><constant>V4L2_CID_ALPHA_COMPONENT</constant></entry>
-           <entry>integer</entry>
-           <entry>Sets the alpha color component. When a capture device (or
-           capture queue of a mem-to-mem device) produces a frame format that
-           includes an alpha component
-           (e.g. <link linkend="rgb-formats">packed RGB image formats</link>)
-           and the alpha value is not defined by the device or the mem-to-mem
-           input data this control lets you select the alpha component value of
-           all pixels. When an output device (or output queue of a mem-to-mem
-           device) consumes a frame format that doesn't include an alpha
-           component and the device supports alpha channel processing this
-           control lets you set the alpha component value of all pixels for
-           further processing in the device.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_LASTP1</constant></entry>
-           <entry></entry>
-           <entry>End of the predefined control IDs (currently
-             <constant>V4L2_CID_ALPHA_COMPONENT</constant> + 1).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
-           <entry></entry>
-           <entry>ID of the first custom (driver specific) control.
-Applications depending on particular custom controls should check the
-driver name and version, see <xref linkend="querycap" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Applications can enumerate the available controls with the
-&VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls, get and set a
-control value with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls.
-Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
-<constant>VIDIOC_G_CTRL</constant> and
-<constant>VIDIOC_S_CTRL</constant> when the device has one or more
-controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
-more menu type controls.</para>
-
-    <example id="enum_all_controls">
-      <title>Enumerating all user controls</title>
-
-      <programlisting>
-&v4l2-queryctrl; queryctrl;
-&v4l2-querymenu; querymenu;
-
-static void enumerate_menu(void)
-{
-       printf("  Menu items:\n");
-
-       memset(&amp;querymenu, 0, sizeof(querymenu));
-       querymenu.id = queryctrl.id;
-
-       for (querymenu.index = queryctrl.minimum;
-            querymenu.index &lt;= queryctrl.maximum;
-            querymenu.index++) {
-               if (0 == ioctl(fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
-                       printf("  %s\n", querymenu.name);
-               }
-       }
-}
-
-memset(&amp;queryctrl, 0, sizeof(queryctrl));
-
-for (queryctrl.id = V4L2_CID_BASE;
-     queryctrl.id &lt; V4L2_CID_LASTP1;
-     queryctrl.id++) {
-       if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
-                       continue;
-
-               printf("Control %s\n", queryctrl.name);
-
-               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-                       enumerate_menu();
-       } else {
-               if (errno == EINVAL)
-                       continue;
-
-               perror("VIDIOC_QUERYCTRL");
-               exit(EXIT_FAILURE);
-       }
-}
-
-for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
-     queryctrl.id++) {
-       if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
-                       continue;
-
-               printf("Control %s\n", queryctrl.name);
-
-               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-                       enumerate_menu();
-       } else {
-               if (errno == EINVAL)
-                       break;
-
-               perror("VIDIOC_QUERYCTRL");
-               exit(EXIT_FAILURE);
-       }
-}
-</programlisting>
-    </example>
-
-    <example>
-      <title>Enumerating all user controls (alternative)</title>
-       <programlisting>
-memset(&amp;queryctrl, 0, sizeof(queryctrl));
-
-queryctrl.id = V4L2_CTRL_CLASS_USER | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-       if (V4L2_CTRL_ID2CLASS(queryctrl.id) != V4L2_CTRL_CLASS_USER)
-               break;
-       if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
-               continue;
-
-       printf("Control %s\n", queryctrl.name);
-
-       if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-               enumerate_menu();
-
-       queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-}
-if (errno != EINVAL) {
-       perror("VIDIOC_QUERYCTRL");
-       exit(EXIT_FAILURE);
-}
-</programlisting>
-    </example>
-
-    <example>
-      <title>Changing controls</title>
-
-      <programlisting>
-&v4l2-queryctrl; queryctrl;
-&v4l2-control; control;
-
-memset(&amp;queryctrl, 0, sizeof(queryctrl));
-queryctrl.id = V4L2_CID_BRIGHTNESS;
-
-if (-1 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-       if (errno != EINVAL) {
-               perror("VIDIOC_QUERYCTRL");
-               exit(EXIT_FAILURE);
-       } else {
-               printf("V4L2_CID_BRIGHTNESS is not supported\n");
-       }
-} else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
-       printf("V4L2_CID_BRIGHTNESS is not supported\n");
-} else {
-       memset(&amp;control, 0, sizeof (control));
-       control.id = V4L2_CID_BRIGHTNESS;
-       control.value = queryctrl.default_value;
-
-       if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)) {
-               perror("VIDIOC_S_CTRL");
-               exit(EXIT_FAILURE);
-       }
-}
-
-memset(&amp;control, 0, sizeof(control));
-control.id = V4L2_CID_CONTRAST;
-
-if (0 == ioctl(fd, &VIDIOC-G-CTRL;, &amp;control)) {
-       control.value += 1;
-
-       /* The driver may clamp the value or return ERANGE, ignored here */
-
-       if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &amp;control)
-           &amp;&amp; errno != ERANGE) {
-               perror("VIDIOC_S_CTRL");
-               exit(EXIT_FAILURE);
-       }
-/* Ignore if V4L2_CID_CONTRAST is unsupported */
-} else if (errno != EINVAL) {
-       perror("VIDIOC_G_CTRL");
-       exit(EXIT_FAILURE);
-}
-
-control.id = V4L2_CID_AUDIO_MUTE;
-control.value = 1; /* silence */
-
-/* Errors ignored */
-ioctl(fd, VIDIOC_S_CTRL, &amp;control);
-</programlisting>
-    </example>
-  </section>
-
-  <section id="extended-controls">
-    <title>Extended Controls</title>
-
-    <section>
-      <title>Introduction</title>
-
-      <para>The control mechanism as originally designed was meant
-to be used for user settings (brightness, saturation, etc). However,
-it turned out to be a very useful model for implementing more
-complicated driver APIs where each driver implements only a subset of
-a larger API.</para>
-
-      <para>The MPEG encoding API was the driving force behind
-designing and implementing this extended control mechanism: the MPEG
-standard is quite large and the currently supported hardware MPEG
-encoders each only implement a subset of this standard. Further more,
-many parameters relating to how the video is encoded into an MPEG
-stream are specific to the MPEG encoding chip since the MPEG standard
-only defines the format of the resulting MPEG stream, not how the
-video is actually encoded into that format.</para>
-
-      <para>Unfortunately, the original control API lacked some
-features needed for these new uses and so it was extended into the
-(not terribly originally named) extended control API.</para>
-
-      <para>Even though the MPEG encoding API was the first effort
-to use the Extended Control API, nowadays there are also other classes
-of Extended Controls, such as Camera Controls and FM Transmitter Controls.
-The Extended Controls API as well as all Extended Controls classes are
-described in the following text.</para>
-    </section>
-
-    <section>
-      <title>The Extended Control API</title>
-
-      <para>Three new ioctls are available: &VIDIOC-G-EXT-CTRLS;,
-&VIDIOC-S-EXT-CTRLS; and &VIDIOC-TRY-EXT-CTRLS;. These ioctls act on
-arrays of controls (as opposed to the &VIDIOC-G-CTRL; and
-&VIDIOC-S-CTRL; ioctls that act on a single control). This is needed
-since it is often required to atomically change several controls at
-once.</para>
-
-      <para>Each of the new ioctls expects a pointer to a
-&v4l2-ext-controls;. This structure contains a pointer to the control
-array, a count of the number of controls in that array and a control
-class. Control classes are used to group similar controls into a
-single class. For example, control class
-<constant>V4L2_CTRL_CLASS_USER</constant> contains all user controls
-(&ie; all controls that can also be set using the old
-<constant>VIDIOC_S_CTRL</constant> ioctl). Control class
-<constant>V4L2_CTRL_CLASS_MPEG</constant> contains all controls
-relating to MPEG encoding, etc.</para>
-
-      <para>All controls in the control array must belong to the
-specified control class. An error is returned if this is not the
-case.</para>
-
-      <para>It is also possible to use an empty control array (count
-== 0) to check whether the specified control class is
-supported.</para>
-
-      <para>The control array is a &v4l2-ext-control; array. The
-<structname>v4l2_ext_control</structname> structure is very similar to
-&v4l2-control;, except for the fact that it also allows for 64-bit
-values and pointers to be passed.</para>
-
-      <para>Since the &v4l2-ext-control; supports pointers it is now
-also possible to have controls with compound types such as N-dimensional arrays
-and/or structures. You need to specify the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
-when enumerating controls to actually be able to see such compound controls.
-In other words, these controls with compound types should only be used
-programmatically.</para>
-
-      <para>Since such compound controls need to expose more information
-about themselves than is possible with &VIDIOC-QUERYCTRL; the
-&VIDIOC-QUERY-EXT-CTRL; ioctl was added. In particular, this ioctl gives
-the dimensions of the N-dimensional array if this control consists of more than
-one element.</para>
-
-      <para>It is important to realize that due to the flexibility of
-controls it is necessary to check whether the control you want to set
-actually is supported in the driver and what the valid range of values
-is. So use the &VIDIOC-QUERYCTRL; (or &VIDIOC-QUERY-EXT-CTRL;) and
-&VIDIOC-QUERYMENU; ioctls to check this. Also note that it is possible
-that some of the menu indices in a control of type
-<constant>V4L2_CTRL_TYPE_MENU</constant> may not be supported
-(<constant>VIDIOC_QUERYMENU</constant> will return an error). A good
-example is the list of supported MPEG audio bitrates. Some drivers only
-support one or two bitrates, others support a wider range.</para>
-
-      <para>
-       All controls use machine endianness.
-      </para>
-    </section>
-
-    <section>
-      <title>Enumerating Extended Controls</title>
-
-      <para>The recommended way to enumerate over the extended
-controls is by using &VIDIOC-QUERYCTRL; in combination with the
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag:</para>
-
-      <informalexample>
-       <programlisting>
-&v4l2-queryctrl; qctrl;
-
-qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-       /* ... */
-       qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-}
-</programlisting>
-      </informalexample>
-
-      <para>The initial control ID is set to 0 ORed with the
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag. The
-<constant>VIDIOC_QUERYCTRL</constant> ioctl will return the first
-control with a higher ID than the specified one. When no such controls
-are found an error is returned.</para>
-
-      <para>If you want to get all controls within a specific control
-class, then you can set the initial
-<structfield>qctrl.id</structfield> value to the control class and add
-an extra check to break out of the loop when a control of another
-control class is found:</para>
-
-      <informalexample>
-       <programlisting>
-qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-       if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_MPEG)
-               break;
-               /* ... */
-       qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-}
-</programlisting>
-      </informalexample>
-
-      <para>The 32-bit <structfield>qctrl.id</structfield> value is
-subdivided into three bit ranges: the top 4 bits are reserved for
-flags (&eg; <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>) and are not
-actually part of the ID. The remaining 28 bits form the control ID, of
-which the most significant 12 bits define the control class and the
-least significant 16 bits identify the control within the control
-class. It is guaranteed that these last 16 bits are always non-zero
-for controls. The range of 0x1000 and up are reserved for
-driver-specific controls. The macro
-<constant>V4L2_CTRL_ID2CLASS(id)</constant> returns the control class
-ID based on a control ID.</para>
-
-      <para>If the driver does not support extended controls, then
-<constant>VIDIOC_QUERYCTRL</constant> will fail when used in
-combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
-that case the old method of enumerating control should be used (see
-<xref linkend="enum_all_controls" />). But if it is supported, then it is guaranteed to enumerate over
-all controls, including driver-private controls.</para>
-    </section>
-
-    <section>
-      <title>Creating Control Panels</title>
-
-      <para>It is possible to create control panels for a graphical
-user interface where the user can select the various controls.
-Basically you will have to iterate over all controls using the method
-described above. Each control class starts with a control of type
-<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant>.
-<constant>VIDIOC_QUERYCTRL</constant> will return the name of this
-control class which can be used as the title of a tab page within a
-control panel.</para>
-
-      <para>The flags field of &v4l2-queryctrl; also contains hints on
-the behavior of the control. See the &VIDIOC-QUERYCTRL; documentation
-for more details.</para>
-    </section>
-
-    <section id="mpeg-controls">
-      <title>Codec Control Reference</title>
-
-      <para>Below all controls within the Codec control class are
-described. First the generic controls, then controls specific for
-certain hardware.</para>
-
-      <para>Note: These controls are applicable to all codecs and
-not just MPEG. The defines are prefixed with V4L2_CID_MPEG/V4L2_MPEG
-as the controls were originally made for MPEG codecs and later
-extended to cover all encoding formats.</para>
-
-      <section>
-       <title>Generic Codec Controls</title>
-
-       <table pgwide="1" frame="none" id="mpeg-control-id">
-         <title>Codec Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
-             <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CLASS</constant>&nbsp;</entry>
-               <entry>class</entry>
-             </row><row><entry spanname="descr">The Codec class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class. This description can be used as the
-caption of a Tab page in a GUI, for example.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-stream-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_stream_type</entry>
-             </row><row><entry spanname="descr">The MPEG-1, -2 or -4
-output stream type. One cannot assume anything here. Each hardware
-MPEG encoder tends to support different subsets of the available MPEG
-stream types. This control is specific to multiplexed MPEG streams.
-The currently defined stream types are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_PS</constant>&nbsp;</entry>
-                     <entry>MPEG-2 program stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_TS</constant>&nbsp;</entry>
-                     <entry>MPEG-2 transport stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_SS</constant>&nbsp;</entry>
-                     <entry>MPEG-1 system stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_DVD</constant>&nbsp;</entry>
-                     <entry>MPEG-2 DVD-compatible stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_VCD</constant>&nbsp;</entry>
-                     <entry>MPEG-1 VCD-compatible stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD</constant>&nbsp;</entry>
-                     <entry>MPEG-2 SVCD-compatible stream</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PMT</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Program Map Table
-Packet ID for the MPEG transport stream (default 16)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_AUDIO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Audio Packet ID for
-the MPEG transport stream (default 256)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_VIDEO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video Packet ID for
-the MPEG transport stream (default 260)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PCR</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Packet ID for the
-MPEG transport stream carrying PCR fields (default 259)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_AUDIO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Audio ID for MPEG
-PES</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_VIDEO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video ID for MPEG
-PES</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-stream-vbi-fmt">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_VBI_FMT</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_stream_vbi_fmt</entry>
-             </row><row><entry spanname="descr">Some cards can embed
-VBI data (&eg; Closed Caption, Teletext) into the MPEG stream. This
-control selects whether VBI data should be embedded, and if so, what
-embedding method should be used. The list of possible VBI formats
-depends on the driver. The currently defined VBI format types
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_NONE</constant>&nbsp;</entry>
-                     <entry>No VBI in the MPEG stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant>&nbsp;</entry>
-                     <entry>VBI in private packets, IVTV format (documented
-in the kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>)</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-sampling-freq">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_sampling_freq</entry>
-             </row><row><entry spanname="descr">MPEG Audio sampling
-frequency. Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100</constant>&nbsp;</entry>
-                     <entry>44.1 kHz</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000</constant>&nbsp;</entry>
-                     <entry>48 kHz</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000</constant>&nbsp;</entry>
-                     <entry>32 kHz</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-encoding">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_ENCODING</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_encoding</entry>
-             </row><row><entry spanname="descr">MPEG Audio encoding.
-This control is specific to multiplexed MPEG streams.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_1</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer I encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_2</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer II encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_3</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer III encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant>&nbsp;</entry>
-                     <entry>MPEG-2/4 AAC (Advanced Audio Coding)</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant>&nbsp;</entry>
-                     <entry>AC-3 aka ATSC A/52 encoding</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l1-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L1_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l1_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer I bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry></row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_288K</constant>&nbsp;</entry>
-                     <entry>288 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_352K</constant>&nbsp;</entry>
-                     <entry>352 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_416K</constant>&nbsp;</entry>
-                     <entry>416 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_448K</constant>&nbsp;</entry>
-                     <entry>448 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l2-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L2_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l2_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer II bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l3-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L3_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l3_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer III bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_40K</constant>&nbsp;</entry>
-                     <entry>40 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AAC_BITRATE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">AAC bitrate in bits per second.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-ac3-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AC3_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_ac3_bitrate</entry>
-             </row><row><entry spanname="descr">AC-3 bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_40K</constant>&nbsp;</entry>
-                     <entry>40 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_448K</constant>&nbsp;</entry>
-                     <entry>448 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_512K</constant>&nbsp;</entry>
-                     <entry>512 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_576K</constant>&nbsp;</entry>
-                     <entry>576 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_640K</constant>&nbsp;</entry>
-                     <entry>640 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_mode</entry>
-             </row><row><entry spanname="descr">MPEG Audio mode.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_STEREO</constant>&nbsp;</entry>
-                     <entry>Stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_JOINT_STEREO</constant>&nbsp;</entry>
-                     <entry>Joint Stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_DUAL</constant>&nbsp;</entry>
-                     <entry>Bilingual</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_MONO</constant>&nbsp;</entry>
-                     <entry>Mono</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-mode-extension">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE_EXTENSION</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_mode_extension</entry>
-             </row><row><entry spanname="descr">Joint Stereo
-audio mode extension. In Layer I and II they indicate which subbands
-are in intensity stereo. All other subbands are coded in stereo. Layer
-III is not (yet) supported. Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4</constant>&nbsp;</entry>
-                     <entry>Subbands 4-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8</constant>&nbsp;</entry>
-                     <entry>Subbands 8-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12</constant>&nbsp;</entry>
-                     <entry>Subbands 12-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16</constant>&nbsp;</entry>
-                     <entry>Subbands 16-31 in intensity stereo</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-emphasis">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_EMPHASIS</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_emphasis</entry>
-             </row><row><entry spanname="descr">Audio Emphasis.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_NONE</constant>&nbsp;</entry>
-                     <entry>None</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS</constant>&nbsp;</entry>
-                     <entry>50/15 microsecond emphasis</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17</constant>&nbsp;</entry>
-                     <entry>CCITT J.17</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-crc">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_CRC</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_crc</entry>
-             </row><row><entry spanname="descr">CRC method. Possible
-values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_CRC_NONE</constant>&nbsp;</entry>
-                     <entry>None</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_CRC_CRC16</constant>&nbsp;</entry>
-                     <entry>16 bit parity check</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MUTE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Mutes the audio when
-capturing. This is not done by muting audio hardware, which can still
-produce a slight hiss, but in the encoder itself, guaranteeing a fixed
-and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-dec-playback">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
-             </row><row><entry spanname="descr">Determines how monolingual audio should be played back.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO</constant>&nbsp;</entry>
-                     <entry>Automatically determines the best playback mode.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO</constant>&nbsp;</entry>
-                     <entry>Stereo playback.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT</constant>&nbsp;</entry>
-                     <entry>Left channel playback.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT</constant>&nbsp;</entry>
-                     <entry>Right channel playback.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO</constant>&nbsp;</entry>
-                     <entry>Mono playback.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO</constant>&nbsp;</entry>
-                     <entry>Stereo playback with swapped left and right channels.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-dec-multilingual-playback">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
-             </row><row><entry spanname="descr">Determines how multilingual audio should be played back.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-encoding">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
-             </row><row><entry spanname="descr">MPEG Video encoding
-method. This control is specific to multiplexed MPEG streams.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_1</constant>&nbsp;</entry>
-                     <entry>MPEG-1 Video encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_2</constant>&nbsp;</entry>
-                     <entry>MPEG-2 Video encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant>&nbsp;</entry>
-                     <entry>MPEG-4 AVC (H.264) Video encoding</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-aspect">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ASPECT</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_aspect</entry>
-             </row><row><entry spanname="descr">Video aspect.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_1x1</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_4x3</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_16x9</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_221x100</constant>&nbsp;</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_B_FRAMES</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Number of B-Frames
-(default 2)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_SIZE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">GOP size (default
-12)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_CLOSURE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">GOP closure (default
-1)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_PULLDOWN</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Enable 3:2 pulldown
-(default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-bitrate-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_bitrate_mode</entry>
-             </row><row><entry spanname="descr">Video bitrate mode.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_VBR</constant>&nbsp;</entry>
-                     <entry>Variable bitrate</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_CBR</constant>&nbsp;</entry>
-                     <entry>Constant bitrate</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video bitrate in bits
-per second.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_PEAK</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Peak video bitrate in
-bits per second. Must be larger or equal to the average video bitrate.
-It is ignored if the video bitrate mode is set to constant
-bitrate.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">For every captured
-frame, skip this many subsequent frames (default 0).</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">"Mutes" the video to a
-fixed color when capturing. This is useful for testing, to produce a
-fixed video bitstream. 0 = unmuted, 1 = muted.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE_YUV</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Sets the "mute" color
-of the video. The supplied 32-bit integer is interpreted as follows (bit
-0 = least significant bit):</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry>Bit 0:7</entry>
-                     <entry>V chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 8:15</entry>
-                     <entry>U chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 16:23</entry>
-                     <entry>Y luminance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 24:31</entry>
-                     <entry>Must be zero.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-dec-pts">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant>&nbsp;</entry>
-               <entry>integer64</entry>
-             </row><row><entry spanname="descr">This read-only control returns the
-33-bit video Presentation Time Stamp as defined in ITU T-REC-H.222.0 and ISO/IEC 13818-1 of
-the currently displayed frame. This is the same PTS as is used in &VIDIOC-DECODER-CMD;.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-dec-frame">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant>&nbsp;</entry>
-               <entry>integer64</entry>
-             </row><row><entry spanname="descr">This read-only control returns the
-frame counter of the frame that is currently displayed (decoded). This value is reset to 0 whenever
-the decoder is started.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">If enabled the decoder expects to receive a single slice per buffer, otherwise
-the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs.
-</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enable writing sample aspect ratio in the Video Usability Information.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-vui-sar-idc">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_vui_sar_idc</entry>
-             </row>
-             <row><entry spanname="descr">VUI sample aspect ratio indicator for H.264 encoding. The value
-is defined in the table E-1 in the standard. Applicable to the H264 encoder.</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED</constant>&nbsp;</entry>
-                         <entry>Unspecified</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1</constant>&nbsp;</entry>
-                         <entry>1x1</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11</constant>&nbsp;</entry>
-                         <entry>12x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11</constant>&nbsp;</entry>
-                         <entry>10x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11</constant>&nbsp;</entry>
-                         <entry>16x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33</constant>&nbsp;</entry>
-                         <entry>40x33</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11</constant>&nbsp;</entry>
-                         <entry>24x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11</constant>&nbsp;</entry>
-                         <entry>20x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11</constant>&nbsp;</entry>
-                         <entry>32x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33</constant>&nbsp;</entry>
-                         <entry>80x33</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11</constant>&nbsp;</entry>
-                         <entry>18x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11</constant>&nbsp;</entry>
-                         <entry>15x11</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33</constant>&nbsp;</entry>
-                         <entry>64x33</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99</constant>&nbsp;</entry>
-                         <entry>160x99</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3</constant>&nbsp;</entry>
-                         <entry>4x3</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2</constant>&nbsp;</entry>
-                         <entry>3x2</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1</constant>&nbsp;</entry>
-                         <entry>2x1</entry>
-                       </row>
-                       <row>
-                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED</constant>&nbsp;</entry>
-                         <entry>Extended SAR</entry>
-                       </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Extended sample aspect ratio width for H.264 VUI encoding.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Extended sample aspect ratio height for H.264 VUI encoding.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-level">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_level</entry>
-             </row>
-             <row><entry spanname="descr">The level information for the H264 video elementary stream.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_0</constant>&nbsp;</entry>
-                     <entry>Level 1.0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1B</constant>&nbsp;</entry>
-                     <entry>Level 1B</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_1</constant>&nbsp;</entry>
-                     <entry>Level 1.1</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_2</constant>&nbsp;</entry>
-                     <entry>Level 1.2</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_3</constant>&nbsp;</entry>
-                     <entry>Level 1.3</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_0</constant>&nbsp;</entry>
-                     <entry>Level 2.0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_1</constant>&nbsp;</entry>
-                     <entry>Level 2.1</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_2</constant>&nbsp;</entry>
-                     <entry>Level 2.2</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_0</constant>&nbsp;</entry>
-                     <entry>Level 3.0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_1</constant>&nbsp;</entry>
-                     <entry>Level 3.1</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_2</constant>&nbsp;</entry>
-                     <entry>Level 3.2</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_0</constant>&nbsp;</entry>
-                     <entry>Level 4.0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_1</constant>&nbsp;</entry>
-                     <entry>Level 4.1</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_2</constant>&nbsp;</entry>
-                     <entry>Level 4.2</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_0</constant>&nbsp;</entry>
-                     <entry>Level 5.0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_1</constant>&nbsp;</entry>
-                     <entry>Level 5.1</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-mpeg4-level">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_mpeg4_level</entry>
-             </row>
-             <row><entry spanname="descr">The level information for the MPEG4 elementary stream.
-Applicable to the MPEG4 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0</constant>&nbsp;</entry>
-                     <entry>Level 0</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0B</constant>&nbsp;</entry>
-                     <entry>Level 0b</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_1</constant>&nbsp;</entry>
-                     <entry>Level 1</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_2</constant>&nbsp;</entry>
-                     <entry>Level 2</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3</constant>&nbsp;</entry>
-                     <entry>Level 3</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3B</constant>&nbsp;</entry>
-                     <entry>Level 3b</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_4</constant>&nbsp;</entry>
-                     <entry>Level 4</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_5</constant>&nbsp;</entry>
-                     <entry>Level 5</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-profile">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_profile</entry>
-             </row>
-             <row><entry spanname="descr">The profile information for H264.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE</constant>&nbsp;</entry>
-                     <entry>Baseline profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE</constant>&nbsp;</entry>
-                     <entry>Constrained Baseline profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MAIN</constant>&nbsp;</entry>
-                     <entry>Main profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED</constant>&nbsp;</entry>
-                     <entry>Extended profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH</constant>&nbsp;</entry>
-                     <entry>High profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10</constant>&nbsp;</entry>
-                     <entry>High 10 profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422</constant>&nbsp;</entry>
-                     <entry>High 422 profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE</constant>&nbsp;</entry>
-                     <entry>High 444 Predictive profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA</constant>&nbsp;</entry>
-                     <entry>High 10 Intra profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA</constant>&nbsp;</entry>
-                     <entry>High 422 Intra profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA</constant>&nbsp;</entry>
-                     <entry>High 444 Intra profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA</constant>&nbsp;</entry>
-                     <entry>CAVLC 444 Intra profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE</constant>&nbsp;</entry>
-                     <entry>Scalable Baseline profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH</constant>&nbsp;</entry>
-                     <entry>Scalable High profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA</constant>&nbsp;</entry>
-                     <entry>Scalable High Intra profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH</constant>&nbsp;</entry>
-                     <entry>Stereo High profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH</constant>&nbsp;</entry>
-                     <entry>Multiview High profile</entry>
-                   </row>
-
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-mpeg4-profile">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_mpeg4_profile</entry>
-             </row>
-             <row><entry spanname="descr">The profile information for MPEG4.
-Applicable to the MPEG4 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE</constant>&nbsp;</entry>
-                     <entry>Simple profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE</constant>&nbsp;</entry>
-                     <entry>Advanced Simple profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_CORE</constant>&nbsp;</entry>
-                     <entry>Core profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE</constant>&nbsp;</entry>
-                     <entry>Simple Scalable profile</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY</constant>&nbsp;</entry>
-                     <entry></entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MAX_REF_PIC</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">The maximum number of reference pictures used for encoding.
-Applicable to the encoder.
-</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-multi-slice-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_multi_slice_mode</entry>
-             </row>
-             <row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
-Applicable to the encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE</constant>&nbsp;</entry>
-                     <entry>Single slice per frame.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>&nbsp;</entry>
-                     <entry>Multiple slices with set maximum number of macroblocks per slice.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>&nbsp;</entry>
-                     <entry>Multiple slice with set maximum size in bytes per slice.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">The maximum number of macroblocks in a slice. Used when
-<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>.
-Applicable to the encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">The maximum size of a slice in bytes. Used when
-<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>.
-Applicable to the encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-loop-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_loop_filter_mode</entry>
-             </row>
-             <row><entry spanname="descr">Loop filter mode for H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED</constant>&nbsp;</entry>
-                     <entry>Loop filter is enabled.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED</constant>&nbsp;</entry>
-                     <entry>Loop filter is disabled.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY</constant>&nbsp;</entry>
-                     <entry>Loop filter is disabled at the slice boundary.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Loop filter alpha coefficient, defined in the H264 standard.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Loop filter beta coefficient, defined in the H264 standard.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-entropy-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_entropy_mode</entry>
-             </row>
-             <row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC</constant>&nbsp;</entry>
-                     <entry>Use CAVLC entropy coding.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC</constant>&nbsp;</entry>
-                     <entry>Use CABAC entropy coding.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enable 8X8 transform for H264. Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
-refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the
-top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Frame level rate control enable.
-If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls
-(e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>).
-If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value
-for the quantization parameter can be set with appropriate controls (e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>).
-Applicable to encoders.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Macroblock level rate control enable.
-Applicable to the MPEG4 and H264 encoders.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_QPEL</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an I frame for H263. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Minimum quantization parameter for H263. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MAX_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Maximum quantization parameter for H263. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an P frame for H263. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an B frame for H263. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an I frame for H264. Valid range: from 0 to 51.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MIN_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Minimum quantization parameter for H264. Valid range: from 0 to 51.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MAX_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Maximum quantization parameter for H264. Valid range: from 0 to 51.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an P frame for H264. Valid range: from 0 to 51.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an B frame for H264. Valid range: from 0 to 51.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Minimum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Maximum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_SIZE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
-The VBV is defined in the standard as a mean to verify that the produced stream will be successfully decoded.
-The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
-output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
-encoder or editing process may produce.".
-Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-vbv-delay">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_DELAY</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Sets the initial delay in milliseconds for
-VBV buffer control.</entry>
-             </row>
-
-                 <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-hor-search-range">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-               <row><entry spanname="descr">Horizontal search range defines maximum horizontal search area in pixels
-to search and match for the present Macroblock (MB) in the reference picture. This V4L2 control macro is used to set
-horizontal search range for motion estimation module in video encoder.</entry>
-             </row>
-
-                <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-vert-search-range">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-               <row><entry spanname="descr">Vertical search range defines maximum vertical search area in pixels
-to search and match for the present Macroblock (MB) in the reference picture. This V4L2 control macro is used to set
-vertical search range for motion estimation module in video encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-force-key-frame">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME</constant>&nbsp;</entry>
-               <entry>button</entry>
-             </row><row><entry spanname="descr">Force a key frame for the next queued buffer. Applicable to encoders.
-This is a general, codec-agnostic keyframe control.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
-The CPB is defined in the H264 standard as a mean to verify that the produced stream will be successfully decoded.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_PERIOD</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Period between I-frames in the open GOP for H264. In case of an open GOP
-this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control.
-An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are
-referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any
-previous frames. Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-header-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_header_mode</entry>
-             </row>
-             <row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
-it returned together with the first frame. Applicable to encoders.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE</constant>&nbsp;</entry>
-                     <entry>The stream header is returned separately in the first buffer.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME</constant>&nbsp;</entry>
-                     <entry>The stream header is returned together with the first encoded frame.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Repeat the video sequence headers. Repeating these
-headers makes random access to the video stream easier. Applicable to the MPEG1, 2 and 4 encoder.</entry>
-             </row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Enabled the deblocking post processing filter for MPEG4 decoder.
-Applicable to the MPEG4 decoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enable generation of frame packing supplemental enhancement information in the encoded bitstream.
-The frame packing SEI message contains the arrangement of L and R planes for 3D viewing. Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Sets current frame as frame0 in frame packing SEI.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-sei-fp-arrangement-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_sei_fp_arrangement_type</entry>
-             </row>
-             <row><entry spanname="descr">Frame packing arrangement type for H264 SEI.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHEKERBOARD</constant>&nbsp;</entry>
-                     <entry>Pixels are alternatively from L and R.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN</constant>&nbsp;</entry>
-                     <entry>L and R are interlaced by column.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW</constant>&nbsp;</entry>
-                     <entry>L and R are interlaced by row.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE</constant>&nbsp;</entry>
-                     <entry>L is on the left, R on the right.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM</constant>&nbsp;</entry>
-                     <entry>L is on top, R on bottom.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL</constant>&nbsp;</entry>
-                     <entry>One view per frame.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enables flexible macroblock ordering in the encoded bitstream. It is a technique
-used for restructuring the ordering of macroblocks in pictures. Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-fmo-map-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_fmo_map_type</entry>
-             </row>
-             <row><entry spanname="descr">When using FMO, the map type divides the image in different scan patterns of macroblocks.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES</constant>&nbsp;</entry>
-                     <entry>Slices are interleaved one after other with macroblocks in run length order.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES</constant>&nbsp;</entry>
-                     <entry>Scatters the macroblocks based on a mathematical function known to both encoder and decoder.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER</constant>&nbsp;</entry>
-                     <entry>Macroblocks arranged in rectangular areas or regions of interest.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT</constant>&nbsp;</entry>
-                     <entry>Slice groups grow in a cyclic way from centre to outwards.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN</constant>&nbsp;</entry>
-                     <entry>Slice groups grow in raster scan pattern from left to right.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN</constant>&nbsp;</entry>
-                     <entry>Slice groups grow in wipe scan pattern from top to bottom.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT</constant>&nbsp;</entry>
-                     <entry>User defined map type.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Number of slice groups in FMO.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-fmo-change-direction">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_fmo_change_dir</entry>
-             </row>
-             <row><entry spanname="descr">Specifies a direction of the slice group change for raster and wipe maps.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT</constant>&nbsp;</entry>
-                     <entry>Raster scan or wipe right.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT</constant>&nbsp;</entry>
-                     <entry>Reverse raster scan or wipe left.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Specifies the size of the first slice group for raster and wipe map.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Specifies the number of consecutive macroblocks for the interleaved map.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enables arbitrary slice ordering in encoded bitstream.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Specifies the slice order in ASO. Applicable to the H264 encoder.
-The supplied 32-bit integer is interpreted as follows (bit
-0 = least significant bit):</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry>Bit 0:15</entry>
-                     <entry>Slice ID</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 16:32</entry>
-                     <entry>Slice position or order</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Enables H264 hierarchical coding.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-h264-hierarchical-coding-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_h264_hierarchical_coding_type</entry>
-             </row>
-             <row><entry spanname="descr">Specifies the hierarchical coding type.
-Applicable to the H264 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B</constant>&nbsp;</entry>
-                     <entry>Hierarchical B coding.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P</constant>&nbsp;</entry>
-                     <entry>Hierarchical P coding.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Specifies the number of hierarchical coding layers.
-Applicable to the H264 encoder.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Specifies a user defined QP for each layer. Applicable to the H264 encoder.
-The supplied 32-bit integer is interpreted as follows (bit
-0 = least significant bit):</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry>Bit 0:15</entry>
-                     <entry>QP value</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 16:32</entry>
-                     <entry>Layer number</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
-
-      <section>
-       <title>MFC 5.1 MPEG Controls</title>
-
-       <para>The following MPEG class controls deal with MPEG
-decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present
-in the S5P family of SoCs by Samsung.
-</para>
-
-       <table pgwide="1" frame="none" id="mfc51-control-id">
-         <title>MFC 5.1 Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
-             <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row><entry spanname="descr" align="left">Description</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">If the display delay is enabled then the decoder is forced to return a
-CAPTURE buffer (decoded frame) after processing a certain number of OUTPUT buffers. The delay can be set through
-<constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>. This feature can be used for example
-for generating thumbnails of videos. Applicable to the H264 decoder.
-             </entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Display delay value for H264 decoder.
-The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is
-low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer
-as a reference picture for subsequent frames.
-</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">The number of reference pictures used for encoding a P picture.
-Applicable to the H264 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Padding enable in the encoder - use a color instead of repeating border pixels.
-Applicable to encoders.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit
-0 = least significant bit):</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry>Bit 0:7</entry>
-                     <entry>V chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 8:15</entry>
-                     <entry>U chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 16:23</entry>
-                     <entry>Y luminance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 24:31</entry>
-                     <entry>Must be zero.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Reaction coefficient for MFC rate control. Applicable to encoders.
-<para>Note 1: Valid only when the frame level RC is enabled.</para>
-<para>Note 2: For tight CBR, this field must be small (ex. 2 ~ 10).
-For VBR, this field must be large (ex. 100 ~ 1000).</para>
-<para>Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE).</para>
-</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Adaptive rate control for dark region.
-Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
-Applicable to the H264 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Adaptive rate control for smooth region.
-Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
-Applicable to the H264 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Adaptive rate control for static region.
-Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
-Applicable to the H264 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Adaptive rate control for activity region.
-Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
-Applicable to the H264 encoder.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-mfc51-video-frame-skip-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_mfc51_video_frame_skip_mode</entry>
-             </row>
-             <row><entry spanname="descr">
-Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
-a chosen data limit then the frame will be skipped.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED</constant>&nbsp;</entry>
-                     <entry>Frame skip mode is disabled.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT</constant>&nbsp;</entry>
-                     <entry>Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT</constant>&nbsp;</entry>
-                     <entry>Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Enable rate-control with fixed target bit.
-If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate
-for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the
-overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case
-the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the
-average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that
-the stream will meet tight bandwidth constraints. Applicable to encoders.
-</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-mfc51-video-force-frame-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_mfc51_video_force_frame_type</entry>
-             </row>
-             <row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED</constant>&nbsp;</entry>
-                     <entry>Forcing a specific frame type disabled.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME</constant>&nbsp;</entry>
-                     <entry>Force an I-frame.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED</constant>&nbsp;</entry>
-                     <entry>Force a non-coded frame.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
-
-      <section>
-       <title>CX2341x MPEG Controls</title>
-
-       <para>The following MPEG class controls deal with MPEG
-encoding settings that are specific to the Conexant CX23415 and
-CX23416 MPEG encoding chips.</para>
-
-       <table pgwide="1" frame="none" id="cx2341x-control-id">
-         <title>CX2341x Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
-             <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row><entry spanname="descr" align="left">Description</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Spatial
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-15)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="luma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-to use for the Luma Spatial Filter (default
-<constant>1D_HOR</constant>). Possible values:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
-                     <entry>One-dimensional vertical</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional separable</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional symmetrical
-non-separable</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="chroma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Temporal
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-31)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
-capturing and 0 for scaled capturing.)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
-             </row><row><entry spanname="descr">Median Filter Type
-(default <constant>OFF</constant>). Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
-                     <entry>Horizontal filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
-                     <entry>Vertical filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
-                     <entry>Horizontal and vertical filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
-                     <entry>Diagonal filter</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the luminance median filter is enabled (default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the luminance median filter is enabled (default 255)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the chroma median filter is enabled (default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the chroma median filter is enabled (default 255)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">The CX2341X MPEG encoder
-can insert one empty MPEG-2 PES packet into the stream between every
-four video frames. The packet size is 2048 bytes, including the
-packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
-(private stream 2). The payload consists of 0x00 bytes, to be filled
-in by the application. 0 = do not insert, 1 = insert packets.</entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
-
-    <section>
-      <title>VPX Control Reference</title>
-
-      <para>The VPX controls include controls for encoding parameters
-      of VPx video codec.</para>
-
-      <table pgwide="1" frame="none" id="vpx-control-id">
-      <title>VPX Control IDs</title>
-
-      <tgroup cols="4">
-        <colspec colname="c1" colwidth="1*" />
-        <colspec colname="c2" colwidth="6*" />
-        <colspec colname="c3" colwidth="2*" />
-        <colspec colname="c4" colwidth="6*" />
-        <spanspec namest="c1" nameend="c2" spanname="id" />
-        <spanspec namest="c2" nameend="c4" spanname="descr" />
-        <thead>
-          <row>
-            <entry spanname="id" align="left">ID</entry>
-            <entry align="left">Type</entry>
-          </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-          </row>
-        </thead>
-        <tbody valign="top">
-          <row><entry></entry></row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-vpx-num-partitions">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS</constant></entry>
-               <entry>enum v4l2_vp8_num_partitions</entry>
-             </row>
-             <row><entry spanname="descr">The number of token partitions to use in VP8 encoder.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION</constant></entry>
-                     <entry>1 coefficient partition</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS</constant></entry>
-                     <entry>2 coefficient partitions</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS</constant></entry>
-                     <entry>4 coefficient partitions</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS</constant></entry>
-                     <entry>8 coefficient partitions</entry>
-                   </row>
-                  </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4</constant></entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">Setting this prevents intra 4x4 mode in the intra mode decision.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-vpx-num-ref-frames">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES</constant></entry>
-               <entry>enum v4l2_vp8_num_ref_frames</entry>
-             </row>
-             <row><entry spanname="descr">The number of reference pictures for encoding P frames.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME</constant></entry>
-                     <entry>Last encoded frame will be searched</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME</constant></entry>
-                     <entry>Two frames will be searched among the last encoded frame, the golden frame
-and the alternate reference (altref) frame. The encoder implementation will decide which two are chosen.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_3_REF_FRAME</constant></entry>
-                     <entry>The last encoded frame, the golden frame and the altref frame will be searched.</entry>
-                   </row>
-                  </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL</constant></entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Indicates the loop filter level. The adjustment of the loop
-filter level is done via a delta value against a baseline loop filter value.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS</constant></entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">This parameter affects the loop filter. Anything above
-zero weakens the deblocking effect on the loop filter.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD</constant></entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Sets the refresh period for the golden frame. The period is defined
-in number of frames. For a value of 'n', every nth frame starting from the first key frame will be taken as a golden frame.
-For eg. for encoding sequence of 0, 1, 2, 3, 4, 5, 6, 7 where the golden frame refresh period is set as 4, the frames
-0, 4, 8 etc will be taken as the golden frames as frame 0 is always a key frame.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row id="v4l2-vpx-golden-frame-sel">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL</constant></entry>
-               <entry>enum v4l2_vp8_golden_frame_sel</entry>
-             </row>
-             <row><entry spanname="descr">Selects the golden frame for encoding.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV</constant></entry>
-                     <entry>Use the (n-2)th frame as a golden frame, current frame index being 'n'.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD</constant></entry>
-                     <entry>Use the previous specific frame indicated by
-V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD as a golden frame.</entry>
-                   </row>
-                  </tbody>
-               </entrytbl>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MIN_QP</constant></entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Minimum quantization parameter for VP8.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MAX_QP</constant></entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Maximum quantization parameter for VP8.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for an I frame for VP8.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Quantization parameter for a P frame for VP8.</entry>
-             </row>
-
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_PROFILE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row>
-             <row><entry spanname="descr">Select the desired profile for VPx encoder.
-Acceptable values are 0, 1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3.</entry>
-             </row>
-
-          <row><entry></entry></row>
-        </tbody>
-      </tgroup>
-      </table>
-
-      </section>
-    </section>
-
-    <section id="camera-controls">
-      <title>Camera Control Reference</title>
-
-      <para>The Camera class includes controls for mechanical (or
-equivalent digital) features of a device such as controllable lenses
-or sensors.</para>
-
-    <table pgwide="1" frame="none" id="camera-control-id">
-      <title>Camera Control IDs</title>
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_CAMERA_CLASS</constant>&nbsp;</entry>
-           <entry>class</entry>
-         </row><row><entry spanname="descr">The Camera class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-exposure-auto-type">
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_exposure_auto_type</entry>
-         </row><row><entry spanname="descr">Enables automatic
-adjustments of the exposure time and/or iris aperture. The effect of
-manual changes of the exposure time or iris aperture while these
-features are enabled is undefined, drivers should ignore such
-requests. Possible values are:</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_AUTO</constant>&nbsp;</entry>
-                     <entry>Automatic exposure time, automatic iris
-aperture.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_MANUAL</constant>&nbsp;</entry>
-                 <entry>Manual exposure time, manual iris.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_SHUTTER_PRIORITY</constant>&nbsp;</entry>
-                 <entry>Manual exposure time, auto iris.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_APERTURE_PRIORITY</constant>&nbsp;</entry>
-                 <entry>Auto exposure time, manual iris.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Determines the exposure
-time of the camera sensor. The exposure time is limited by the frame
-interval. Drivers should interpret the values as 100 &micro;s units,
-where the value 1 stands for 1/10000th of a second, 10000 for 1 second
-and 100000 for 10 seconds.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">When
-<constant>V4L2_CID_EXPOSURE_AUTO</constant> is set to
-<constant>AUTO</constant> or <constant>APERTURE_PRIORITY</constant>,
-this control determines if the device may dynamically vary the frame
-rate. By default this feature is disabled (0) and the frame rate must
-remain constant.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_BIAS</constant>&nbsp;</entry>
-           <entry>integer menu</entry>
-         </row><row><entry spanname="descr"> Determines the automatic
-exposure compensation, it is effective only when <constant>V4L2_CID_EXPOSURE_AUTO</constant>
-control is set to <constant>AUTO</constant>, <constant>SHUTTER_PRIORITY </constant>
-or <constant>APERTURE_PRIORITY</constant>.
-It is expressed in terms of EV, drivers should interpret the values as 0.001 EV
-units, where the value 1000 stands for +1 EV.
-<para>Increasing the exposure compensation value is equivalent to decreasing
-the exposure value (EV) and will increase the amount of light at the image
-sensor. The camera performs the exposure compensation by adjusting absolute
-exposure time and/or aperture.</para></entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-exposure-metering">
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_METERING</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_exposure_metering</entry>
-         </row><row><entry spanname="descr">Determines how the camera measures
-the amount of light available for the frame exposure. Possible values are:</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_METERING_AVERAGE</constant>&nbsp;</entry>
-                 <entry>Use the light information coming from the entire frame
-and average giving no weighting to any particular portion of the metered area.
-                 </entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_METERING_CENTER_WEIGHTED</constant>&nbsp;</entry>
-                 <entry>Average the light information coming from the entire frame
-giving priority to the center of the metered area.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_METERING_SPOT</constant>&nbsp;</entry>
-                 <entry>Measure only very small area at the center of the frame.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_METERING_MATRIX</constant>&nbsp;</entry>
-                 <entry>A multi-zone metering. The light intensity is measured
-in several points of the frame and the results are combined. The
-algorithm of the zones selection and their significance in calculating the
-final value is device dependent.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera horizontally by the specified amount. The unit is undefined. A
-positive value moves the camera to the right (clockwise when viewed
-from above), a negative value to the left. A value of zero does not
-cause motion. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera vertically by the specified amount. The unit is undefined. A
-positive value moves the camera up, a negative value down. A value of
-zero does not cause motion. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_RESET</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">When this control is set,
-the camera moves horizontally to the default position.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_RESET</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">When this control is set,
-the camera moves vertically to the default position.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control
-turns the camera horizontally to the specified position. Positive
-values move the camera to the right (clockwise when viewed from above),
-negative values to the left. Drivers should interpret the values as arc
-seconds, with valid values between -180 * 3600 and +180 * 3600
-inclusive.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control
-turns the camera vertically to the specified position. Positive values
-move the camera up, negative values down. Drivers should interpret the
-values as arc seconds, with valid values between -180 * 3600 and +180
-* 3600 inclusive.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control sets the
-focal point of the camera to the specified position. The unit is
-undefined. Positive values set the focus closer to the camera,
-negative values towards infinity.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control moves the
-focal point of the camera by the specified amount. The unit is
-undefined. Positive values move the focus closer to the camera,
-negative values towards infinity. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">Enables continuous automatic
-focus adjustments. The effect of manual focus adjustments while this feature
-is enabled is undefined, drivers should ignore such requests.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_START</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">Starts single auto focus process.
-The effect of setting this control when <constant>V4L2_CID_FOCUS_AUTO</constant>
-is set to <constant>TRUE</constant> (1) is undefined, drivers should ignore
-such requests.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_STOP</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">Aborts automatic focusing
-started with <constant>V4L2_CID_AUTO_FOCUS_START</constant> control. It is
-effective only when the continuous autofocus is disabled, that is when
-<constant>V4L2_CID_FOCUS_AUTO</constant> control is set to <constant>FALSE
-</constant> (0).</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-auto-focus-status">
-           <entry spanname="id">
-             <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>&nbsp;</entry>
-           <entry>bitmask</entry>
-         </row>
-         <row><entry spanname="descr">The automatic focus status. This is a read-only
-         control.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_STATUS_IDLE</constant>&nbsp;</entry>
-                 <entry>Automatic focus is not active.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_STATUS_BUSY</constant>&nbsp;</entry>
-                 <entry>Automatic focusing is in progress.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_STATUS_REACHED</constant>&nbsp;</entry>
-                 <entry>Focus has been reached.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_STATUS_FAILED</constant>&nbsp;</entry>
-                 <entry>Automatic focus has failed, the driver will not
-                 transition from this state until another action is
-                 performed by an application.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry spanname="descr">
-Setting <constant>V4L2_LOCK_FOCUS</constant> lock bit of the <constant>V4L2_CID_3A_LOCK
-</constant> control may stop updates of the <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>
-control value.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-auto-focus-range">
-           <entry spanname="id">
-             <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_auto_focus_range</entry>
-         </row>
-         <row><entry spanname="descr">Determines auto focus distance range
-for which lens may be adjusted. </entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_RANGE_AUTO</constant>&nbsp;</entry>
-                 <entry>The camera automatically selects the focus range.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_RANGE_NORMAL</constant>&nbsp;</entry>
-                 <entry>Normal distance range, limited for best automatic focus
-performance.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_RANGE_MACRO</constant>&nbsp;</entry>
-                 <entry>Macro (close-up) auto focus. The camera will
-use its minimum possible distance for auto focus.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_AUTO_FOCUS_RANGE_INFINITY</constant>&nbsp;</entry>
-                 <entry>The lens is set to focus on an object at infinite distance.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Specify the objective lens
-focal length as an absolute value. The zoom unit is driver-specific and its
-value should be a positive integer.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Specify the objective lens
-focal length relatively to the current value. Positive values move the zoom
-lens group towards the telephoto direction, negative values towards the
-wide-angle direction. The zoom unit is driver-specific. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_CONTINUOUS</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Move the objective lens group
-at the specified speed until it reaches physical device limits or until an
-explicit request to stop the movement. A positive value moves the zoom lens
-group towards the telephoto direction. A value of zero stops the zoom lens
-group movement. A negative value moves the zoom lens group towards the
-wide-angle direction. The zoom speed unit is driver-specific.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control sets the
-camera's aperture to the specified value. The unit is undefined.
-Larger values open the iris wider, smaller values close it.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control modifies the
-camera's aperture by the specified amount. The unit is undefined.
-Positive values open the iris one step further, negative values close
-it one step further. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">Prevent video from being acquired
-by the camera. When this control is set to <constant>TRUE</constant> (1), no
-image can be captured by the camera. Common means to enforce privacy are
-mechanical obturation of the sensor and firmware image processing, but the
-device is not restricted to these methods. Devices that implement the privacy
-control must support read access and may support write access.</entry>
-         </row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_BAND_STOP_FILTER</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Switch the band-stop filter of a
-camera sensor on or off, or specify its strength. Such band-stop filters can
-be used, for example, to filter out the fluorescent light component.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-auto-n-preset-white-balance">
-           <entry spanname="id"><constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_auto_n_preset_white_balance</entry>
-         </row><row><entry spanname="descr">Sets white balance to automatic,
-manual or a preset. The presets determine color temperature of the light as
-a hint to the camera for white balance adjustments resulting in most accurate
-color representation. The following white balance presets are listed in order
-of increasing color temperature.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_MANUAL</constant>&nbsp;</entry>
-                 <entry>Manual white balance.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_AUTO</constant>&nbsp;</entry>
-                 <entry>Automatic white balance adjustments.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_INCANDESCENT</constant>&nbsp;</entry>
-                 <entry>White balance setting for incandescent (tungsten) lighting.
-It generally cools down the colors and corresponds approximately to 2500...3500 K
-color temperature range.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT</constant>&nbsp;</entry>
-                 <entry>White balance preset for fluorescent lighting.
-It corresponds approximately to 4000...5000 K color temperature.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT_H</constant>&nbsp;</entry>
-                 <entry>With this setting the camera will compensate for
-fluorescent H lighting.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_HORIZON</constant>&nbsp;</entry>
-                 <entry>White balance setting for horizon daylight.
-It corresponds approximately to 5000 K color temperature.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_DAYLIGHT</constant>&nbsp;</entry>
-                 <entry>White balance preset for daylight (with clear sky).
-It corresponds approximately to 5000...6500 K color temperature.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_FLASH</constant>&nbsp;</entry>
-                 <entry>With this setting the camera will compensate for the flash
-light. It slightly warms up the colors and corresponds roughly to 5000...5500 K
-color temperature.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_CLOUDY</constant>&nbsp;</entry>
-                 <entry>White balance preset for moderately overcast sky.
-This option corresponds approximately to 6500...8000 K color temperature
-range.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_WHITE_BALANCE_SHADE</constant>&nbsp;</entry>
-                 <entry>White balance preset for shade or heavily overcast
-sky. It corresponds approximately to 9000...10000 K color temperature.
-</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-wide-dynamic-range">
-           <entry spanname="id"><constant>V4L2_CID_WIDE_DYNAMIC_RANGE</constant></entry>
-           <entry>boolean</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Enables or disables the camera's wide dynamic
-range feature. This feature allows to obtain clear images in situations where
-intensity of the illumination varies significantly throughout the scene, i.e.
-there are simultaneously very dark and very bright areas. It is most commonly
-realized in cameras by combining two subsequent frames with different exposure
-times. <footnote id="ctypeconv"><para> This control may be changed to a menu
-control in the future, if more options are required.</para></footnote></entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-image-stabilization">
-           <entry spanname="id"><constant>V4L2_CID_IMAGE_STABILIZATION</constant></entry>
-           <entry>boolean</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Enables or disables image stabilization.
-             <footnoteref linkend="ctypeconv"/></entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY</constant>&nbsp;</entry>
-           <entry>integer menu</entry>
-         </row><row><entry spanname="descr">Determines ISO equivalent of an
-image sensor indicating the sensor's sensitivity to light. The numbers are
-expressed in arithmetic scale, as per <xref linkend="iso12232" /> standard,
-where doubling the sensor sensitivity is represented by doubling the numerical
-ISO value. Applications should interpret the values as standard ISO values
-multiplied by 1000, e.g. control value 800 stands for ISO 0.8. Drivers will
-usually support only a subset of standard ISO values. The effect of setting
-this control while the <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>
-control is set to a value other than <constant>V4L2_CID_ISO_SENSITIVITY_MANUAL
-</constant> is undefined, drivers should ignore such requests.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-iso-sensitivity-auto-type">
-           <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_iso_sensitivity_type</entry>
-         </row><row><entry spanname="descr">Enables or disables automatic ISO
-sensitivity adjustments.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_CID_ISO_SENSITIVITY_MANUAL</constant>&nbsp;</entry>
-                 <entry>Manual ISO sensitivity.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
-                 <entry>Automatic ISO sensitivity adjustments.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-scene-mode">
-           <entry spanname="id"><constant>V4L2_CID_SCENE_MODE</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_scene_mode</entry>
-         </row><row><entry spanname="descr">This control allows to select
-scene programs as the camera automatic modes optimized for common shooting
-scenes. Within these modes the camera determines best exposure, aperture,
-focusing, light metering, white balance and equivalent sensitivity. The
-controls of those parameters are influenced by the scene mode control.
-An exact behavior in each mode is subject to the camera specification.
-
-<para>When the scene mode feature is not used, this control should be set to
-<constant>V4L2_SCENE_MODE_NONE</constant> to make sure the other possibly
-related controls are accessible. The following scene programs are defined:
-</para>
-</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_NONE</constant>&nbsp;</entry>
-                 <entry>The scene mode feature is disabled.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_BACKLIGHT</constant>&nbsp;</entry>
-                 <entry>Backlight. Compensates for dark shadows when light is
-                 coming from behind a subject, also by automatically turning
-                 on the flash.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_BEACH_SNOW</constant>&nbsp;</entry>
-                 <entry>Beach and snow. This mode compensates for all-white or
-bright scenes, which tend to look gray and low contrast, when camera's automatic
-exposure is based on an average scene brightness. To compensate, this mode
-automatically slightly overexposes the frames. The white balance may also be
-adjusted to compensate for the fact that reflected snow looks bluish rather
-than white.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_CANDLELIGHT</constant>&nbsp;</entry>
-                 <entry>Candle light. The camera generally raises the ISO
-sensitivity and lowers the shutter speed. This mode compensates for relatively
-close subject in the scene. The flash is disabled in order to preserve the
-ambiance of the light.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_DAWN_DUSK</constant>&nbsp;</entry>
-                 <entry>Dawn and dusk. Preserves the colors seen in low
-natural light before dusk and after down. The camera may turn off the flash,
-and automatically focus at infinity. It will usually boost saturation and
-lower the shutter speed.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_FALL_COLORS</constant>&nbsp;</entry>
-                 <entry>Fall colors. Increases saturation and adjusts white
-balance for color enhancement. Pictures of autumn leaves get saturated reds
-and yellows.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_FIREWORKS</constant>&nbsp;</entry>
-                 <entry>Fireworks. Long exposure times are used to capture
-the expanding burst of light from a firework. The camera may invoke image
-stabilization.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_LANDSCAPE</constant>&nbsp;</entry>
-                 <entry>Landscape. The camera may choose a small aperture to
-provide deep depth of field and long exposure duration to help capture detail
-in dim light conditions. The focus is fixed at infinity. Suitable for distant
-and wide scenery.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_NIGHT</constant>&nbsp;</entry>
-                 <entry>Night, also known as Night Landscape. Designed for low
-light conditions, it preserves detail in the dark areas without blowing out bright
-objects. The camera generally sets itself to a medium-to-high ISO sensitivity,
-with a relatively long exposure time, and turns flash off. As such, there will be
-increased image noise and the possibility of blurred image.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_PARTY_INDOOR</constant>&nbsp;</entry>
-                 <entry>Party and indoor. Designed to capture indoor scenes
-that are lit by indoor background lighting as well as the flash. The camera
-usually increases ISO sensitivity, and adjusts exposure for the low light
-conditions.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_PORTRAIT</constant>&nbsp;</entry>
-                 <entry>Portrait. The camera adjusts the aperture so that the
-depth of field is reduced, which helps to isolate the subject against a smooth
-background. Most cameras recognize the presence of faces in the scene and focus
-on them. The color hue is adjusted to enhance skin tones. The intensity of the
-flash is often reduced.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_SPORTS</constant>&nbsp;</entry>
-                 <entry>Sports. Significantly increases ISO and uses a fast
-shutter speed to freeze motion of rapidly-moving subjects. Increased image
-noise may be seen in this mode.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_SUNSET</constant>&nbsp;</entry>
-                 <entry>Sunset. Preserves deep hues seen in sunsets and
-sunrises. It bumps up the saturation.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_SCENE_MODE_TEXT</constant>&nbsp;</entry>
-                 <entry>Text. It applies extra contrast and sharpness, it is
-typically a black-and-white mode optimized for readability. Automatic focus
-may be switched to close-up mode and this setting may also involve some
-lens-distortion correction.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_3A_LOCK</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">This control locks or unlocks the automatic
-focus, exposure and white balance. The automatic adjustments can be paused
-independently by setting the corresponding lock bit to 1. The camera then retains
-the settings until the lock bit is cleared. The following lock bits are defined:
-</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_LOCK_EXPOSURE</constant></entry>
-                 <entry>Automatic exposure adjustments lock.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_LOCK_WHITE_BALANCE</constant></entry>
-                 <entry>Automatic white balance adjustments lock.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_LOCK_FOCUS</constant></entry>
-                 <entry>Automatic focus lock.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry spanname="descr">
-When a given algorithm is not enabled, drivers should ignore requests
-to lock it and should return no error. An example might be an application
-setting bit <constant>V4L2_LOCK_WHITE_BALANCE</constant> when the
-<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant> control is set to
-<constant>FALSE</constant>. The value of this control may be changed
-by exposure, white balance or focus controls.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_SPEED</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera horizontally at the specific speed. The unit is undefined. A
-positive value moves the camera to the right (clockwise when viewed
-from above), a negative value to the left. A value of zero stops the motion
-if one is in progress and has no effect otherwise.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_SPEED</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera vertically at the specified speed. The unit is undefined. A
-positive value moves the camera up, a negative value down. A value of zero
-stops the motion if one is in progress and has no effect otherwise.</entry>
-         </row>
-         <row><entry></entry></row>
-
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-    <section id="fm-tx-controls">
-      <title>FM Transmitter Control Reference</title>
-
-      <para>The FM Transmitter (FM_TX) class includes controls for common features of
-FM transmissions capable devices. Currently this class includes parameters for audio
-compression, pilot tone generation, audio deviation limiter, RDS transmission and
-tuning power features.</para>
-
-      <table pgwide="1" frame="none" id="fm-tx-control-id">
-      <title>FM_TX Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FM_TX_CLASS</constant>&nbsp;</entry>
-           <entry>class</entry>
-         </row><row><entry spanname="descr">The FM_TX class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures RDS signal frequency deviation level in Hz.
-The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PI</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the RDS Programme Identification field
-for transmission.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PTY</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the RDS Programme Type field for transmission.
-This encodes up to 31 pre-defined programme types.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PS_NAME</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
-It is intended for static display on a receiver. It is the primary aid to listeners in programme service
-identification and selection.  In Annex E of <xref linkend="iec62106" />, the RDS specification,
-there is a full description of the correct character encoding for Programme Service name strings.
-Also from RDS specification, PS is usually a single eight character text. However, it is also possible
-to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
-with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_RADIO_TEXT</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Radio Text info for transmission. It is a textual description of
-what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
-programme-related information or any other text. In these cases, RadioText should be used in addition to
-<constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
-in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
-used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
-to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
-with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_MONO_STEREO</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Mono/Stereo bit of the Decoder Identification code. If set,
-then the audio was recorded as stereo.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_ARTIFICIAL_HEAD</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Sets the
-<ulink url="http://en.wikipedia.org/wiki/Artificial_head">Artificial Head</ulink> bit of the Decoder
-Identification code. If set, then the audio was recorded using an artificial head.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_COMPRESSED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Compressed bit of the Decoder Identification code. If set,
-then the audio is compressed.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_DYNAMIC_PTY</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Dynamic PTY bit of the Decoder Identification code. If set,
-then the PTY code is dynamically switched.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_MUSIC_SPEECH</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
-broadcasts speech. If the transmitter doesn't make this distinction, then it should be set.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_ALT_FREQS_ENABLE</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then transmit alternate frequencies.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_ALT_FREQS</constant>&nbsp;</entry>
-           <entry>__u32 array</entry>
-         </row>
-         <row><entry spanname="descr">The alternate frequencies in kHz units. The RDS standard allows
-for up to 25 frequencies to be defined. Drivers may support fewer frequencies so check
-the array size.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the audio deviation limiter feature.
-The limiter is useful when trying to maximize the audio volume, minimize receiver-generated
-distortion and prevent overmodulation.
-</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_RELEASE_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the audio deviation limiter feature release time.
-Unit is in useconds. Step and range are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures audio frequency deviation level in Hz.
-The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the audio compression feature.
-This feature amplifies signals below the threshold by a fixed gain and compresses audio
-signals above the threshold by the ratio of Threshold/(Gain + Threshold).</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_GAIN</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the gain for audio compression feature. It is
-a dB value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_THRESHOLD</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the threshold level for audio compression freature.
-It is a dB value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the attack time for audio compression feature.
-It is a useconds value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the release time for audio compression feature.
-It is a useconds value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the pilot tone generation feature.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures pilot tone frequency deviation level. Unit is
-in Hz. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_FREQUENCY</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures pilot tone frequency value. Unit is
-in Hz. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_PREEMPHASIS</constant>&nbsp;</entry>
-           <entry>enum v4l2_preemphasis</entry>
-         </row>
-         <row id="v4l2-preemphasis"><entry spanname="descr">Configures the pre-emphasis value for broadcasting.
-A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
-Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_preemphasis
-defines possible values for pre-emphasis. Here they are:</entry>
-       </row><row>
-       <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_DISABLED</constant>&nbsp;</entry>
-                     <entry>No pre-emphasis is applied.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_50_uS</constant>&nbsp;</entry>
-                     <entry>A pre-emphasis of 50 uS is used.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_75_uS</constant>&nbsp;</entry>
-                     <entry>A pre-emphasis of 75 uS is used.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_POWER_LEVEL</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the output power level for signal transmission.
-Unit is in dBuV. Range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_ANTENNA_CAPACITOR</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">This selects the value of antenna tuning capacitor
-manually or automatically if set to zero. Unit, range and step are driver-specific.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-
-<para>For more details about RDS specification, refer to
-<xref linkend="iec62106" /> document, from CENELEC.</para>
-    </section>
-
-    <section id="flash-controls">
-      <title>Flash Control Reference</title>
-
-      <para>
-       The V4L2 flash controls are intended to provide generic access
-       to flash controller devices. Flash controller devices are
-       typically used in digital cameras.
-      </para>
-
-      <para>
-       The interface can support both LED and xenon flash devices. As
-       of writing this, there is no xenon flash driver using this
-       interface.
-      </para>
-
-      <section id="flash-controls-use-cases">
-       <title>Supported use cases</title>
-
-       <section>
-         <title>Unsynchronised LED flash (software strobe)</title>
-
-         <para>
-           Unsynchronised LED flash is controlled directly by the
-           host as the sensor. The flash must be enabled by the host
-           before the exposure of the image starts and disabled once
-           it ends. The host is fully responsible for the timing of
-           the flash.
-         </para>
-
-         <para>Example of such device: Nokia N900.</para>
-       </section>
-
-       <section>
-         <title>Synchronised LED flash (hardware strobe)</title>
-
-         <para>
-           The synchronised LED flash is pre-programmed by the host
-           (power and timeout) but controlled by the sensor through a
-           strobe signal from the sensor to the flash.
-         </para>
-
-         <para>
-           The sensor controls the flash duration and timing. This
-           information typically must be made available to the
-           sensor.
-         </para>
-
-       </section>
-
-       <section>
-         <title>LED flash as torch</title>
-
-         <para>
-           LED flash may be used as torch in conjunction with another
-           use case involving camera or individually.
-         </para>
-
-
-          <table pgwide="1" frame="none" id="flash-control-id">
-          <title>Flash Control IDs</title>
-    
-          <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
-           <entry>class</entry>
-         </row>
-         <row>
-           <entry spanname="descr">The FLASH class descriptor.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
-           <entry>menu</entry>
-         </row>
-         <row id="v4l2-flash-led-mode">
-           <entry spanname="descr">Defines the mode of the flash LED,
-           the high-power white LED attached to the flash controller.
-           Setting this control may not be possible in presence of
-           some faults. See V4L2_CID_FLASH_FAULT.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
-                 <entry>Off.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
-                 <entry>Flash mode.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
-                 <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
-           <entry>menu</entry>
-         </row>
-         <row id="v4l2-flash-strobe-source"><entry
-         spanname="descr">Defines the source of the flash LED
-         strobe.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
-                 <entry>The flash strobe is triggered by using
-                 the V4L2_CID_FLASH_STROBE control.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
-                 <entry>The flash strobe is triggered by an
-                 external source. Typically this is a sensor,
-                 which makes it possible to synchronises the
-                 flash strobe start to exposure start.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
-           <entry>button</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Strobe flash. Valid when
-           V4L2_CID_FLASH_LED_MODE is set to
-           V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
-           is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
-           control may not be possible in presence of some faults.
-           See V4L2_CID_FLASH_FAULT.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
-           <entry>button</entry>
-         </row>
-         <row><entry spanname="descr">Stop flash strobe immediately.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
-           <entry>boolean</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Strobe status: whether the flash
-           is strobing at the moment or not. This is a read-only
-           control.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Hardware timeout for flash. The
-           flash strobe is stopped after this period of time has
-           passed from the start of the strobe.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Intensity of the flash strobe when
-           the flash LED is in flash mode
-           (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
-           (mA) if possible.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Intensity of the flash LED in
-           torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
-           milliamps (mA) if possible. Setting this control may not
-           be possible in presence of some faults. See
-           V4L2_CID_FLASH_FAULT.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Intensity of the indicator LED.
-           The indicator LED may be fully independent of the flash
-           LED. The unit should be microamps (uA) if possible.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Faults related to the flash. The
-           faults tell about specific problems in the flash chip
-           itself or the LEDs attached to it. Faults may prevent
-           further use of some of the flash controls. In particular,
-           V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
-           if the fault affects the flash LED. Exactly which faults
-           have such an effect is chip dependent. Reading the faults
-           resets the control and returns the chip to a usable state
-           if possible.</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
-                 <entry>Flash controller voltage to the flash LED
-                 has exceeded the limit specific to the flash
-                 controller.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
-                 <entry>The flash strobe was still on when
-                 the timeout set by the user ---
-                 V4L2_CID_FLASH_TIMEOUT control --- has expired.
-                 Not all flash controllers may set this in all
-                 such conditions.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
-                 <entry>The flash controller has overheated.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
-                 <entry>The short circuit protection of the flash
-                 controller has been triggered.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry>
-                 <entry>Current in the LED power supply has exceeded the limit
-                 specific to the flash controller.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry>
-                 <entry>The flash controller has detected a short or open
-                 circuit condition on the indicator LED.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_UNDER_VOLTAGE</constant></entry>
-                 <entry>Flash controller voltage to the flash LED
-                 has been below the minimum limit specific to the flash
-                 controller.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_INPUT_VOLTAGE</constant></entry>
-                 <entry>The input voltage of the flash controller is below
-                 the limit under which strobing the flash at full current
-                 will not be possible.The condition persists until this flag
-                 is no longer set.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE</constant></entry>
-                 <entry>The temperature of the LED has exceeded its
-                 allowed upper limit.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enable or disable charging of the xenon
-         flash capacitor.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
-           <entry>boolean</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Is the flash ready to strobe?
-           Xenon flashes require their capacitors charged before
-           strobing. LED flashes often require a cooldown period
-           after strobe during which another strobe will not be
-           possible. This is a read-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-          </tgroup>
-          </table>
-       </section>
-      </section>
-    </section>
-
-    <section id="jpeg-controls">
-      <title>JPEG Control Reference</title>
-      <para>The JPEG class includes controls for common features of JPEG
-      encoders and decoders. Currently it includes features for codecs
-      implementing progressive baseline DCT compression process with
-      Huffman entrophy coding.</para>
-      <table pgwide="1" frame="none" id="jpeg-control-id">
-      <title>JPEG Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_JPEG_CLASS</constant>&nbsp;</entry>
-           <entry>class</entry>
-         </row><row><entry spanname="descr">The JPEG class descriptor. Calling
-         &VIDIOC-QUERYCTRL; for this control will return a description of this
-         control class.
-
-       </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
-           <entry>menu</entry>
-         </row>
-         <row id="v4l2-jpeg-chroma-subsampling">
-           <entry spanname="descr">The chroma subsampling factors describe how
-           each component of an input image is sampled, in respect to maximum
-           sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
-           clause A.1.1. for more details. The <constant>
-           V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant> control determines how
-           Cb and Cr components are downsampled after coverting an input image
-           from RGB to Y'CbCr color space.
-           </entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_444</constant>
-                 </entry><entry>No chroma subsampling, each pixel has
-                 Y, Cr and Cb values.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_422</constant>
-                 </entry><entry>Horizontally subsample Cr, Cb components
-                 by a factor of 2.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_420</constant>
-                 </entry><entry>Subsample Cr, Cb components horizontally
-                 and vertically by 2.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_411</constant>
-                 </entry><entry>Horizontally subsample Cr, Cb components
-                 by a factor of 4.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_410</constant>
-                 </entry><entry>Subsample Cr, Cb components horizontally
-                 by 4 and vertically by 2.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY</constant>
-                 </entry><entry>Use only luminance component.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_JPEG_RESTART_INTERVAL</constant>
-           </entry><entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">
-             The restart interval determines an interval of inserting RSTm
-             markers (m = 0..7). The purpose of these markers is to additionally
-             reinitialize the encoder process, in order to process blocks of
-             an image independently.
-             For the lossy compression processes the restart interval unit is
-             MCU (Minimum Coded Unit) and its value is contained in DRI
-             (Define Restart Interval) marker. If <constant>
-             V4L2_CID_JPEG_RESTART_INTERVAL</constant> control is set to 0,
-             DRI and RSTm markers will not be inserted.
-           </entry>
-         </row>
-         <row id="jpeg-quality-control">
-           <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">
-             <constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control
-             determines trade-off between image quality and size.
-             It provides simpler method for applications to control image quality,
-             without a need for direct reconfiguration of luminance and chrominance
-             quantization tables.
-
-             In cases where a driver uses quantization tables configured directly
-             by an application, using interfaces defined elsewhere, <constant>
-             V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control should be set
-             by driver to 0.
-
-             <para>The value range of this control is driver-specific. Only
-             positive, non-zero values are meaningful. The recommended range
-             is 1 - 100, where larger values correspond to better image quality.
-             </para>
-           </entry>
-           </row>
-         <row id="jpeg-active-marker-control">
-           <entry spanname="id"><constant>V4L2_CID_JPEG_ACTIVE_MARKER</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Specify which JPEG markers are included
-           in compressed stream. This control is valid only for encoders.
-           </entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP0</constant></entry>
-                 <entry>Application data segment APP<subscript>0</subscript>.</entry>
-               </row><row>
-                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP1</constant></entry>
-                 <entry>Application data segment APP<subscript>1</subscript>.</entry>
-               </row><row>
-                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_COM</constant></entry>
-                 <entry>Comment segment.</entry>
-               </row><row>
-                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DQT</constant></entry>
-                 <entry>Quantization tables segment.</entry>
-               </row><row>
-                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DHT</constant></entry>
-                 <entry>Huffman tables segment.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-      <para>For more details about JPEG specification, refer
-      to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
-      <xref linkend="w3c-jpeg-jfif"/>.</para>
-    </section>
-
-    <section id="image-source-controls">
-      <title>Image Source Control Reference</title>
-
-      <para>
-       The Image Source control class is intended for low-level
-       control of image source devices such as image sensors. The
-       devices feature an analogue to digital converter and a bus
-       transmitter to transmit the image data out of the device.
-      </para>
-
-      <table pgwide="1" frame="none" id="image-source-control-id">
-      <title>Image Source Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
-           <entry>class</entry>
-         </row>
-         <row>
-           <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_VBLANK</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Vertical blanking. The idle period
-           after every frame during which no image data is produced.
-           The unit of vertical blanking is a line. Every line has
-           length of the image width plus horizontal blanking at the
-           pixel rate defined by
-           <constant>V4L2_CID_PIXEL_RATE</constant> control in the
-           same sub-device.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_HBLANK</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Horizontal blanking. The idle
-           period after every line of image data during which no
-           image data is produced. The unit of horizontal blanking is
-           pixels.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ANALOGUE_GAIN</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Analogue gain is gain affecting
-           all colour components in the pixel matrix. The gain
-           operation is performed in the analogue domain before A/D
-           conversion.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_RED</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Test pattern red colour component.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENR</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Test pattern green (next to red)
-           colour component.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_BLUE</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Test pattern blue colour component.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENB</constant></entry>
-           <entry>integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Test pattern green (next to blue)
-           colour component.
-           </entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-
-    </section>
-
-    <section id="image-process-controls">
-      <title>Image Process Control Reference</title>
-
-      <para>
-       The Image Process control class is intended for low-level control of
-       image processing functions. Unlike
-       <constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant>, the controls in
-       this class affect processing the image, and do not control capturing
-       of it.
-      </para>
-
-      <table pgwide="1" frame="none" id="image-process-control-id">
-      <title>Image Process Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IMAGE_PROC_CLASS</constant></entry>
-           <entry>class</entry>
-         </row>
-         <row>
-           <entry spanname="descr">The IMAGE_PROC class descriptor.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_LINK_FREQ</constant></entry>
-           <entry>integer menu</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Data bus frequency. Together with the
-           media bus pixel code, bus type (clock cycles per sample), the
-           data bus frequency defines the pixel rate
-           (<constant>V4L2_CID_PIXEL_RATE</constant>) in the
-           pixel array (or possibly elsewhere, if the device is not an
-           image sensor). The frame rate can be calculated from the pixel
-           clock, image width and height and horizontal and vertical
-           blanking. While the pixel rate control may be defined elsewhere
-           than in the subdev containing the pixel array, the frame rate
-           cannot be obtained from that information. This is because only
-           on the pixel array it can be assumed that the vertical and
-           horizontal blanking information is exact: no other blanking is
-           allowed in the pixel array. The selection of frame rate is
-           performed by selecting the desired horizontal and vertical
-           blanking. The unit of this control is Hz. </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PIXEL_RATE</constant></entry>
-           <entry>64-bit integer</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Pixel rate in the source pads of
-           the subdev. This control is read-only and its unit is
-           pixels / second.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN</constant></entry>
-           <entry>menu</entry>
-         </row>
-         <row id="v4l2-test-pattern">
-           <entry spanname="descr"> Some capture/display/sensor devices have
-           the capability to generate test pattern images. These hardware
-           specific test patterns can be used to test if a device is working
-           properly.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-
-    </section>
-
-    <section id="dv-controls">
-      <title>Digital Video Control Reference</title>
-
-      <para>
-       The Digital Video control class is intended to control receivers
-       and transmitters for <ulink url="http://en.wikipedia.org/wiki/Vga">VGA</ulink>,
-       <ulink url="http://en.wikipedia.org/wiki/Digital_Visual_Interface">DVI</ulink>
-       (Digital Visual Interface), HDMI (<xref linkend="hdmi" />) and DisplayPort (<xref linkend="dp" />).
-       These controls are generally expected to be private to the receiver or transmitter
-       subdevice that implements them, so they are only exposed on the
-       <filename>/dev/v4l-subdev*</filename> device node.
-      </para>
-
-      <para>Note that these devices can have multiple input or output pads which are
-      hooked up to e.g. HDMI connectors. Even though the subdevice will receive or
-      transmit video from/to only one of those pads, the other pads can still be
-      active when it comes to EDID (Extended Display Identification Data,
-      <xref linkend="vesaedid" />) and HDCP (High-bandwidth Digital Content
-      Protection System, <xref linkend="hdcp" />) processing, allowing the device
-      to do the fairly slow EDID/HDCP handling in advance. This allows for quick
-      switching between connectors.</para>
-
-      <para>These pads appear in several of the controls in this section as
-      bitmasks, one bit for each pad. Bit 0 corresponds to pad 0, bit 1 to pad 1,
-      etc. The maximum value of the control is the set of valid pads.</para>
-
-      <table pgwide="1" frame="none" id="dv-control-id">
-      <title>Digital Video Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_CLASS</constant></entry>
-           <entry>class</entry>
-         </row>
-         <row>
-           <entry spanname="descr">The Digital Video class descriptor.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_HOTPLUG</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Many connectors have a hotplug pin which is high
-           if EDID information is available from the source. This control shows the
-           state of the hotplug pin as seen by the transmitter.
-           Each bit corresponds to an output pad on the transmitter. If an output pad
-           does not have an associated hotplug pin, then the bit for that pad will be 0.
-           This read-only control is applicable to DVI-D, HDMI and DisplayPort connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_RXSENSE</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Rx Sense is the detection of pull-ups on the TMDS
-            clock lines. This normally means that the sink has left/entered standby (i.e.
-           the transmitter can sense that the receiver is ready to receive video).
-           Each bit corresponds to an output pad on the transmitter. If an output pad
-           does not have an associated Rx Sense, then the bit for that pad will be 0.
-           This read-only control is applicable to DVI-D and HDMI devices.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_EDID_PRESENT</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">When the transmitter sees the hotplug signal from the
-           receiver it will attempt to read the EDID. If set, then the transmitter has read
-           at least the first block (= 128 bytes).
-           Each bit corresponds to an output pad on the transmitter. If an output pad
-           does not support EDIDs, then the bit for that pad will be 0.
-           This read-only control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_MODE</constant></entry>
-           <entry id="v4l2-dv-tx-mode">enum v4l2_dv_tx_mode</entry>
-         </row>
-         <row>
-           <entry spanname="descr">HDMI transmitters can transmit in DVI-D mode (just video)
-           or in HDMI mode (video + audio + auxiliary data). This control selects which mode
-           to use: V4L2_DV_TX_MODE_DVI_D or V4L2_DV_TX_MODE_HDMI.
-           This control is applicable to HDMI connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_RGB_RANGE</constant></entry>
-           <entry id="v4l2-dv-rgb-range">enum v4l2_dv_rgb_range</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Select the quantization range for RGB output. V4L2_DV_RANGE_AUTO
-           follows the RGB quantization range specified in the standard for the video interface
-           (ie. <xref linkend="cea861" /> for HDMI). V4L2_DV_RANGE_LIMITED and V4L2_DV_RANGE_FULL override the standard
-           to be compatible with sinks that have not implemented the standard correctly
-           (unfortunately quite common for HDMI and DVI-D). Full range allows all possible values to be
-           used whereas limited range sets the range to (16 &lt;&lt; (N-8)) - (235 &lt;&lt; (N-8))
-           where N is the number of bits per component.
-           This control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_TX_IT_CONTENT_TYPE</constant></entry>
-           <entry id="v4l2-dv-content-type">enum v4l2_dv_it_content_type</entry>
-         </row>
-         <row><entry spanname="descr">Configures the IT Content Type
-           of the transmitted video. This information is sent over HDMI and DisplayPort connectors
-           as part of the AVI InfoFrame. The term 'IT Content' is used for content that originates
-           from a computer as opposed to content from a TV broadcast or an analog source. The
-           enum&nbsp;v4l2_dv_it_content_type defines the possible content types:</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_DV_IT_CONTENT_TYPE_GRAPHICS</constant>&nbsp;</entry>
-                 <entry>Graphics content. Pixel data should be passed unfiltered and without
-                 analog reconstruction.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DV_IT_CONTENT_TYPE_PHOTO</constant>&nbsp;</entry>
-                 <entry>Photo content. The content is derived from digital still pictures.
-                 The content should be passed through with minimal scaling and picture
-                 enhancements.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DV_IT_CONTENT_TYPE_CINEMA</constant>&nbsp;</entry>
-                 <entry>Cinema content.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DV_IT_CONTENT_TYPE_GAME</constant>&nbsp;</entry>
-                 <entry>Game content. Audio and video latency should be minimized.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DV_IT_CONTENT_TYPE_NO_ITC</constant>&nbsp;</entry>
-                 <entry>No IT Content information is available and the ITC bit in the AVI
-                 InfoFrame is set to 0.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_RX_POWER_PRESENT</constant></entry>
-           <entry>bitmask</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Detects whether the receiver receives power from the source
-           (e.g. HDMI carries 5V on one of the pins). This is often used to power an eeprom
-           which contains EDID information, such that the source can read the EDID even if
-           the sink is in standby/power off.
-           Each bit corresponds to an input pad on the transmitter. If an input pad
-           cannot detect whether power is present, then the bit for that pad will be 0.
-           This read-only control is applicable to DVI-D, HDMI and DisplayPort connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_RX_RGB_RANGE</constant></entry>
-           <entry>enum v4l2_dv_rgb_range</entry>
-         </row>
-         <row>
-           <entry spanname="descr">Select the quantization range for RGB input. V4L2_DV_RANGE_AUTO
-           follows the RGB quantization range specified in the standard for the video interface
-           (ie. <xref linkend="cea861" /> for HDMI). V4L2_DV_RANGE_LIMITED and V4L2_DV_RANGE_FULL override the standard
-           to be compatible with sources that have not implemented the standard correctly
-           (unfortunately quite common for HDMI and DVI-D). Full range allows all possible values to be
-           used whereas limited range sets the range to (16 &lt;&lt; (N-8)) - (235 &lt;&lt; (N-8))
-           where N is the number of bits per component.
-           This control is applicable to VGA, DVI-A/D, HDMI and DisplayPort connectors.
-           </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_DV_RX_IT_CONTENT_TYPE</constant></entry>
-           <entry>enum v4l2_dv_it_content_type</entry>
-         </row>
-         <row><entry spanname="descr">Reads the IT Content Type
-           of the received video. This information is sent over HDMI and DisplayPort connectors
-           as part of the AVI InfoFrame. The term 'IT Content' is used for content that originates
-           from a computer as opposed to content from a TV broadcast or an analog source. See
-           <constant>V4L2_CID_DV_TX_IT_CONTENT_TYPE</constant> for the available content types.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-
-    </section>
-
-    <section id="fm-rx-controls">
-      <title>FM Receiver Control Reference</title>
-
-      <para>The FM Receiver (FM_RX) class includes controls for common features of
-      FM Reception capable devices.</para>
-
-      <table pgwide="1" frame="none" id="fm-rx-control-id">
-      <title>FM_RX Control IDs</title>
-
-      <tgroup cols="4">
-        <colspec colname="c1" colwidth="1*" />
-        <colspec colname="c2" colwidth="6*" />
-        <colspec colname="c3" colwidth="2*" />
-        <colspec colname="c4" colwidth="6*" />
-        <spanspec namest="c1" nameend="c2" spanname="id" />
-        <spanspec namest="c2" nameend="c4" spanname="descr" />
-        <thead>
-          <row>
-            <entry spanname="id" align="left">ID</entry>
-            <entry align="left">Type</entry>
-          </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-          </row>
-        </thead>
-        <tbody valign="top">
-          <row><entry></entry></row>
-          <row>
-            <entry spanname="id"><constant>V4L2_CID_FM_RX_CLASS</constant>&nbsp;</entry>
-            <entry>class</entry>
-          </row><row><entry spanname="descr">The FM_RX class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-          </row>
-          <row>
-            <entry spanname="id"><constant>V4L2_CID_RDS_RECEPTION</constant>&nbsp;</entry>
-            <entry>boolean</entry>
-          </row><row><entry spanname="descr">Enables/disables RDS
-         reception by the radio tuner</entry>
-          </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_PTY</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Gets RDS Programme Type field.
-This encodes up to 31 pre-defined programme types.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_PS_NAME</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Gets the Programme Service name (PS_NAME).
-It is intended for static display on a receiver. It is the primary aid to listeners in programme service
-identification and selection.  In Annex E of <xref linkend="iec62106" />, the RDS specification,
-there is a full description of the correct character encoding for Programme Service name strings.
-Also from RDS specification, PS is usually a single eight character text. However, it is also possible
-to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
-with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_RADIO_TEXT</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Gets the Radio Text info. It is a textual description of
-what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
-programme-related information or any other text. In these cases, RadioText can be used in addition to
-<constant>V4L2_CID_RDS_RX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
-in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
-used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
-to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
-with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_RX_MUSIC_SPEECH</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
-broadcasts speech. If the transmitter doesn't make this distinction, then it will be set.</entry>
-         </row>
-          <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_DEEMPHASIS</constant>&nbsp;</entry>
-           <entry>enum v4l2_deemphasis</entry>
-         </row>
-         <row id="v4l2-deemphasis"><entry spanname="descr">Configures the de-emphasis value for reception.
-A de-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
-Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_deemphasis
-defines possible values for de-emphasis. Here they are:</entry>
-       </row><row>
-       <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_DEEMPHASIS_DISABLED</constant>&nbsp;</entry>
-                     <entry>No de-emphasis is applied.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_DEEMPHASIS_50_uS</constant>&nbsp;</entry>
-                     <entry>A de-emphasis of 50 uS is used.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_DEEMPHASIS_75_uS</constant>&nbsp;</entry>
-                     <entry>A de-emphasis of 75 uS is used.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-
-         </row>
-          <row><entry></entry></row>
-        </tbody>
-      </tgroup>
-      </table>
-    </section>
-
-    <section id="detect-controls">
-      <title>Detect Control Reference</title>
-
-      <para>The Detect class includes controls for common features of
-      various motion or object detection capable devices.</para>
-
-      <table pgwide="1" frame="none" id="detect-control-id">
-      <title>Detect Control IDs</title>
-
-      <tgroup cols="4">
-        <colspec colname="c1" colwidth="1*" />
-        <colspec colname="c2" colwidth="6*" />
-        <colspec colname="c3" colwidth="2*" />
-        <colspec colname="c4" colwidth="6*" />
-        <spanspec namest="c1" nameend="c2" spanname="id" />
-        <spanspec namest="c2" nameend="c4" spanname="descr" />
-        <thead>
-          <row>
-            <entry spanname="id" align="left">ID</entry>
-            <entry align="left">Type</entry>
-          </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-          </row>
-        </thead>
-        <tbody valign="top">
-          <row><entry></entry></row>
-          <row>
-            <entry spanname="id"><constant>V4L2_CID_DETECT_CLASS</constant>&nbsp;</entry>
-            <entry>class</entry>
-          </row><row><entry spanname="descr">The Detect class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-          </row>
-          <row>
-            <entry spanname="id"><constant>V4L2_CID_DETECT_MD_MODE</constant>&nbsp;</entry>
-            <entry>menu</entry>
-          </row><row><entry spanname="descr">Sets the motion detection mode.</entry>
-          </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_DETECT_MD_MODE_DISABLED</constant>
-                 </entry><entry>Disable motion detection.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DETECT_MD_MODE_GLOBAL</constant>
-                 </entry><entry>Use a single motion detection threshold.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
-                 </entry><entry>The image is divided into a grid, each cell with its own
-                 motion detection threshold. These thresholds are set through the
-                 <constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant> matrix control.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
-                 </entry><entry>The image is divided into a grid, each cell with its own
-                 region value that specifies which per-region motion detection thresholds
-                 should be used. Each region has its own thresholds. How these per-region
-                 thresholds are set up is driver-specific. The region values for the grid are set
-                 through the <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> matrix
-                 control.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-          <row>
-           <entry spanname="id"><constant>V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the global motion detection threshold to be
-         used with the <constant>V4L2_DETECT_MD_MODE_GLOBAL</constant> motion detection mode.</entry>
-          </row>
-          <row>
-           <entry spanname="id"><constant>V4L2_CID_DETECT_MD_THRESHOLD_GRID</constant>&nbsp;</entry>
-           <entry>__u16 matrix</entry>
-         </row>
-         <row><entry spanname="descr">Sets the motion detection thresholds for each cell in the grid.
-         To be used with the <constant>V4L2_DETECT_MD_MODE_THRESHOLD_GRID</constant>
-         motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
-         grid.</entry>
-          </row>
-          <row>
-           <entry spanname="id"><constant>V4L2_CID_DETECT_MD_REGION_GRID</constant>&nbsp;</entry>
-           <entry>__u8 matrix</entry>
-         </row>
-         <row><entry spanname="descr">Sets the motion detection region value for each cell in the grid.
-         To be used with the <constant>V4L2_DETECT_MD_MODE_REGION_GRID</constant>
-         motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
-         grid.</entry>
-          </row>
-        </tbody>
-      </tgroup>
-      </table>
-
-      </section>
-
-    <section id="rf-tuner-controls">
-      <title>RF Tuner Control Reference</title>
-
-      <para>
-The RF Tuner (RF_TUNER) class includes controls for common features of devices
-having RF tuner.
-      </para>
-      <para>
-In this context, RF tuner is radio receiver circuit between antenna and
-demodulator. It receives radio frequency (RF) from the antenna and converts that
-received signal to lower intermediate frequency (IF) or baseband frequency (BB).
-Tuners that could do baseband output are often called Zero-IF tuners. Older
-tuners were typically simple PLL tuners inside a metal box, whilst newer ones
-are highly integrated chips without a metal box "silicon tuners". These controls
-are mostly applicable for new feature rich silicon tuners, just because older
-tuners does not have much adjustable features.
-      </para>
-      <para>
-For more information about RF tuners see
-<ulink url="http://en.wikipedia.org/wiki/Tuner_%28radio%29">Tuner (radio)</ulink>
-and
-<ulink url="http://en.wikipedia.org/wiki/RF_front_end">RF front end</ulink>
-from Wikipedia.
-      </para>
-
-      <table pgwide="1" frame="none" id="rf-tuner-control-id">
-        <title>RF_TUNER Control IDs</title>
-
-        <tgroup cols="4">
-          <colspec colname="c1" colwidth="1*" />
-          <colspec colname="c2" colwidth="6*" />
-          <colspec colname="c3" colwidth="2*" />
-          <colspec colname="c4" colwidth="6*" />
-          <spanspec namest="c1" nameend="c2" spanname="id" />
-          <spanspec namest="c2" nameend="c4" spanname="descr" />
-          <thead>
-            <row>
-              <entry spanname="id" align="left">ID</entry>
-              <entry align="left">Type</entry>
-            </row>
-            <row rowsep="1">
-              <entry spanname="descr" align="left">Description</entry>
-            </row>
-          </thead>
-          <tbody valign="top">
-            <row><entry></entry></row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_CLASS</constant>&nbsp;</entry>
-              <entry>class</entry>
-            </row><row><entry spanname="descr">The RF_TUNER class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_BANDWIDTH_AUTO</constant>&nbsp;</entry>
-              <entry>boolean</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Enables/disables tuner radio channel
-bandwidth configuration. In automatic mode bandwidth configuration is performed
-by the driver.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_BANDWIDTH</constant>&nbsp;</entry>
-              <entry>integer</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Filter(s) on tuner signal path are used to
-filter signal according to receiving party needs. Driver configures filters to
-fulfill desired bandwidth requirement. Used when V4L2_CID_RF_TUNER_BANDWIDTH_AUTO is not
-set. Unit is in Hz. The range and step are driver-specific.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant>&nbsp;</entry>
-              <entry>boolean</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Enables/disables LNA automatic gain control (AGC)</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO</constant>&nbsp;</entry>
-              <entry>boolean</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Enables/disables mixer automatic gain control (AGC)</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_IF_GAIN_AUTO</constant>&nbsp;</entry>
-              <entry>boolean</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Enables/disables IF automatic gain control (AGC)</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>&nbsp;</entry>
-              <entry>integer</entry>
-            </row>
-            <row>
-              <entry spanname="descr">The RF amplifier is the very first
-amplifier on the receiver signal path, just right after the antenna input.
-The difference between the LNA gain and the RF gain in this document is that
-the LNA gain is integrated in the tuner chip while the RF gain is a separate
-chip. There may be both RF and LNA gain controls in the same device.
-The range and step are driver-specific.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN</constant>&nbsp;</entry>
-              <entry>integer</entry>
-            </row>
-            <row>
-              <entry spanname="descr">LNA (low noise amplifier) gain is first
-gain stage on the RF tuner signal path. It is located very close to tuner
-antenna input. Used when <constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant> is not set.
-See <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant> to understand how RF gain
-and LNA gain differs from the each others.
-The range and step are driver-specific.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_MIXER_GAIN</constant>&nbsp;</entry>
-              <entry>integer</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Mixer gain is second gain stage on the RF
-tuner signal path. It is located inside mixer block, where RF signal is
-down-converted by the mixer. Used when <constant>V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO</constant>
-is not set. The range and step are driver-specific.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_IF_GAIN</constant>&nbsp;</entry>
-              <entry>integer</entry>
-            </row>
-            <row>
-              <entry spanname="descr">IF gain is last gain stage on the RF tuner
-signal path. It is located on output of RF tuner. It controls signal level of
-intermediate frequency output or baseband output. Used when
-<constant>V4L2_CID_RF_TUNER_IF_GAIN_AUTO</constant> is not set. The range and step are
-driver-specific.</entry>
-            </row>
-            <row>
-              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_PLL_LOCK</constant>&nbsp;</entry>
-              <entry>boolean</entry>
-            </row>
-            <row>
-              <entry spanname="descr">Is synthesizer PLL locked? RF tuner is
-receiving given frequency when that control is set. This is a read-only control.
-</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-    </section>
-</section>
diff --git a/Documentation/DocBook/media/v4l/crop.pdf b/Documentation/DocBook/media/v4l/crop.pdf
deleted file mode 100644 (file)
index c9fb81c..0000000
Binary files a/Documentation/DocBook/media/v4l/crop.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/dev-capture.xml b/Documentation/DocBook/media/v4l/dev-capture.xml
deleted file mode 100644 (file)
index e1c5f94..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-  <title>Video Capture Interface</title>
-
-  <para>Video capture devices sample an analog video signal and store
-the digitized images in memory. Today nearly all devices can capture
-at full 25 or 30 frames/second. With this interface applications can
-control the capture process and move images from the driver into user
-space.</para>
-
-  <para>Conventionally V4L2 video capture devices are accessed through
-character device special files named <filename>/dev/video</filename>
-and <filename>/dev/video0</filename> to
-<filename>/dev/video63</filename> with major number 81 and minor
-numbers 0 to 63. <filename>/dev/video</filename> is typically a
-symbolic link to the preferred video device. Note the same device
-files are used for video output devices.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video capture interface set the
-<constant>V4L2_CAP_VIDEO_CAPTURE</constant> or
-<constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
-they may also support the <link linkend="overlay">video overlay</link>
-(<constant>V4L2_CAP_VIDEO_OVERLAY</constant>) and the <link
-linkend="raw-vbi">raw VBI capture</link>
-(<constant>V4L2_CAP_VBI_CAPTURE</constant>) interface. At least one of
-the read/write or streaming I/O methods must be supported. Tuners and
-audio inputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video capture devices shall support <link
-linkend="audio">audio input</link>, <link
-linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video input</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video capture devices.</para>
-  </section>
-
-  <section>
-    <title>Image Format Negotiation</title>
-
-    <para>The result of a capture operation is determined by
-cropping and image format parameters. The former select an area of the
-video picture to capture, the latter how images are stored in memory,
-&ie; in RGB or YUV format, the number of bits per pixel or width and
-height. Together they also define how images are scaled in the
-process.</para>
-
-    <para>As usual these parameters are <emphasis>not</emphasis> reset
-at &func-open; time to permit Unix tool chains, programming a device
-and then reading from it as if it was a plain file. Well written V4L2
-applications ensure they really get what they want, including cropping
-and scaling.</para>
-
-    <para>Cropping initialization at minimum requires to reset the
-parameters to defaults. An example is given in <xref
-linkend="crop" />.</para>
-
-    <para>To query the current image format applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> or the
-&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-    <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-pix-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
-adjust the parameters and finally return the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does.</para>
-
-    <para>Like <constant>VIDIOC_S_FMT</constant> the
-&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
-without disabling I/O or possibly time consuming hardware
-preparations.</para>
-
-    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
-are discussed in <xref linkend="pixfmt" />. See also the specification of the
-<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
-and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
-capture devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-  </section>
-
-  <section>
-    <title>Reading Images</title>
-
-    <para>A video capture device may support the <link
-linkend="rw">read() function</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> or <link
-linkend="userp">user pointer</link>) I/O. See <xref
-linkend="io" /> for details.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-codec.xml b/Documentation/DocBook/media/v4l/dev-codec.xml
deleted file mode 100644 (file)
index ff44c16..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-  <title>Codec Interface</title>
-
-  <para>A V4L2 codec can compress, decompress, transform, or otherwise
-convert video data from one format into another format, in memory. Typically
-such devices are memory-to-memory devices (i.e. devices with the
-<constant>V4L2_CAP_VIDEO_M2M</constant> or <constant>V4L2_CAP_VIDEO_M2M_MPLANE</constant>
-capability set).
-</para>
-
-  <para>A memory-to-memory video node acts just like a normal video node, but it
-supports both output (sending frames from memory to the codec hardware) and
-capture (receiving the processed frames from the codec hardware into memory)
-stream I/O. An application will have to setup the stream
-I/O for both sides and finally call &VIDIOC-STREAMON; for both capture and output
-to start the codec.</para>
-
-  <para>Video compression codecs use the MPEG controls to setup their codec parameters
-(note that the MPEG controls actually support many more codecs than just MPEG).
-See <xref linkend="mpeg-controls"></xref>.</para>
-
-  <para>Memory-to-memory devices can often be used as a shared resource: you can
-open the video node multiple times, each application setting up their own codec properties
-that are local to the file handle, and each can use it independently from the others.
-The driver will arbitrate access to the codec and reprogram it whenever another file
-handler gets access. This is different from the usual video node behavior where the video properties
-are global to the device (i.e. changing something through one file handle is visible
-through another file handle).</para>
diff --git a/Documentation/DocBook/media/v4l/dev-effect.xml b/Documentation/DocBook/media/v4l/dev-effect.xml
deleted file mode 100644 (file)
index 2350a67..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-  <title>Effect Devices Interface</title>
-
-  <note>
-    <title>Suspended</title>
-
-    <para>This interface has been be suspended from the V4L2 API
-implemented in Linux 2.6 until we have more experience with effect
-device interfaces.</para>
-  </note>
-
-  <para>A V4L2 video effect device can do image effects, filtering, or
-combine two or more images or image streams. For example video
-transitions or wipes. Applications send data to be processed and
-receive the result data either with &func-read; and &func-write;
-functions, or through the streaming I/O mechanism.</para>
-
-  <para>[to do]</para>
diff --git a/Documentation/DocBook/media/v4l/dev-event.xml b/Documentation/DocBook/media/v4l/dev-event.xml
deleted file mode 100644 (file)
index 19f4bec..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-  <title>Event Interface</title>
-
-  <para>The V4L2 event interface provides a means for a user to get
-  immediately notified on certain conditions taking place on a device.
-  This might include start of frame or loss of signal events, for
-  example. Changes in the value or state of a V4L2 control can also be
-  reported through events.
-  </para>
-
-  <para>To receive events, the events the user is interested in first must
-  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
-  subscribed, the events of subscribed types are dequeueable using the
-  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
-  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
-  be used to unsubscribe all the events the driver supports.</para>
-
-  <para>The event subscriptions and event queues are specific to file
-  handles. Subscribing an event on one file handle does not affect
-  other file handles.</para>
-
-  <para>The information on dequeueable events is obtained by using select or
-  poll system calls on video devices. The V4L2 events use POLLPRI events on
-  poll system call and exceptions on select system call.</para>
-
-  <para>Starting with kernel 3.1 certain guarantees can be given with
-  regards to events:<orderedlist>
-       <listitem>
-         <para>Each subscribed event has its own internal dedicated event queue.
-This means that flooding of one event type will not interfere with other
-event types.</para>
-       </listitem>
-       <listitem>
-         <para>If the internal event queue for a particular subscribed event
-becomes full, then the oldest event in that queue will be dropped.</para>
-       </listitem>
-       <listitem>
-         <para>Where applicable, certain event types can ensure that the payload
-of the oldest event that is about to be dropped will be merged with the payload
-of the next oldest event. Thus ensuring that no information is lost, but only an
-intermediate step leading up to that information. See the documentation for the
-event you want to subscribe to whether this is applicable for that event or not.</para>
-       </listitem>
-      </orderedlist></para>
diff --git a/Documentation/DocBook/media/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml
deleted file mode 100644 (file)
index 5485332..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-  <title>Video Output Overlay Interface</title>
-  <subtitle>Also known as On-Screen Display (OSD)</subtitle>
-
-  <para>Some video output devices can overlay a framebuffer image onto
-the outgoing video signal. Applications can set up such an overlay
-using this interface, which borrows structures and ioctls of the <link
-linkend="overlay">Video Overlay</link> interface.</para>
-
-  <para>The OSD function is accessible through the same character
-special file as the <link linkend="capture">Video Output</link> function.
-Note the default function of such a <filename>/dev/video</filename> device
-is video capturing or output. The OSD function is only available after
-calling the &VIDIOC-S-FMT; ioctl.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the <wordasword>Video Output
-Overlay</wordasword> interface set the
-<constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.</para>
-  </section>
-
-  <section>
-    <title>Framebuffer</title>
-
-    <para>Contrary to the <wordasword>Video Overlay</wordasword>
-interface the framebuffer is normally implemented on the TV card and
-not the graphics card. On Linux it is accessible as a framebuffer
-device (<filename>/dev/fbN</filename>). Given a V4L2 device,
-applications can find the corresponding framebuffer device by calling
-the &VIDIOC-G-FBUF; ioctl. It returns, amongst other information, the
-physical address of the framebuffer in the
-<structfield>base</structfield> field of &v4l2-framebuffer;. The
-framebuffer device ioctl <constant>FBIOGET_FSCREENINFO</constant>
-returns the same address in the <structfield>smem_start</structfield>
-field of struct <structname>fb_fix_screeninfo</structname>. The
-<constant>FBIOGET_FSCREENINFO</constant> ioctl and struct
-<structname>fb_fix_screeninfo</structname> are defined in the
-<filename>linux/fb.h</filename> header file.</para>
-
-    <para>The width and height of the framebuffer depends on the
-current video standard. A V4L2 driver may reject attempts to change
-the video standard (or any other ioctl which would imply a framebuffer
-size change) with an &EBUSY; until all applications closed the
-framebuffer device.</para>
-
-    <example>
-      <title>Finding a framebuffer device for OSD</title>
-
-      <programlisting>
-#include &lt;linux/fb.h&gt;
-
-&v4l2-framebuffer; fbuf;
-unsigned int i;
-int fb_fd;
-
-if (-1 == ioctl(fd, VIDIOC_G_FBUF, &amp;fbuf)) {
-       perror("VIDIOC_G_FBUF");
-       exit(EXIT_FAILURE);
-}
-
-for (i = 0; i &lt; 30; i++) {
-       char dev_name[16];
-       struct fb_fix_screeninfo si;
-
-       snprintf(dev_name, sizeof(dev_name), "/dev/fb%u", i);
-
-       fb_fd = open(dev_name, O_RDWR);
-       if (-1 == fb_fd) {
-               switch (errno) {
-               case ENOENT: /* no such file */
-               case ENXIO:  /* no driver */
-                       continue;
-
-               default:
-                       perror("open");
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       if (0 == ioctl(fb_fd, FBIOGET_FSCREENINFO, &amp;si)) {
-               if (si.smem_start == (unsigned long)fbuf.base)
-                       break;
-       } else {
-               /* Apparently not a framebuffer device. */
-       }
-
-       close(fb_fd);
-       fb_fd = -1;
-}
-
-/* fb_fd is the file descriptor of the framebuffer device
-   for the video output overlay, or -1 if no device was found. */
-</programlisting>
-    </example>
-  </section>
-
-  <section>
-    <title>Overlay Window and Scaling</title>
-
-    <para>The overlay is controlled by source and target rectangles.
-The source rectangle selects a subsection of the framebuffer image to
-be overlaid, the target rectangle an area in the outgoing video signal
-where the image will appear. Drivers may or may not support scaling,
-and arbitrary sizes and positions of these rectangles. Further drivers
-may support any (or none) of the clipping/blending methods defined for
-the <link linkend="overlay">Video Overlay</link> interface.</para>
-
-    <para>A &v4l2-window; defines the size of the source rectangle,
-its position in the framebuffer and the clipping/blending method to be
-used for the overlay. To get the current parameters applications set
-the <structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant> and call the
-&VIDIOC-G-FMT; ioctl. The driver fills the
-<structname>v4l2_window</structname> substructure named
-<structfield>win</structfield>. It is not possible to retrieve a
-previously programmed clipping list or bitmap.</para>
-
-    <para>To program the source rectangle applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>, initialize
-the <structfield>win</structfield> substructure and call the
-&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
-hardware limits and returns the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does. Like
-<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
-used to learn about driver capabilities without actually changing
-driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
-after the overlay has been enabled.</para>
-
-    <para>A &v4l2-crop; defines the size and position of the target
-rectangle. The scaling factor of the overlay is implied by the width
-and height given in &v4l2-window; and &v4l2-crop;. The cropping API
-applies to <wordasword>Video Output</wordasword> and <wordasword>Video
-Output Overlay</wordasword> devices in the same way as to
-<wordasword>Video Capture</wordasword> and <wordasword>Video
-Overlay</wordasword> devices, merely reversing the direction of the
-data flow. For more information see <xref linkend="crop" />.</para>
-  </section>
-
-  <section>
-    <title>Enabling Overlay</title>
-
-    <para>There is no V4L2 ioctl to enable or disable the overlay,
-however the framebuffer interface of the driver may support the
-<constant>FBIOBLANK</constant> ioctl.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-output.xml b/Documentation/DocBook/media/v4l/dev-output.xml
deleted file mode 100644 (file)
index 9130a3d..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-  <title>Video Output Interface</title>
-
-  <para>Video output devices encode stills or image sequences as
-analog video signal. With this interface applications can
-control the encoding process and move images from user space to
-the driver.</para>
-
-  <para>Conventionally V4L2 video output devices are accessed through
-character device special files named <filename>/dev/video</filename>
-and <filename>/dev/video0</filename> to
-<filename>/dev/video63</filename> with major number 81 and minor
-numbers 0 to 63. <filename>/dev/video</filename> is typically a
-symbolic link to the preferred video device. Note the same device
-files are used for video capture devices.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video output interface set the
-<constant>V4L2_CAP_VIDEO_OUTPUT</constant> or
-<constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
-they may also support the <link linkend="raw-vbi">raw VBI
-output</link> (<constant>V4L2_CAP_VBI_OUTPUT</constant>) interface. At
-least one of the read/write or streaming I/O methods must be
-supported. Modulators and audio outputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video output devices shall support <link
-linkend="audio">audio output</link>, <link
-linkend="tuner">modulator</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video output</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video output devices.</para>
-  </section>
-
-  <section>
-    <title>Image Format Negotiation</title>
-
-    <para>The output is determined by cropping and image format
-parameters. The former select an area of the video picture where the
-image will appear, the latter how images are stored in memory, &ie; in
-RGB or YUV format, the number of bits per pixel or width and height.
-Together they also define how images are scaled in the process.</para>
-
-    <para>As usual these parameters are <emphasis>not</emphasis> reset
-at &func-open; time to permit Unix tool chains, programming a device
-and then writing to it as if it was a plain file. Well written V4L2
-applications ensure they really get what they want, including cropping
-and scaling.</para>
-
-    <para>Cropping initialization at minimum requires to reset the
-parameters to defaults. An example is given in <xref
-linkend="crop" />.</para>
-
-    <para>To query the current image format applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> or the
-&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-    <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-pix-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
-adjust the parameters and finally return the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does.</para>
-
-    <para>Like <constant>VIDIOC_S_FMT</constant> the
-&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
-without disabling I/O or possibly time consuming hardware
-preparations.</para>
-
-    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
-are discussed in <xref linkend="pixfmt" />. See also the specification of the
-<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
-and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
-output devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-  </section>
-
-  <section>
-    <title>Writing Images</title>
-
-    <para>A video output device may support the <link
-linkend="rw">write() function</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> or <link
-linkend="userp">user pointer</link>) I/O. See <xref
-linkend="io" /> for details.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-overlay.xml b/Documentation/DocBook/media/v4l/dev-overlay.xml
deleted file mode 100644 (file)
index cc6e0c5..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-  <title>Video Overlay Interface</title>
-  <subtitle>Also known as Framebuffer Overlay or Previewing</subtitle>
-
-  <para>Video overlay devices have the ability to genlock (TV-)video
-into the (VGA-)video signal of a graphics card, or to store captured
-images directly in video memory of a graphics card, typically with
-clipping. This can be considerable more efficient than capturing
-images and displaying them by other means. In the old days when only
-nuclear power plants needed cooling towers this used to be the only
-way to put live video into a window.</para>
-
-  <para>Video overlay devices are accessed through the same character
-special files as <link linkend="capture">video capture</link> devices.
-Note the default function of a <filename>/dev/video</filename> device
-is video capturing. The overlay function is only available after
-calling the &VIDIOC-S-FMT; ioctl.</para>
-
-    <para>The driver may support simultaneous overlay and capturing
-using the read/write and streaming I/O methods. If so, operation at
-the nominal frame rate of the video standard is not guaranteed. Frames
-may be directed away from overlay to capture, or one field may be used
-for overlay and the other for capture if the capture parameters permit
-this.</para>
-
-  <para>Applications should use different file descriptors for
-capturing and overlay. This must be supported by all drivers capable
-of simultaneous capturing and overlay. Optionally these drivers may
-also permit capturing and overlay with a single file descriptor for
-compatibility with V4L and earlier versions of V4L2.<footnote>
-       <para>A common application of two file descriptors is the
-XFree86 <link linkend="xvideo">Xv/V4L</link> interface driver and
-a V4L2 application. While the X server controls video overlay, the
-application can take advantage of memory mapping and DMA.</para>
-       <para>In the opinion of the designers of this API, no driver
-writer taking the efforts to support simultaneous capturing and
-overlay will restrict this ability by requiring a single file
-descriptor, as in V4L and earlier versions of V4L2. Making this
-optional means applications depending on two file descriptors need
-backup routines to be compatible with all drivers, which is
-considerable more work than using two fds in applications which do
-not. Also two fd's fit the general concept of one file descriptor for
-each logical stream. Hence as a complexity trade-off drivers
-<emphasis>must</emphasis> support two file descriptors and
-<emphasis>may</emphasis> support single fd operation.</para>
-      </footnote></para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video overlay interface set the
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. The overlay I/O method specified
-below must be supported. Tuners and audio inputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video overlay devices shall support <link
-linkend="audio">audio input</link>, <link
-linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video input</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video overlay devices.</para>
-  </section>
-
-  <section>
-    <title>Setup</title>
-
-    <para>Before overlay can commence applications must program the
-driver with frame buffer parameters, namely the address and size of
-the frame buffer and the image format, for example RGB 5:6:5. The
-&VIDIOC-G-FBUF; and &VIDIOC-S-FBUF; ioctls are available to get
-and set these parameters, respectively. The
-<constant>VIDIOC_S_FBUF</constant> ioctl is privileged because it
-allows to set up DMA into physical memory, bypassing the memory
-protection mechanisms of the kernel. Only the superuser can change the
-frame buffer address and size. Users are not supposed to run TV
-applications as root or with SUID bit set. A small helper application
-with suitable privileges should query the graphics system and program
-the V4L2 driver at the appropriate time.</para>
-
-    <para>Some devices add the video overlay to the output signal
-of the graphics card. In this case the frame buffer is not modified by
-the video device, and the frame buffer address and pixel format are
-not needed by the driver. The <constant>VIDIOC_S_FBUF</constant> ioctl
-is not privileged. An application can check for this type of device by
-calling the <constant>VIDIOC_G_FBUF</constant> ioctl.</para>
-
-    <para>A driver may support any (or none) of five clipping/blending
-methods:<orderedlist>
-       <listitem>
-         <para>Chroma-keying displays the overlaid image only where
-pixels in the primary graphics surface assume a certain color.</para>
-       </listitem>
-       <listitem>
-         <para>A bitmap can be specified where each bit corresponds
-to a pixel in the overlaid image. When the bit is set, the
-corresponding video pixel is displayed, otherwise a pixel of the
-graphics surface.</para>
-       </listitem>
-       <listitem>
-         <para>A list of clipping rectangles can be specified. In
-these regions <emphasis>no</emphasis> video is displayed, so the
-graphics surface can be seen here.</para>
-       </listitem>
-       <listitem>
-         <para>The framebuffer has an alpha channel that can be used
-to clip or blend the framebuffer with the video.</para>
-       </listitem>
-       <listitem>
-         <para>A global alpha value can be specified to blend the
-framebuffer contents with video images.</para>
-       </listitem>
-      </orderedlist></para>
-
-    <para>When simultaneous capturing and overlay is supported and
-the hardware prohibits different image and frame buffer formats, the
-format requested first takes precedence. The attempt to capture
-(&VIDIOC-S-FMT;) or overlay (&VIDIOC-S-FBUF;) may fail with an
-&EBUSY; or return accordingly modified parameters..</para>
-  </section>
-
-  <section>
-    <title>Overlay Window</title>
-
-    <para>The overlaid image is determined by cropping and overlay
-window parameters. The former select an area of the video picture to
-capture, the latter how images are overlaid and clipped. Cropping
-initialization at minimum requires to reset the parameters to
-defaults. An example is given in <xref linkend="crop" />.</para>
-
-    <para>The overlay window is described by a &v4l2-window;. It
-defines the size of the image, its position over the graphics surface
-and the clipping to be applied. To get the current parameters
-applications set the <structfield>type</structfield> field of a
-&v4l2-format; to <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant> and
-call the &VIDIOC-G-FMT; ioctl. The driver fills the
-<structname>v4l2_window</structname> substructure named
-<structfield>win</structfield>. It is not possible to retrieve a
-previously programmed clipping list or bitmap.</para>
-
-    <para>To program the overlay window applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, initialize the
-<structfield>win</structfield> substructure and call the
-&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
-hardware limits and returns the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does. Like
-<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
-used to learn about driver capabilities without actually changing
-driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
-after the overlay has been enabled.</para>
-
-    <para>The scaling factor of the overlaid image is implied by the
-width and height given in &v4l2-window; and the size of the cropping
-rectangle. For more information see <xref linkend="crop" />.</para>
-
-    <para>When simultaneous capturing and overlay is supported and
-the hardware prohibits different image and window sizes, the size
-requested first takes precedence. The attempt to capture or overlay as
-well (&VIDIOC-S-FMT;) may fail with an &EBUSY; or return accordingly
-modified parameters.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-window">
-      <title>struct <structname>v4l2_window</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>w</structfield></entry>
-           <entry>Size and position of the window relative to the
-top, left corner of the frame buffer defined with &VIDIOC-S-FBUF;. The
-window can extend the frame buffer width and height, the
-<structfield>x</structfield> and <structfield>y</structfield>
-coordinates can be negative, and it can lie completely outside the
-frame buffer. The driver clips the window accordingly, or if that is
-not possible, modifies its size and/or position.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-field;</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>Applications set this field to determine which
-video field shall be overlaid, typically one of
-<constant>V4L2_FIELD_ANY</constant> (0),
-<constant>V4L2_FIELD_TOP</constant>,
-<constant>V4L2_FIELD_BOTTOM</constant> or
-<constant>V4L2_FIELD_INTERLACED</constant>. Drivers may have to choose
-a different field order and return the actual setting here.</entry>
-           </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>chromakey</structfield></entry>
-           <entry>When chroma-keying has been negotiated with
-&VIDIOC-S-FBUF; applications set this field to the desired pixel value
-for the chroma key. The format is the same as the pixel format of the
-framebuffer (&v4l2-framebuffer;
-<structfield>fmt.pixelformat</structfield> field), with bytes in host
-order. E.&nbsp;g. for <link
-linkend="V4L2-PIX-FMT-BGR32"><constant>V4L2_PIX_FMT_BGR24</constant></link>
-the value should be 0xRRGGBB on a little endian, 0xBBGGRR on a big
-endian host.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-clip; *</entry>
-           <entry><structfield>clips</structfield></entry>
-           <entry>When chroma-keying has <emphasis>not</emphasis>
-been negotiated and &VIDIOC-G-FBUF; indicated this capability,
-applications can set this field to point to an array of
-clipping rectangles.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Like the window coordinates
-<structfield>w</structfield>, clipping rectangles are defined relative
-to the top, left corner of the frame buffer. However clipping
-rectangles must not extend the frame buffer width and height, and they
-must not overlap. If possible applications should merge adjacent
-rectangles. Whether this must create x-y or y-x bands, or the order of
-rectangles, is not defined. When clip lists are not supported the
-driver ignores this field. Its contents after calling &VIDIOC-S-FMT;
-are undefined.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>clipcount</structfield></entry>
-           <entry>When the application set the
-<structfield>clips</structfield> field, this field must contain the
-number of clipping rectangles in the list. When clip lists are not
-supported the driver ignores this field, its contents after calling
-<constant>VIDIOC_S_FMT</constant> are undefined. When clip lists are
-supported but no clipping is desired this field must be set to
-zero.</entry>
-         </row>
-         <row>
-           <entry>void *</entry>
-           <entry><structfield>bitmap</structfield></entry>
-           <entry>When chroma-keying has
-<emphasis>not</emphasis> been negotiated and &VIDIOC-G-FBUF; indicated
-this capability, applications can set this field to point to a
-clipping bit mask.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>It must be of the same size
-as the window, <structfield>w.width</structfield> and
-<structfield>w.height</structfield>. Each bit corresponds to a pixel
-in the overlaid image, which is displayed only when the bit is
-<emphasis>set</emphasis>. Pixel coordinates translate to bits like:
-<programlisting>
-((__u8 *) <structfield>bitmap</structfield>)[<structfield>w.width</structfield> * y + x / 8] &amp; (1 &lt;&lt; (x &amp; 7))</programlisting></para><para>where <structfield>0</structfield> &le; x &lt;
-<structfield>w.width</structfield> and <structfield>0</structfield> &le;
-y &lt;<structfield>w.height</structfield>.<footnote>
-                 <para>Should we require
-             <structfield>w.width</structfield> to be a multiple of
-             eight?</para>
-               </footnote></para><para>When a clipping
-bit mask is not supported the driver ignores this field, its contents
-after calling &VIDIOC-S-FMT; are undefined. When a bit mask is supported
-but no clipping is desired this field must be set to
-<constant>NULL</constant>.</para><para>Applications need not create a
-clip list or bit mask. When they pass both, or despite negotiating
-chroma-keying, the results are undefined. Regardless of the chosen
-method, the clipping abilities of the hardware may be limited in
-quantity or quality. The results when these limits are exceeded are
-undefined.<footnote>
-                 <para>When the image is written into frame buffer
-memory it will be undesirable if the driver clips out less pixels
-than expected, because the application and graphics system are not
-aware these regions need to be refreshed. The driver should clip out
-more pixels or not write the image at all.</para>
-               </footnote></para></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>global_alpha</structfield></entry>
-           <entry>The global alpha value used to blend the
-framebuffer with video images, if global alpha blending has been
-negotiated (<constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant>, see
-&VIDIOC-S-FBUF;, <xref linkend="framebuffer-flags" />).</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Note this field was added in Linux 2.6.23, extending the structure. However
-the <link linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls,
-which take a pointer to a <link
-linkend="v4l2-format">v4l2_format</link> parent structure with padding
-bytes at the end, are not affected.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-clip">
-      <title>struct <structname>v4l2_clip</structname><footnote>
-         <para>The X Window system defines "regions" which are
-vectors of struct BoxRec { short x1, y1, x2, y2; } with width = x2 -
-x1 and height = y2 - y1, so one cannot pass X11 clip lists
-directly.</para>
-       </footnote></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>c</structfield></entry>
-           <entry>Coordinates of the clipping rectangle, relative to
-the top, left corner of the frame buffer. Only window pixels
-<emphasis>outside</emphasis> all clipping rectangles are
-displayed.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-clip; *</entry>
-           <entry><structfield>next</structfield></entry>
-           <entry>Pointer to the next clipping rectangle, NULL when
-this is the last rectangle. Drivers ignore this field, it cannot be
-used to pass a linked list of clipping rectangles.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- NB for easier reading this table is duplicated
-    in the vidioc-cropcap chapter.-->
-
-    <table pgwide="1" frame="none" id="v4l2-rect">
-      <title>struct <structname>v4l2_rect</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>left</structfield></entry>
-           <entry>Horizontal offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>top</structfield></entry>
-           <entry>Vertical offset of the top, left corner of the
-rectangle, in pixels. Offsets increase to the right and down.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section>
-    <title>Enabling Overlay</title>
-
-    <para>To start or stop the frame buffer overlay applications call
-the &VIDIOC-OVERLAY; ioctl.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-radio.xml b/Documentation/DocBook/media/v4l/dev-radio.xml
deleted file mode 100644 (file)
index 3e6ac73..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-  <title>Radio Interface</title>
-
-  <para>This interface is intended for AM and FM (analog) radio
-receivers and transmitters.</para>
-
-  <para>Conventionally V4L2 radio devices are accessed through
-character device special files named <filename>/dev/radio</filename>
-and <filename>/dev/radio0</filename> to
-<filename>/dev/radio63</filename> with major number 81 and minor
-numbers 64 to 127.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the radio interface set the
-<constant>V4L2_CAP_RADIO</constant> and
-<constant>V4L2_CAP_TUNER</constant> or
-<constant>V4L2_CAP_MODULATOR</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. Other combinations of
-capability flags are reserved for future extensions.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Radio devices can support <link
-linkend="control">controls</link>, and must support the <link
-linkend="tuner">tuner or modulator</link> ioctls.</para>
-
-    <para>They do not support the video input or output, audio input
-or output, video standard, cropping and scaling, compression and
-streaming parameter, or overlay ioctls. All other ioctls and I/O
-methods are reserved for future extensions.</para>
-  </section>
-
-  <section>
-    <title>Programming</title>
-
-    <para>Radio devices may have a couple audio controls (as discussed
-in <xref linkend="control" />) such as a volume control, possibly custom
-controls. Further all radio devices have one tuner or modulator (these are
-discussed in <xref linkend="tuner" />) with index number zero to select
-the radio frequency and to determine if a monaural or FM stereo
-program is received/emitted. Drivers switch automatically between AM and FM
-depending on the selected frequency. The &VIDIOC-G-TUNER; or
-&VIDIOC-G-MODULATOR; ioctl
-reports the supported frequency range.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml
deleted file mode 100644 (file)
index 78599bb..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-  <title>Raw VBI Data Interface</title>
-
-  <para>VBI is an abbreviation of Vertical Blanking Interval, a gap
-in the sequence of lines of an analog video signal. During VBI
-no picture information is transmitted, allowing some time while the
-electron beam of a cathode ray tube TV returns to the top of the
-screen. Using an oscilloscope you will find here the vertical
-synchronization pulses and short data packages ASK
-modulated<footnote><para>ASK: Amplitude-Shift Keying. A high signal
-level represents a '1' bit, a low level a '0' bit.</para></footnote>
-onto the video signal. These are transmissions of services such as
-Teletext or Closed Caption.</para>
-
-  <para>Subject of this interface type is raw VBI data, as sampled off
-a video signal, or to be added to a signal for output.
-The data format is similar to uncompressed video images, a number of
-lines times a number of samples per line, we call this a VBI image.</para>
-
-  <para>Conventionally V4L2 VBI devices are accessed through character
-device special files named <filename>/dev/vbi</filename> and
-<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> with
-major number 81 and minor numbers 224 to 255.
-<filename>/dev/vbi</filename> is typically a symbolic link to the
-preferred VBI device. This convention applies to both input and output
-devices.</para>
-
-  <para>To address the problems of finding related video and VBI
-devices VBI capturing and output is also available as device function
-under <filename>/dev/video</filename>. To capture or output raw VBI
-data with these devices applications must call the &VIDIOC-S-FMT;
-ioctl. Accessed as <filename>/dev/vbi</filename>, raw VBI capturing
-or output is the default device function.</para>
-
-    <section>
-      <title>Querying Capabilities</title>
-
-      <para>Devices supporting the raw VBI capturing or output API set
-the <constant>V4L2_CAP_VBI_CAPTURE</constant> or
-<constant>V4L2_CAP_VBI_OUTPUT</constant> flags, respectively, in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
-read/write, streaming or asynchronous I/O methods must be
-supported. VBI devices may or may not have a tuner or modulator.</para>
-    </section>
-
-    <section>
-      <title>Supplemental Functions</title>
-
-      <para>VBI devices shall support <link linkend="video">video
-input or output</link>, <link linkend="tuner">tuner or
-modulator</link>, and <link linkend="control">controls</link> ioctls
-as needed. The <link linkend="standard">video standard</link> ioctls provide
-information vital to program a VBI device, therefore must be
-supported.</para>
-    </section>
-
-    <section>
-      <title>Raw VBI Format Negotiation</title>
-
-      <para>Raw VBI sampling abilities can vary, in particular the
-sampling frequency. To properly interpret the data V4L2 specifies an
-ioctl to query the sampling parameters. Moreover, to allow for some
-flexibility applications can also suggest different parameters.</para>
-
-      <para>As usual these parameters are <emphasis>not</emphasis>
-reset at &func-open; time to permit Unix tool chains, programming a
-device and then reading from it as if it was a plain file. Well
-written V4L2 applications should always ensure they really get what
-they want, requesting reasonable parameters and then checking if the
-actual parameters are suitable.</para>
-
-      <para>To query the current raw VBI capture parameters
-applications set the <structfield>type</structfield> field of a
-&v4l2-format; to <constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>, and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-vbi-format; <structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-      <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-vbi-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers return
-an &EINVAL; only when the given parameters are ambiguous, otherwise
-they modify the parameters according to the hardware capabilities and
-return the actual parameters. When the driver allocates resources at
-this point, it may return an &EBUSY; to indicate the returned
-parameters are valid but the required resources are currently not
-available. That may happen for instance when the video and VBI areas
-to capture would overlap, or when the driver supports multiple opens
-and another process already requested VBI capturing or output. Anyway,
-applications must expect other resource allocation points which may
-return <errorcode>EBUSY</errorcode>, at the &VIDIOC-STREAMON; ioctl
-and the first read(), write() and select() call.</para>
-
-      <para>VBI devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-
-      <table pgwide="1" frame="none" id="v4l2-vbi-format">
-       <title>struct <structname>v4l2_vbi_format</structname></title>
-       <tgroup cols="3">
-         &cs-str;
-         <tbody valign="top">
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>sampling_rate</structfield></entry>
-             <entry>Samples per second, i.&nbsp;e. unit 1 Hz.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>offset</structfield></entry>
-             <entry><para>Horizontal offset of the VBI image,
-relative to the leading edge of the line synchronization pulse and
-counted in samples: The first sample in the VBI image will be located
-<structfield>offset</structfield> /
-<structfield>sampling_rate</structfield> seconds following the leading
-edge. See also <xref linkend="vbi-hsync" />.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>samples_per_line</structfield></entry>
-             <entry></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>sample_format</structfield></entry>
-             <entry><para>Defines the sample format as in <xref
-linkend="pixfmt" />, a four-character-code.<footnote>
-                   <para>A few devices may be unable to
-sample VBI data at all but can extend the video capture window to the
-VBI region.</para>
-                 </footnote> Usually this is
-<constant>V4L2_PIX_FMT_GREY</constant>, i.&nbsp;e. each sample
-consists of 8 bits with lower values oriented towards the black level.
-Do not assume any other correlation of values with the signal level.
-For example, the MSB does not necessarily indicate if the signal is
-'high' or 'low' because 128 may not be the mean value of the
-signal. Drivers shall not convert the sample format by software.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>start</structfield>[2]</entry>
-             <entry>This is the scanning system line number
-associated with the first line of the VBI image, of the first and the
-second field respectively. See <xref linkend="vbi-525" /> and
-<xref linkend="vbi-625" /> for valid values.
-The <constant>V4L2_VBI_ITU_525_F1_START</constant>,
-<constant>V4L2_VBI_ITU_525_F2_START</constant>,
-<constant>V4L2_VBI_ITU_625_F1_START</constant> and
-<constant>V4L2_VBI_ITU_625_F2_START</constant> defines give the start line
-numbers for each field for each 525 or 625 line format as a convenience.
-Don't forget that ITU line numbering starts at 1, not 0.
-VBI input drivers can return start values 0 if the hardware cannot
-reliable identify scanning lines, VBI acquisition may not require this
-information.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>count</structfield>[2]</entry>
-             <entry>The number of lines in the first and second
-field image, respectively.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>Drivers should be as
-flexibility as possible. For example, it may be possible to extend or
-move the VBI capture window down to the picture area, implementing a
-'full field mode' to capture data service transmissions embedded in
-the picture.</para><para>An application can set the first or second
-<structfield>count</structfield> value to zero if no data is required
-from the respective field; <structfield>count</structfield>[1] if the
-scanning system is progressive, &ie; not interlaced. The
-corresponding start value shall be ignored by the application and
-driver. Anyway, drivers may not support single field capturing and
-return both count values non-zero.</para><para>Both
-<structfield>count</structfield> values set to zero, or line numbers
-outside the bounds depicted in <xref linkend="vbi-525" /> and <xref
-                   linkend="vbi-625" />, or a field image covering
-lines of two fields, are invalid and shall not be returned by the
-driver.</para><para>To initialize the <structfield>start</structfield>
-and <structfield>count</structfield> fields, applications must first
-determine the current video standard selection. The &v4l2-std-id; or
-the <structfield>framelines</structfield> field of &v4l2-standard; can
-be evaluated for this purpose.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>flags</structfield></entry>
-             <entry>See <xref linkend="vbifmt-flags" /> below. Currently
-only drivers set flags, applications must set this field to
-zero.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>reserved</structfield>[2]</entry>
-             <entry>This array is reserved for future extensions.
-Drivers and applications must set it to zero.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table pgwide="1" frame="none" id="vbifmt-flags">
-       <title>Raw VBI Format Flags</title>
-       <tgroup cols="3">
-         &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_VBI_UNSYNC</constant></entry>
-             <entry>0x0001</entry>
-             <entry><para>This flag indicates hardware which does not
-properly distinguish between fields. Normally the VBI image stores the
-first field (lower scanning line numbers) first in memory. This may be
-a top or bottom field depending on the video standard. When this flag
-is set the first or second field may be stored first, however the
-fields are still in correct temporal order with the older field first
-in memory.<footnote>
-                 <para>Most VBI services transmit on both fields, but
-some have different semantics depending on the field number. These
-cannot be reliable decoded or encoded when
-<constant>V4L2_VBI_UNSYNC</constant> is set.</para>
-               </footnote></para></entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_VBI_INTERLACED</constant></entry>
-             <entry>0x0002</entry>
-             <entry>By default the two field images will be passed
-sequentially; all lines of the first field followed by all lines of
-the second field (compare <xref linkend="field-order" />
-<constant>V4L2_FIELD_SEQ_TB</constant> and
-<constant>V4L2_FIELD_SEQ_BT</constant>, whether the top or bottom
-field is first in memory depends on the video standard). When this
-flag is set, the two fields are interlaced (cf.
-<constant>V4L2_FIELD_INTERLACED</constant>). The first line of the
-first field followed by the first line of the second field, then the
-two second lines, and so on. Such a layout may be necessary when the
-hardware has been programmed to capture or output interlaced video
-images and is unable to separate the fields for VBI capturing at
-the same time. For simplicity setting this flag implies that both
-<structfield>count</structfield> values are equal and non-zero.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <figure id="vbi-hsync">
-       <title>Line synchronization</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_hsync.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_hsync.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>Line synchronization diagram</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <figure id="vbi-525">
-       <title>ITU-R 525 line numbering (M/NTSC and M/PAL)</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_525.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_525.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>NTSC field synchronization diagram</phrase>
-         </textobject>
-         <caption>
-           <para>(1) For the purpose of this specification field 2
-starts in line 264 and not 263.5 because half line capturing is not
-supported.</para>
-         </caption>
-       </mediaobject>
-      </figure>
-
-      <figure id="vbi-625">
-       <title>ITU-R 625 line numbering</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_625.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_625.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>PAL/SECAM field synchronization diagram</phrase>
-         </textobject>
-         <caption>
-           <para>(1) For the purpose of this specification field 2
-starts in line 314 and not 313.5 because half line capturing is not
-supported.</para>
-         </caption>
-       </mediaobject>
-      </figure>
-
-      <para>Remember the VBI image format depends on the selected
-video standard, therefore the application must choose a new standard or
-query the current standard first. Attempts to read or write data ahead
-of format negotiation, or after switching the video standard which may
-invalidate the negotiated VBI parameters, should be refused by the
-driver. A format change during active I/O is not permitted.</para>
-    </section>
-
-    <section>
-      <title>Reading and writing VBI images</title>
-
-      <para>To assure synchronization with the field number and easier
-implementation, the smallest unit of data passed at a time is one
-frame, consisting of two fields of VBI images immediately following in
-memory.</para>
-
-      <para>The total size of a frame computes as follows:</para>
-
-      <programlisting>
-(<structfield>count</structfield>[0] + <structfield>count</structfield>[1]) *
-<structfield>samples_per_line</structfield> * sample size in bytes</programlisting>
-
-      <para>The sample size is most likely always one byte,
-applications must check the <structfield>sample_format</structfield>
-field though, to function properly with other drivers.</para>
-
-      <para>A VBI device may support <link
-      linkend="rw">read/write</link> and/or streaming (<link
-      linkend="mmap">memory mapping</link> or <link
-      linkend="userp">user pointer</link>) I/O. The latter bears the
-possibility of synchronizing video and
-VBI data by using buffer timestamps.</para>
-
-      <para>Remember the &VIDIOC-STREAMON; ioctl and the first read(),
-write() and select() call can be resource allocation points returning
-an &EBUSY; if the required hardware resources are temporarily
-unavailable, for example the device is already in use by another
-process.</para>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml
deleted file mode 100644 (file)
index be2f337..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-     <title>RDS Interface</title>
-
-      <para>The Radio Data System transmits supplementary
-information in binary format, for example the station name or travel
-information, on an inaudible audio subcarrier of a radio program. This
-interface is aimed at devices capable of receiving and/or transmitting RDS
-information.</para>
-
-      <para>For more information see the core RDS standard <xref linkend="iec62106" />
-and the RBDS standard <xref linkend="nrsc4" />.</para>
-
-      <para>Note that the RBDS standard as is used in the USA is almost identical
-to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
-fields have slightly different meanings. See the RBDS standard for more
-information.</para>
-
-      <para>The RBDS standard also specifies support for MMBS (Modified Mobile Search).
-This is a proprietary format which seems to be discontinued. The RDS interface does not
-support this format. Should support for MMBS (or the so-called 'E blocks' in general)
-be needed, then please contact the linux-media mailing list: &v4l-ml;.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the RDS capturing API set
-the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
-will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
-the <structfield>capability</structfield> field of &v4l2-tuner;.  If
-the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be
-set, see <link linkend="reading-rds-data">Reading RDS data</link>.
-For future use the
-flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> has also been
-defined. However, a driver for a radio tuner with this capability does
-not yet exist, so if you are planning to write such a driver you
-should discuss this on the linux-media mailing list: &v4l-ml;.</para>
-
-    <para> Whether an RDS signal is present can be detected by looking
-at the <structfield>rxsubchans</structfield> field of &v4l2-tuner;:
-the <constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data
-was detected.</para>
-
-    <para>Devices supporting the RDS output API
-set the <constant>V4L2_CAP_RDS_OUTPUT</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.
-Any modulator that supports RDS will set the
-<constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
-field of &v4l2-modulator;.
-In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
-bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
-If the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be set. If the
-tuner is capable of handling RDS entities like program identification codes and radio
-text, the flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> should be set,
-see <link linkend="writing-rds-data">Writing RDS data</link> and
-<link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
-  </section>
-
-  <section  id="reading-rds-data">
-    <title>Reading RDS data</title>
-
-      <para>RDS data can be read from the radio device
-with the &func-read; function. The data is packed in groups of three bytes.</para>
-  </section>
-
-  <section  id="writing-rds-data">
-    <title>Writing RDS data</title>
-
-      <para>RDS data can be written to the radio device
-with the &func-write; function. The data is packed in groups of three bytes,
-as follows:</para>
-  </section>
-
-  <section>
-    <title>RDS datastructures</title>
-    <table frame="none" pgwide="1" id="v4l2-rds-data">
-      <title>struct
-<structname>v4l2_rds_data</structname></title>
-      <tgroup cols="3">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>lsb</structfield></entry>
-           <entry>Least Significant Byte of RDS Block</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>msb</structfield></entry>
-           <entry>Most Significant Byte of RDS Block</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>block</structfield></entry>
-           <entry>Block description</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <table frame="none" pgwide="1" id="v4l2-rds-block">
-      <title>Block description</title>
-      <tgroup cols="2">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>Bits 0-2</entry>
-           <entry>Block (aka offset) of the received data.</entry>
-         </row>
-         <row>
-           <entry>Bits 3-5</entry>
-           <entry>Deprecated. Currently identical to bits 0-2. Do not use these bits.</entry>
-         </row>
-         <row>
-           <entry>Bit 6</entry>
-           <entry>Corrected bit. Indicates that an error was corrected for this data block.</entry>
-         </row>
-         <row>
-           <entry>Bit 7</entry>
-           <entry>Error bit. Indicates that an uncorrectable error occurred during reception of this block.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-rds-block-codes">
-      <title>Block defines</title>
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>V4L2_RDS_BLOCK_MSK</entry>
-           <entry> </entry>
-           <entry>7</entry>
-           <entry>Mask for bits 0-2 to get the block ID.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_A</entry>
-           <entry> </entry>
-           <entry>0</entry>
-           <entry>Block A.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_B</entry>
-           <entry> </entry>
-           <entry>1</entry>
-           <entry>Block B.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_C</entry>
-           <entry> </entry>
-           <entry>2</entry>
-           <entry>Block C.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_D</entry>
-           <entry> </entry>
-           <entry>3</entry>
-           <entry>Block D.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_C_ALT</entry>
-           <entry> </entry>
-           <entry>4</entry>
-           <entry>Block C'.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_INVALID</entry>
-           <entry>read-only</entry>
-           <entry>7</entry>
-           <entry>An invalid block.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_CORRECTED</entry>
-           <entry>read-only</entry>
-           <entry>0x40</entry>
-           <entry>A bit error was detected but corrected.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_ERROR</entry>
-           <entry>read-only</entry>
-           <entry>0x80</entry>
-           <entry>An uncorrectable error occurred.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml
deleted file mode 100644 (file)
index 6da1157..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-  <title>Software Defined Radio Interface (SDR)</title>
-
-  <para>
-SDR is an abbreviation of Software Defined Radio, the radio device
-which uses application software for modulation or demodulation. This interface
-is intended for controlling and data streaming of such devices.
-  </para>
-
-  <para>
-SDR devices are accessed through character device special files named
-<filename>/dev/swradio0</filename> to <filename>/dev/swradio255</filename>
-with major number 81 and dynamically allocated minor numbers 0 to 255.
-  </para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>
-Devices supporting the SDR receiver interface set the
-<constant>V4L2_CAP_SDR_CAPTURE</constant> and
-<constant>V4L2_CAP_TUNER</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an
-Analog to Digital Converter (ADC), which is a mandatory element for the SDR receiver.
-    </para>
-    <para>
-Devices supporting the SDR transmitter interface set the
-<constant>V4L2_CAP_SDR_OUTPUT</constant> and
-<constant>V4L2_CAP_MODULATOR</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an
-Digital to Analog Converter (DAC), which is a mandatory element for the SDR transmitter.
-    </para>
-    <para>
-At least one of the read/write, streaming or asynchronous I/O methods must
-be supported.
-    </para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>
-SDR devices can support <link linkend="control">controls</link>, and must
-support the <link linkend="tuner">tuner</link> ioctls. Tuner ioctls are used
-for setting the ADC/DAC sampling rate (sampling frequency) and the possible
-radio frequency (RF).
-    </para>
-
-    <para>
-The <constant>V4L2_TUNER_SDR</constant> tuner type is used for setting SDR
-device ADC/DAC frequency, and the <constant>V4L2_TUNER_RF</constant>
-tuner type is used for setting radio frequency.
-The tuner index of the RF tuner (if any) must always follow the SDR tuner index.
-Normally the SDR tuner is #0 and the RF tuner is #1.
-    </para>
-
-    <para>
-The &VIDIOC-S-HW-FREQ-SEEK; ioctl is not supported.
-    </para>
-  </section>
-
-  <section>
-    <title>Data Format Negotiation</title>
-
-    <para>
-The SDR device uses the <link linkend="format">format</link> ioctls to
-select the capture and output format. Both the sampling resolution and the data
-streaming format are bound to that selectable format. In addition to the basic
-<link linkend="format">format</link> ioctls, the &VIDIOC-ENUM-FMT; ioctl
-must be supported as well.
-    </para>
-
-    <para>
-To use the <link linkend="format">format</link> ioctls applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_SDR_OUTPUT</constant> and use the &v4l2-sdr-format;
-<structfield>sdr</structfield> member of the <structfield>fmt</structfield>
-union as needed per the desired operation.
-Currently there is two fields, <structfield>pixelformat</structfield> and
-<structfield>buffersize</structfield>, of struct &v4l2-sdr-format; which are
-used. Content of the <structfield>pixelformat</structfield> is V4L2 FourCC
-code of the data format. The <structfield>buffersize</structfield> field is
-maximum buffer size in bytes required for data transfer, set by the driver in
-order to inform application.
-    </para>
-
-    <table pgwide="1" frame="none" id="v4l2-sdr-format">
-      <title>struct <structname>v4l2_sdr_format</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-        <tbody valign="top">
-          <row>
-            <entry>__u32</entry>
-            <entry><structfield>pixelformat</structfield></entry>
-            <entry>
-The data format or type of compression, set by the application. This is a
-little endian <link linkend="v4l2-fourcc">four character code</link>.
-V4L2 defines SDR formats in <xref linkend="sdr-formats" />.
-           </entry>
-          </row>
-          <row>
-            <entry>__u32</entry>
-            <entry><structfield>buffersize</structfield></entry>
-            <entry>
-Maximum size in bytes required for data. Value is set by the driver.
-           </entry>
-          </row>
-          <row>
-            <entry>__u8</entry>
-            <entry><structfield>reserved[24]</structfield></entry>
-            <entry>This array is reserved for future extensions.
-Drivers and applications must set it to zero.</entry>
-          </row>
-        </tbody>
-      </tgroup>
-    </table>
-
-    <para>
-An SDR device may support <link linkend="rw">read/write</link>
-and/or streaming (<link linkend="mmap">memory mapping</link>
-or <link linkend="userp">user pointer</link>) I/O.
-    </para>
-
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
deleted file mode 100644 (file)
index 0aec62e..0000000
+++ /dev/null
@@ -1,706 +0,0 @@
-  <title>Sliced VBI Data Interface</title>
-
-  <para>VBI stands for Vertical Blanking Interval, a gap in the
-sequence of lines of an analog video signal. During VBI no picture
-information is transmitted, allowing some time while the electron beam
-of a cathode ray tube TV returns to the top of the screen.</para>
-
-  <para>Sliced VBI devices use hardware to demodulate data transmitted
-in the VBI. V4L2 drivers shall <emphasis>not</emphasis> do this by
-software, see also the <link linkend="raw-vbi">raw VBI
-interface</link>. The data is passed as short packets of fixed size,
-covering one scan line each. The number of packets per video frame is
-variable.</para>
-
-  <para>Sliced VBI capture and output devices are accessed through the
-same character special files as raw VBI devices. When a driver
-supports both interfaces, the default function of a
-<filename>/dev/vbi</filename> device is <emphasis>raw</emphasis> VBI
-capturing or output, and the sliced VBI function is only available
-after calling the &VIDIOC-S-FMT; ioctl as defined below. Likewise a
-<filename>/dev/video</filename> device may support the sliced VBI API,
-however the default function here is video capturing or output.
-Different file descriptors must be used to pass raw and sliced VBI
-data simultaneously, if this is supported by the driver.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the sliced VBI capturing or output API
-set the <constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant> or
-<constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant> flag respectively, in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
-read/write, streaming or asynchronous <link linkend="io">I/O
-methods</link> must be supported. Sliced VBI devices may have a tuner
-or modulator.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Sliced VBI devices shall support <link linkend="video">video
-input or output</link> and <link linkend="tuner">tuner or
-modulator</link> ioctls if they have these capabilities, and they may
-support <link linkend="control">control</link> ioctls. The <link
-linkend="standard">video standard</link> ioctls provide information
-vital to program a sliced VBI device, therefore must be
-supported.</para>
-  </section>
-
-  <section id="sliced-vbi-format-negotitation">
-    <title>Sliced VBI Format Negotiation</title>
-
-    <para>To find out which data services are supported by the
-hardware applications can call the &VIDIOC-G-SLICED-VBI-CAP; ioctl.
-All drivers implementing the sliced VBI interface must support this
-ioctl. The results may differ from those of the &VIDIOC-S-FMT; ioctl
-when the number of VBI lines the hardware can capture or output per
-frame, or the number of services it can identify on a given line are
-limited. For example on PAL line 16 the hardware may be able to look
-for a VPS or Teletext signal, but not both at the same time.</para>
-
-    <para>To determine the currently selected services applications
-set the <structfield>type </structfield> field of &v4l2-format; to
-<constant> V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or <constant>
-V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>, and the &VIDIOC-G-FMT;
-ioctl fills the <structfield>fmt.sliced</structfield> member, a
-&v4l2-sliced-vbi-format;.</para>
-
-    <para>Applications can request different parameters by
-initializing or modifying the <structfield>fmt.sliced</structfield>
-member and calling the &VIDIOC-S-FMT; ioctl with a pointer to the
-<structname>v4l2_format</structname> structure.</para>
-
-    <para>The sliced VBI API is more complicated than the raw VBI API
-because the hardware must be told which VBI service to expect on each
-scan line. Not all services may be supported by the hardware on all
-lines (this is especially true for VBI output where Teletext is often
-unsupported and other services can only be inserted in one specific
-line). In many cases, however, it is sufficient to just set the
-<structfield>service_set</structfield> field to the required services
-and let the driver fill the <structfield>service_lines</structfield>
-array according to hardware capabilities. Only if more precise control
-is needed should the programmer set the
-<structfield>service_lines</structfield> array explicitly.</para>
-
-    <para>The &VIDIOC-S-FMT; ioctl modifies the parameters
-according to hardware capabilities. When the driver allocates
-resources at this point, it may return an &EBUSY; if the required
-resources are temporarily unavailable. Other resource allocation
-points which may return <errorcode>EBUSY</errorcode> can be the
-&VIDIOC-STREAMON; ioctl and the first &func-read;, &func-write; and
-&func-select; call.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-format">
-      <title>struct
-<structname>v4l2_sliced_vbi_format</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="3*" />
-       <colspec colname="c2" colwidth="3*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec namest="c3" nameend="c5" spanname="hspan" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>service_set</structfield></entry>
-           <entry spanname="hspan"><para>If
-<structfield>service_set</structfield> is non-zero when passed with
-&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;, the
-<structfield>service_lines</structfield> array will be filled by the
-driver according to the services specified in this field. For example,
-if <structfield>service_set</structfield> is initialized with
-<constant>V4L2_SLICED_TELETEXT_B | V4L2_SLICED_WSS_625</constant>, a
-driver for the cx25840 video decoder sets lines 7-22 of both
-fields<footnote><para>According to <link
-linkend="ets300706">ETS&nbsp;300&nbsp;706</link> lines 6-22 of the
-first field and lines 5-22 of the second field may carry Teletext
-data.</para></footnote> to <constant>V4L2_SLICED_TELETEXT_B</constant>
-and line 23 of the first field to
-<constant>V4L2_SLICED_WSS_625</constant>. If
-<structfield>service_set</structfield> is set to zero, then the values
-of <structfield>service_lines</structfield> will be used instead.
-</para><para>On return the driver sets this field to the union of all
-elements of the returned <structfield>service_lines</structfield>
-array. It may contain less services than requested, perhaps just one,
-if the hardware cannot handle more services simultaneously. It may be
-empty (zero) if none of the requested services are supported by the
-hardware.</para></entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_lines</structfield>[2][24]</entry>
-           <entry spanname="hspan"><para>Applications initialize this
-array with sets of data services the driver shall look for or insert
-on the respective scan line. Subject to hardware capabilities drivers
-return the requested set, a subset, which may be just a single
-service, or an empty set. When the hardware cannot handle multiple
-services on the same line the driver shall choose one. No assumptions
-can be made on which service the driver chooses.</para><para>Data
-services are defined in <xref linkend="vbi-services2" />. Array indices
-map to ITU-R line numbers (see also <xref linkend="vbi-525" /> and <xref
-                 linkend="vbi-625" />) as follows: <!-- No nested
-tables, sigh. --></para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Element</entry>
-           <entry>525 line systems</entry>
-           <entry>625 line systems</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][1]</entry>
-           <entry align="center">1</entry>
-           <entry align="center">1</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][23]</entry>
-           <entry align="center">23</entry>
-           <entry align="center">23</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][1]</entry>
-           <entry align="center">264</entry>
-           <entry align="center">314</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][23]</entry>
-           <entry align="center">286</entry>
-           <entry align="center">336</entry>
-         </row>
-         <!-- End of line numbers table. -->
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">Drivers must set
-<structfield>service_lines</structfield>[0][0] and
-<structfield>service_lines</structfield>[1][0] to zero.
-The <constant>V4L2_VBI_ITU_525_F1_START</constant>,
-<constant>V4L2_VBI_ITU_525_F2_START</constant>,
-<constant>V4L2_VBI_ITU_625_F1_START</constant> and
-<constant>V4L2_VBI_ITU_625_F2_START</constant> defines give the start
-line numbers for each field for each 525 or 625 line format as a
-convenience.  Don't forget that ITU line numbering starts at 1, not 0.
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>io_size</structfield></entry>
-           <entry spanname="hspan">Maximum number of bytes passed by
-one &func-read; or &func-write; call, and the buffer size in bytes for
-the &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. Drivers set this field to
-the size of &v4l2-sliced-vbi-data; times the number of non-zero
-elements in the returned <structfield>service_lines</structfield>
-array (that is the number of lines potentially carrying data).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry spanname="hspan">This array is reserved for future
-extensions. Applications and drivers must set it to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- See also vidioc-g-sliced-vbi-cap.sgml -->
-    <table frame="none" pgwide="1" id="vbi-services2">
-      <title>Sliced VBI services</title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="2*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec namest="c3" nameend="c5" spanname="rlp" />
-       <thead>
-         <row>
-           <entry>Symbol</entry>
-           <entry>Value</entry>
-           <entry>Reference</entry>
-           <entry>Lines, usually</entry>
-           <entry>Payload</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SLICED_TELETEXT_B</constant>
-(Teletext System B)</entry>
-           <entry>0x0001</entry>
-           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
-           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
-           <entry>Last 42 of the 45 byte Teletext packet, that is
-without clock run-in and framing code, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VPS</constant></entry>
-           <entry>0x0400</entry>
-           <entry><xref linkend="ets300231" /></entry>
-           <entry>PAL line 16</entry>
-           <entry>Byte number 3 to 15 according to Figure 9 of
-ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry><xref linkend="cea608" /></entry>
-           <entry>NTSC line 21, 284 (second field 21)</entry>
-           <entry>Two bytes in transmission order, including parity
-bit, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
-           <entry>0x4000</entry>
-           <entry><xref linkend="itu1119" />, <xref linkend="en300294" /></entry>
-           <entry>PAL/SECAM line 23</entry>
-           <entry><screen>
-Byte         0                 1
-      msb         lsb  msb           lsb
- Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
-</screen></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry spanname="rlp">Set of services applicable to 525
-line systems.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
-           <entry>0x4401</entry>
-           <entry spanname="rlp">Set of services applicable to 625
-line systems.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Drivers may return an &EINVAL; when applications attempt to
-read or write data without prior format negotiation, after switching
-the video standard (which may invalidate the negotiated VBI
-parameters) and after switching the video input (which may change the
-video standard as a side effect). The &VIDIOC-S-FMT; ioctl may return
-an &EBUSY; when applications attempt to change the format while i/o is
-in progress (between a &VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; call,
-and after the first &func-read; or &func-write; call).</para>
-  </section>
-
-  <section>
-    <title>Reading and writing sliced VBI data</title>
-
-    <para>A single &func-read; or &func-write; call must pass all data
-belonging to one video frame. That is an array of
-<structname>v4l2_sliced_vbi_data</structname> structures with one or
-more elements and a total size not exceeding
-<structfield>io_size</structfield> bytes. Likewise in streaming I/O
-mode one buffer of <structfield>io_size</structfield> bytes must
-contain data of one video frame. The <structfield>id</structfield> of
-unused <structname>v4l2_sliced_vbi_data</structname> elements must be
-zero.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-data">
-      <title>struct
-<structname>v4l2_sliced_vbi_data</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>A flag from <xref linkend="vbi-services" />
-identifying the type of data in this packet. Only a single bit must be
-set. When the <structfield>id</structfield> of a captured packet is
-zero, the packet is empty and the contents of other fields are
-undefined. Applications shall ignore empty packets. When the
-<structfield>id</structfield> of a packet for output is zero the
-contents of the <structfield>data</structfield> field are undefined
-and the driver must no longer insert data on the requested
-<structfield>field</structfield> and
-<structfield>line</structfield>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The video field number this data has been captured
-from, or shall be inserted at. <constant>0</constant> for the first
-field, <constant>1</constant> for the second field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>line</structfield></entry>
-           <entry>The field (as opposed to frame) line number this
-data has been captured from, or shall be inserted at. See <xref
-           linkend="vbi-525" /> and <xref linkend="vbi-625" /> for valid
-values. Sliced VBI capture devices can set the line number of all
-packets to <constant>0</constant> if the hardware cannot reliably
-identify scan lines. The field number must always be valid.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry>This field is reserved for future extensions.
-Applications and drivers must set it to zero.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>data</structfield>[48]</entry>
-           <entry>The packet payload. See <xref
-           linkend="vbi-services" /> for the contents and number of
-bytes passed for each data type. The contents of padding bytes at the
-end of this array are undefined, drivers and applications shall ignore
-them.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Packets are always passed in ascending line number order,
-without duplicate line numbers. The &func-write; function and the
-&VIDIOC-QBUF; ioctl must return an &EINVAL; when applications violate
-this rule. They must also return an &EINVAL; when applications pass an
-incorrect field or line number, or a combination of
-<structfield>field</structfield>, <structfield>line</structfield> and
-<structfield>id</structfield> which has not been negotiated with the
-&VIDIOC-G-FMT; or &VIDIOC-S-FMT; ioctl. When the line numbers are
-unknown the driver must pass the packets in transmitted order. The
-driver can insert empty packets with <structfield>id</structfield> set
-to zero anywhere in the packet array.</para>
-
-    <para>To assure synchronization and to distinguish from frame
-dropping, when a captured frame does not carry any of the requested
-data services drivers must pass one or more empty packets. When an
-application fails to pass VBI data in time for output, the driver
-must output the last VPS and WSS packet again, and disable the output
-of Closed Caption and Teletext data, or output data which is ignored
-by Closed Caption and Teletext decoders.</para>
-
-    <para>A sliced VBI device may support <link
-linkend="rw">read/write</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> and/or <link linkend="userp">user
-pointer</link>) I/O. The latter bears the possibility of synchronizing
-video and VBI data by using buffer timestamps.</para>
-
-  </section>
-
-  <section>
-    <title>Sliced VBI Data in MPEG Streams</title>
-
-    <para>If a device can produce an MPEG output stream, it may be
-capable of providing <link
-linkend="sliced-vbi-format-negotitation">negotiated sliced VBI
-services</link> as data embedded in the MPEG stream.  Users or
-applications control this sliced VBI data insertion with the <link
-linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
-control.</para>
-
-    <para>If the driver does not provide the <link
-linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
-control, or only allows that control to be set to <link
-linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link>, then the device
-cannot embed sliced VBI data in the MPEG stream.</para>
-
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt">
-V4L2_CID_MPEG_STREAM_VBI_FMT</link> control does not implicitly set
-the device driver to capture nor cease capturing sliced VBI data.  The
-control only indicates to embed sliced VBI data in the MPEG stream, if
-an application has negotiated sliced VBI service be captured.</para>
-
-    <para>It may also be the case that a device can embed sliced VBI
-data in only certain types of MPEG streams: for example in an MPEG-2
-PS but not an MPEG-2 TS.  In this situation, if sliced VBI data
-insertion is requested, the sliced VBI data will be embedded in MPEG
-stream types when supported, and silently omitted from MPEG stream
-types where sliced VBI data insertion is not supported by the device.
-</para>
-
-    <para>The following subsections specify the format of the
-embedded sliced VBI data.</para>
-
-  <section>
-    <title>MPEG Stream Embedded, Sliced VBI Data Format: NONE</title>
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link> embedded sliced VBI
-format shall be interpreted by drivers as a control to cease
-embedding sliced VBI data in MPEG streams.  Neither the device nor
-driver shall insert "empty" embedded sliced VBI data packets in the
-MPEG stream when this format is set.  No MPEG stream data structures
-are specified for this format.</para>
-  </section>
-
-  <section>
-    <title>MPEG Stream Embedded, Sliced VBI Data Format: IVTV</title>
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> embedded sliced VBI
-format, when supported, indicates to the driver to embed up to 36
-lines of sliced VBI data per frame in an MPEG-2 <emphasis>Private
-Stream 1 PES</emphasis> packet encapsulated in an MPEG-2 <emphasis>
-Program Pack</emphasis> in the MPEG stream.</para>
-
-    <para><emphasis>Historical context</emphasis>: This format
-specification originates from a custom, embedded, sliced VBI data
-format used by the <filename>ivtv</filename> driver.  This format
-has already been informally specified in the kernel sources in the
-file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>
-.  The maximum size of the payload and other aspects of this format
-are driven by the CX23415 MPEG decoder's capabilities and limitations
-with respect to extracting, decoding, and displaying sliced VBI data
-embedded within an MPEG stream.</para>
-
-    <para>This format's use is <emphasis>not</emphasis> exclusive to
-the <filename>ivtv</filename> driver <emphasis>nor</emphasis>
-exclusive to CX2341x devices, as the sliced VBI data packet insertion
-into the MPEG stream is implemented in driver software.  At least the
-<filename>cx18</filename> driver provides sliced VBI data insertion
-into an MPEG-2 PS in this format as well.</para>
-
-    <para>The following definitions specify the payload of the
-MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packets that contain
-sliced VBI data when <link linkend="v4l2-mpeg-stream-vbi-fmt">
-<constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> is set.
-(The MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packet header
-and encapsulating MPEG-2 <emphasis>Program Pack</emphasis> header are
-not detailed here.  Please refer to the MPEG-2 specifications for
-details on those packet headers.)</para>
-
-    <para>The payload of the MPEG-2 <emphasis>Private Stream 1 PES
-</emphasis> packets that contain sliced VBI data is specified by
-&v4l2-mpeg-vbi-fmt-ivtv;.  The payload is variable
-length, depending on the actual number of lines of sliced VBI data
-present in a video frame.  The payload may be padded at the end with
-unspecified fill bytes to align the end of the payload to a 4-byte
-boundary.  The payload shall never exceed 1552 bytes (2 fields with
-18 lines/field with 43 bytes of data/line and a 4 byte magic number).
-</para>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv">
-      <title>struct <structname>v4l2_mpeg_vbi_fmt_ivtv</structname>
-      </title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>magic</structfield>[4]</entry>
-           <entry></entry>
-           <entry>A "magic" constant from <xref
-           linkend="v4l2-mpeg-vbi-fmt-ivtv-magic" /> that indicates
-this is a valid sliced VBI data payload and also indicates which
-member of the anonymous union, <structfield>itv0</structfield> or
-<structfield>ITV0</structfield>, to use for the payload data.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0">
-             <structname>v4l2_mpeg_vbi_itv0</structname></link>
-           </entry>
-           <entry><structfield>itv0</structfield></entry>
-           <entry>The primary form of the sliced VBI data payload
-that contains anywhere from 1 to 35 lines of sliced VBI data.
-Line masks are provided in this form of the payload indicating
-which VBI lines are provided.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-1">
-             <structname>v4l2_mpeg_vbi_ITV0</structname></link>
-           </entry>
-           <entry><structfield>ITV0</structfield></entry>
-           <entry>An alternate form of the sliced VBI data payload
-used when 36 lines of sliced VBI data are present.  No line masks are
-provided in this form of the payload; all valid line mask bits are
-implcitly set.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv-magic">
-      <title>Magic Constants for &v4l2-mpeg-vbi-fmt-ivtv;
-       <structfield>magic</structfield> field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry align="left">Defined Symbol</entry>
-           <entry align="left">Value</entry>
-           <entry align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC0</constant>
-           </entry>
-           <entry>"itv0"</entry>
-           <entry>Indicates the <structfield>itv0</structfield>
-member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC1</constant>
-           </entry>
-           <entry>"ITV0"</entry>
-           <entry>Indicates the <structfield>ITV0</structfield>
-member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid and
-that 36 lines of sliced VBI data are present.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0">
-      <title>struct <structname>v4l2_mpeg_vbi_itv0</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__le32</entry>
-           <entry><structfield>linemask</structfield>[2]</entry>
-           <entry><para>Bitmasks indicating the VBI service lines
-present.  These <structfield>linemask</structfield> values are stored
-in little endian byte order in the MPEG stream.  Some reference
-<structfield>linemask</structfield> bit positions with their
-corresponding VBI line number and video field are given below.
-b<subscript>0</subscript> indicates the least significant bit of a
-<structfield>linemask</structfield> value:<screen>
-<structfield>linemask</structfield>[0] b<subscript>0</subscript>:              line  6         first field
-<structfield>linemask</structfield>[0] b<subscript>17</subscript>:             line 23         first field
-<structfield>linemask</structfield>[0] b<subscript>18</subscript>:             line  6         second field
-<structfield>linemask</structfield>[0] b<subscript>31</subscript>:             line 19         second field
-<structfield>linemask</structfield>[1] b<subscript>0</subscript>:              line 20         second field
-<structfield>linemask</structfield>[1] b<subscript>3</subscript>:              line 23         second field
-<structfield>linemask</structfield>[1] b<subscript>4</subscript>-b<subscript>31</subscript>:   unused and set to 0</screen></para></entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
-             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
-           </entry>
-           <entry><structfield>line</structfield>[35]</entry>
-           <entry>This is a variable length array that holds from 1
-to 35 lines of sliced VBI data.  The sliced VBI data lines present
-correspond to the bits set in the <structfield>linemask</structfield>
-array, starting from b<subscript>0</subscript> of <structfield>
-linemask</structfield>[0] up through b<subscript>31</subscript> of
-<structfield>linemask</structfield>[0], and from b<subscript>0
-</subscript> of <structfield>linemask</structfield>[1] up through b
-<subscript>3</subscript> of <structfield>linemask</structfield>[1].
-<structfield>line</structfield>[0] corresponds to the first bit
-found set in the <structfield>linemask</structfield> array,
-<structfield>line</structfield>[1] corresponds to the second bit
-found set in the <structfield>linemask</structfield> array, etc.
-If no <structfield>linemask</structfield> array bits are set, then
-<structfield>line</structfield>[0] may contain one line of
-unspecified data that should be ignored by applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-1">
-      <title>struct <structname>v4l2_mpeg_vbi_ITV0</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
-             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
-           </entry>
-           <entry><structfield>line</structfield>[36]</entry>
-           <entry>A fixed length array of 36 lines of sliced VBI
-data.  <structfield>line</structfield>[0] through <structfield>line
-</structfield>[17] correspond to lines 6 through 23 of the
-first field.  <structfield>line</structfield>[18] through
-<structfield>line</structfield>[35] corresponds to lines 6
-through 23 of the second field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-line">
-      <title>struct <structname>v4l2_mpeg_vbi_itv0_line</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>A line identifier value from
-<xref linkend="ITV0-Line-Identifier-Constants" /> that indicates
-the type of sliced VBI data stored on this line.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>data</structfield>[42]</entry>
-           <entry>The sliced VBI data for the line.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="ITV0-Line-Identifier-Constants">
-      <title>Line Identifiers for struct <link
-      linkend="v4l2-mpeg-vbi-itv0-line"><structname>
-v4l2_mpeg_vbi_itv0_line</structname></link> <structfield>id
-</structfield> field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry align="left">Defined Symbol</entry>
-           <entry align="left">Value</entry>
-           <entry align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_TELETEXT_B</constant>
-           </entry>
-           <entry>1</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_CAPTION_525</constant>
-           </entry>
-           <entry>4</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_WSS_625</constant>
-           </entry>
-           <entry>5</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_VPS</constant>
-           </entry>
-           <entry>7</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </section>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
deleted file mode 100644 (file)
index f4bc27a..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-  <title>Sub-device Interface</title>
-
-  <para>The complex nature of V4L2 devices, where hardware is often made of
-  several integrated circuits that need to interact with each other in a
-  controlled way, leads to complex V4L2 drivers. The drivers usually reflect
-  the hardware model in software, and model the different hardware components
-  as software blocks called sub-devices.</para>
-
-  <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
-  implements the media device API, they will automatically inherit from media
-  entities. Applications will be able to enumerate the sub-devices and discover
-  the hardware topology using the media entities, pads and links enumeration
-  API.</para>
-
-  <para>In addition to make sub-devices discoverable, drivers can also choose
-  to make them directly configurable by applications. When both the sub-device
-  driver and the V4L2 device driver support this, sub-devices will feature a
-  character device node on which ioctls can be called to
-  <itemizedlist>
-    <listitem><para>query, read and write sub-devices controls</para></listitem>
-    <listitem><para>subscribe and unsubscribe to events and retrieve them</para></listitem>
-    <listitem><para>negotiate image formats on individual pads</para></listitem>
-  </itemizedlist>
-  </para>
-
-  <para>Sub-device character device nodes, conventionally named
-  <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
-
-  <section>
-    <title>Controls</title>
-    <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
-    usually merge all controls and expose them through video device nodes.
-    Applications can control all sub-devices through a single interface.</para>
-
-    <para>Complex devices sometimes implement the same control in different
-    pieces of hardware. This situation is common in embedded platforms, where
-    both sensors and image processing hardware implement identical functions,
-    such as contrast adjustment, white balance or faulty pixels correction. As
-    the V4L2 controls API doesn't support several identical controls in a single
-    device, all but one of the identical controls are hidden.</para>
-
-    <para>Applications can access those hidden controls through the sub-device
-    node with the V4L2 control API described in <xref linkend="control" />. The
-    ioctls behave identically as when issued on V4L2 device nodes, with the
-    exception that they deal only with controls implemented in the sub-device.
-    </para>
-
-    <para>Depending on the driver, those controls might also be exposed through
-    one (or several) V4L2 device nodes.</para>
-  </section>
-
-  <section>
-    <title>Events</title>
-    <para>V4L2 sub-devices can notify applications of events as described in
-    <xref linkend="event" />. The API behaves identically as when used on V4L2
-    device nodes, with the exception that it only deals with events generated by
-    the sub-device. Depending on the driver, those events might also be reported
-    on one (or several) V4L2 device nodes.</para>
-  </section>
-
-  <section id="pad-level-formats">
-    <title>Pad-level Formats</title>
-
-    <warning><para>Pad-level formats are only applicable to very complex device that
-    need to expose low-level format configuration to user space. Generic V4L2
-    applications do <emphasis>not</emphasis> need to use the API described in
-    this section.</para></warning>
-
-    <note><para>For the purpose of this section, the term
-    <wordasword>format</wordasword> means the combination of media bus data
-    format, frame width and frame height.</para></note>
-
-    <para>Image formats are typically negotiated on video capture and
-    output devices using the format and <link
-    linkend="vidioc-subdev-g-selection">selection</link> ioctls. The
-    driver is responsible for configuring every block in the video
-    pipeline according to the requested format at the pipeline input
-    and/or output.</para>
-
-    <para>For complex devices, such as often found in embedded systems,
-    identical image sizes at the output of a pipeline can be achieved using
-    different hardware configurations. One such example is shown on
-    <xref linkend="pipeline-scaling" />, where
-    image scaling can be performed on both the video sensor and the host image
-    processing hardware.</para>
-
-    <figure id="pipeline-scaling">
-      <title>Image Format Negotiation on Pipelines</title>
-      <mediaobject>
-       <imageobject>
-         <imagedata fileref="pipeline.pdf" format="PS" />
-       </imageobject>
-       <imageobject>
-         <imagedata fileref="pipeline.png" format="PNG" />
-       </imageobject>
-       <textobject>
-         <phrase>High quality and high speed pipeline configuration</phrase>
-       </textobject>
-      </mediaobject>
-    </figure>
-
-    <para>The sensor scaler is usually of less quality than the host scaler, but
-    scaling on the sensor is required to achieve higher frame rates. Depending
-    on the use case (quality vs. speed), the pipeline must be configured
-    differently. Applications need to configure the formats at every point in
-    the pipeline explicitly.</para>
-
-    <para>Drivers that implement the <link linkend="media-controller-intro">media
-    API</link> can expose pad-level image format configuration to applications.
-    When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
-    &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
-
-    <para>Applications are responsible for configuring coherent parameters on
-    the whole pipeline and making sure that connected pads have compatible
-    formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
-    time, and an &EPIPE; is then returned if the configuration is
-    invalid.</para>
-
-    <para>Pad-level image format configuration support can be tested by calling
-    the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
-    pad-level format configuration is not supported by the sub-device.</para>
-
-    <section>
-      <title>Format Negotiation</title>
-
-      <para>Acceptable formats on pads can (and usually do) depend on a number
-      of external parameters, such as formats on other pads, active links, or
-      even controls. Finding a combination of formats on all pads in a video
-      pipeline, acceptable to both application and driver, can't rely on formats
-      enumeration only. A format negotiation mechanism is required.</para>
-
-      <para>Central to the format negotiation mechanism are the get/set format
-      operations. When called with the <structfield>which</structfield> argument
-      set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
-      &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
-      formats parameters that are not connected to the hardware configuration.
-      Modifying those 'try' formats leaves the device state untouched (this
-      applies to both the software state stored in the driver and the hardware
-      state stored in the device itself).</para>
-
-      <para>While not kept as part of the device state, try formats are stored
-      in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
-      the last try format set <emphasis>on the same sub-device file
-      handle</emphasis>. Several applications querying the same sub-device at
-      the same time will thus not interact with each other.</para>
-
-      <para>To find out whether a particular format is supported by the device,
-      applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
-      needed, change the requested <structfield>format</structfield> based on
-      device requirements and return the possibly modified value. Applications
-      can then choose to try a different format or accept the returned value and
-      continue.</para>
-
-      <para>Formats returned by the driver during a negotiation iteration are
-      guaranteed to be supported by the device. In particular, drivers guarantee
-      that a returned format will not be further changed if passed to an
-      &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
-      formats on other pads or links' configuration are not changed).</para>
-
-      <para>Drivers automatically propagate formats inside sub-devices. When a
-      try or active format is set on a pad, corresponding formats on other pads
-      of the same sub-device can be modified by the driver. Drivers are free to
-      modify formats as required by the device. However, they should comply with
-      the following rules when possible:
-      <itemizedlist>
-        <listitem><para>Formats should be propagated from sink pads to source pads.
-       Modifying a format on a source pad should not modify the format on any
-       sink pad.</para></listitem>
-        <listitem><para>Sub-devices that scale frames using variable scaling factors
-       should reset the scale factors to default values when sink pads formats
-       are modified. If the 1:1 scaling ratio is supported, this means that
-       source pads formats should be reset to the sink pads formats.</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>Formats are not propagated across links, as that would involve
-      propagating them from one sub-device file handle to another. Applications
-      must then take care to configure both ends of every link explicitly with
-      compatible formats. Identical formats on the two ends of a link are
-      guaranteed to be compatible. Drivers are free to accept different formats
-      matching device requirements as being compatible.</para>
-
-      <para><xref linkend="sample-pipeline-config" />
-      shows a sample configuration sequence for the pipeline described in
-      <xref linkend="pipeline-scaling" /> (table
-      columns list entity names and pad numbers).</para>
-
-      <table pgwide="0" frame="none" id="sample-pipeline-config">
-       <title>Sample Pipeline Configuration</title>
-       <tgroup cols="3">
-         <colspec colname="what"/>
-         <colspec colname="sensor-0 format" />
-         <colspec colname="frontend-0 format" />
-         <colspec colname="frontend-1 format" />
-         <colspec colname="scaler-0 format" />
-         <colspec colname="scaler-0 compose" />
-         <colspec colname="scaler-1 format" />
-         <thead>
-           <row>
-             <entry></entry>
-             <entry>Sensor/0 format</entry>
-             <entry>Frontend/0 format</entry>
-             <entry>Frontend/1 format</entry>
-             <entry>Scaler/0 format</entry>
-             <entry>Scaler/0 compose selection rectangle</entry>
-             <entry>Scaler/1 format</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row>
-             <entry>Initial state</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-           </row>
-           <row>
-             <entry>Configure frontend sink format</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry><emphasis>2048x1536/SGRBG8_1X8</emphasis></entry>
-             <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-             <entry>(default)</entry>
-           </row>
-           <row>
-             <entry>Configure scaler sink format</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry>2046x1534/SGRBG8_1X8</entry>
-             <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
-             <entry><emphasis>0,0/2046x1534</emphasis></entry>
-             <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
-           </row>
-           <row>
-             <entry>Configure scaler sink compose selection</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry>2048x1536/SGRBG8_1X8</entry>
-             <entry>2046x1534/SGRBG8_1X8</entry>
-             <entry>2046x1534/SGRBG8_1X8</entry>
-             <entry><emphasis>0,0/1280x960</emphasis></entry>
-             <entry><emphasis>1280x960/SGRBG8_1X8</emphasis></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <para>
-      <orderedlist>
-       <listitem><para>Initial state. The sensor source pad format is
-       set to its native 3MP size and V4L2_MBUS_FMT_SGRBG8_1X8
-       media bus code. Formats on the host frontend and scaler sink
-       and source pads have the default values, as well as the
-       compose rectangle on the scaler's sink pad.</para></listitem>
-
-       <listitem><para>The application configures the frontend sink
-       pad format's size to 2048x1536 and its media bus code to
-       V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the format to
-       the frontend source pad.</para></listitem>
-
-       <listitem><para>The application configures the scaler sink pad
-       format's size to 2046x1534 and the media bus code to
-       V4L2_MBUS_FMT_SGRBG_1X8 to match the frontend source size and
-       media bus code. The media bus code on the sink pad is set to
-       V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the size to the
-       compose selection rectangle on the scaler's sink pad, and the
-       format to the scaler source pad.</para></listitem>
-
-       <listitem><para>The application configures the size of the compose
-       selection rectangle of the scaler's sink pad 1280x960. The driver
-       propagates the size to the scaler's source pad
-       format.</para></listitem>
-
-      </orderedlist>
-      </para>
-
-      <para>When satisfied with the try results, applications can set the active
-      formats by setting the <structfield>which</structfield> argument to
-      <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. Active formats are changed
-      exactly as try formats by drivers. To avoid modifying the hardware state
-      during format negotiation, applications should negotiate try formats first
-      and then modify the active settings using the try formats returned during
-      the last negotiation iteration. This guarantees that the active format
-      will be applied as-is by the driver without being modified.
-      </para>
-    </section>
-
-    <section id="v4l2-subdev-selections">
-      <title>Selections: cropping, scaling and composition</title>
-
-      <para>Many sub-devices support cropping frames on their input or output
-      pads (or possible even on both). Cropping is used to select the area of
-      interest in an image, typically on an image sensor or a video decoder. It can
-      also be used as part of digital zoom implementations to select the area of
-      the image that will be scaled up.</para>
-
-      <para>Crop settings are defined by a crop rectangle and represented in a
-      &v4l2-rect; by the coordinates of the top left corner and the rectangle
-      size. Both the coordinates and sizes are expressed in pixels.</para>
-
-      <para>As for pad formats, drivers store try and active
-      rectangles for the selection targets <xref
-      linkend="v4l2-selections-common" />.</para>
-
-      <para>On sink pads, cropping is applied relative to the
-      current pad format. The pad format represents the image size as
-      received by the sub-device from the previous block in the
-      pipeline, and the crop rectangle represents the sub-image that
-      will be transmitted further inside the sub-device for
-      processing.</para>
-
-      <para>The scaling operation changes the size of the image by
-      scaling it to new dimensions. The scaling ratio isn't specified
-      explicitly, but is implied from the original and scaled image
-      sizes. Both sizes are represented by &v4l2-rect;.</para>
-
-      <para>Scaling support is optional. When supported by a subdev,
-      the crop rectangle on the subdev's sink pad is scaled to the
-      size configured using the &VIDIOC-SUBDEV-S-SELECTION; IOCTL
-      using <constant>V4L2_SEL_TGT_COMPOSE</constant>
-      selection target on the same pad. If the subdev supports scaling
-      but not composing, the top and left values are not used and must
-      always be set to zero.</para>
-
-      <para>On source pads, cropping is similar to sink pads, with the
-      exception that the source size from which the cropping is
-      performed, is the COMPOSE rectangle on the sink pad. In both
-      sink and source pads, the crop rectangle must be entirely
-      contained inside the source image size for the crop
-      operation.</para>
-
-      <para>The drivers should always use the closest possible
-      rectangle the user requests on all selection targets, unless
-      specifically told otherwise.
-      <constant>V4L2_SEL_FLAG_GE</constant> and
-      <constant>V4L2_SEL_FLAG_LE</constant> flags may be
-      used to round the image size either up or down. <xref
-      linkend="v4l2-selection-flags" /></para>
-    </section>
-
-    <section>
-      <title>Types of selection targets</title>
-
-      <section>
-       <title>Actual targets</title>
-
-       <para>Actual targets (without a postfix) reflect the actual
-       hardware configuration at any point of time. There is a BOUNDS
-       target corresponding to every actual target.</para>
-      </section>
-
-      <section>
-       <title>BOUNDS targets</title>
-
-       <para>BOUNDS targets is the smallest rectangle that contains all
-       valid actual rectangles. It may not be possible to set the actual
-       rectangle as large as the BOUNDS rectangle, however. This may be
-       because e.g. a sensor's pixel array is not rectangular but
-       cross-shaped or round. The maximum size may also be smaller than the
-       BOUNDS rectangle.</para>
-      </section>
-
-    </section>
-
-    <section>
-      <title>Order of configuration and format propagation</title>
-
-      <para>Inside subdevs, the order of image processing steps will
-      always be from the sink pad towards the source pad. This is also
-      reflected in the order in which the configuration must be
-      performed by the user: the changes made will be propagated to
-      any subsequent stages. If this behaviour is not desired, the
-      user must set
-      <constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant> flag. This
-      flag causes no propagation of the changes are allowed in any
-      circumstances. This may also cause the accessed rectangle to be
-      adjusted by the driver, depending on the properties of the
-      underlying hardware.</para>
-
-      <para>The coordinates to a step always refer to the actual size
-      of the previous step. The exception to this rule is the source
-      compose rectangle, which refers to the sink compose bounds
-      rectangle --- if it is supported by the hardware.</para>
-
-      <orderedlist>
-       <listitem><para>Sink pad format. The user configures the sink pad
-       format. This format defines the parameters of the image the
-       entity receives through the pad for further processing.</para></listitem>
-
-       <listitem><para>Sink pad actual crop selection. The sink pad crop
-       defines the crop performed to the sink pad format.</para></listitem>
-
-       <listitem><para>Sink pad actual compose selection. The size of the
-       sink pad compose rectangle defines the scaling ratio compared
-       to the size of the sink pad crop rectangle. The location of
-       the compose rectangle specifies the location of the actual
-       sink compose rectangle in the sink compose bounds
-       rectangle.</para></listitem>
-
-       <listitem><para>Source pad actual crop selection. Crop on the source
-       pad defines crop performed to the image in the sink compose
-       bounds rectangle.</para></listitem>
-
-       <listitem><para>Source pad format. The source pad format defines the
-       output pixel format of the subdev, as well as the other
-       parameters with the exception of the image width and height.
-       Width and height are defined by the size of the source pad
-       actual crop selection.</para></listitem>
-      </orderedlist>
-
-      <para>Accessing any of the above rectangles not supported by the
-      subdev will return <constant>EINVAL</constant>. Any rectangle
-      referring to a previous unsupported rectangle coordinates will
-      instead refer to the previous supported rectangle. For example,
-      if sink crop is not supported, the compose selection will refer
-      to the sink pad format dimensions instead.</para>
-
-      <figure id="subdev-image-processing-crop">
-       <title>Image processing in subdevs: simple crop example</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="subdev-image-processing-crop.svg"
-           format="SVG" scale="200" />
-         </imageobject>
-       </mediaobject>
-      </figure>
-
-      <para>In the above example, the subdev supports cropping on its
-      sink pad. To configure it, the user sets the media bus format on
-      the subdev's sink pad. Now the actual crop rectangle can be set
-      on the sink pad --- the location and size of this rectangle
-      reflect the location and size of a rectangle to be cropped from
-      the sink format. The size of the sink crop rectangle will also
-      be the size of the format of the subdev's source pad.</para>
-
-      <figure id="subdev-image-processing-scaling-multi-source">
-       <title>Image processing in subdevs: scaling with multiple sources</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="subdev-image-processing-scaling-multi-source.svg"
-           format="SVG" scale="200" />
-         </imageobject>
-       </mediaobject>
-      </figure>
-
-      <para>In this example, the subdev is capable of first cropping,
-      then scaling and finally cropping for two source pads
-      individually from the resulting scaled image. The location of
-      the scaled image in the cropped image is ignored in sink compose
-      target. Both of the locations of the source crop rectangles
-      refer to the sink scaling rectangle, independently cropping an
-      area at location specified by the source crop rectangle from
-      it.</para>
-
-      <figure id="subdev-image-processing-full">
-       <title>Image processing in subdevs: scaling and composition
-       with multiple sinks and sources</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="subdev-image-processing-full.svg"
-           format="SVG" scale="200" />
-         </imageobject>
-       </mediaobject>
-      </figure>
-
-      <para>The subdev driver supports two sink pads and two source
-      pads. The images from both of the sink pads are individually
-      cropped, then scaled and further composed on the composition
-      bounds rectangle. From that, two independent streams are cropped
-      and sent out of the subdev from the source pads.</para>
-
-    </section>
-
-  </section>
-
-  &sub-subdev-formats;
diff --git a/Documentation/DocBook/media/v4l/dev-teletext.xml b/Documentation/DocBook/media/v4l/dev-teletext.xml
deleted file mode 100644 (file)
index bd21c64..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-  <title>Teletext Interface</title>
-
-  <para>This interface was aimed at devices receiving and demodulating
-Teletext data [<xref linkend="ets300706" />, <xref linkend="itu653" />], evaluating the
-Teletext packages and storing formatted pages in cache memory. Such
-devices are usually implemented as microcontrollers with serial
-interface (I<superscript>2</superscript>C) and could be found on old
-TV cards, dedicated Teletext decoding cards and home-brew devices
-connected to the PC parallel port.</para>
-
-  <para>The Teletext API was designed by Martin Buck. It was defined in
-the kernel header file <filename>linux/videotext.h</filename>, the
-specification is available from <ulink url="ftp://ftp.gwdg.de/pub/linux/misc/videotext/">
-ftp://ftp.gwdg.de/pub/linux/misc/videotext/</ulink>. (Videotext is the name of
-the German public television Teletext service.)</para>
-
-  <para>Eventually the Teletext API was integrated into the V4L API
-with character device file names <filename>/dev/vtx0</filename> to
-<filename>/dev/vtx31</filename>, device major number 81, minor numbers
-192 to 223.</para>
-
-  <para>However, teletext decoders were quickly replaced by more
-generic VBI demodulators and those dedicated teletext decoders no longer exist.
-For many years the vtx devices were still around, even though nobody used
-them. So the decision was made to finally remove support for the Teletext API in
-kernel 2.6.37.</para>
-
-  <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
-<link linkend="sliced">sliced</link> VBI API.</para>
diff --git a/Documentation/DocBook/media/v4l/driver.xml b/Documentation/DocBook/media/v4l/driver.xml
deleted file mode 100644 (file)
index 7c6638b..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-  <title>V4L2 Driver Programming</title>
-
-  <!-- This part defines the interface between the "videodev"
-    module and individual drivers. -->
-
-  <para>to do</para>
-<!--
-  <para>V4L2 is a two-layer driver system. The top layer is the "videodev"
-kernel module. When videodev initializes it registers as character device
-with major number 81, and it registers a set of file operations. All V4L2
-drivers are really clients of videodev, which calls V4L2 drivers through
-driver method functions. V4L2 drivers are also written as kernel modules.
-After probing the hardware they register one or more devices with
-videodev.</para>
-
-  <section id="driver-modules">
-    <title>Driver Modules</title>
-
-    <para>V4L2 driver modules must have an initialization function which is
-called after the module was loaded into kernel, an exit function whis is
-called before the module is removed.  When the driver is compiled into the
-kernel these functions called at system boot and shutdown time.</para>
-
-    <informalexample>
-      <programlisting>
-#include &lt;linux/module.h&gt;
-
-/* Export information about this module. For details and other useful
-   macros see <filename>linux/module.h</filename>. */
-MODULE_DESCRIPTION("my - driver for my hardware");
-MODULE_AUTHOR("Your name here");
-MODULE_LICENSE("GPL");
-
-static void
-my_module_exit (void)
-{
-       /* Free all resources allocated by my_module_init(). */
-}
-
-static int
-my_module_init (void)
-{
-       /* Bind the driver to the supported hardware, see
-          <link linkend="driver-pci"> and
-          <link linkend="driver-usb"> for examples. */
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-/* Export module functions. */
-module_init (my_module_init);
-module_exit (my_module_exit);
-</programlisting>
-    </informalexample>
-
-    <para>Users can add parameters when kernel modules are inserted:</para>
-
-    <informalexample>
-      <programlisting>
-include &lt;linux/moduleparam.h&gt;
-
-static int my_option = 123;
-static int my_option_array[47];
-
-/* Export the symbol, an int, with access permissions 0664.
-   See <filename>linux/moduleparam.h</filename> for other types. */
-module_param (my_option, int, 0644);
-module_param_array (my_option_array, int, NULL, 0644);
-
-MODULE_PARM_DESC (my_option, "Does magic things, default 123");
-</programlisting>
-    </informalexample>
-
-    <para>One parameter should be supported by all V4L2 drivers, the minor
-number of the device it will register. Purpose is to predictably link V4L2
-drivers to device nodes if more than one video device is installed. Use the
-name of the device node followed by a "_nr" suffix, for example "video_nr"
-for <filename>/dev/video</filename>.</para>
-
-    <informalexample>
-      <programlisting>
-/* Minor number of the device, -1 to allocate the first unused. */
-static int video_nr = -1;
-
-module_param (video_nr, int, 0444);
-</programlisting>
-    </informalexample>
-  </section>
-
-  <section id="driver-pci">
-    <title>PCI Devices</title>
-
-    <para>PCI devices are initialized like this:</para>
-
-    <informalexample>
-      <programlisting>
-typedef struct {
-       /* State of one physical device. */
-} my_device;
-
-static int
-my_resume               (struct pci_dev *               pci_dev)
-{
-       /* Restore the suspended device to working state. */
-}
-
-static int
-my_suspend              (struct pci_dev *               pci_dev,
-                        pm_message_t                   state)
-{
-       /* This function is called before the system goes to sleep.
-          Stop all DMAs and disable interrupts, then put the device
-          into a low power state. For details see the kernel
-          sources under <filename>Documentation/power</filename>. */
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-static void
-my_remove               (struct pci_dev *               pci_dev)
-{
-       my_device *my = pci_get_drvdata (pci_dev);
-
-       /* Describe me. */
-}
-
-static int
-my_probe                (struct pci_dev *               pci_dev,
-                        const struct pci_device_id *   pci_id)
-{
-       my_device *my;
-
-       /* Describe me. */
-
-       /* You can allocate per-device data here and store a pointer
-          to it in the pci_dev structure. */
-       my = ...;
-       pci_set_drvdata (pci_dev, my);
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-/* A list of supported PCI devices. */
-static struct pci_device_id
-my_pci_device_ids [] = {
-       { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { 0 } /* end of list */
-};
-
-/* Load our module if supported PCI devices are installed. */
-MODULE_DEVICE_TABLE (pci, my_pci_device_ids);
-
-static struct pci_driver
-my_pci_driver = {
-       .name     = "my",
-       .id_table = my_pci_device_ids,
-
-       .probe    = my_probe,
-       .remove   = my_remove,
-
-       /* Power management functions. */
-       .suspend  = my_suspend,
-       .resume   = my_resume,
-};
-
-static void
-my_module_exit          (void)
-{
-       pci_unregister_driver (&my_pci_driver);
-}
-
-static int
-my_module_init          (void)
-{
-       return pci_register_driver (&my_pci_driver);
-}
-</programlisting>
-    </informalexample>
-  </section>
-
-  <section id="driver-usb">
-    <title>USB Devices</title>
-    <para>to do</para>
-  </section>
-  <section id="driver-registering">
-    <title>Registering V4L2 Drivers</title>
-
-    <para>After a V4L2 driver probed the hardware it registers one or more
-devices with the videodev module.</para>
-  </section>
-  <section id="driver-file-ops">
-    <title>File Operations</title>
-    <para>to do</para>
-  </section>
-  <section id="driver-internal-api">
-    <title>Internal API</title>
-    <para>to do</para>
-  </section>
--->
diff --git a/Documentation/DocBook/media/v4l/fdl-appendix.xml b/Documentation/DocBook/media/v4l/fdl-appendix.xml
deleted file mode 100644 (file)
index 71299a3..0000000
+++ /dev/null
@@ -1,671 +0,0 @@
-<!--
-     The GNU Free Documentation License 1.1 in DocBook
-     Markup by Eric Baudais <baudais@okstate.edu>
-     Maintained by the GNOME Documentation Project
-     http://live.gnome.org/DocumentationProject
-     Version: 1.0.1
-     Last Modified: Nov 16, 2000
--->
-
-<appendix id="fdl">
-  <appendixinfo>
-    <releaseinfo>
-      Version 1.1, March 2000
-    </releaseinfo>
-    <copyright>
-      <year>2000</year><holder>Free Software Foundation, Inc.</holder>
-    </copyright>
-    <legalnotice id="fdl-legalnotice">
-      <para>
-       <address>Free Software Foundation, Inc. <street>59 Temple Place,
-       Suite 330</street>, <city>Boston</city>, <state>MA</state>
-       <postcode>02111-1307</postcode>  <country>USA</country></address>
-       Everyone is permitted to copy and distribute verbatim copies of this
-       license document, but changing it is not allowed.
-      </para>
-    </legalnotice>
-  </appendixinfo>
-  <title>GNU Free Documentation License</title>
-
-  <sect1 id="fdl-preamble">
-    <title>0. PREAMBLE</title>
-    <para>
-      The purpose of this License is to make a manual, textbook, or
-      other written document <quote>free</quote> in the sense of
-      freedom: to assure everyone the effective freedom to copy and
-      redistribute it, with or without modifying it, either
-      commercially or noncommercially. Secondarily, this License
-      preserves for the author and publisher a way to get credit for
-      their work, while not being considered responsible for
-      modifications made by others.
-    </para>
-
-    <para>
-      This License is a kind of <quote>copyleft</quote>, which means
-      that derivative works of the document must themselves be free in
-      the same sense. It complements the GNU General Public License,
-      which is a copyleft license designed for free software.
-    </para>
-
-    <para>
-      We have designed this License in order to use it for manuals for
-      free software, because free software needs free documentation: a
-      free program should come with manuals providing the same
-      freedoms that the software does. But this License is not limited
-      to software manuals; it can be used for any textual work,
-      regardless of subject matter or whether it is published as a
-      printed book. We recommend this License principally for works
-      whose purpose is instruction or reference.
-    </para>
-  </sect1>
-  <sect1 id="fdl-section1">
-    <title>1. APPLICABILITY AND DEFINITIONS</title>
-    <para id="fdl-document">
-      This License applies to any manual or other work that contains a
-      notice placed by the copyright holder saying it can be
-      distributed under the terms of this License. The
-      <quote>Document</quote>, below, refers to any such manual or
-      work. Any member of the public is a licensee, and is addressed
-      as <quote>you</quote>.
-    </para>
-
-    <para id="fdl-modified">
-      A <quote>Modified Version</quote> of the Document means any work
-      containing the Document or a portion of it, either copied
-      verbatim, or with modifications and/or translated into another
-      language.
-    </para>
-
-    <para id="fdl-secondary">
-      A <quote>Secondary Section</quote> is a named appendix or a
-      front-matter section of the <link
-      linkend="fdl-document">Document</link> that deals exclusively
-      with the relationship of the publishers or authors of the
-      Document to the Document's overall subject (or to related
-      matters) and contains nothing that could fall directly within
-      that overall subject. (For example, if the Document is in part a
-      textbook of mathematics, a Secondary Section may not explain any
-      mathematics.)  The relationship could be a matter of historical
-      connection with the subject or with related matters, or of
-      legal, commercial, philosophical, ethical or political position
-      regarding them.
-    </para>
-
-    <para id="fdl-invariant">
-      The <quote>Invariant Sections</quote> are certain <link
-      linkend="fdl-secondary"> Secondary Sections</link> whose titles
-      are designated, as being those of Invariant Sections, in the
-      notice that says that the <link
-      linkend="fdl-document">Document</link> is released under this
-      License.
-    </para>
-
-    <para id="fdl-cover-texts">
-      The <quote>Cover Texts</quote> are certain short passages of
-      text that are listed, as Front-Cover Texts or Back-Cover Texts,
-      in the notice that says that the <link
-      linkend="fdl-document">Document</link> is released under this
-      License.
-    </para>
-
-    <para id="fdl-transparent">
-      A <quote>Transparent</quote> copy of the <link
-      linkend="fdl-document"> Document</link> means a machine-readable
-      copy, represented in a format whose specification is available
-      to the general public, whose contents can be viewed and edited
-      directly and straightforwardly with generic text editors or (for
-      images composed of pixels) generic paint programs or (for
-      drawings) some widely available drawing editor, and that is
-      suitable for input to text formatters or for automatic
-      translation to a variety of formats suitable for input to text
-      formatters. A copy made in an otherwise Transparent file format
-      whose markup has been designed to thwart or discourage
-      subsequent modification by readers is not Transparent.  A copy
-      that is not <quote>Transparent</quote> is called
-      <quote>Opaque</quote>.
-    </para>
-
-    <para>
-      Examples of suitable formats for Transparent copies include
-      plain ASCII without markup, Texinfo input format, LaTeX input
-      format, SGML or XML using a publicly available DTD, and
-      standard-conforming simple HTML designed for human
-      modification. Opaque formats include PostScript, PDF,
-      proprietary formats that can be read and edited only by
-      proprietary word processors, SGML or XML for which the DTD
-      and/or processing tools are not generally available, and the
-      machine-generated HTML produced by some word processors for
-      output purposes only.
-    </para>
-
-    <para id="fdl-title-page">
-      The <quote>Title Page</quote> means, for a printed book, the
-      title page itself, plus such following pages as are needed to
-      hold, legibly, the material this License requires to appear in
-      the title page. For works in formats which do not have any title
-      page as such, <quote>Title Page</quote> means the text near the
-      most prominent appearance of the work's title, preceding the
-      beginning of the body of the text.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-section2">
-    <title>2. VERBATIM COPYING</title>
-    <para>
-      You may copy and distribute the <link
-      linkend="fdl-document">Document</link> in any medium, either
-      commercially or noncommercially, provided that this License, the
-      copyright notices, and the license notice saying this License
-      applies to the Document are reproduced in all copies, and that
-      you add no other conditions whatsoever to those of this
-      License. You may not use technical measures to obstruct or
-      control the reading or further copying of the copies you make or
-      distribute. However, you may accept compensation in exchange for
-      copies. If you distribute a large enough number of copies you
-      must also follow the conditions in <link
-      linkend="fdl-section3">section 3</link>.
-    </para>
-
-    <para>
-      You may also lend copies, under the same conditions stated
-      above, and you may publicly display copies.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section3">
-    <title>3. COPYING IN QUANTITY</title>
-    <para>
-      If you publish printed copies of the <link
-      linkend="fdl-document">Document</link> numbering more than 100,
-      and the Document's license notice requires <link
-      linkend="fdl-cover-texts">Cover Texts</link>, you must enclose
-      the copies in covers that carry, clearly and legibly, all these
-      Cover Texts: Front-Cover Texts on the front cover, and
-      Back-Cover Texts on the back cover. Both covers must also
-      clearly and legibly identify you as the publisher of these
-      copies. The front cover must present the full title with all
-      words of the title equally prominent and visible. You may add
-      other material on the covers in addition. Copying with changes
-      limited to the covers, as long as they preserve the title of the
-      <link linkend="fdl-document">Document</link> and satisfy these
-      conditions, can be treated as verbatim copying in other
-      respects.
-    </para>
-
-    <para>
-      If the required texts for either cover are too voluminous to fit
-      legibly, you should put the first ones listed (as many as fit
-      reasonably) on the actual cover, and continue the rest onto
-      adjacent pages.
-    </para>
-
-    <para>
-      If you publish or distribute <link
-      linkend="fdl-transparent">Opaque</link> copies of the <link
-      linkend="fdl-document">Document</link> numbering more than 100,
-      you must either include a machine-readable <link
-      linkend="fdl-transparent">Transparent</link> copy along with
-      each Opaque copy, or state in or with each Opaque copy a
-      publicly-accessible computer-network location containing a
-      complete Transparent copy of the Document, free of added
-      material, which the general network-using public has access to
-      download anonymously at no charge using public-standard network
-      protocols. If you use the latter option, you must take
-      reasonably prudent steps, when you begin distribution of Opaque
-      copies in quantity, to ensure that this Transparent copy will
-      remain thus accessible at the stated location until at least one
-      year after the last time you distribute an Opaque copy (directly
-      or through your agents or retailers) of that edition to the
-      public.
-    </para>
-
-    <para>
-      It is requested, but not required, that you contact the authors
-      of the <link linkend="fdl-document">Document</link> well before
-      redistributing any large number of copies, to give them a chance
-      to provide you with an updated version of the Document.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section4">
-    <title>4. MODIFICATIONS</title>
-    <para>
-      You may copy and distribute a <link
-      linkend="fdl-modified">Modified Version</link> of the <link
-      linkend="fdl-document">Document</link> under the conditions of
-      sections <link linkend="fdl-section2">2</link> and <link
-      linkend="fdl-section3">3</link> above, provided that you release
-      the Modified Version under precisely this License, with the
-      Modified Version filling the role of the Document, thus
-      licensing distribution and modification of the Modified Version
-      to whoever possesses a copy of it. In addition, you must do
-      these things in the Modified Version:
-    </para>
-
-    <itemizedlist mark="opencircle">
-      <listitem>
-       <formalpara>
-         <title>A</title>
-         <para>
-           Use in the <link linkend="fdl-title-page">Title
-           Page</link> (and on the covers, if any) a title distinct
-           from that of the <link
-           linkend="fdl-document">Document</link>, and from those of
-           previous versions (which should, if there were any, be
-           listed in the History section of the Document). You may
-           use the same title as a previous version if the original
-           publisher of that version gives permission.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>B</title>
-         <para>
-           List on the <link linkend="fdl-title-page">Title
-           Page</link>, as authors, one or more persons or entities
-           responsible for authorship of the modifications in the
-           <link linkend="fdl-modified">Modified Version</link>,
-           together with at least five of the principal authors of
-           the <link linkend="fdl-document">Document</link> (all of
-           its principal authors, if it has less than five).
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>C</title>
-         <para>
-           State on the <link linkend="fdl-title-page">Title
-           Page</link> the name of the publisher of the <link
-           linkend="fdl-modified">Modified Version</link>, as the
-           publisher.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>D</title>
-         <para>
-           Preserve all the copyright notices of the <link
-           linkend="fdl-document">Document</link>.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>E</title>
-         <para>
-           Add an appropriate copyright notice for your modifications
-           adjacent to the other copyright notices.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>F</title>
-         <para>
-           Include, immediately after the copyright notices, a
-           license notice giving the public permission to use the
-           <link linkend="fdl-modified">Modified Version</link> under
-           the terms of this License, in the form shown in the
-           Addendum below.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>G</title>
-         <para>
-           Preserve in that license notice the full lists of <link
-           linkend="fdl-invariant"> Invariant Sections</link> and
-           required <link linkend="fdl-cover-texts">Cover
-           Texts</link> given in the <link
-           linkend="fdl-document">Document's</link> license notice.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>H</title>
-         <para>
-           Include an unaltered copy of this License.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>I</title>
-         <para>
-           Preserve the section entitled <quote>History</quote>, and
-           its title, and add to it an item stating at least the
-           title, year, new authors, and publisher of the <link
-           linkend="fdl-modified">Modified Version </link>as given on
-           the <link linkend="fdl-title-page">Title Page</link>.  If
-           there is no section entitled <quote>History</quote> in the
-           <link linkend="fdl-document">Document</link>, create one
-           stating the title, year, authors, and publisher of the
-           Document as given on its Title Page, then add an item
-           describing the Modified Version as stated in the previous
-           sentence.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>J</title>
-         <para>
-           Preserve the network location, if any, given in the <link
-           linkend="fdl-document">Document</link> for public access
-           to a <link linkend="fdl-transparent">Transparent</link>
-           copy of the Document, and likewise the network locations
-           given in the Document for previous versions it was based
-           on. These may be placed in the <quote>History</quote>
-           section.  You may omit a network location for a work that
-           was published at least four years before the Document
-           itself, or if the original publisher of the version it
-           refers to gives permission.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>K</title>
-         <para>
-           In any section entitled <quote>Acknowledgements</quote> or
-           <quote>Dedications</quote>, preserve the section's title,
-           and preserve in the section all the substance and tone of
-           each of the contributor acknowledgements and/or
-           dedications given therein.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>L</title>
-         <para>
-           Preserve all the <link linkend="fdl-invariant">Invariant
-           Sections</link> of the <link
-           linkend="fdl-document">Document</link>, unaltered in their
-           text and in their titles.  Section numbers or the
-           equivalent are not considered part of the section titles.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>M</title>
-         <para>
-           Delete any section entitled
-           <quote>Endorsements</quote>. Such a section may not be
-           included in the <link linkend="fdl-modified">Modified
-           Version</link>.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>N</title>
-         <para>
-           Do not retitle any existing section as
-           <quote>Endorsements</quote> or to conflict in title with
-           any <link linkend="fdl-invariant">Invariant
-           Section</link>.
-         </para>
-       </formalpara>
-      </listitem>
-    </itemizedlist>
-
-    <para>
-      If the <link linkend="fdl-modified">Modified Version</link>
-      includes new front-matter sections or appendices that qualify as
-      <link linkend="fdl-secondary">Secondary Sections</link> and
-      contain no material copied from the Document, you may at your
-      option designate some or all of these sections as invariant. To
-      do this, add their titles to the list of <link
-      linkend="fdl-invariant">Invariant Sections</link> in the
-      Modified Version's license notice.  These titles must be
-      distinct from any other section titles.
-    </para>
-
-    <para>
-      You may add a section entitled <quote>Endorsements</quote>,
-      provided it contains nothing but endorsements of your <link
-      linkend="fdl-modified">Modified Version</link> by various
-      parties--for example, statements of peer review or that the text
-      has been approved by an organization as the authoritative
-      definition of a standard.
-    </para>
-
-    <para>
-      You may add a passage of up to five words as a <link
-      linkend="fdl-cover-texts">Front-Cover Text</link>, and a passage
-      of up to 25 words as a <link
-      linkend="fdl-cover-texts">Back-Cover Text</link>, to the end of
-      the list of <link linkend="fdl-cover-texts">Cover Texts</link>
-      in the <link linkend="fdl-modified">Modified Version</link>.
-      Only one passage of Front-Cover Text and one of Back-Cover Text
-      may be added by (or through arrangements made by) any one
-      entity. If the <link linkend="fdl-document">Document</link>
-      already includes a cover text for the same cover, previously
-      added by you or by arrangement made by the same entity you are
-      acting on behalf of, you may not add another; but you may
-      replace the old one, on explicit permission from the previous
-      publisher that added the old one.
-    </para>
-
-    <para>
-      The author(s) and publisher(s) of the <link
-      linkend="fdl-document">Document</link> do not by this License
-      give permission to use their names for publicity for or to
-      assert or imply endorsement of any <link
-      linkend="fdl-modified">Modified Version </link>.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-section5">
-    <title>5. COMBINING DOCUMENTS</title>
-    <para>
-      You may combine the <link linkend="fdl-document">Document</link>
-      with other documents released under this License, under the
-      terms defined in <link linkend="fdl-section4">section 4</link>
-      above for modified versions, provided that you include in the
-      combination all of the <link linkend="fdl-invariant">Invariant
-      Sections</link> of all of the original documents, unmodified,
-      and list them all as Invariant Sections of your combined work in
-      its license notice.
-    </para>
-
-    <para>
-      The combined work need only contain one copy of this License,
-      and multiple identical <link linkend="fdl-invariant">Invariant
-      Sections</link> may be replaced with a single copy. If there are
-      multiple Invariant Sections with the same name but different
-      contents, make the title of each such section unique by adding
-      at the end of it, in parentheses, the name of the original
-      author or publisher of that section if known, or else a unique
-      number. Make the same adjustment to the section titles in the
-      list of Invariant Sections in the license notice of the combined
-      work.
-    </para>
-
-    <para>
-      In the combination, you must combine any sections entitled
-      <quote>History</quote> in the various original documents,
-      forming one section entitled <quote>History</quote>; likewise
-      combine any sections entitled <quote>Acknowledgements</quote>,
-      and any sections entitled <quote>Dedications</quote>.  You must
-      delete all sections entitled <quote>Endorsements.</quote>
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section6">
-    <title>6. COLLECTIONS OF DOCUMENTS</title>
-    <para>
-      You may make a collection consisting of the <link
-      linkend="fdl-document">Document</link> and other documents
-      released under this License, and replace the individual copies
-      of this License in the various documents with a single copy that
-      is included in the collection, provided that you follow the
-      rules of this License for verbatim copying of each of the
-      documents in all other respects.
-    </para>
-
-    <para>
-      You may extract a single document from such a collection, and
-      distribute it individually under this License, provided you
-      insert a copy of this License into the extracted document, and
-      follow this License in all other respects regarding verbatim
-      copying of that document.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section7">
-    <title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
-    <para>
-      A compilation of the <link
-      linkend="fdl-document">Document</link> or its derivatives with
-      other separate and independent documents or works, in or on a
-      volume of a storage or distribution medium, does not as a whole
-      count as a <link linkend="fdl-modified">Modified Version</link>
-      of the Document, provided no compilation copyright is claimed
-      for the compilation.  Such a compilation is called an
-      <quote>aggregate</quote>, and this License does not apply to the
-      other self-contained works thus compiled with the Document , on
-      account of their being thus compiled, if they are not themselves
-      derivative works of the Document.  If the <link
-      linkend="fdl-cover-texts">Cover Text</link> requirement of <link
-      linkend="fdl-section3">section 3</link> is applicable to these
-      copies of the Document, then if the Document is less than one
-      quarter of the entire aggregate, the Document's Cover Texts may
-      be placed on covers that surround only the Document within the
-      aggregate. Otherwise they must appear on covers around the whole
-      aggregate.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section8">
-    <title>8. TRANSLATION</title>
-    <para>
-      Translation is considered a kind of modification, so you may
-      distribute translations of the <link
-      linkend="fdl-document">Document</link> under the terms of <link
-      linkend="fdl-section4">section 4</link>. Replacing <link
-      linkend="fdl-invariant"> Invariant Sections</link> with
-      translations requires special permission from their copyright
-      holders, but you may include translations of some or all
-      Invariant Sections in addition to the original versions of these
-      Invariant Sections. You may include a translation of this
-      License provided that you also include the original English
-      version of this License. In case of a disagreement between the
-      translation and the original English version of this License,
-      the original English version will prevail.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section9">
-    <title>9. TERMINATION</title>
-    <para>
-      You may not copy, modify, sublicense, or distribute the <link
-      linkend="fdl-document">Document</link> except as expressly
-      provided for under this License. Any other attempt to copy,
-      modify, sublicense or distribute the Document is void, and will
-      automatically terminate your rights under this License. However,
-      parties who have received copies, or rights, from you under this
-      License will not have their licenses terminated so long as such
-      parties remain in full compliance.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section10">
-    <title>10. FUTURE REVISIONS OF THIS LICENSE</title>
-    <para>
-      The <ulink type="http"
-      url="http://www.gnu.org/fsf/fsf.html">Free Software
-      Foundation</ulink> may publish new, revised versions of the GNU
-      Free Documentation License from time to time. Such new versions
-      will be similar in spirit to the present version, but may differ
-      in detail to address new problems or concerns. See <ulink
-      type="http"
-      url="http://www.gnu.org/copyleft">http://www.gnu.org/copyleft/</ulink>.
-    </para>
-
-    <para>
-      Each version of the License is given a distinguishing version
-      number. If the <link linkend="fdl-document">Document</link>
-      specifies that a particular numbered version of this License
-      <quote>or any later version</quote> applies to it, you have the
-      option of following the terms and conditions either of that
-      specified version or of any later version that has been
-      published (not as a draft) by the Free Software Foundation. If
-      the Document does not specify a version number of this License,
-      you may choose any version ever published (not as a draft) by
-      the Free Software Foundation.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-using">
-    <title>Addendum</title>
-    <para>
-      To use this License in a document you have written, include a copy of
-      the License in the document and put the following copyright and
-      license notices just after the title page:
-    </para>
-
-    <blockquote>
-      <para>
-       Copyright &copy; YEAR YOUR NAME.
-      </para>
-      <para>
-       Permission is granted to copy, distribute and/or modify this
-       document under the terms of the GNU Free Documentation
-       License, Version 1.1 or any later version published by the
-       Free Software Foundation; with the <link
-       linkend="fdl-invariant">Invariant Sections</link> being LIST
-       THEIR TITLES, with the <link
-       linkend="fdl-cover-texts">Front-Cover Texts</link> being LIST,
-       and with the <link linkend="fdl-cover-texts">Back-Cover
-       Texts</link> being LIST.  A copy of the license is included in
-       the section entitled <quote>GNU Free Documentation
-       License</quote>.
-      </para>
-    </blockquote>
-
-    <para>
-      If you have no <link linkend="fdl-invariant">Invariant
-      Sections</link>, write <quote>with no Invariant Sections</quote>
-      instead of saying which ones are invariant.  If you have no
-      <link linkend="fdl-cover-texts">Front-Cover Texts</link>, write
-      <quote>no Front-Cover Texts</quote> instead of
-      <quote>Front-Cover Texts being LIST</quote>; likewise for <link
-      linkend="fdl-cover-texts">Back-Cover Texts</link>.
-    </para>
-
-    <para>
-      If your document contains nontrivial examples of program code,
-      we recommend releasing these examples in parallel under your
-      choice of free software license, such as the <ulink type="http"
-      url="http://www.gnu.org/copyleft/gpl.html"> GNU General Public
-      License</ulink>, to permit their use in free software.
-    </para>
-  </sect1>
-</appendix>
-
-
-
-
-
-
diff --git a/Documentation/DocBook/media/v4l/fieldseq_bt.pdf b/Documentation/DocBook/media/v4l/fieldseq_bt.pdf
deleted file mode 100644 (file)
index 26598b2..0000000
Binary files a/Documentation/DocBook/media/v4l/fieldseq_bt.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/fieldseq_tb.pdf b/Documentation/DocBook/media/v4l/fieldseq_tb.pdf
deleted file mode 100644 (file)
index 4965b22..0000000
Binary files a/Documentation/DocBook/media/v4l/fieldseq_tb.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/func-close.xml b/Documentation/DocBook/media/v4l/func-close.xml
deleted file mode 100644 (file)
index 232920d..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<refentry id="func-close">
-  <refmeta>
-    <refentrytitle>V4L2 close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-close</refname>
-    <refpurpose>Close a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Closes the device. Any I/O in progress is terminated and
-resources associated with the file descriptor are freed. However data
-format parameters, current input or output, control values or other
-properties remain unchanged.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>The function returns <returnvalue>0</returnvalue> on
-success, <returnvalue>-1</returnvalue> on failure and the
-<varname>errno</varname> is set appropriately. Possible error
-codes:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-ioctl.xml b/Documentation/DocBook/media/v4l/func-ioctl.xml
deleted file mode 100644 (file)
index 4394184..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<refentry id="func-ioctl">
-  <refmeta>
-    <refentrytitle>V4L2 ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-ioctl</refname>
-    <refpurpose>Program a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<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>V4L2 ioctl request code as defined in the <filename>videodev2.h</filename> header file, for example
-VIDIOC_QUERYCAP.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a function parameter, usually a structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <function>ioctl()</function> function is used to program
-V4L2 devices. The argument <parameter>fd</parameter> must be an open
-file descriptor. An ioctl <parameter>request</parameter> has encoded
-in it whether the argument is an input, output or read/write
-parameter, and the size of the argument <parameter>argp</parameter> in
-bytes. Macros and defines specifying V4L2 ioctl requests are located
-in the <filename>videodev2.h</filename> header file.
-Applications should use their own copy, not include the version in the
-kernel sources on the system they compile on. All V4L2 ioctl requests,
-their respective function and parameters are specified in <xref
-       linkend="user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-    <para>When an ioctl that takes an output or read/write parameter fails,
-    the parameter remains unmodified.</para>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-mmap.xml b/Documentation/DocBook/media/v4l/func-mmap.xml
deleted file mode 100644 (file)
index f31ad71..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-<refentry id="func-mmap">
-  <refmeta>
-    <refentrytitle>V4L2 mmap()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-mmap</refname>
-    <refpurpose>Map device memory into application address space</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;unistd.h&gt;
-#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>void *<function>mmap</function></funcdef>
-       <paramdef>void *<parameter>start</parameter></paramdef>
-       <paramdef>size_t <parameter>length</parameter></paramdef>
-       <paramdef>int <parameter>prot</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>off_t <parameter>offset</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-    <variablelist>
-      <varlistentry>
-       <term><parameter>start</parameter></term>
-       <listitem>
-         <para>Map the buffer to this address in the
-application's address space. When the <constant>MAP_FIXED</constant>
-flag is specified, <parameter>start</parameter> must be a multiple of the
-pagesize and mmap will fail when the specified address
-cannot be used. Use of this option is discouraged; applications should
-just specify a <constant>NULL</constant> pointer here.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>length</parameter></term>
-       <listitem>
-         <para>Length of the memory area to map. This must be the
-same value as returned by the driver in the &v4l2-buffer;
-<structfield>length</structfield> field for the
-single-planar API, and the same value as returned by the driver
-in the &v4l2-plane; <structfield>length</structfield> field for the
-multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>prot</parameter></term>
-       <listitem>
-         <para>The <parameter>prot</parameter> argument describes the
-desired memory protection. Regardless of the device type and the
-direction of data exchange it should be set to
-<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>,
-permitting read and write access to image buffers. Drivers should
-support at least this combination of flags. Note the Linux
-<filename>video-buf</filename> kernel module, which is used by the
-bttv, saa7134, saa7146, cx88 and vivi driver supports only
-<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>. When
-the driver does not support the desired protection the
-<function>mmap()</function> function fails.</para>
-         <para>Note device memory accesses (&eg; the memory on a
-graphics card with video capturing hardware) may incur a performance
-penalty compared to main memory accesses, or reads may be
-significantly slower than writes or vice versa. Other I/O methods may
-be more efficient in this case.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>The <parameter>flags</parameter> parameter
-specifies the type of the mapped object, mapping options and whether
-modifications made to the mapped copy of the page are private to the
-process or are to be shared with other references.</para>
-         <para><constant>MAP_FIXED</constant> requests that the
-driver selects no other address than the one specified. If the
-specified address cannot be used, <function>mmap()</function> will fail. If
-<constant>MAP_FIXED</constant> is specified,
-<parameter>start</parameter> must be a multiple of the pagesize. Use
-of this option is discouraged.</para>
-         <para>One of the <constant>MAP_SHARED</constant> or
-<constant>MAP_PRIVATE</constant> flags must be set.
-<constant>MAP_SHARED</constant> allows applications to share the
-mapped memory with other (&eg; child-) processes. Note the Linux
-<filename>video-buf</filename> module which is used by the bttv,
-saa7134, saa7146, cx88 and vivi driver supports only
-<constant>MAP_SHARED</constant>. <constant>MAP_PRIVATE</constant>
-requests copy-on-write semantics. V4L2 applications should not set the
-<constant>MAP_PRIVATE</constant>, <constant>MAP_DENYWRITE</constant>,
-<constant>MAP_EXECUTABLE</constant> or <constant>MAP_ANON</constant>
-flag.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>offset</parameter></term>
-       <listitem>
-         <para>Offset of the buffer in device memory. This must be the
-same value as returned by the driver in the &v4l2-buffer;
-<structfield>m</structfield> union <structfield>offset</structfield> field for
-the single-planar API, and the same value as returned by the driver
-in the &v4l2-plane; <structfield>m</structfield> union
-<structfield>mem_offset</structfield> field for the multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <function>mmap()</function> function asks to map
-<parameter>length</parameter> bytes starting at
-<parameter>offset</parameter> in the memory of the device specified by
-<parameter>fd</parameter> into the application address space,
-preferably at address <parameter>start</parameter>. This latter
-address is a hint only, and is usually specified as 0.</para>
-
-    <para>Suitable length and offset parameters are queried with the
-&VIDIOC-QUERYBUF; ioctl. Buffers must be allocated with the
-&VIDIOC-REQBUFS; ioctl before they can be queried.</para>
-
-    <para>To unmap buffers the &func-munmap; function is used.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>mmap()</function> returns a pointer to
-the mapped buffer. On error <constant>MAP_FAILED</constant> (-1) is
-returned, and the <varname>errno</varname> variable is set
-appropriately. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is
-not open for reading and writing.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>start</parameter> or
-<parameter>length</parameter> or <parameter>offset</parameter> are not
-suitable. (E.&nbsp;g. they are too large, or not aligned on a
-<constant>PAGESIZE</constant> boundary.)</para>
-         <para>The <parameter>flags</parameter> or
-<parameter>prot</parameter> value is not supported.</para>
-         <para>No buffers have been allocated with the
-&VIDIOC-REQBUFS; ioctl.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-complete the request.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-munmap.xml b/Documentation/DocBook/media/v4l/func-munmap.xml
deleted file mode 100644 (file)
index 860d49c..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<refentry id="func-munmap">
-  <refmeta>
-    <refentrytitle>V4L2 munmap()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-munmap</refname>
-    <refpurpose>Unmap device memory</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;unistd.h&gt;
-#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>munmap</function></funcdef>
-       <paramdef>void *<parameter>start</parameter></paramdef>
-       <paramdef>size_t <parameter>length</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>Arguments</title>
-    <variablelist>
-      <varlistentry>
-       <term><parameter>start</parameter></term>
-       <listitem>
-         <para>Address of the mapped buffer as returned by the
-&func-mmap; function.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>length</parameter></term>
-       <listitem>
-         <para>Length of the mapped buffer. This must be the same
-value as given to <function>mmap()</function> and returned by the
-driver in the &v4l2-buffer; <structfield>length</structfield>
-field for the single-planar API and in the &v4l2-plane;
-<structfield>length</structfield> field for the multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Unmaps a previously with the &func-mmap; function mapped
-buffer and frees it, if possible. <!-- ? This function (not freeing)
-has no impact on I/O in progress, specifically it does not imply
-&VIDIOC-STREAMOFF; to terminate I/O. Unmapped buffers can still be
-enqueued, dequeued or queried, they are just not accessible by the
-application.--></para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>munmap()</function> returns 0, on
-failure -1 and the <varname>errno</varname> variable is set
-appropriately:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>start</parameter> or
-<parameter>length</parameter> is incorrect, or no buffers have been
-mapped yet.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-open.xml b/Documentation/DocBook/media/v4l/func-open.xml
deleted file mode 100644 (file)
index cf64e20..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<refentry id="func-open">
-  <refmeta>
-    <refentrytitle>V4L2 open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-open</refname>
-    <refpurpose>Open a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access mode must be
-<constant>O_RDWR</constant>. This is just a technicality, input devices
-still support only reading and output devices only writing.</para>
-         <para>When the <constant>O_NONBLOCK</constant> flag is
-given, the read() function and the &VIDIOC-DQBUF; ioctl will return
-the &EAGAIN; when no data is available or no buffer is in the driver
-outgoing queue, otherwise these functions block until data becomes
-available. All V4L2 drivers exchanging data with applications must
-support the <constant>O_NONBLOCK</constant> flag.</para>
-         <para>Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-
-    <para>To open a V4L2 device applications call
-<function>open()</function> with the desired device name. This
-function has no side effects; all data format parameters, current
-input or output, control values or other properties remain unchanged.
-At the first <function>open()</function> call after loading the driver
-they will be reset to default values, drivers are never in an
-undefined state.</para>
-  </refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>open</function> returns the new file
-descriptor. On error -1 is returned, and the <varname>errno</varname>
-variable is set appropriately. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The caller has no permission to access the
-device.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple opens and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file
-exists.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough kernel memory was available to complete the
-request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of
-files open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The limit on the total number of files open on the
-system has been reached.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-poll.xml b/Documentation/DocBook/media/v4l/func-poll.xml
deleted file mode 100644 (file)
index 4c73f11..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-<refentry id="func-poll">
-  <refmeta>
-    <refentrytitle>V4L2 poll()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-poll</refname>
-    <refpurpose>Wait for some event on a file descriptor</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/poll.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>poll</function></funcdef>
-       <paramdef>struct pollfd *<parameter>ufds</parameter></paramdef>
-       <paramdef>unsigned int <parameter>nfds</parameter></paramdef>
-       <paramdef>int <parameter>timeout</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>With the <function>poll()</function> function applications
-can suspend execution until the driver has captured data or is ready
-to accept data for output.</para>
-
-    <para>When streaming I/O has been negotiated this function waits
-until a buffer has been filled by the capture device and can be dequeued
-with the &VIDIOC-DQBUF; ioctl. For output devices this function waits
-until the device is ready to accept a new buffer to be queued up with
-the &VIDIOC-QBUF; ioctl for display. When buffers are already in the outgoing
-queue of the driver (capture) or the incoming queue isn't full (display)
-the function returns immediately.</para>
-
-    <para>On success <function>poll()</function> returns the number of
-file descriptors that have been selected (that is, file descriptors
-for which the <structfield>revents</structfield> field of the
-respective <structname>pollfd</structname> structure is non-zero).
-Capture devices set the <constant>POLLIN</constant> and
-<constant>POLLRDNORM</constant> flags in the
-<structfield>revents</structfield> field, output devices the
-<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant>
-flags. When the function timed out it returns a value of zero, on
-failure it returns <returnvalue>-1</returnvalue> and the
-<varname>errno</varname> variable is set appropriately. When the
-application did not call &VIDIOC-STREAMON; the
-<function>poll()</function> function succeeds, but sets the
-<constant>POLLERR</constant> flag in the
-<structfield>revents</structfield> field. When the
-application has called &VIDIOC-STREAMON; for a capture device but hasn't
-yet called &VIDIOC-QBUF;, the <function>poll()</function> function
-succeeds and sets the <constant>POLLERR</constant> flag in the
-<structfield>revents</structfield> field. For output devices this
-same situation will cause <function>poll()</function> to succeed
-as well, but it sets the <constant>POLLOUT</constant> and
-<constant>POLLWRNORM</constant> flags in the <structfield>revents</structfield>
-field.</para>
-
-    <para>If an event occurred (see &VIDIOC-DQEVENT;) then
-<constant>POLLPRI</constant> will be set in the <structfield>revents</structfield>
-field and <function>poll()</function> will return.</para>
-
-    <para>When use of the <function>read()</function> function has
-been negotiated and the driver does not capture yet, the
-<function>poll</function> function starts capturing. When that fails
-it returns a <constant>POLLERR</constant> as above. Otherwise it waits
-until data has been captured and can be read. When the driver captures
-continuously (as opposed to, for example, still images) the function
-may return immediately.</para>
-
-    <para>When use of the <function>write()</function> function has
-been negotiated and the driver does not stream yet, the
-<function>poll</function> function starts streaming. When that fails
-it returns a <constant>POLLERR</constant> as above. Otherwise it waits
-until the driver is ready for a non-blocking
-<function>write()</function> call.</para>
-
-    <para>If the caller is only interested in events (just
-<constant>POLLPRI</constant> is set in the <structfield>events</structfield>
-field), then <function>poll()</function> will <emphasis>not</emphasis>
-start streaming if the driver does not stream yet. This makes it
-possible to just poll for events and not for buffers.</para>
-
-    <para>All drivers implementing the <function>read()</function> or
-<function>write()</function> function or streaming I/O must also
-support the <function>poll()</function> function.</para>
-
-    <para>For more details see the
-<function>poll()</function> manual page.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, <function>poll()</function> returns the number
-structures which have non-zero <structfield>revents</structfield>
-fields, or zero if the call timed out. On error
-<returnvalue>-1</returnvalue> is returned, and the
-<varname>errno</varname> variable is set appropriately:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para>One or more of the <parameter>ufds</parameter> members
-specify an invalid file descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read or write
-streams and the device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>ufds</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>nfds</parameter> argument is greater
-than <constant>OPEN_MAX</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-read.xml b/Documentation/DocBook/media/v4l/func-read.xml
deleted file mode 100644 (file)
index e218bbf..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-<refentry id="func-read">
-  <refmeta>
-    <refentrytitle>V4L2 read()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-read</refname>
-    <refpurpose>Read from a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>ssize_t <function>read</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>void *<parameter>buf</parameter></paramdef>
-       <paramdef>size_t <parameter>count</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>buf</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>count</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para><function>read()</function> attempts to read up to
-<parameter>count</parameter> bytes from file descriptor
-<parameter>fd</parameter> into the buffer starting at
-<parameter>buf</parameter>. The layout of the data in the buffer is
-discussed in the respective device interface section, see ##. If <parameter>count</parameter> is zero,
-<function>read()</function> returns zero and has no other results. If
-<parameter>count</parameter> is greater than
-<constant>SSIZE_MAX</constant>, the result is unspecified. Regardless
-of the <parameter>count</parameter> value each
-<function>read()</function> call will provide at most one frame (two
-fields) worth of data.</para>
-
-    <para>By default <function>read()</function> blocks until data
-becomes available. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function it
-returns immediately with an &EAGAIN; when no data is available. The
-&func-select; or &func-poll; functions
-can always be used to suspend execution until data becomes available. All
-drivers supporting the <function>read()</function> function must also
-support <function>select()</function> and
-<function>poll()</function>.</para>
-
-    <para>Drivers can implement read functionality in different
-ways, using a single or multiple buffers and discarding the oldest or
-newest frames once the internal buffers are filled.</para>
-
-    <para><function>read()</function> never returns a "snapshot" of a
-buffer being filled. Using a single buffer the driver will stop
-capturing when the application starts reading the buffer until the
-read is finished. Thus only the period of the vertical blanking
-interval is available for reading, or the capture rate must fall below
-the nominal frame rate of the video standard.</para>
-
-<para>The behavior of
-<function>read()</function> when called during the active picture
-period or the vertical blanking separating the top and bottom field
-depends on the discarding policy. A driver discarding the oldest
-frames keeps capturing into an internal buffer, continuously
-overwriting the previously, not read frame, and returns the frame
-being received at the time of the <function>read()</function> call as
-soon as it is complete.</para>
-
-    <para>A driver discarding the newest frames stops capturing until
-the next <function>read()</function> call. The frame being received at
-<function>read()</function> time is discarded, returning the following
-frame instead. Again this implies a reduction of the capture rate to
-one half or less of the nominal frame rate. An example of this model
-is the video read mode of the bttv driver, initiating a DMA to user
-memory when <function>read()</function> is called and returning when
-the DMA finished.</para>
-
-    <para>In the multiple buffer model drivers maintain a ring of
-internal buffers, automatically advancing to the next free buffer.
-This allows continuous capturing when the application can empty the
-buffers fast enough. Again, the behavior when the driver runs out of
-free buffers depends on the discarding policy.</para>
-
-    <para>Applications can get and set the number of buffers used
-internally by the driver with the &VIDIOC-G-PARM; and &VIDIOC-S-PARM;
-ioctls. They are optional, however. The discarding policy is not
-reported and cannot be changed. For minimum requirements see <xref
-       linkend="devices" />.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, the number of bytes read is returned. It is not
-an error if this number is smaller than the number of bytes requested,
-or the amount of data required for one frame. This may happen for
-example because <function>read()</function> was interrupted by a
-signal. On error, -1 is returned, and the <varname>errno</varname>
-variable is set appropriately. In this case the next read will start
-at the beginning of a new frame. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using
-O_NONBLOCK and no data was immediately available for reading.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor or is not open for reading, or the process already has the
-maximum number of files open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read streams and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>buf</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal before any
-data was read.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para>I/O error. This indicates some hardware problem or a
-failure to communicate with a remote device (USB camera etc.).</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <function>read()</function> function is not
-supported by this driver, not on this device, or generally not on this
-type of device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-select.xml b/Documentation/DocBook/media/v4l/func-select.xml
deleted file mode 100644 (file)
index e12a60d..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<refentry id="func-select">
-  <refmeta>
-    <refentrytitle>V4L2 select()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-select</refname>
-    <refpurpose>Synchronous I/O multiplexing</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;sys/time.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>select</function></funcdef>
-       <paramdef>int <parameter>nfds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>readfds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>writefds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>exceptfds</parameter></paramdef>
-       <paramdef>struct timeval *<parameter>timeout</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>With the <function>select()</function> function applications
-can suspend execution until the driver has captured data or is ready
-to accept data for output.</para>
-
-    <para>When streaming I/O has been negotiated this function waits
-until a buffer has been filled or displayed and can be dequeued with
-the &VIDIOC-DQBUF; ioctl. When buffers are already in the outgoing
-queue of the driver the function returns immediately.</para>
-
-    <para>On success <function>select()</function> returns the total
-number of bits set in the <structname>fd_set</structname>s. When the
-function timed out it returns a value of zero. On failure it returns
-<returnvalue>-1</returnvalue> and the <varname>errno</varname>
-variable is set appropriately. When the application did not call
-&VIDIOC-QBUF; or &VIDIOC-STREAMON; yet the
-<function>select()</function> function succeeds, setting the bit of
-the file descriptor in <parameter>readfds</parameter> or
-<parameter>writefds</parameter>, but subsequent &VIDIOC-DQBUF; calls
-will fail.<footnote><para>The Linux kernel implements
-<function>select()</function> like the &func-poll; function, but
-<function>select()</function> cannot return a
-<constant>POLLERR</constant>.</para>
-      </footnote></para>
-
-    <para>When use of the <function>read()</function> function has
-been negotiated and the driver does not capture yet, the
-<function>select()</function> function starts capturing. When that
-fails, <function>select()</function> returns successful and a
-subsequent <function>read()</function> call, which also attempts to
-start capturing, will return an appropriate error code. When the
-driver captures continuously (as opposed to, for example, still
-images) and data is already available the
-<function>select()</function> function returns immediately.</para>
-
-    <para>When use of the <function>write()</function> function has
-been negotiated the <function>select()</function> function just waits
-until the driver is ready for a non-blocking
-<function>write()</function> call.</para>
-
-    <para>All drivers implementing the <function>read()</function> or
-<function>write()</function> function or streaming I/O must also
-support the <function>select()</function> function.</para>
-
-    <para>For more details see the <function>select()</function>
-manual page.</para>
-
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, <function>select()</function> returns the number
-of descriptors contained in the three returned descriptor sets, which
-will be zero if the timeout expired. On error
-<returnvalue>-1</returnvalue> is returned, and the
-<varname>errno</varname> variable is set appropriately; the sets and
-<parameter>timeout</parameter> are undefined. Possible error codes
-are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para>One or more of the file descriptor sets specified a
-file descriptor that is not open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read or write
-streams and the device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para>The <parameter>readfds</parameter>,
-<parameter>writefds</parameter>, <parameter>exceptfds</parameter> or
-<parameter>timeout</parameter> pointer references an inaccessible memory
-area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>nfds</parameter> argument is less than
-zero or greater than <constant>FD_SETSIZE</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/func-write.xml b/Documentation/DocBook/media/v4l/func-write.xml
deleted file mode 100644 (file)
index 5752078..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<refentry id="func-write">
-  <refmeta>
-    <refentrytitle>V4L2 write()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-write</refname>
-    <refpurpose>Write to a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>ssize_t <function>write</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>void *<parameter>buf</parameter></paramdef>
-       <paramdef>size_t <parameter>count</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>buf</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>count</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para><function>write()</function> writes up to
-<parameter>count</parameter> bytes to the device referenced by the
-file descriptor <parameter>fd</parameter> from the buffer starting at
-<parameter>buf</parameter>. When the hardware outputs are not active
-yet, this function enables them. When <parameter>count</parameter> is
-zero, <function>write()</function> returns
-<returnvalue>0</returnvalue> without any other effect.</para>
-
-    <para>When the application does not provide more data in time, the
-previous video frame, raw VBI image, sliced VPS or WSS data is
-displayed again. Sliced Teletext or Closed Caption data is not
-repeated, the driver inserts a blank line instead.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, the number of bytes written are returned. Zero
-indicates nothing was written. On error, <returnvalue>-1</returnvalue>
-is returned, and the <varname>errno</varname> variable is set
-appropriately. In this case the next write will start at the beginning
-of a new frame. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using the <link
-linkend="func-open"><constant>O_NONBLOCK</constant></link> flag and no
-buffer space was available to write the data immediately.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor or is not open for writing.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple write streams and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>buf</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal before any
-data was written.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para>I/O error. This indicates some hardware problem.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <function>write()</function> function is not
-supported by this driver, not on this device, or generally not on this
-type of device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/gen-errors.xml b/Documentation/DocBook/media/v4l/gen-errors.xml
deleted file mode 100644 (file)
index 7e29a4e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-<title>Generic Error Codes</title>
-
-<table frame="none" pgwide="1" id="gen-errors">
-  <title>Generic error codes</title>
-  <tgroup cols="2">
-    &cs-str;
-    <tbody valign="top">
-       <!-- Keep it ordered alphabetically -->
-      <row>
-       <entry>EAGAIN (aka EWOULDBLOCK)</entry>
-       <entry>The ioctl can't be handled because the device is in state where
-              it can't perform it. This could happen for example in case where
-              device is sleeping and ioctl is performed to query statistics.
-              It is also returned when the ioctl would need to wait
-              for an event, but the device was opened in non-blocking mode.
-       </entry>
-      </row>
-      <row>
-       <entry>EBADF</entry>
-       <entry>The file descriptor is not a valid.</entry>
-      </row>
-      <row>
-       <entry>EBUSY</entry>
-       <entry>The ioctl can't be handled because the device is busy. This is
-              typically return while device is streaming, and an ioctl tried to
-              change something that would affect the stream, or would require the
-              usage of a hardware resource that was already allocated. The ioctl
-              must not be retried without performing another action to fix the
-              problem first (typically: stop the stream before retrying).</entry>
-      </row>
-      <row>
-       <entry>EFAULT</entry>
-       <entry>There was a failure while copying data from/to userspace,
-              probably caused by an invalid pointer reference.</entry>
-      </row>
-      <row>
-       <entry>EINVAL</entry>
-       <entry>One or more of the ioctl parameters are invalid or out of the
-              allowed range. This is a widely used error code. See the individual
-              ioctl requests for specific causes.</entry>
-      </row>
-      <row>
-        <entry>ENODEV</entry>
-       <entry>Device not found or was removed.</entry>
-      </row>
-      <row>
-       <entry>ENOMEM</entry>
-       <entry>There's not enough memory to handle the desired operation.</entry>
-      </row>
-      <row>
-       <entry>ENOTTY</entry>
-       <entry>The ioctl is not supported by the driver, actually meaning that
-              the required functionality is not available, or the file
-              descriptor is not for a media device.</entry>
-      </row>
-      <row>
-       <entry>ENOSPC</entry>
-       <entry>On USB devices, the stream ioctl's can return this error, meaning
-              that this request would overcommit the usb bandwidth reserved
-              for periodic transfers (up to 80% of the USB bandwidth).</entry>
-      </row>
-      <row>
-       <entry>EPERM</entry>
-       <entry>Permission denied. Can be returned if the device needs write
-               permission, or some special capabilities is needed
-               (e. g. root)</entry>
-      </row>
-    </tbody>
-  </tgroup>
-</table>
-
-<para>Note 1: ioctls may return other error codes. Since errors may have side
-effects such as a driver reset, applications should abort on unexpected errors.
-</para>
-
-<para>Note 2: Request-specific error codes are listed in the individual
-requests descriptions.</para>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
deleted file mode 100644 (file)
index 21a3dde..0000000
+++ /dev/null
@@ -1,1545 +0,0 @@
-  <title>Input/Output</title>
-
-  <para>The V4L2 API defines several different methods to read from or
-write to a device. All drivers exchanging data with applications must
-support at least one of them.</para>
-
-  <para>The classic I/O method using the <function>read()</function>
-and <function>write()</function> function is automatically selected
-after opening a V4L2 device. When the driver does not support this
-method attempts to read or write will fail at any time.</para>
-
-  <para>Other methods must be negotiated. To select the streaming I/O
-method with memory mapped or user buffers applications call the
-&VIDIOC-REQBUFS; ioctl. The asynchronous I/O method is not defined
-yet.</para>
-
-  <para>Video overlay can be considered another I/O method, although
-the application does not directly receive the image data. It is
-selected by initiating video overlay with the &VIDIOC-S-FMT; ioctl.
-For more information see <xref linkend="overlay" />.</para>
-
-  <para>Generally exactly one I/O method, including overlay, is
-associated with each file descriptor. The only exceptions are
-applications not exchanging data with a driver ("panel applications",
-see <xref linkend="open" />) and drivers permitting simultaneous video capturing
-and overlay using the same file descriptor, for compatibility with V4L
-and earlier versions of V4L2.</para>
-
-  <para><constant>VIDIOC_S_FMT</constant> and
-<constant>VIDIOC_REQBUFS</constant> would permit this to some degree,
-but for simplicity drivers need not support switching the I/O method
-(after first switching away from read/write) other than by closing
-and reopening the device.</para>
-
-  <para>The following sections describe the various I/O methods in
-more detail.</para>
-
-  <section id="rw">
-    <title>Read/Write</title>
-
-    <para>Input and output devices support the
-<function>read()</function> and <function>write()</function> function,
-respectively, when the <constant>V4L2_CAP_READWRITE</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set.</para>
-
-    <para>Drivers may need the CPU to copy the data, but they may also
-support DMA to or from user memory, so this I/O method is not
-necessarily less efficient than other methods merely exchanging buffer
-pointers. It is considered inferior though because no meta-information
-like frame counters or timestamps are passed. This information is
-necessary to recognize frame dropping and to synchronize with other
-data streams. However this is also the simplest I/O method, requiring
-little or no setup to exchange data. It permits command line stunts
-like this (the <application>vidctrl</application> tool is
-fictitious):</para>
-
-    <informalexample>
-      <screen>
-&gt; vidctrl /dev/video --input=0 --format=YUYV --size=352x288
-&gt; dd if=/dev/video of=myimage.422 bs=202752 count=1
-</screen>
-    </informalexample>
-
-    <para>To read from the device applications use the
-&func-read; function, to write the &func-write; function.
-Drivers must implement one I/O method if they
-exchange data with applications, but it need not be this.<footnote>
-       <para>It would be desirable if applications could depend on
-drivers supporting all I/O interfaces, but as much as the complex
-memory mapping I/O can be inadequate for some devices we have no
-reason to require this interface, which is most useful for simple
-applications capturing still images.</para>
-      </footnote> When reading or writing is supported, the driver
-must also support the &func-select; and &func-poll;
-function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional.</para>
-      </footnote></para>
-  </section>
-
-  <section id="mmap">
-    <title>Streaming I/O (Memory Mapping)</title>
-
-    <para>Input and output devices support this I/O method when the
-<constant>V4L2_CAP_STREAMING</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two
-streaming methods, to determine if the memory mapping flavor is
-supported applications must call the &VIDIOC-REQBUFS; ioctl with the memory type set to <constant>V4L2_MEMORY_MMAP</constant>.</para>
-
-    <para>Streaming is an I/O method where only pointers to buffers
-are exchanged between application and driver, the data itself is not
-copied. Memory mapping is primarily intended to map buffers in device
-memory into the application's address space. Device memory can be for
-example the video memory on a graphics card with a video capture
-add-on. However, being the most efficient I/O method available for a
-long time, many other drivers support streaming as well, allocating
-buffers in DMA-able main memory.</para>
-
-    <para>A driver can support many sets of buffers. Each set is
-identified by a unique buffer type value. The sets are independent and
-each set can hold a different type of data. To access different sets
-at the same time different file descriptors must be used.<footnote>
-       <para>One could use one file descriptor and set the buffer
-type field accordingly when calling &VIDIOC-QBUF; etc., but it makes
-the <function>select()</function> function ambiguous. We also like the
-clean approach of one file descriptor per logical stream. Video
-overlay for example is also a logical stream, although the CPU is not
-needed for continuous operation.</para>
-      </footnote></para>
-
-    <para>To allocate device buffers applications call the
-&VIDIOC-REQBUFS; ioctl with the desired number of buffers and buffer
-type, for example <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.
-This ioctl can also be used to change the number of buffers or to free
-the allocated memory, provided none of the buffers are still
-mapped.</para>
-
-    <para>Before applications can access the buffers they must map
-them into their address space with the &func-mmap; function. The
-location of the buffers in device memory can be determined with the
-&VIDIOC-QUERYBUF; ioctl. In the single-planar API case, the
-<structfield>m.offset</structfield> and <structfield>length</structfield>
-returned in a &v4l2-buffer; are passed as sixth and second parameter to the
-<function>mmap()</function> function. When using the multi-planar API,
-&v4l2-buffer; contains an array of &v4l2-plane; structures, each
-containing its own <structfield>m.offset</structfield> and
-<structfield>length</structfield>. When using the multi-planar API, every
-plane of every buffer has to be mapped separately, so the number of
-calls to &func-mmap; should be equal to number of buffers times number of
-planes in each buffer. The offset and length values must not be modified.
-Remember, the buffers are allocated in physical memory, as opposed to virtual
-memory, which can be swapped out to disk. Applications should free the buffers
-as soon as possible with the &func-munmap; function.</para>
-
-    <example>
-      <title>Mapping buffers in the single-planar API</title>
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-struct {
-       void *start;
-       size_t length;
-} *buffers;
-unsigned int i;
-
-memset(&amp;reqbuf, 0, sizeof(reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-reqbuf.memory = V4L2_MEMORY_MMAP;
-reqbuf.count = 20;
-
-if (-1 == ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf)) {
-       if (errno == EINVAL)
-               printf("Video capturing or mmap-streaming is not supported\n");
-       else
-               perror("VIDIOC_REQBUFS");
-
-       exit(EXIT_FAILURE);
-}
-
-/* We want at least five buffers. */
-
-if (reqbuf.count &lt; 5) {
-       /* You may need to free the buffers here. */
-       printf("Not enough buffer memory\n");
-       exit(EXIT_FAILURE);
-}
-
-buffers = calloc(reqbuf.count, sizeof(*buffers));
-assert(buffers != NULL);
-
-for (i = 0; i &lt; reqbuf.count; i++) {
-       &v4l2-buffer; buffer;
-
-       memset(&amp;buffer, 0, sizeof(buffer));
-       buffer.type = reqbuf.type;
-       buffer.memory = V4L2_MEMORY_MMAP;
-       buffer.index = i;
-
-       if (-1 == ioctl (fd, &VIDIOC-QUERYBUF;, &amp;buffer)) {
-               perror("VIDIOC_QUERYBUF");
-               exit(EXIT_FAILURE);
-       }
-
-       buffers[i].length = buffer.length; /* remember for munmap() */
-
-       buffers[i].start = mmap(NULL, buffer.length,
-                               PROT_READ | PROT_WRITE, /* recommended */
-                               MAP_SHARED,             /* recommended */
-                               fd, buffer.m.offset);
-
-       if (MAP_FAILED == buffers[i].start) {
-               /* If you do not exit here you should unmap() and free()
-                  the buffers mapped so far. */
-               perror("mmap");
-               exit(EXIT_FAILURE);
-       }
-}
-
-/* Cleanup. */
-
-for (i = 0; i &lt; reqbuf.count; i++)
-       munmap(buffers[i].start, buffers[i].length);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Mapping buffers in the multi-planar API</title>
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-/* Our current format uses 3 planes per buffer */
-#define FMT_NUM_PLANES = 3
-
-struct {
-       void *start[FMT_NUM_PLANES];
-       size_t length[FMT_NUM_PLANES];
-} *buffers;
-unsigned int i, j;
-
-memset(&amp;reqbuf, 0, sizeof(reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-reqbuf.memory = V4L2_MEMORY_MMAP;
-reqbuf.count = 20;
-
-if (ioctl(fd, &VIDIOC-REQBUFS;, &amp;reqbuf) &lt; 0) {
-       if (errno == EINVAL)
-               printf("Video capturing or mmap-streaming is not supported\n");
-       else
-               perror("VIDIOC_REQBUFS");
-
-       exit(EXIT_FAILURE);
-}
-
-/* We want at least five buffers. */
-
-if (reqbuf.count &lt; 5) {
-       /* You may need to free the buffers here. */
-       printf("Not enough buffer memory\n");
-       exit(EXIT_FAILURE);
-}
-
-buffers = calloc(reqbuf.count, sizeof(*buffers));
-assert(buffers != NULL);
-
-for (i = 0; i &lt; reqbuf.count; i++) {
-       &v4l2-buffer; buffer;
-       &v4l2-plane; planes[FMT_NUM_PLANES];
-
-       memset(&amp;buffer, 0, sizeof(buffer));
-       buffer.type = reqbuf.type;
-       buffer.memory = V4L2_MEMORY_MMAP;
-       buffer.index = i;
-       /* length in struct v4l2_buffer in multi-planar API stores the size
-        * of planes array. */
-       buffer.length = FMT_NUM_PLANES;
-       buffer.m.planes = planes;
-
-       if (ioctl(fd, &VIDIOC-QUERYBUF;, &amp;buffer) &lt; 0) {
-               perror("VIDIOC_QUERYBUF");
-               exit(EXIT_FAILURE);
-       }
-
-       /* Every plane has to be mapped separately */
-       for (j = 0; j &lt; FMT_NUM_PLANES; j++) {
-               buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
-
-               buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
-                                PROT_READ | PROT_WRITE, /* recommended */
-                                MAP_SHARED,             /* recommended */
-                                fd, buffer.m.planes[j].m.offset);
-
-               if (MAP_FAILED == buffers[i].start[j]) {
-                       /* If you do not exit here you should unmap() and free()
-                          the buffers and planes mapped so far. */
-                       perror("mmap");
-                       exit(EXIT_FAILURE);
-               }
-       }
-}
-
-/* Cleanup. */
-
-for (i = 0; i &lt; reqbuf.count; i++)
-       for (j = 0; j &lt; FMT_NUM_PLANES; j++)
-               munmap(buffers[i].start[j], buffers[i].length[j]);
-      </programlisting>
-    </example>
-
-    <para>Conceptually streaming drivers maintain two buffer queues, an incoming
-and an outgoing queue. They separate the synchronous capture or output
-operation locked to a video clock from the application which is
-subject to random disk or network delays and preemption by
-other processes, thereby reducing the probability of data loss.
-The queues are organized as FIFOs, buffers will be
-output in the order enqueued in the incoming FIFO, and were
-captured in the order dequeued from the outgoing FIFO.</para>
-
-    <para>The driver may require a minimum number of buffers enqueued
-at all times to function, apart of this no limit exists on the number
-of buffers applications can enqueue in advance, or dequeue and
-process. They can also enqueue in a different order than buffers have
-been dequeued, and the driver can <emphasis>fill</emphasis> enqueued
-<emphasis>empty</emphasis> buffers in any order. <footnote>
-       <para>Random enqueue order permits applications processing
-images out of order (such as video codecs) to return buffers earlier,
-reducing the probability of data loss. Random fill order allows
-drivers to reuse buffers on a LIFO-basis, taking advantage of caches
-holding scatter-gather lists and the like.</para>
-      </footnote> The index number of a buffer (&v4l2-buffer;
-<structfield>index</structfield>) plays no role here, it only
-identifies the buffer.</para>
-
-    <para>Initially all mapped buffers are in dequeued state,
-inaccessible by the driver. For capturing applications it is customary
-to first enqueue all mapped buffers, then to start capturing and enter
-the read loop. Here the application waits until a filled buffer can be
-dequeued, and re-enqueues the buffer when the data is no longer
-needed. Output applications fill and enqueue buffers, when enough
-buffers are stacked up the output is started with
-<constant>VIDIOC_STREAMON</constant>. In the write loop, when
-the application runs out of free buffers, it must wait until an empty
-buffer can be dequeued and reused.</para>
-
-    <para>To enqueue and dequeue a buffer applications use the
-&VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. The status of a buffer being
-mapped, enqueued, full or empty can be determined at any time using the
-&VIDIOC-QUERYBUF; ioctl. Two methods exist to suspend execution of the
-application until one or more buffers can be dequeued. By default
-<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
-outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
-returns immediately with an &EAGAIN; when no buffer is available. The
-&func-select; or &func-poll; functions are always available.</para>
-
-    <para>To start and stop capturing or output applications call the
-&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
-<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
-queues as a side effect. Since there is no notion of doing anything
-"now" on a multitasking system, if an application needs to synchronize
-with another event it should examine the &v4l2-buffer;
-<structfield>timestamp</structfield> of captured or outputted buffers.
-</para>
-
-    <para>Drivers implementing memory mapping I/O must
-support the <constant>VIDIOC_REQBUFS</constant>,
-<constant>VIDIOC_QUERYBUF</constant>,
-<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
-<constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl, the
-<function>mmap()</function>, <function>munmap()</function>,
-<function>select()</function> and <function>poll()</function>
-function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional. The
-rest should be evident.</para>
-      </footnote></para>
-
-    <para>[capture example]</para>
-
-  </section>
-
-  <section id="userp">
-    <title>Streaming I/O (User Pointers)</title>
-
-    <para>Input and output devices support this I/O method when the
-<constant>V4L2_CAP_STREAMING</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user
-pointer method (not only memory mapping) is supported must be
-determined by calling the &VIDIOC-REQBUFS; ioctl with the memory type set to <constant>V4L2_MEMORY_USERPTR</constant>.</para>
-
-    <para>This I/O method combines advantages of the read/write and
-memory mapping methods. Buffers (planes) are allocated by the application
-itself, and can reside for example in virtual or shared memory. Only
-pointers to data are exchanged, these pointers and meta-information
-are passed in &v4l2-buffer; (or in &v4l2-plane; in the multi-planar API case).
-The driver must be switched into user pointer I/O mode by calling the
-&VIDIOC-REQBUFS; with the desired buffer type. No buffers (planes) are allocated
-beforehand, consequently they are not indexed and cannot be queried like mapped
-buffers with the <constant>VIDIOC_QUERYBUF</constant> ioctl.</para>
-
-    <example>
-      <title>Initiating streaming I/O with user pointers</title>
-
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-
-memset (&amp;reqbuf, 0, sizeof (reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-reqbuf.memory = V4L2_MEMORY_USERPTR;
-
-if (ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf) == -1) {
-       if (errno == EINVAL)
-               printf ("Video capturing or user pointer streaming is not supported\n");
-       else
-               perror ("VIDIOC_REQBUFS");
-
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <para>Buffer (plane) addresses and sizes are passed on the fly with the
-&VIDIOC-QBUF; ioctl. Although buffers are commonly cycled,
-applications can pass different addresses and sizes at each
-<constant>VIDIOC_QBUF</constant> call. If required by the hardware the
-driver swaps memory pages within physical memory to create a
-continuous area of memory. This happens transparently to the
-application in the virtual memory subsystem of the kernel. When buffer
-pages have been swapped out to disk they are brought back and finally
-locked in physical memory for DMA.<footnote>
-       <para>We expect that frequently used buffers are typically not
-swapped out. Anyway, the process of swapping, locking or generating
-scatter-gather lists may be time consuming. The delay can be masked by
-the depth of the incoming buffer queue, and perhaps by maintaining
-caches assuming a buffer will be soon enqueued again. On the other
-hand, to optimize memory usage drivers can limit the number of buffers
-locked in advance and recycle the most recently used buffers first. Of
-course, the pages of empty buffers in the incoming queue need not be
-saved to disk. Output buffers must be saved on the incoming and
-outgoing queue because an application may share them with other
-processes.</para>
-      </footnote></para>
-
-    <para>Filled or displayed buffers are dequeued with the
-&VIDIOC-DQBUF; ioctl. The driver can unlock the memory pages at any
-time between the completion of the DMA and this ioctl. The memory is
-also unlocked when &VIDIOC-STREAMOFF; is called, &VIDIOC-REQBUFS;, or
-when the device is closed. Applications must take care not to free
-buffers without dequeuing. For once, the buffers remain locked until
-further, wasting physical memory. Second the driver will not be
-notified when the memory is returned to the application's free list
-and subsequently reused for other purposes, possibly completing the
-requested DMA and overwriting valuable data.</para>
-
-    <para>For capturing applications it is customary to enqueue a
-number of empty buffers, to start capturing and enter the read loop.
-Here the application waits until a filled buffer can be dequeued, and
-re-enqueues the buffer when the data is no longer needed. Output
-applications fill and enqueue buffers, when enough buffers are stacked
-up output is started. In the write loop, when the application
-runs out of free buffers it must wait until an empty buffer can be
-dequeued and reused. Two methods exist to suspend execution of the
-application until one or more buffers can be dequeued. By default
-<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
-outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
-returns immediately with an &EAGAIN; when no buffer is available. The
-&func-select; or &func-poll; function are always available.</para>
-
-    <para>To start and stop capturing or output applications call the
-&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
-<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
-queues and unlocks all buffers as a side effect. Since there is no
-notion of doing anything "now" on a multitasking system, if an
-application needs to synchronize with another event it should examine
-the &v4l2-buffer; <structfield>timestamp</structfield> of captured
-or outputted buffers.</para>
-
-    <para>Drivers implementing user pointer I/O must
-support the <constant>VIDIOC_REQBUFS</constant>,
-<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
-<constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl, the
-<function>select()</function> and <function>poll()</function> function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional. The
-rest should be evident.</para>
-      </footnote></para>
-  </section>
-
-  <section id="dmabuf">
-    <title>Streaming I/O (DMA buffer importing)</title>
-
-<para>The DMABUF framework provides a generic method for sharing buffers
-between multiple devices. Device drivers that support DMABUF can export a DMA
-buffer to userspace as a file descriptor (known as the exporter role), import a
-DMA buffer from userspace using a file descriptor previously exported for a
-different or the same device (known as the importer role), or both. This
-section describes the DMABUF importer role API in V4L2.</para>
-
-    <para>Refer to <link linkend="vidioc-expbuf">DMABUF exporting</link> for
-details about exporting V4L2 buffers as DMABUF file descriptors.</para>
-
-<para>Input and output devices support the streaming I/O method when the
-<constant>V4L2_CAP_STREAMING</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability; returned by
-the &VIDIOC-QUERYCAP; ioctl is set. Whether importing DMA buffers through
-DMABUF file descriptors is supported is determined by calling the
-&VIDIOC-REQBUFS; ioctl with the memory type set to
-<constant>V4L2_MEMORY_DMABUF</constant>.</para>
-
-    <para>This I/O method is dedicated to sharing DMA buffers between different
-devices, which may be V4L devices or other video-related devices (e.g. DRM).
-Buffers (planes) are allocated by a driver on behalf of an application. Next,
-these buffers are exported to the application as file descriptors using an API
-which is specific for an allocator driver.  Only such file descriptor are
-exchanged. The descriptors and meta-information are passed in &v4l2-buffer; (or
-in &v4l2-plane; in the multi-planar API case).  The driver must be switched
-into DMABUF I/O mode by calling the &VIDIOC-REQBUFS; with the desired buffer
-type.</para>
-
-    <example>
-      <title>Initiating streaming I/O with DMABUF file descriptors</title>
-
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-
-memset(&amp;reqbuf, 0, sizeof (reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-reqbuf.memory = V4L2_MEMORY_DMABUF;
-reqbuf.count = 1;
-
-if (ioctl(fd, &VIDIOC-REQBUFS;, &amp;reqbuf) == -1) {
-       if (errno == EINVAL)
-               printf("Video capturing or DMABUF streaming is not supported\n");
-       else
-               perror("VIDIOC_REQBUFS");
-
-       exit(EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <para>The buffer (plane) file descriptor is passed on the fly with the
-&VIDIOC-QBUF; ioctl. In case of multiplanar buffers, every plane can be
-associated with a different DMABUF descriptor. Although buffers are commonly
-cycled, applications can pass a different DMABUF descriptor at each
-<constant>VIDIOC_QBUF</constant> call.</para>
-
-    <example>
-      <title>Queueing DMABUF using single plane API</title>
-
-      <programlisting>
-int buffer_queue(int v4lfd, int index, int dmafd)
-{
-       &v4l2-buffer; buf;
-
-       memset(&amp;buf, 0, sizeof buf);
-       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       buf.memory = V4L2_MEMORY_DMABUF;
-       buf.index = index;
-       buf.m.fd = dmafd;
-
-       if (ioctl(v4lfd, &VIDIOC-QBUF;, &amp;buf) == -1) {
-               perror("VIDIOC_QBUF");
-               return -1;
-       }
-
-       return 0;
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Queueing DMABUF using multi plane API</title>
-
-      <programlisting>
-int buffer_queue_mp(int v4lfd, int index, int dmafd[], int n_planes)
-{
-       &v4l2-buffer; buf;
-       &v4l2-plane; planes[VIDEO_MAX_PLANES];
-       int i;
-
-       memset(&amp;buf, 0, sizeof buf);
-       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       buf.memory = V4L2_MEMORY_DMABUF;
-       buf.index = index;
-       buf.m.planes = planes;
-       buf.length = n_planes;
-
-       memset(&amp;planes, 0, sizeof planes);
-
-       for (i = 0; i &lt; n_planes; ++i)
-               buf.m.planes[i].m.fd = dmafd[i];
-
-       if (ioctl(v4lfd, &VIDIOC-QBUF;, &amp;buf) == -1) {
-               perror("VIDIOC_QBUF");
-               return -1;
-       }
-
-       return 0;
-}
-      </programlisting>
-    </example>
-
-    <para>Captured or displayed buffers are dequeued with the
-&VIDIOC-DQBUF; ioctl. The driver can unlock the buffer at any
-time between the completion of the DMA and this ioctl. The memory is
-also unlocked when &VIDIOC-STREAMOFF; is called, &VIDIOC-REQBUFS;, or
-when the device is closed.</para>
-
-    <para>For capturing applications it is customary to enqueue a
-number of empty buffers, to start capturing and enter the read loop.
-Here the application waits until a filled buffer can be dequeued, and
-re-enqueues the buffer when the data is no longer needed. Output
-applications fill and enqueue buffers, when enough buffers are stacked
-up output is started. In the write loop, when the application
-runs out of free buffers it must wait until an empty buffer can be
-dequeued and reused. Two methods exist to suspend execution of the
-application until one or more buffers can be dequeued. By default
-<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
-outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
-returns immediately with an &EAGAIN; when no buffer is available. The
-&func-select; and &func-poll; functions are always available.</para>
-
-    <para>To start and stop capturing or displaying applications call the
-&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctls. Note that
-<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both queues and
-unlocks all buffers as a side effect. Since there is no notion of doing
-anything "now" on a multitasking system, if an application needs to synchronize
-with another event it should examine the &v4l2-buffer;
-<structfield>timestamp</structfield> of captured or outputted buffers.</para>
-
-    <para>Drivers implementing DMABUF importing I/O must support the
-<constant>VIDIOC_REQBUFS</constant>, <constant>VIDIOC_QBUF</constant>,
-<constant>VIDIOC_DQBUF</constant>, <constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctls, and the
-<function>select()</function> and <function>poll()</function> functions.</para>
-
-  </section>
-
-  <section id="async">
-    <title>Asynchronous I/O</title>
-
-    <para>This method is not defined yet.</para>
-  </section>
-
-  <section id="buffer">
-    <title>Buffers</title>
-
-    <para>A buffer contains data exchanged by application and
-driver using one of the Streaming I/O methods. In the multi-planar API, the
-data is held in planes, while the buffer structure acts as a container
-for the planes. Only pointers to buffers (planes) are exchanged, the data
-itself is not copied. These pointers, together with meta-information like
-timestamps or field parity, are stored in a struct
-<structname>v4l2_buffer</structname>, argument to
-the &VIDIOC-QUERYBUF;, &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl.
-In the multi-planar API, some plane-specific members of struct
-<structname>v4l2_buffer</structname>, such as pointers and sizes for each
-plane, are stored in struct <structname>v4l2_plane</structname> instead.
-In that case, struct <structname>v4l2_buffer</structname> contains an array of
-plane structures.</para>
-
-    <para>Dequeued video buffers come with timestamps. The driver
-    decides at which part of the frame and with which clock the
-    timestamp is taken. Please see flags in the masks
-    <constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant> and
-    <constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant> in <xref
-    linkend="buffer-flags" />. These flags are always valid and constant
-    across all buffers during the whole video stream. Changes in these
-    flags may take place as a side effect of &VIDIOC-S-INPUT; or
-    &VIDIOC-S-OUTPUT; however. The
-    <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant> timestamp type
-    which is used by e.g. on mem-to-mem devices is an exception to the
-    rule: the timestamp source flags are copied from the OUTPUT video
-    buffer to the CAPTURE video buffer.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-buffer">
-      <title>struct <structname>v4l2_buffer</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>Number of the buffer, set by the application except
-when calling &VIDIOC-DQBUF;, then it is set by the driver.
-This field can range from zero to the number of buffers allocated
-with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>),
-plus any buffers allocated with &VIDIOC-CREATE-BUFS; minus one.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of the buffer, same as &v4l2-format;
-<structfield>type</structfield> or &v4l2-requestbuffers;
-<structfield>type</structfield>, set by the application. See <xref
-linkend="v4l2-buf-type" /></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>bytesused</structfield></entry>
-           <entry></entry>
-           <entry>The number of bytes occupied by the data in the
-buffer. It depends on the negotiated data format and may change with
-each buffer for compressed variable size data like JPEG images.
-Drivers must set this field when <structfield>type</structfield>
-refers to a capture stream, applications when it refers to an output stream.
-If the application sets this to 0 for an output stream, then
-<structfield>bytesused</structfield> will be set to the size of the
-buffer (see the <structfield>length</structfield> field of this struct) by
-the driver. For multiplanar formats this field is ignored and the
-<structfield>planes</structfield> pointer is used instead.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>Flags set by the application or driver, see <xref
-linkend="buffer-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry></entry>
-           <entry>Indicates the field order of the image in the
-buffer, see <xref linkend="v4l2-field" />. This field is not used when
-the buffer contains VBI data. Drivers must set it when
-<structfield>type</structfield> refers to a capture stream,
-applications when it refers to an output stream.</entry>
-         </row>
-         <row>
-           <entry>struct timeval</entry>
-           <entry><structfield>timestamp</structfield></entry>
-           <entry></entry>
-           <entry><para>For capture streams this is time when the first data
-           byte was captured, as returned by the
-           <function>clock_gettime()</function> function for the relevant
-           clock id; see <constant>V4L2_BUF_FLAG_TIMESTAMP_*</constant> in
-           <xref linkend="buffer-flags" />. For output streams the driver
-           stores the time at which the last data byte was actually sent out
-           in the  <structfield>timestamp</structfield> field. This permits
-           applications to monitor the drift between the video and system
-           clock. For output streams that use <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant>
-           the application has to fill in the timestamp which will be copied
-           by the driver to the capture stream.</para></entry>
-         </row>
-         <row>
-           <entry>&v4l2-timecode;</entry>
-           <entry><structfield>timecode</structfield></entry>
-           <entry></entry>
-           <entry>When <structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> and the
-<constant>V4L2_BUF_FLAG_TIMECODE</constant> flag is set in
-<structfield>flags</structfield>, this structure contains a frame
-timecode. In <link linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link>
-mode the top and bottom field contain the same timecode.
-Timecodes are intended to help video editing and are typically recorded on
-video tapes, but also embedded in compressed formats like MPEG. This
-field is independent of the <structfield>timestamp</structfield> and
-<structfield>sequence</structfield> fields.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sequence</structfield></entry>
-           <entry></entry>
-           <entry>Set by the driver, counting the frames (not fields!) in
-sequence. This field is set for both input and output devices.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>In <link
-linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link> mode the top and
-bottom field have the same sequence number. The count starts at zero
-and includes dropped or repeated frames. A dropped frame was received
-by an input device but could not be stored due to lack of free buffer
-space. A repeated frame was displayed again by an output device
-because the application did not pass new data in
-time.</para><para>Note this may count the frames received
-e.g. over USB, without taking into account the frames dropped by the
-remote hardware due to limited compression throughput or bus
-bandwidth. These devices identify by not enumerating any video
-standards, see <xref linkend="standard" />.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>memory</structfield></entry>
-           <entry></entry>
-           <entry>This field must be set by applications and/or drivers
-in accordance with the selected I/O method. See <xref linkend="v4l2-memory"
-           /></entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>m</structfield></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>offset</structfield></entry>
-           <entry>For the single-planar API and when
-<structfield>memory</structfield> is <constant>V4L2_MEMORY_MMAP</constant> this
-is the offset of the buffer from the start of the device memory. The value is
-returned by the driver and apart of serving as parameter to the &func-mmap;
-function not useful for applications. See <xref linkend="mmap" /> for details
-         </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>unsigned long</entry>
-           <entry><structfield>userptr</structfield></entry>
-           <entry>For the single-planar API and when
-<structfield>memory</structfield> is <constant>V4L2_MEMORY_USERPTR</constant>
-this is a pointer to the buffer (casted to unsigned long type) in virtual
-memory, set by the application. See <xref linkend="userp" /> for details.
-           </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct v4l2_plane</entry>
-           <entry><structfield>*planes</structfield></entry>
-           <entry>When using the multi-planar API, contains a userspace pointer
-           to an array of &v4l2-plane;. The size of the array should be put
-           in the <structfield>length</structfield> field of this
-           <structname>v4l2_buffer</structname> structure.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>int</entry>
-           <entry><structfield>fd</structfield></entry>
-           <entry>For the single-plane API and when
-<structfield>memory</structfield> is <constant>V4L2_MEMORY_DMABUF</constant> this
-is the file descriptor associated with a DMABUF buffer.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry></entry>
-           <entry>Size of the buffer (not the payload) in bytes for the
-           single-planar API. This is set by the driver based on the calls to
-           &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;. For the multi-planar API the application sets
-           this to the number of elements in the <structfield>planes</structfield>
-           array. The driver will fill in the actual number of valid elements in
-           that array.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved2</structfield></entry>
-           <entry></entry>
-           <entry>A place holder for future extensions. Drivers and applications
-must set this to 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry></entry>
-           <entry>A place holder for future extensions. Drivers and applications
-must set this to 0.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-plane">
-      <title>struct <structname>v4l2_plane</structname></title>
-      <tgroup cols="4">
-        &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>bytesused</structfield></entry>
-           <entry></entry>
-           <entry>The number of bytes occupied by data in the plane
-             (its payload). Drivers must set this field when <structfield>type</structfield>
-             refers to a capture stream, applications when it refers to an output stream.
-             If the application sets this to 0 for an output stream, then
-             <structfield>bytesused</structfield> will be set to the size of the
-             plane (see the <structfield>length</structfield> field of this struct)
-             by the driver. Note that the actual image data starts at
-             <structfield>data_offset</structfield> which may not be 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry></entry>
-           <entry>Size in bytes of the plane (not its payload). This is set by the driver
-           based on the calls to &VIDIOC-REQBUFS; and/or &VIDIOC-CREATE-BUFS;.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>m</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>mem_offset</structfield></entry>
-           <entry>When the memory type in the containing &v4l2-buffer; is
-             <constant>V4L2_MEMORY_MMAP</constant>, this is the value that
-             should be passed to &func-mmap;, similar to the
-             <structfield>offset</structfield> field in &v4l2-buffer;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>unsigned long</entry>
-           <entry><structfield>userptr</structfield></entry>
-           <entry>When the memory type in the containing &v4l2-buffer; is
-             <constant>V4L2_MEMORY_USERPTR</constant>, this is a userspace
-             pointer to the memory allocated for this plane by an application.
-             </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>int</entry>
-           <entry><structfield>fd</structfield></entry>
-           <entry>When the memory type in the containing &v4l2-buffer; is
-               <constant>V4L2_MEMORY_DMABUF</constant>, this is a file
-               descriptor associated with a DMABUF buffer, similar to the
-               <structfield>fd</structfield> field in &v4l2-buffer;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>data_offset</structfield></entry>
-           <entry></entry>
-           <entry>Offset in bytes to video data in the plane.
-             Drivers must set this field when <structfield>type</structfield>
-             refers to a capture stream, applications when it refers to an output stream.
-             Note that data_offset is included in <structfield>bytesused</structfield>.
-             So the size of the image in the plane is
-             <structfield>bytesused</structfield>-<structfield>data_offset</structfield> at
-             offset <structfield>data_offset</structfield> from the start of the plane.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[11]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved for future use. Should be zeroed by drivers and
-           applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-buf-type">
-      <title>enum v4l2_buf_type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
-           <entry>1</entry>
-           <entry>Buffer of a single-planar video capture stream, see <xref
-               linkend="capture" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
-           </entry>
-           <entry>9</entry>
-           <entry>Buffer of a multi-planar video capture stream, see <xref
-               linkend="capture" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
-           <entry>2</entry>
-           <entry>Buffer of a single-planar video output stream, see <xref
-               linkend="output" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>
-           </entry>
-           <entry>10</entry>
-           <entry>Buffer of a multi-planar video output stream, see <xref
-               linkend="output" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>Buffer for video overlay, see <xref linkend="overlay" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
-           <entry>4</entry>
-           <entry>Buffer of a raw VBI capture stream, see <xref
-               linkend="raw-vbi" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
-           <entry>5</entry>
-           <entry>Buffer of a raw VBI output stream, see <xref
-               linkend="raw-vbi" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
-           <entry>6</entry>
-           <entry>Buffer of a sliced VBI capture stream, see <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
-           <entry>7</entry>
-           <entry>Buffer of a sliced VBI output stream, see <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant></entry>
-           <entry>8</entry>
-           <entry>Buffer for video output overlay (OSD), see <xref
-               linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant></entry>
-           <entry>11</entry>
-           <entry>Buffer for Software Defined Radio (SDR) capture stream, see
-               <xref linkend="sdr" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SDR_OUTPUT</constant></entry>
-           <entry>12</entry>
-           <entry>Buffer for Software Defined Radio (SDR) output stream, see
-               <xref linkend="sdr" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="buffer-flags">
-      <title>Buffer Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_MAPPED</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>The buffer resides in device memory and has been mapped
-into the application's address space, see <xref linkend="mmap" /> for details.
-Drivers set or clear this flag when the
-<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
-         linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link
-         linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called. Set by the driver.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_QUEUED</constant></entry>
-           <entry>0x00000002</entry>
-         <entry>Internally drivers maintain two buffer queues, an
-incoming and outgoing queue. When this flag is set, the buffer is
-currently on the incoming queue. It automatically moves to the
-outgoing queue after the buffer has been filled (capture devices) or
-displayed (output devices). Drivers set or clear this flag when the
-<constant>VIDIOC_QUERYBUF</constant> ioctl is called. After
-(successful) calling the <constant>VIDIOC_QBUF </constant>ioctl it is
-always set and after <constant>VIDIOC_DQBUF</constant> always
-cleared.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_DONE</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>When this flag is set, the buffer is currently on
-the outgoing queue, ready to be dequeued from the driver. Drivers set
-or clear this flag when the <constant>VIDIOC_QUERYBUF</constant> ioctl
-is called. After calling the <constant>VIDIOC_QBUF</constant> or
-<constant>VIDIOC_DQBUF</constant> it is always cleared. Of course a
-buffer cannot be on both queues at the same time, the
-<constant>V4L2_BUF_FLAG_QUEUED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flag are mutually exclusive.
-They can be both cleared however, then the buffer is in "dequeued"
-state, in the application domain so to say.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
-           <entry>0x00000040</entry>
-           <entry>When this flag is set, the buffer has been dequeued
-           successfully, although the data might have been corrupted.
-           This is recoverable, streaming may continue as normal and
-           the buffer may be reused normally.
-           Drivers set this flag when the <constant>VIDIOC_DQBUF</constant>
-           ioctl is called.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
-           <entry>0x00000008</entry>
-         <entry>Drivers set or clear this flag when calling the
-<constant>VIDIOC_DQBUF</constant> ioctl. It may be set by video
-capture devices when the buffer contains a compressed image which is a
-key frame (or field), &ie; can be decompressed on its own. Also known as
-an I-frame.  Applications can set this bit when <structfield>type</structfield>
-refers to an output stream.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_PFRAME</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
-this flags predicted frames or fields which contain only differences to a
-previous key frame. Applications can set this bit when <structfield>type</structfield>
-refers to an output stream.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_BFRAME</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
-this flags a bi-directional predicted frame or field which contains only
-the differences between the current frame and both the preceding and following
-key frames to specify its content. Applications can set this bit when
-<structfield>type</structfield> refers to an output stream.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMECODE</constant></entry>
-           <entry>0x00000100</entry>
-           <entry>The <structfield>timecode</structfield> field is valid.
-Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
-ioctl is called.  Applications can set this bit and the corresponding
-<structfield>timecode</structfield> structure when <structfield>type</structfield>
-refers to an output stream.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry>
-           <entry>0x00000400</entry>
-           <entry>The buffer has been prepared for I/O and can be queued by the
-application. Drivers set or clear this flag when the
-<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
-         linkend="vidioc-qbuf">VIDIOC_PREPARE_BUF</link>, <link
-         linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link
-         linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
-           <entry>0x00000800</entry>
-           <entry>Caches do not have to be invalidated for this buffer.
-Typically applications shall use this flag if the data captured in the buffer
-is not going to be touched by the CPU, instead the buffer will, probably, be
-passed on to a DMA-capable hardware unit for further processing or output.
-</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
-           <entry>0x00001000</entry>
-           <entry>Caches do not have to be cleaned for this buffer.
-Typically applications shall use this flag for output buffers if the data
-in this buffer has not been created by the CPU but by some DMA-capable unit,
-in which case caches have not been used.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_LAST</constant></entry>
-           <entry>0x00100000</entry>
-           <entry>Last buffer produced by the hardware. mem2mem codec drivers
-set this flag on the capture queue for the last buffer when the
-<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link> or
-<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called. Due to hardware
-limitations, the last buffer may be empty. In this case the driver will set the
-<structfield>bytesused</structfield> field to 0, regardless of the format. Any
-Any subsequent call to the <link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl
-will not block anymore, but return an &EPIPE;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MASK</constant></entry>
-           <entry>0x0000e000</entry>
-           <entry>Mask for timestamp types below. To test the
-           timestamp type, mask out bits not belonging to timestamp
-           type by performing a logical and operation with buffer
-           flags and timestamp mask.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN</constant></entry>
-           <entry>0x00000000</entry>
-           <entry>Unknown timestamp type. This type is used by
-           drivers before Linux 3.9 and may be either monotonic (see
-           below) or realtime (wall clock). Monotonic clock has been
-           favoured in embedded systems whereas most of the drivers
-           use the realtime clock. Either kinds of timestamps are
-           available in user space via
-           <function>clock_gettime(2)</function> using clock IDs
-           <constant>CLOCK_MONOTONIC</constant> and
-           <constant>CLOCK_REALTIME</constant>, respectively.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC</constant></entry>
-           <entry>0x00002000</entry>
-           <entry>The buffer timestamp has been taken from the
-           <constant>CLOCK_MONOTONIC</constant> clock. To access the
-           same clock outside V4L2, use
-           <function>clock_gettime(2)</function>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant></entry>
-           <entry>0x00004000</entry>
-           <entry>The CAPTURE buffer timestamp has been taken from the
-           corresponding OUTPUT buffer. This flag applies only to mem2mem devices.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant></entry>
-           <entry>0x00070000</entry>
-           <entry>Mask for timestamp sources below. The timestamp source
-           defines the point of time the timestamp is taken in relation to
-           the frame. Logical 'and' operation between the
-           <structfield>flags</structfield> field and
-           <constant>V4L2_BUF_FLAG_TSTAMP_SRC_MASK</constant> produces the
-           value of the timestamp source. Applications must set the timestamp
-           source when <structfield>type</structfield> refers to an output stream
-           and <constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant> is set.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_EOF</constant></entry>
-           <entry>0x00000000</entry>
-           <entry>End Of Frame. The buffer timestamp has been taken
-           when the last pixel of the frame has been received or the
-           last pixel of the frame has been transmitted. In practice,
-           software generated timestamps will typically be read from
-           the clock a small amount of time after the last pixel has
-           been received or transmitten, depending on the system and
-           other activity in it.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TSTAMP_SRC_SOE</constant></entry>
-           <entry>0x00010000</entry>
-           <entry>Start Of Exposure. The buffer timestamp has been
-           taken when the exposure of the frame has begun. This is
-           only valid for the
-           <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> buffer
-           type.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-memory">
-      <title>enum v4l2_memory</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MEMORY_MMAP</constant></entry>
-           <entry>1</entry>
-           <entry>The buffer is used for <link linkend="mmap">memory
-mapping</link> I/O.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MEMORY_USERPTR</constant></entry>
-           <entry>2</entry>
-           <entry>The buffer is used for <link linkend="userp">user
-pointer</link> I/O.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MEMORY_OVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>[to do]</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MEMORY_DMABUF</constant></entry>
-           <entry>4</entry>
-           <entry>The buffer is used for <link linkend="dmabuf">DMA shared
-buffer</link> I/O.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <section>
-      <title>Timecodes</title>
-
-      <para>The <structname>v4l2_timecode</structname> structure is
-designed to hold a <xref linkend="smpte12m" /> or similar timecode.
-(struct <structname>timeval</structname> timestamps are stored in
-&v4l2-buffer; field <structfield>timestamp</structfield>.)</para>
-
-      <table frame="none" pgwide="1" id="v4l2-timecode">
-       <title>struct <structname>v4l2_timecode</structname></title>
-       <tgroup cols="3">
-         &cs-str;
-         <tbody valign="top">
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>type</structfield></entry>
-             <entry>Frame rate the timecodes are based on, see <xref
-                 linkend="timecode-type" />.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>flags</structfield></entry>
-             <entry>Timecode flags, see <xref linkend="timecode-flags" />.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>frames</structfield></entry>
-             <entry>Frame count, 0 ... 23/24/29/49/59, depending on the
-           type of timecode.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>seconds</structfield></entry>
-             <entry>Seconds count, 0 ... 59. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>minutes</structfield></entry>
-             <entry>Minutes count, 0 ... 59. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>hours</structfield></entry>
-             <entry>Hours count, 0 ... 29. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>userbits</structfield>[4]</entry>
-             <entry>The "user group" bits from the timecode.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table frame="none" pgwide="1" id="timecode-type">
-       <title>Timecode Types</title>
-       <tgroup cols="3">
-       &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_TC_TYPE_24FPS</constant></entry>
-             <entry>1</entry>
-             <entry>24 frames per second, i.&nbsp;e. film.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_25FPS</constant></entry>
-             <entry>2</entry>
-             <entry>25 frames per second, &ie; PAL or SECAM video.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_30FPS</constant></entry>
-             <entry>3</entry>
-             <entry>30 frames per second, &ie; NTSC video.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_50FPS</constant></entry>
-             <entry>4</entry>
-             <entry></entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_60FPS</constant></entry>
-             <entry>5</entry>
-             <entry></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table frame="none" pgwide="1" id="timecode-flags">
-       <title>Timecode Flags</title>
-       <tgroup cols="3">
-       &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_TC_FLAG_DROPFRAME</constant></entry>
-             <entry>0x0001</entry>
-             <entry>Indicates "drop frame" semantics for counting frames
-in 29.97 fps material. When set, frame numbers 0 and 1 at the start of
-each minute, except minutes 0, 10, 20, 30, 40, 50 are omitted from the
-count.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_FLAG_COLORFRAME</constant></entry>
-             <entry>0x0002</entry>
-             <entry>The "color frame" flag.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_field</constant></entry>
-             <entry>0x000C</entry>
-             <entry>Field mask for the "binary group flags".</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_USERDEFINED</constant></entry>
-             <entry>0x0000</entry>
-             <entry>Unspecified format.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_8BITCHARS</constant></entry>
-             <entry>0x0008</entry>
-             <entry>8-bit ISO characters.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-  </section>
-
-  <section id="field-order">
-    <title>Field Order</title>
-
-    <para>We have to distinguish between progressive and interlaced
-video. Progressive video transmits all lines of a video image
-sequentially. Interlaced video divides an image into two fields,
-containing only the odd and even lines of the image, respectively.
-Alternating the so called odd and even field are transmitted, and due
-to a small delay between fields a cathode ray TV displays the lines
-interleaved, yielding the original frame. This curious technique was
-invented because at refresh rates similar to film the image would
-fade out too quickly. Transmitting fields reduces the flicker without
-the necessity of doubling the frame rate and with it the bandwidth
-required for each channel.</para>
-
-    <para>It is important to understand a video camera does not expose
-one frame at a time, merely transmitting the frames separated into
-fields. The fields are in fact captured at two different instances in
-time. An object on screen may well move between one field and the
-next. For applications analysing motion it is of paramount importance
-to recognize which field of a frame is older, the <emphasis>temporal
-order</emphasis>.</para>
-
-    <para>When the driver provides or accepts images field by field
-rather than interleaved, it is also important applications understand
-how the fields combine to frames. We distinguish between top (aka odd) and
-bottom (aka even) fields, the <emphasis>spatial order</emphasis>: The first line
-of the top field is the first line of an interlaced frame, the first
-line of the bottom field is the second line of that frame.</para>
-
-    <para>However because fields were captured one after the other,
-arguing whether a frame commences with the top or bottom field is
-pointless. Any two successive top and bottom, or bottom and top fields
-yield a valid frame. Only when the source was progressive to begin
-with, &eg; when transferring film to video, two fields may come from
-the same frame, creating a natural order.</para>
-
-    <para>Counter to intuition the top field is not necessarily the
-older field. Whether the older field contains the top or bottom lines
-is a convention determined by the video standard. Hence the
-distinction between temporal and spatial order of fields. The diagrams
-below should make this clearer.</para>
-
-    <para>All video capture and output devices must report the current
-field order. Some drivers may permit the selection of a different
-order, to this end applications initialize the
-<structfield>field</structfield> field of &v4l2-pix-format; before
-calling the &VIDIOC-S-FMT; ioctl. If this is not desired it should
-have the value <constant>V4L2_FIELD_ANY</constant> (0).</para>
-
-    <table frame="none" pgwide="1" id="v4l2-field">
-      <title>enum v4l2_field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FIELD_ANY</constant></entry>
-           <entry>0</entry>
-           <entry>Applications request this field order when any
-one of the <constant>V4L2_FIELD_NONE</constant>,
-<constant>V4L2_FIELD_TOP</constant>,
-<constant>V4L2_FIELD_BOTTOM</constant>, or
-<constant>V4L2_FIELD_INTERLACED</constant> formats is acceptable.
-Drivers choose depending on hardware capabilities or e.&nbsp;g. the
-requested image size, and return the actual field order. Drivers must
-never return <constant>V4L2_FIELD_ANY</constant>. If multiple
-field orders are possible the driver must choose one of the possible
-field orders during &VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;. &v4l2-buffer;
-<structfield>field</structfield> can never be
-<constant>V4L2_FIELD_ANY</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_NONE</constant></entry>
-           <entry>1</entry>
-           <entry>Images are in progressive format, not interlaced.
-The driver may also indicate this order when it cannot distinguish
-between <constant>V4L2_FIELD_TOP</constant> and
-<constant>V4L2_FIELD_BOTTOM</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_TOP</constant></entry>
-           <entry>2</entry>
-           <entry>Images consist of the top (aka odd) field only.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
-           <entry>3</entry>
-           <entry>Images consist of the bottom (aka even) field only.
-Applications may wish to prevent a device from capturing interlaced
-images because they will have "comb" or "feathering" artefacts around
-moving objects.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
-           <entry>4</entry>
-           <entry>Images contain both fields, interleaved line by
-line. The temporal order of the fields (whether the top or bottom
-field is first transmitted) depends on the current video standard.
-M/NTSC transmits the bottom field first, all other standards the top
-field first.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
-           <entry>5</entry>
-           <entry>Images contain both fields, the top field lines
-are stored first in memory, immediately followed by the bottom field
-lines. Fields are always stored in temporal order, the older one first
-in memory. Image sizes refer to the frame, not fields.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
-           <entry>6</entry>
-           <entry>Images contain both fields, the bottom field
-lines are stored first in memory, immediately followed by the top
-field lines. Fields are always stored in temporal order, the older one
-first in memory. Image sizes refer to the frame, not fields.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
-           <entry>7</entry>
-           <entry>The two fields of a frame are passed in separate
-buffers, in temporal order, &ie; the older one first. To indicate the field
-parity (whether the current field is a top or bottom field) the driver
-or application, depending on data direction, must set &v4l2-buffer;
-<structfield>field</structfield> to
-<constant>V4L2_FIELD_TOP</constant> or
-<constant>V4L2_FIELD_BOTTOM</constant>. Any two successive fields pair
-to build a frame. If fields are successive, without any dropped fields
-between them (fields can drop individually), can be determined from
-the &v4l2-buffer; <structfield>sequence</structfield> field. This format
-cannot be selected when using the read/write I/O method since there
-is no way to communicate if a field was a top or bottom field.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED_TB</constant></entry>
-           <entry>8</entry>
-           <entry>Images contain both fields, interleaved line by
-line, top field first. The top field is transmitted first.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED_BT</constant></entry>
-           <entry>9</entry>
-           <entry>Images contain both fields, interleaved line by
-line, top field first. The bottom field is transmitted first.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <figure id="fieldseq-tb">
-       <title>Field Order, Top Field First Transmitted</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_tb.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_tb.gif" format="GIF" />
-         </imageobject>
-       </mediaobject>
-    </figure>
-
-    <figure id="fieldseq-bt">
-       <title>Field Order, Bottom Field First Transmitted</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_bt.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_bt.gif" format="GIF" />
-         </imageobject>
-       </mediaobject>
-    </figure>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/keytable.c.xml b/Documentation/DocBook/media/v4l/keytable.c.xml
deleted file mode 100644 (file)
index d53254a..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<programlisting>
-/* keytable.c - This program allows checking/replacing keys at IR
-
-   Copyright (C) 2006-2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
- */
-
-#include &lt;ctype.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;linux/input.h&gt;
-#include &lt;sys/ioctl.h&gt;
-
-#include "parse.h"
-
-void prtcode (int *codes)
-{
-        struct parse_key *p;
-
-        for (p=keynames;p-&gt;name!=NULL;p++) {
-                if (p-&gt;value == (unsigned)codes[1]) {
-                        printf("scancode 0x%04x = %s (0x%02x)\n", codes[0], p-&gt;name, codes[1]);
-                        return;
-                }
-        }
-
-        if (isprint (codes[1]))
-                printf("scancode %d = '%c' (0x%02x)\n", codes[0], codes[1], codes[1]);
-        else
-                printf("scancode %d = 0x%02x\n", codes[0], codes[1]);
-}
-
-int parse_code(char *string)
-{
-        struct parse_key *p;
-
-        for (p=keynames;p-&gt;name!=NULL;p++) {
-                if (!strcasecmp(p-&gt;name, string)) {
-                        return p-&gt;value;
-                }
-        }
-        return -1;
-}
-
-int main (int argc, char *argv[])
-{
-        int fd;
-        unsigned int i, j;
-        int codes[2];
-
-        if (argc&lt;2 || argc&gt;4) {
-                printf ("usage: %s &lt;device&gt; to get table; or\n"
-                        "       %s &lt;device&gt; &lt;scancode&gt; &lt;keycode&gt;\n"
-                        "       %s &lt;device&gt; &lt;keycode_file&gt;\n",*argv,*argv,*argv);
-                return -1;
-        }
-
-        if ((fd = open(argv[1], O_RDONLY)) &lt; 0) {
-                perror("Couldn't open input device");
-                return(-1);
-        }
-
-        if (argc==4) {
-                int value;
-
-                value=parse_code(argv[3]);
-
-                if (value==-1) {
-                        value = strtol(argv[3], NULL, 0);
-                        if (errno)
-                                perror("value");
-                }
-
-                codes [0] = (unsigned) strtol(argv[2], NULL, 0);
-                codes [1] = (unsigned) value;
-
-                if(ioctl(fd, EVIOCSKEYCODE, codes))
-                        perror ("EVIOCSKEYCODE");
-
-                if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
-                        prtcode(codes);
-                return 0;
-        }
-
-        if (argc==3) {
-                FILE *fin;
-                int value;
-                char *scancode, *keycode, s[2048];
-
-                fin=fopen(argv[2],"r");
-                if (fin==NULL) {
-                        perror ("opening keycode file");
-                        return -1;
-                }
-
-                /* Clears old table */
-                for (j = 0; j &lt; 256; j++) {
-                        for (i = 0; i &lt; 256; i++) {
-                                codes[0] = (j &lt;&lt; 8) | i;
-                                codes[1] = KEY_RESERVED;
-                                ioctl(fd, EVIOCSKEYCODE, codes);
-                        }
-                }
-
-                while (fgets(s,sizeof(s),fin)) {
-                        scancode=strtok(s,"\n\t =:");
-                        if (!scancode) {
-                                perror ("parsing input file scancode");
-                                return -1;
-                        }
-                        if (!strcasecmp(scancode, "scancode")) {
-                                scancode = strtok(NULL,"\n\t =:");
-                                if (!scancode) {
-                                        perror ("parsing input file scancode");
-                                        return -1;
-                                }
-                        }
-
-                        keycode=strtok(NULL,"\n\t =:(");
-                        if (!keycode) {
-                                perror ("parsing input file keycode");
-                                return -1;
-                        }
-
-                        // printf ("parsing %s=%s:", scancode, keycode);
-                        value=parse_code(keycode);
-                        // printf ("\tvalue=%d\n",value);
-
-                        if (value==-1) {
-                                value = strtol(keycode, NULL, 0);
-                                if (errno)
-                                        perror("value");
-                        }
-
-                        codes [0] = (unsigned) strtol(scancode, NULL, 0);
-                        codes [1] = (unsigned) value;
-
-                        // printf("\t%04x=%04x\n",codes[0], codes[1]);
-                        if(ioctl(fd, EVIOCSKEYCODE, codes)) {
-                                fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]);
-                                perror ("EVIOCSKEYCODE");
-                        }
-
-                        if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
-                                prtcode(codes);
-                }
-                return 0;
-        }
-
-        /* Get scancode table */
-        for (j = 0; j &lt; 256; j++) {
-                for (i = 0; i &lt; 256; i++) {
-                        codes[0] = (j &lt;&lt; 8) | i;
-                        if (!ioctl(fd, EVIOCGKEYCODE, codes) &amp;&amp; codes[1] != KEY_RESERVED)
-                                prtcode(codes);
-                }
-        }
-        return 0;
-}
-
-</programlisting>
diff --git a/Documentation/DocBook/media/v4l/libv4l.xml b/Documentation/DocBook/media/v4l/libv4l.xml
deleted file mode 100644 (file)
index d3b71e2..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<title>Libv4l Userspace Library</title>
-<section id="libv4l-introduction">
-       <title>Introduction</title>
-
-       <para>libv4l is a collection of libraries which adds a thin abstraction
-layer on top of video4linux2 devices. The purpose of this (thin) layer
-is to make it easy for application writers to support a wide variety of
-devices without having to write separate code for different devices in the
-same class.</para>
-<para>An example of using libv4l is provided by
-<link linkend='v4l2grab-example'>v4l2grab</link>.
-</para>
-
-       <para>libv4l consists of 3 different libraries:</para>
-       <section>
-               <title>libv4lconvert</title>
-
-               <para>libv4lconvert is a library that converts several
-different pixelformats found in V4L2 drivers into a few common RGB and
-YUY formats.</para>
-               <para>It currently accepts the following V4L2 driver formats:
-<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
-<link linkend="V4L2-PIX-FMT-HM12"><constant>V4L2_PIX_FMT_HM12</constant></link>,
-<link linkend="V4L2-PIX-FMT-JPEG"><constant>V4L2_PIX_FMT_JPEG</constant></link>,
-<link linkend="V4L2-PIX-FMT-MJPEG"><constant>V4L2_PIX_FMT_MJPEG</constant></link>,
-<link linkend="V4L2-PIX-FMT-MR97310A"><constant>V4L2_PIX_FMT_MR97310A</constant></link>,
-<link linkend="V4L2-PIX-FMT-OV511"><constant>V4L2_PIX_FMT_OV511</constant></link>,
-<link linkend="V4L2-PIX-FMT-OV518"><constant>V4L2_PIX_FMT_OV518</constant></link>,
-<link linkend="V4L2-PIX-FMT-PAC207"><constant>V4L2_PIX_FMT_PAC207</constant></link>,
-<link linkend="V4L2-PIX-FMT-PJPG"><constant>V4L2_PIX_FMT_PJPG</constant></link>,
-<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
-<link linkend="V4L2-PIX-FMT-SBGGR8"><constant>V4L2_PIX_FMT_SBGGR8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SGBRG8"><constant>V4L2_PIX_FMT_SGBRG8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SGRBG8"><constant>V4L2_PIX_FMT_SGRBG8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SN9C10X"><constant>V4L2_PIX_FMT_SN9C10X</constant></link>,
-<link linkend="V4L2-PIX-FMT-SN9C20X-I420"><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA501"><constant>V4L2_PIX_FMT_SPCA501</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA505"><constant>V4L2_PIX_FMT_SPCA505</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA508"><constant>V4L2_PIX_FMT_SPCA508</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA561"><constant>V4L2_PIX_FMT_SPCA561</constant></link>,
-<link linkend="V4L2-PIX-FMT-SQ905C"><constant>V4L2_PIX_FMT_SQ905C</constant></link>,
-<constant>V4L2_PIX_FMT_SRGGB8</constant>,
-<link linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link>,
-<link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
-and <link linkend="V4L2-PIX-FMT-YVYU"><constant>V4L2_PIX_FMT_YVYU</constant></link>.
-</para>
-               <para>Later on libv4lconvert was expanded to also be able to do
-various        video processing functions to improve webcam video quality.
-The video processing is split in to 2 parts: libv4lconvert/control and
-libv4lconvert/processing.</para>
-
-               <para>The control part is used to offer video controls which can
-be used        to control the video processing functions made available by
-       libv4lconvert/processing. These controls are stored application wide
-(until reboot) by using a persistent shared memory object.</para>
-
-               <para>libv4lconvert/processing offers the actual video
-processing functionality.</para>
-       </section>
-       <section>
-               <title>libv4l1</title>
-               <para>This library offers functions that can be used to quickly
-make v4l1 applications work with v4l2 devices. These functions work exactly
-like the normal open/close/etc, except that libv4l1 does full emulation of
-the v4l1 api on top of v4l2 drivers, in case of v4l1 drivers it
-will just pass calls through.</para>
-               <para>Since those functions are emulations of the old V4L1 API,
-it shouldn't be used for new applications.</para>
-       </section>
-       <section>
-               <title>libv4l2</title>
-               <para>This library should be used for all modern V4L2
-applications.</para>
-               <para>It provides handles to call V4L2 open/ioctl/close/poll
-methods. Instead of just providing the raw output of the device, it enhances
-the calls in the sense that it will use libv4lconvert to provide more video
-formats and to enhance the image quality.</para>
-               <para>In most cases, libv4l2 just passes the calls directly
-through to the v4l2 driver, intercepting the calls to
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>,
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_G_FMT</constant></link>
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>
-<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>
-and <link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>
-in order to emulate the formats
-<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
-<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
-and <link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
-if they aren't available in the driver.
-<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>
-keeps enumerating the hardware supported formats, plus the emulated formats
-offered by libv4l at the end.
-</para>
-               <section id="libv4l-ops">
-                       <title>Libv4l device control functions</title>
-                       <para>The common file operation methods are provided by
-libv4l.</para>
-                       <para>Those functions operate just like glibc
-open/close/dup/ioctl/read/mmap/munmap:</para>
-<itemizedlist><listitem>
-                       <para>int v4l2_open(const char *file, int oflag,
-...) -
-operates like the standard <link linkend='func-open'>open()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_close(int fd) -
-operates like the standard <link linkend='func-close'>close()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_dup(int fd) -
-operates like the standard dup() function, duplicating a file handler.
-</para></listitem><listitem>
-                       <para>int v4l2_ioctl (int fd, unsigned long int request, ...) -
-operates like the standard <link linkend='func-ioctl'>ioctl()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_read (int fd, void* buffer, size_t n) -
-operates like the standard <link linkend='func-read'>read()</link> function.
-</para></listitem><listitem>
-                       <para>void v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset); -
-operates like the standard <link linkend='func-mmap'>mmap()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_munmap(void *_start, size_t length); -
-operates like the standard <link linkend='func-munmap'>munmap()</link> function.
-</para></listitem>
-</itemizedlist>
-                       <para>Those functions provide additional control:</para>
-<itemizedlist><listitem>
-                       <para>int v4l2_fd_open(int fd, int v4l2_flags) -
-opens an already opened fd for further use through v4l2lib and possibly
-modify libv4l2's default behavior through the v4l2_flags argument.
-Currently, v4l2_flags can be <constant>V4L2_DISABLE_CONVERSION</constant>,
-to disable format conversion.
-</para></listitem><listitem>
-                       <para>int v4l2_set_control(int fd, int cid, int value) -
-This function takes a value of 0 - 65535, and then scales that range to
-the actual range of the given v4l control id, and then if the cid exists
-and is not locked sets the cid to the scaled value.
-</para></listitem><listitem>
-                       <para>int v4l2_get_control(int fd, int cid) -
-This function returns a value of 0 - 65535, scaled to from the actual range
-of the given v4l control id. when the cid does not exist, could not be
-accessed for some reason, or some error occurred 0 is returned.
-</para></listitem>
-</itemizedlist>
-               </section>
-       </section>
-       <section>
-
-               <title>v4l1compat.so wrapper library</title>
-
-               <para>This library intercepts calls to
-open/close/ioctl/mmap/mmunmap operations and redirects them to the libv4l
-counterparts, by using LD_PRELOAD=/usr/lib/v4l1compat.so. It also
-emulates V4L1 calls via V4L2 API.</para>
-               <para>It allows usage of binary legacy applications that
-still don't use libv4l.</para>
-       </section>
-
-</section>
diff --git a/Documentation/DocBook/media/v4l/lirc_device_interface.xml b/Documentation/DocBook/media/v4l/lirc_device_interface.xml
deleted file mode 100644 (file)
index f53ad58..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-<section id="lirc_dev">
-<title>LIRC Device Interface</title>
-
-
-<section id="lirc_dev_intro">
-<title>Introduction</title>
-
-<para>The LIRC device interface is a bi-directional interface for
-transporting raw IR data between userspace and kernelspace. Fundamentally,
-it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
-of standard struct file_operations defined on it. With respect to
-transporting raw IR data to and fro, the essential fops are read, write
-and ioctl.</para>
-
-<para>Example dmesg output upon a driver registering w/LIRC:</para>
-  <blockquote>
-    <para>$ dmesg |grep lirc_dev</para>
-    <para>lirc_dev: IR Remote Control driver registered, major 248</para>
-    <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
-  </blockquote>
-
-<para>What you should see for a chardev:</para>
-  <blockquote>
-    <para>$ ls -l /dev/lirc*</para>
-    <para>crw-rw---- 1 root root 248, 0 Jul  2 22:20 /dev/lirc0</para>
-  </blockquote>
-</section>
-
-<section id="lirc_read">
-<title>LIRC read fop</title>
-
-<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
-exact format of the data depends on what modes a driver supports, and what
-mode has been selected. lircd obtains supported modes and sets the active mode
-via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
-preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
-describing an IR signal are read from the chardev.</para>
-
-<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
-</section>
-
-<section id="lirc_write">
-<title>LIRC write fop</title>
-
-<para>The data written to the chardev is a pulse/space sequence of integer
-values. Pulses and spaces are only marked implicitly by their position. The
-data must start and end with a pulse, therefore, the data must always include
-an uneven number of samples. The write function must block until the data has
-been transmitted by the hardware. If more data is provided than the hardware
-can send, the driver returns EINVAL.</para>
-
-</section>
-
-<section id="lirc_ioctl">
-<title>LIRC ioctl fop</title>
-
-<para>The LIRC device's ioctl definition is bound by the ioctl function
-definition of struct file_operations, leaving us with an unsigned int
-for the ioctl command and an unsigned long for the arg. For the purposes
-of ioctl portability across 32-bit and 64-bit, these values are capped
-to their 32-bit sizes.</para>
-
-<para>The following ioctls can be used to change specific hardware settings.
-In general each driver should have a default set of settings. The driver
-implementation is expected to re-apply the default settings when the device
-is closed by user-space, so that every application opening the device can rely
-on working with the default settings initially.</para>
-
-<variablelist>
-  <varlistentry>
-    <term>LIRC_GET_FEATURES</term>
-    <listitem>
-      <para>Obviously, get the underlying hardware device's features. If a driver
-      does not announce support of certain features, calling of the corresponding
-      ioctls is undefined.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_SEND_MODE</term>
-    <listitem>
-      <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_MODE</term>
-    <listitem>
-      <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
-      are supported by lircd.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_SEND_CARRIER</term>
-    <listitem>
-      <para>Get carrier frequency (in Hz) currently used for transmit.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_CARRIER</term>
-    <listitem>
-      <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
-    <listitem>
-      <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
-      no special meaning is defined for 0 or 100, but this could be used to switch
-      off carrier generation in the future, so these values should be reserved.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_RESOLUTION</term>
-    <listitem>
-      <para>Some receiver have maximum resolution which is defined by internal
-      sample rate or data format limitations. E.g. it's common that signals can
-      only be reported in 50 microsecond steps. This integer value is used by
-      lircd to automatically adjust the steps tolerance value in the lircd
-      config file.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
-    <listitem>
-      <para>Some devices have internal timers that can be used to detect when
-      there's no IR activity for a long time. This can help lircd in detecting
-      that a IR signal is finished and can speed up the decoding process.
-      Returns an integer value with the minimum/maximum timeout that can be
-      set. Some devices have a fixed timeout, in that case both ioctls will
-      return the same value even though the timeout cannot be changed.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
-    <listitem>
-      <para>Some devices are able to filter out spikes in the incoming signal
-      using given filter rules. These ioctls return the hardware capabilities
-      that describe the bounds of the possible filters. Filter settings depend
-      on the IR protocols that are expected. lircd derives the settings from
-      all protocols definitions found in its config file.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_LENGTH</term>
-    <listitem>
-      <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
-      Reads on the device must be done in blocks matching the bit count.
-      The bit could should be rounded up so that it matches full bytes.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_{SEND,REC}_MODE</term>
-    <listitem>
-      <para>Set send/receive mode. Largely obsolete for send, as only
-      LIRC_MODE_PULSE is supported.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_{SEND,REC}_CARRIER</term>
-    <listitem>
-      <para>Set send/receive carrier (in Hz). Return 0 on success.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_TRANSMITTER_MASK</term>
-    <listitem>
-      <para>This enables the given set of transmitters. The first transmitter
-      is encoded by the least significant bit, etc. When an invalid bit mask
-      is given, i.e. a bit is set, even though the device does not have so many
-      transitters, then this ioctl returns the number of available transitters
-      and does nothing otherwise.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_TIMEOUT</term>
-    <listitem>
-      <para>Sets the integer value for IR inactivity timeout (cf.
-      LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
-      supported by the hardware) disables all hardware timeouts and data should
-      be reported as soon as possible. If the exact value cannot be set, then
-      the next possible value _greater_ than the given value should be set.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
-    <listitem>
-      <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
-      default, timeout reports should be turned off.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
-    <listitem>
-      <para>Pulses/spaces shorter than this are filtered out by hardware. If
-      filters cannot be set independently for pulse/space, the corresponding
-      ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
-    <listitem>
-      <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
-      press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
-      this should be turned off.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
-    <listitem>
-      <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
-      with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
-      with the upper bound.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_NOTIFY_DECODE</term>
-    <listitem>
-      <para>This ioctl is called by lircd whenever a successful decoding of an
-      incoming IR signal could be done. This can be used by supporting hardware
-      to give visual feedback to the user e.g. by flashing a LED.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SETUP_{START,END}</term>
-    <listitem>
-      <para>Setting of several driver parameters can be optimized by encapsulating
-      the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
-      driver receives a LIRC_SETUP_START ioctl it can choose to not commit
-      further setting changes to the hardware until a LIRC_SETUP_END is received.
-      But this is open to the driver implementation and every driver must also
-      handle parameter changes which are not encapsulated by LIRC_SETUP_START
-      and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_WIDEBAND_RECEIVER</term>
-    <listitem>
-      <para>Some receivers are equipped with special wide band receiver which is intended
-      to be used to learn output of existing remote.
-      Calling that ioctl with (1) will enable it, and with (0) disable it.
-      This might be useful of receivers that have otherwise narrow band receiver
-      that prevents them to be used with some remotes.
-      Wide band receiver might also be more precise
-      On the other hand its disadvantage it usually reduced range of reception.
-      Note: wide band receiver might be implictly enabled if you enable
-      carrier reports. In that case it will be disabled as soon as you disable
-      carrier reports. Trying to disable wide band receiver while carrier
-      reports are active will do nothing.</para>
-    </listitem>
-  </varlistentry>
-</variablelist>
-<section id="lirc_dev_errors">
-  &return-value;
-</section>
-</section>
-</section>
diff --git a/Documentation/DocBook/media/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml
deleted file mode 100644 (file)
index 5f2fc07..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<partinfo>
-  <authorgroup>
-    <author>
-      <firstname>Laurent</firstname>
-      <surname>Pinchart</surname>
-      <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
-      <contrib>Initial version.</contrib>
-    </author>
-  </authorgroup>
-  <copyright>
-    <year>2010</year>
-    <holder>Laurent Pinchart</holder>
-  </copyright>
-
-  <revhistory>
-    <!-- Put document revisions here, newest first. -->
-    <revision>
-      <revnumber>1.0.0</revnumber>
-      <date>2010-11-10</date>
-      <authorinitials>lp</authorinitials>
-      <revremark>Initial revision</revremark>
-    </revision>
-  </revhistory>
-</partinfo>
-
-<title>Media Controller API</title>
-
-<chapter id="media_controller">
-  <title>Media Controller</title>
-
-  <section id="media-controller-intro">
-    <title>Introduction</title>
-    <para>Media devices increasingly handle multiple related functions. Many USB
-    cameras include microphones, video capture hardware can also output video,
-    or SoC camera interfaces also perform memory-to-memory operations similar to
-    video codecs.</para>
-    <para>Independent functions, even when implemented in the same hardware, can
-    be modelled as separate devices. A USB camera with a microphone will be
-    presented to userspace applications as V4L2 and ALSA capture devices. The
-    devices' relationships (when using a webcam, end-users shouldn't have to
-    manually select the associated USB microphone), while not made available
-    directly to applications by the drivers, can usually be retrieved from
-    sysfs.</para>
-    <para>With more and more advanced SoC devices being introduced, the current
-    approach will not scale. Device topologies are getting increasingly complex
-    and can't always be represented by a tree structure. Hardware blocks are
-    shared between different functions, creating dependencies between seemingly
-    unrelated devices.</para>
-    <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
-    applications to access hardware parameters. As newer hardware expose an
-    increasingly high number of those parameters, drivers need to guess what
-    applications really require based on limited information, thereby
-    implementing policies that belong to userspace.</para>
-    <para>The media controller API aims at solving those problems.</para>
-  </section>
-
-  <section id="media-controller-model">
-    <title>Media device model</title>
-    <para>Discovering a device internal topology, and configuring it at runtime,
-    is one of the goals of the media controller API. To achieve this, hardware
-    devices and Linux Kernel interfaces are modelled as graph objects on
-    an oriented graph. The object types that constitute the graph are:</para>
-    <itemizedlist>
-    <listitem><para>An <emphasis role="bold">entity</emphasis>
-    is a basic media hardware or software building block. It can correspond to
-    a large variety of logical blocks such as physical hardware devices
-    (CMOS sensor for instance), logical hardware devices (a building block in
-    a System-on-Chip image processing pipeline), DMA channels or physical
-    connectors.</para></listitem>
-    <listitem><para>An <emphasis role="bold">interface</emphasis>
-    is a graph representation of a Linux Kernel userspace API interface,
-    like a device node or a sysfs file that controls one or more entities
-    in the graph.</para></listitem>
-    <listitem><para>A <emphasis role="bold">pad</emphasis>
-    is a data connection endpoint through which an entity can interact with
-    other entities. Data (not restricted to video) produced by an entity
-    flows from the entity's output to one or more entity inputs. Pads should
-    not be confused with physical pins at chip boundaries.</para></listitem>
-    <listitem><para>A <emphasis role="bold">data link</emphasis>
-    is a point-to-point oriented connection between two pads, either on the
-    same entity or on different entities. Data flows from a source pad to a
-    sink pad.</para></listitem>
-    <listitem><para>An <emphasis role="bold">interface link</emphasis>
-    is a point-to-point bidirectional control connection between a Linux
-    Kernel interface and an entity.m</para></listitem>
-    </itemizedlist>
-  </section>
-
-  <!-- All non-ioctl specific data types go here. -->
-  &sub-media-types;
-</chapter>
-
-<appendix id="media-user-func">
-  <title>Function Reference</title>
-  <!-- Keep this alphabetically sorted. -->
-  &sub-media-func-open;
-  &sub-media-func-close;
-  &sub-media-func-ioctl;
-  <!-- All ioctls go here. -->
-  &sub-media-ioc-device-info;
-  &sub-media-ioc-g-topology;
-  &sub-media-ioc-enum-entities;
-  &sub-media-ioc-enum-links;
-  &sub-media-ioc-setup-link;
-</appendix>
diff --git a/Documentation/DocBook/media/v4l/media-func-close.xml b/Documentation/DocBook/media/v4l/media-func-close.xml
deleted file mode 100644 (file)
index be149c8..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<refentry id="media-func-close">
-  <refmeta>
-    <refentrytitle>media close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-close</refname>
-    <refpurpose>Close a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Closes the media device. Resources associated with the file descriptor
-    are freed. The device configuration remain unchanged.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>close</function> returns 0 on success. On error, -1 is
-    returned, and <varname>errno</varname> is set appropriately. Possible error
-    codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file descriptor.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-func-ioctl.xml b/Documentation/DocBook/media/v4l/media-func-ioctl.xml
deleted file mode 100644 (file)
index 39478d0..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<refentry id="media-func-ioctl">
-  <refmeta>
-    <refentrytitle>media ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-ioctl</refname>
-    <refpurpose>Control a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<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>Media ioctl request code as defined in the media.h header file,
-         for example MEDIA_IOC_SETUP_LINK.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a request-specific structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>The <function>ioctl()</function> function manipulates media device
-    parameters. The argument <parameter>fd</parameter> must be an open file
-    descriptor.</para>
-    <para>The ioctl <parameter>request</parameter> code specifies the media
-    function to be called. It has encoded in it whether the argument is an
-    input, output or read/write parameter, and the size of the argument
-    <parameter>argp</parameter> in bytes.</para>
-    <para>Macros and structures definitions specifying media ioctl requests and
-    their parameters are located in the media.h header file. All media ioctl
-    requests, their respective function and parameters are specified in
-    <xref linkend="media-user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <para>Request-specific error codes are listed in the
-    individual requests descriptions.</para>
-    <para>When an ioctl that takes an output or read/write parameter fails,
-    the parameter remains unmodified.</para>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-func-open.xml b/Documentation/DocBook/media/v4l/media-func-open.xml
deleted file mode 100644 (file)
index 122374a..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<refentry id="media-func-open">
-  <refmeta>
-    <refentrytitle>media open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-open</refname>
-    <refpurpose>Open a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
-         or <constant>O_RDWR</constant>. Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-    <para>To open a media device applications call <function>open()</function>
-    with the desired device name. The function has no side effects; the device
-    configuration remain unchanged.</para>
-    <para>When the device is opened in read-only mode, attempts to modify its
-    configuration will result in an error, and <varname>errno</varname> will be
-    set to <errorcode>EBADF</errorcode>.</para>
-  </refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>open</function> returns the new file descriptor on success.
-    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
-    Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The requested access to the file is not allowed.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of files open.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The system limit on the total number of open files has been
-         reached.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Insufficient kernel memory was available.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file exists.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-device-info.xml b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml
deleted file mode 100644 (file)
index b0a21ac..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<refentry id="media-ioc-device-info">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_DEVICE_INFO</refname>
-    <refpurpose>Query device information</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 media_device_info *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_DEVICE_INFO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
-    ioctl. To query device information, applications call the ioctl with a
-    pointer to a &media-device-info;. The driver fills the structure and returns
-    the information to the application.
-    The ioctl never fails.</para>
-
-    <table pgwide="1" frame="none" id="media-device-info">
-      <title>struct <structname>media_device_info</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>char</entry>
-           <entry><structfield>driver</structfield>[16]</entry>
-           <entry><para>Name of the driver implementing the media API as a
-           NUL-terminated ASCII string. The driver version is stored in the
-           <structfield>driver_version</structfield> field.</para>
-           <para>Driver specific applications can use this information to
-           verify the driver identity. It is also useful to work around
-           known bugs, or to identify drivers in error reports.</para></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>model</structfield>[32]</entry>
-           <entry>Device model name as a NUL-terminated UTF-8 string. The
-           device version is stored in the <structfield>device_version</structfield>
-           field and is not be appended to the model name.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>serial</structfield>[40]</entry>
-           <entry>Serial number as a NUL-terminated ASCII string.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>bus_info</structfield>[32]</entry>
-           <entry>Location of the device in the system as a NUL-terminated
-           ASCII string. This includes the bus type name (PCI, USB, ...) and a
-           bus-specific identifier.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>media_version</structfield></entry>
-           <entry>Media API version, formatted with the
-           <constant>KERNEL_VERSION()</constant> macro.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hw_revision</structfield></entry>
-           <entry>Hardware device revision in a driver-specific format.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>driver_version</structfield></entry>
-           <entry>Media device driver version, formatted with the
-           <constant>KERNEL_VERSION()</constant> macro. Together with the
-           <structfield>driver</structfield> field this identifies a particular
-           driver.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[31]</entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
-    fields can be used to distinguish between multiple instances of otherwise
-    identical hardware. The serial number takes precedence when provided and can
-    be assumed to be unique. If the serial number is an empty string, the
-    <structfield>bus_info</structfield> field can be used instead. The
-    <structfield>bus_info</structfield> field is guaranteed to be unique, but
-    can vary across reboots or device unplug/replug.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
deleted file mode 100644 (file)
index 0c4f96b..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<refentry id="media-ioc-enum-entities">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
-    <refpurpose>Enumerate entities and their properties</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 media_entity_desc *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_ENUM_ENTITIES</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>To query the attributes of an entity, applications set the id field
-    of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
-    ioctl with a pointer to this structure. The driver fills the rest of the
-    structure or returns an &EINVAL; when the id is invalid.</para>
-    <para>Entities can be enumerated by or'ing the id with the
-    <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
-    information about the entity with the smallest id strictly larger than the
-    requested one ('next entity'), or the &EINVAL; if there is none.</para>
-    <para>Entity IDs can be non-contiguous. Applications must
-    <emphasis>not</emphasis> try to enumerate entities by calling
-    MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
-
-    <table pgwide="1" frame="none" id="media-entity-desc">
-      <title>struct <structname>media_entity_desc</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity id, set by the application. When the id is or'ed with
-           <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
-           flag and returns the first entity with a larger id.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>revision</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity revision. Always zero (obsolete)</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>group_id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity group ID. Always zero (obsolete)</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>pads</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Number of pads</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>links</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Total number of outbound links. Inbound links are not counted
-           in this field.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>dev</structfield></entry>
-           <entry></entry>
-           <entry>Valid for (sub-)devices that create a single device node.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry>Device node major number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry>Device node minor number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw</structfield>[184]</entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-entity-desc; <structfield>id</structfield> references
-         a non-existing entity.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
deleted file mode 100644 (file)
index 2bbeea9..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-<refentry id="media-ioc-enum-links">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_ENUM_LINKS</refname>
-    <refpurpose>Enumerate all pads and links for a given entity</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 media_links_enum *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_ENUM_LINKS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To enumerate pads and/or links for a given entity, applications set
-    the entity field of a &media-links-enum; structure and initialize the
-    &media-pad-desc; and &media-link-desc; structure arrays pointed by the
-    <structfield>pads</structfield> and <structfield>links</structfield> fields.
-    They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
-    structure.</para>
-    <para>If the <structfield>pads</structfield> field is not NULL, the driver
-    fills the <structfield>pads</structfield> array with information about the
-    entity's pads. The array must have enough room to store all the entity's
-    pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
-    ioctl.</para>
-    <para>If the <structfield>links</structfield> field is not NULL, the driver
-    fills the <structfield>links</structfield> array with information about the
-    entity's outbound links. The array must have enough room to store all the
-    entity's outbound links. The number of outbound links can be retrieved with
-    the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
-    <para>Only forward links that originate at one of the entity's source pads
-    are returned during the enumeration process.</para>
-
-    <table pgwide="1" frame="none" id="media-links-enum">
-      <title>struct <structname>media_links_enum</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entity</structfield></entry>
-           <entry>Entity id, set by the application.</entry>
-         </row>
-         <row>
-           <entry>&media-pad-desc;</entry>
-           <entry>*<structfield>pads</structfield></entry>
-           <entry>Pointer to a pads array allocated by the application. Ignored
-           if NULL.</entry>
-         </row>
-         <row>
-           <entry>&media-link-desc;</entry>
-           <entry>*<structfield>links</structfield></entry>
-           <entry>Pointer to a links array allocated by the application. Ignored
-           if NULL.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-pad-desc">
-      <title>struct <structname>media_pad_desc</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entity</structfield></entry>
-           <entry>ID of the entity this pad belongs to.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>0-based pad index.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-link-desc">
-      <title>struct <structname>media_link_desc</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&media-pad-desc;</entry>
-           <entry><structfield>source</structfield></entry>
-           <entry>Pad at the origin of this link.</entry>
-         </row>
-         <row>
-           <entry>&media-pad-desc;</entry>
-           <entry><structfield>sink</structfield></entry>
-           <entry>Pad at the target of this link.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-links-enum; <structfield>id</structfield> references
-         a non-existing entity.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-g-topology.xml b/Documentation/DocBook/media/v4l/media-ioc-g-topology.xml
deleted file mode 100644 (file)
index e0d49fa..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-<refentry id="media-g-topology">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_G_TOPOLOGY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_G_TOPOLOGY</refname>
-    <refpurpose>Enumerate the graph topology and graph element properties</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 media_v2_topology *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_G_TOPOLOGY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>The typical usage of this ioctl is to call it twice.
-    On the first call, the structure defined at &media-v2-topology; should
-    be zeroed. At return, if no errors happen, this ioctl will return the
-    <constant>topology_version</constant> and the total number of entities,
-    interfaces, pads and links.</para>
-    <para>Before the second call, the userspace should allocate arrays to
-    store the graph elements that are desired, putting the pointers to them
-    at the ptr_entities, ptr_interfaces, ptr_links and/or ptr_pads, keeping
-    the other values untouched.</para>
-    <para>If the <constant>topology_version</constant> remains the same, the
-    ioctl should fill the desired arrays with the media graph elements.</para>
-
-    <table pgwide="1" frame="none" id="media-v2-topology">
-      <title>struct <structname>media_v2_topology</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>topology_version</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Version of the media graph topology. When the graph is
-                   created, this field starts with zero. Every time a graph
-                   element is added or removed, this field is
-                   incremented.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>num_entities</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Number of entities in the graph</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ptr_entities</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>A pointer to a memory area where the entities array
-                  will be stored, converted to a 64-bits integer.
-                  It can be zero. if zero, the ioctl won't store the
-                  entities. It will just update
-                  <constant>num_entities</constant></entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>num_interfaces</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Number of interfaces in the graph</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ptr_interfaces</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>A pointer to a memory area where the interfaces array
-                  will be stored, converted to a 64-bits integer.
-                  It can be zero. if zero, the ioctl won't store the
-                  interfaces. It will just update
-                  <constant>num_interfaces</constant></entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>num_pads</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Total number of pads in the graph</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ptr_pads</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>A pointer to a memory area where the pads array
-                  will be stored, converted to a 64-bits integer.
-                  It can be zero. if zero, the ioctl won't store the
-                  pads. It will just update
-                  <constant>num_pads</constant></entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>num_links</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Total number of data and interface links in the graph</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>ptr_links</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>A pointer to a memory area where the links array
-                  will be stored, converted to a 64-bits integer.
-                  It can be zero. if zero, the ioctl won't store the
-                  links. It will just update
-                  <constant>num_links</constant></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-v2-entity">
-      <title>struct <structname>media_v2_entity</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Unique ID for the entity.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name</structfield>[64]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>function</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity main function, see <xref linkend="media-entity-type" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[12]</entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-v2-interface">
-      <title>struct <structname>media_v2_interface</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Unique ID for the interface.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>intf_type</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Interface type, see <xref linkend="media-intf-type" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Interface flags. Currently unused.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-         <row>
-           <entry>struct media_v2_intf_devnode</entry>
-           <entry><structfield>devnode</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Used only for device node interfaces. See <xref linkend="media-v2-intf-devnode" /> for details..</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-v2-intf-devnode">
-      <title>struct <structname>media_v2_interface</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Device node major number.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Device node minor number.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-v2-pad">
-      <title>struct <structname>media_v2_pad</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Unique ID for the pad.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entity_id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Unique ID for the entity where this pad belongs.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-v2-link">
-      <title>struct <structname>media_v2_pad</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Unique ID for the pad.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>source_id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>
-              <para>On pad to pad links: unique ID for the source pad.</para>
-              <para>On interface to entity links: unique ID for the interface.</para>
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sink_id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>
-              <para>On pad to pad links: unique ID for the sink pad.</para>
-              <para>On interface to entity links: unique ID for the entity.</para>
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[5]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>ENOSPC</errorcode></term>
-       <listitem>
-         <para>This is returned when either one or more of the num_entities,
-         num_interfaces, num_links or num_pads are non-zero and are smaller
-         than the actual number of elements inside the graph. This may happen
-         if the <constant>topology_version</constant> changed when compared
-         to the last time this ioctl was called. Userspace should usually
-         free the area for the pointers, zero the struct elements and call
-         this ioctl again.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml
deleted file mode 100644 (file)
index fc2e522..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<refentry id="media-ioc-setup-link">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_SETUP_LINK</refname>
-    <refpurpose>Modify the properties of a link</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 media_link_desc *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_SETUP_LINK</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To change link properties applications fill a &media-link-desc; with
-    link identification information (source and sink pad) and the new requested
-    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
-    that structure.</para>
-    <para>The only configurable property is the <constant>ENABLED</constant>
-    link flag to enable/disable a link. Links marked with the
-    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
-    </para>
-    <para>Link configuration has no side effect on other links. If an enabled
-    link at the sink pad prevents the link from being enabled, the driver
-    returns with an &EBUSY;.</para>
-    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
-    be enabled/disabled while streaming media data. Attempting to enable or
-    disable a streaming non-dynamic link will return an &EBUSY;.</para>
-    <para>If the specified link can't be found the driver returns with an
-    &EINVAL;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-link-desc; references a non-existing link, or the
-         link is immutable and an attempt to modify its configuration was made.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-types.xml b/Documentation/DocBook/media/v4l/media-types.xml
deleted file mode 100644 (file)
index 95aa1f9..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-<section id="media-controller-types">
-<title>Types and flags used to represent the media graph elements</title>
-
-    <table frame="none" pgwide="1" id="media-entity-type">
-      <title>Media entity types</title>
-      <tgroup cols="2">
-       <colspec colname="c1"/>
-       <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_ENT_F_UNKNOWN</constant> and <constant>MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN</constant></entry>
-           <entry>Unknown entity. That generally indicates that
-           a driver didn't initialize properly the entity, with is a Kernel bug</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IO_V4L</constant></entry>
-           <entry>Data streaming input and/or output entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IO_VBI</constant></entry>
-           <entry>V4L VBI streaming input or output entity</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IO_SWRADIO</constant></entry>
-           <entry>V4L Software Digital Radio (SDR) streaming input or output entity</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IO_DTV</constant></entry>
-           <entry>DVB Digital TV streaming input or output entity</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_DTV_DEMOD</constant></entry>
-           <entry>Digital TV demodulator entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_TS_DEMUX</constant></entry>
-           <entry>MPEG Transport stream demux entity. Could be implemented on hardware or in Kernelspace by the Linux DVB subsystem.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_DTV_CA</constant></entry>
-           <entry>Digital TV Conditional Access module (CAM) entity</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_DTV_NET_DECAP</constant></entry>
-           <entry>Digital TV network ULE/MLE desencapsulation entity. Could be implemented on hardware or in Kernelspace</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_CONN_RF</constant></entry>
-           <entry>Connector for a Radio Frequency (RF) signal.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_CONN_SVIDEO</constant></entry>
-           <entry>Connector for a S-Video signal.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_CONN_COMPOSITE</constant></entry>
-           <entry>Connector for a RGB composite signal.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_CAM_SENSOR</constant></entry>
-           <entry>Camera video sensor entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_FLASH</constant></entry>
-           <entry>Flash controller entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_LENS</constant></entry>
-           <entry>Lens controller entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_ATV_DECODER</constant></entry>
-           <entry>Analog video decoder, the basic function of the video decoder
-           is to accept analogue video from a wide variety of sources such as
-           broadcast, DVD players, cameras and video cassette recorders, in
-           either NTSC, PAL, SECAM or HD format, separating the stream
-           into its component parts, luminance and chrominance, and output
-           it in some digital video standard, with appropriate timing
-           signals.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_TUNER</constant></entry>
-           <entry>Digital TV, analog TV, radio and/or software radio tuner,
-                  with consists on a PLL tuning stage that converts radio
-                  frequency (RF) signal into an Intermediate Frequency (IF).
-                  Modern tuners have internally IF-PLL decoders for audio
-                  and video, but older models have those stages implemented
-                  on separate entities.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IF_VID_DECODER</constant></entry>
-           <entry>IF-PLL video decoder. It receives the IF from a PLL
-                  and decodes the analog TV video signal. This is commonly
-                  found on some very old analog tuners, like Philips MK3
-                  designs. They all contain a tda9887 (or some software
-                  compatible similar chip, like tda9885). Those devices
-                  use a different I2C address than the tuner PLL.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_IF_AUD_DECODER</constant></entry>
-           <entry>IF-PLL sound decoder. It receives the IF from a PLL
-                  and decodes the analog TV audio signal. This is commonly
-                  found on some very old analog hardware, like Micronas
-                  msp3400, Philips tda9840, tda985x, etc. Those devices
-                  use a different I2C address than the tuner PLL and
-                  should be controlled together with the IF-PLL video
-                  decoder.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_AUDIO_CAPTURE</constant></entry>
-           <entry>Audio Capture Function Entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_AUDIO_PLAYBACK</constant></entry>
-           <entry>Audio Playback Function Entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry>
-           <entry>Audio Mixer Function Entity.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_COMPOSER</constant></entry>
-           <entry>Video composer (blender). An entity capable of video
-                  composing must have at least two sink pads and one source
-                  pad, and composes input video frames onto output video
-                  frames. Composition can be performed using alpha blending,
-                  color keying, raster operations (ROP), stitching or any other
-                  means.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER</constant></entry>
-           <entry>Video pixel formatter. An entity capable of pixel formatting
-                  must have at least one sink pad and one source pad. Read
-                  pixel formatters read pixels from memory and perform a subset
-                  of unpacking, cropping, color keying, alpha multiplication
-                  and pixel encoding conversion. Write pixel formatters perform
-                  a subset of dithering, pixel encoding conversion and packing
-                  and write pixels to memory.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV</constant></entry>
-           <entry>Video pixel encoding converter. An entity capable of pixel
-                  enconding conversion must have at least one sink pad and one
-                  source pad, and convert the encoding of pixels received on
-                  its sink pad(s) to a different encoding output on its source
-                  pad(s). Pixel encoding conversion includes but isn't limited
-                  to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB
-                  conversions.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_LUT</constant></entry>
-           <entry>Video look-up table. An entity capable of video lookup table
-                  processing must have one sink pad and one source pad. It uses
-                  the values of the pixels received on its sink pad to look up
-                  entries in internal tables and output them on its source pad.
-                  The lookup processing can be performed on all components
-                  separately or combine them for multi-dimensional table
-                  lookups.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_SCALER</constant></entry>
-           <entry>Video scaler. An entity capable of video scaling must have
-                  at least one sink pad and one source pad, and scale the
-                  video frame(s) received on its sink pad(s) to a different
-                  resolution output on its source pad(s). The range of
-                  supported scaling ratios is entity-specific and can differ
-                  between the horizontal and vertical directions (in particular
-                  scaling can be supported in one direction only). Binning and
-                  skipping are considered as scaling.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_PROC_VIDEO_STATISTICS</constant></entry>
-           <entry>Video statistics computation (histogram, 3A, ...). An entity
-                  capable of statistics computation must have one sink pad and
-                  one source pad. It computes statistics over the frames
-                  received on its sink pad and outputs the statistics data on
-                  its source pad.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-entity-flag">
-      <title>Media entity flags</title>
-      <tgroup cols="2">
-       <colspec colname="c1"/>
-       <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
-           <entry>Default entity for its type. Used to discover the default
-           audio, VBI and video devices, the default camera sensor, ...</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_FL_CONNECTOR</constant></entry>
-           <entry>The entity represents a data conector</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-intf-type">
-      <title>Media interface types</title>
-      <tgroup cols="3">
-       <colspec colname="c1"/>
-       <colspec colname="c2"/>
-       <colspec colname="c3"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_INTF_T_DVB_FE</constant></entry>
-           <entry>Device node interface for the Digital TV frontend</entry>
-           <entry>typically, /dev/dvb/adapter?/frontend?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_DVB_DEMUX</constant></entry>
-           <entry>Device node interface for the Digital TV demux</entry>
-           <entry>typically, /dev/dvb/adapter?/demux?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_DVB_DVR</constant></entry>
-           <entry>Device node interface for the Digital TV DVR</entry>
-           <entry>typically, /dev/dvb/adapter?/dvr?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_DVB_CA</constant></entry>
-           <entry>Device node interface for the Digital TV Conditional Access</entry>
-           <entry>typically, /dev/dvb/adapter?/ca?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_DVB_FE</constant></entry>
-           <entry>Device node interface for the Digital TV network control</entry>
-           <entry>typically, /dev/dvb/adapter?/net?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_V4L_VIDEO</constant></entry>
-           <entry>Device node interface for video (V4L)</entry>
-           <entry>typically, /dev/video?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_V4L_VBI</constant></entry>
-           <entry>Device node interface for VBI (V4L)</entry>
-           <entry>typically, /dev/vbi?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_V4L_RADIO</constant></entry>
-           <entry>Device node interface for radio (V4L)</entry>
-           <entry>typically, /dev/vbi?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_V4L_SUBDEV</constant></entry>
-           <entry>Device node interface for a V4L subdevice</entry>
-           <entry>typically, /dev/v4l-subdev?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_V4L_SWRADIO</constant></entry>
-           <entry>Device node interface for Software Defined Radio (V4L)</entry>
-           <entry>typically, /dev/swradio?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_PCM_CAPTURE</constant></entry>
-           <entry>Device node interface for ALSA PCM Capture</entry>
-           <entry>typically, /dev/snd/pcmC?D?c</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_PCM_PLAYBACK</constant></entry>
-           <entry>Device node interface for ALSA PCM Playback</entry>
-           <entry>typically, /dev/snd/pcmC?D?p</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_CONTROL</constant></entry>
-           <entry>Device node interface for ALSA Control</entry>
-           <entry>typically, /dev/snd/controlC?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_COMPRESS</constant></entry>
-           <entry>Device node interface for ALSA Compress</entry>
-           <entry>typically, /dev/snd/compr?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_RAWMIDI</constant></entry>
-           <entry>Device node interface for ALSA Raw MIDI</entry>
-           <entry>typically, /dev/snd/midi?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_HWDEP</constant></entry>
-           <entry>Device node interface for ALSA Hardware Dependent</entry>
-           <entry>typically, /dev/snd/hwC?D?</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_SEQUENCER</constant></entry>
-           <entry>Device node interface for ALSA Sequencer</entry>
-           <entry>typically, /dev/snd/seq</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_INTF_T_ALSA_TIMER</constant></entry>
-           <entry>Device node interface for ALSA Timer</entry>
-           <entry>typically, /dev/snd/timer</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-pad-flag">
-      <title>Media pad flags</title>
-      <tgroup cols="2">
-       <colspec colname="c1"/>
-       <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
-           <entry>Input pad, relative to the entity. Input pads sink data and
-           are targets of links.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
-           <entry>Output pad, relative to the entity. Output pads source data
-           and are origins of links.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_PAD_FL_MUST_CONNECT</constant></entry>
-           <entry>If this flag is set and the pad is linked to any other
-           pad, then at least one of those links must be enabled for the
-           entity to be able to stream. There could be temporary reasons
-           (e.g. device configuration dependent) for the pad to need
-           enabled links even when this flag isn't set; the absence of the
-           flag doesn't imply there is none.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
-    <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
-
-    <table frame="none" pgwide="1" id="media-link-flag">
-      <title>Media link flags</title>
-      <tgroup cols="2">
-       <colspec colname="c1"/>
-       <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
-           <entry>The link is enabled and can be used to transfer media data.
-           When two or more links target a sink pad, only one of them can be
-           enabled at a time.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
-           <entry>The link enabled state can't be modified at runtime. An
-           immutable link is always enabled.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
-           <entry>The link enabled state can be modified during streaming. This
-           flag is set by drivers and is read-only for applications.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_LNK_FL_LINK_TYPE</constant></entry>
-           <entry><para>This is a bitmask that defines the type of the link.
-                  Currently, two types of links are supported:</para>
-           <para><constant>MEDIA_LNK_FL_DATA_LINK</constant>
-           if the link is between two pads</para>
-           <para><constant>MEDIA_LNK_FL_INTERFACE_LINK</constant>
-           if the link is between an interface and an entity</para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-</section>
diff --git a/Documentation/DocBook/media/v4l/pipeline.pdf b/Documentation/DocBook/media/v4l/pipeline.pdf
deleted file mode 100644 (file)
index ee3e37f..0000000
Binary files a/Documentation/DocBook/media/v4l/pipeline.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/pixfmt-grey.xml b/Documentation/DocBook/media/v4l/pixfmt-grey.xml
deleted file mode 100644 (file)
index bee970d..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-GREY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_GREY ('GREY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_GREY</constant></refname>
-       <refpurpose>Grey-scale image</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a grey-scale image. It is really a degenerate
-Y'CbCr format which simply contains no Cb or Cr data.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_GREY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-m420.xml b/Documentation/DocBook/media/v4l/pixfmt-m420.xml
deleted file mode 100644 (file)
index aadae92..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-M420">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_M420</constant></refname>
-       <refpurpose>Format with &frac12; horizontal and vertical chroma
-       resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
-       layout.</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>M420 is a YUV format with &frac12; horizontal and vertical chroma
-       subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
-       chroma planes. Two lines of luma data are followed by one line of chroma
-       data.</para>
-       <para>The luma plane has one byte per pixel. The chroma plane contains
-       interleaved CbCr pixels subsampled by &frac12; in the horizontal and
-       vertical directions. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
-
-       <para>All line lengths are identical: if the Y lines include pad bytes
-       so do the CbCr lines.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12.xml
deleted file mode 100644 (file)
index 84dd4fd..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV12"><constant>V4L2_PIX_FMT_NV12</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV21"><constant>V4L2_PIX_FMT_NV21</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal and vertical
-chroma resolution, also known as YUV 4:2:0. One luminance and one
-chrominance plane with alternating chroma samples as opposed to
-<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are two-plane versions of the YUV 4:2:0 format.
-The three components are separated into two sub-images or planes. The
-Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_NV12</constant>, a combined CbCr plane
-immediately follows the Y plane in memory.  The CbCr plane is the same
-width, in bytes, as the Y plane (and of the image), but is half as
-tall in pixels. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.
-<constant>V4L2_PIX_FMT_NV21</constant> is the same except the Cb and
-Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV12</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
deleted file mode 100644 (file)
index f3a3d45..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12M ('NM12'), V4L2_PIX_FMT_NV21M ('NM21'), V4L2_PIX_FMT_NV12MT_16X16</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV12M"><constant>V4L2_PIX_FMT_NV12M</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV21M"><constant>V4L2_PIX_FMT_NV21M</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV12MT-16X16"><constant>V4L2_PIX_FMT_NV12MT_16X16</constant></refname>
-       <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> and <constant>V4L2_PIX_FMT_NV21</constant> with planes
-         non contiguous in memory. </refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar, two-plane version of the YUV 4:2:0 format.
-The three components are separated into two sub-images or planes.
-<constant>V4L2_PIX_FMT_NV12M</constant> differs from <constant>V4L2_PIX_FMT_NV12
-</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
-plane do not necessarily immediately follows the luma plane.
-The luminance data occupies the first plane. The Y plane has one byte per pixel.
-In the second plane there is a chrominance data with alternating chroma samples.
-The CbCr plane is the same width, in bytes, as the Y plane (and of the image),
-but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.
-<constant>V4L2_PIX_FMT_NV12MT_16X16</constant> is the tiled version of
-<constant>V4L2_PIX_FMT_NV12M</constant> with 16x16 macroblock tiles. Here pixels
-are arranged in 16x16 2D tiles and tiles are arranged in linear order in memory.
-<constant>V4L2_PIX_FMT_NV21M</constant> is the same as <constant>V4L2_PIX_FMT_NV12M</constant>
-except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV12M</constant> 4 &times; 4 pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
deleted file mode 100644 (file)
index 8a70a17..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12MT ('TM12')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV12MT"><constant>V4L2_PIX_FMT_NV12MT
-</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal and vertical
-chroma resolution. This format has two planes - one for luminance and one for
-chrominance. Chroma samples are interleaved. The difference to
-<constant>V4L2_PIX_FMT_NV12</constant> is the memory layout. Pixels are
-grouped in macroblocks of 64x32 size. The order of macroblocks in memory is
-also not standard.
-       </refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is the two-plane versions of the YUV 4:2:0 format where data
-is grouped into 64x32 macroblocks. The three components are separated into two
-sub-images or planes. The Y plane has one byte per pixel and pixels are grouped
-into 64x32 macroblocks. The CbCr plane has the same width, in bytes, as the Y
-plane (and the image), but is half as tall in pixels. The chroma plane is also
-grouped into 64x32 macroblocks.</para>
-       <para>Width of the buffer has to be aligned to the multiple of 128, and
-height alignment is 32. Every four adjacent buffers - two horizontally and two
-vertically are grouped together and are located in memory in Z or flipped Z
-order. </para>
-       <para>Layout of macroblocks in memory is presented in the following
-figure.</para>
-       <para><figure id="nv12mt">
-           <title><constant>V4L2_PIX_FMT_NV12MT</constant> macroblock Z shape
-memory layout</title>
-           <mediaobject>
-             <imageobject>
-               <imagedata fileref="nv12mt.gif" format="GIF" />
-             </imageobject>
-           </mediaobject>
-       </figure>
-       The requirement that width is multiple of 128 is implemented because,
-the Z shape cannot be cut in half horizontally. In case the vertical resolution
-of macroblocks is odd then the last row of macroblocks is arranged in a linear
-order.  </para>
-       <para>In case of chroma the layout is identical. Cb and Cr samples are
-interleaved. Height of the buffer is aligned to 32.
-       </para>
-       <example>
-         <title>Memory layout of macroblocks in <constant>V4L2_PIX_FMT_NV12
-</constant> format pixel image - extreme case</title>
-       <para>
-       <figure id="nv12mt_ex">
-           <title>Example <constant>V4L2_PIX_FMT_NV12MT</constant> memory
-layout of macroblocks</title>
-           <mediaobject>
-             <imageobject>
-               <imagedata fileref="nv12mt_example.gif" format="GIF" />
-             </imageobject>
-           </mediaobject>
-       </figure>
-       Memory layout of macroblocks of <constant>V4L2_PIX_FMT_NV12MT
-</constant> format in most extreme case.
-       </para>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16.xml
deleted file mode 100644 (file)
index 8ae1f8a..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV16 ('NV16'), V4L2_PIX_FMT_NV61 ('NV61')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV16"><constant>V4L2_PIX_FMT_NV16</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV61"><constant>V4L2_PIX_FMT_NV61</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal
-chroma resolution, also known as YUV 4:2:2. One luminance and one
-chrominance plane with alternating chroma samples as opposed to
-<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are two-plane versions of the YUV 4:2:2 format.
-The three components are separated into two sub-images or planes. The
-Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_NV16</constant>, a combined CbCr plane
-immediately follows the Y plane in memory.  The CbCr plane is the same
-width and height, in bytes, as the Y plane (and of the image).
-Each CbCr pair belongs to two pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>.
-<constant>V4L2_PIX_FMT_NV61</constant> is the same except the Cb and
-Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV16</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;28:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16m.xml
deleted file mode 100644 (file)
index fb2b5e3..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV16M ('NM16'), V4L2_PIX_FMT_NV61M ('NM61')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV16M"><constant>V4L2_PIX_FMT_NV16M</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV61M"><constant>V4L2_PIX_FMT_NV61M</constant></refname>
-       <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV16</constant> and <constant>V4L2_PIX_FMT_NV61</constant> with planes
-         non contiguous in memory. </refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar, two-plane version of the YUV 4:2:2 format.
-The three components are separated into two sub-images or planes.
-<constant>V4L2_PIX_FMT_NV16M</constant> differs from <constant>V4L2_PIX_FMT_NV16
-</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
-plane does not necessarily immediately follow the luma plane.
-The luminance data occupies the first plane. The Y plane has one byte per pixel.
-In the second plane there is chrominance data with alternating chroma samples.
-The CbCr plane is the same width and height, in bytes, as the Y plane.
-Each CbCr pair belongs to two pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>.
-<constant>V4L2_PIX_FMT_NV61M</constant> is the same as <constant>V4L2_PIX_FMT_NV16M</constant>
-except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para><constant>V4L2_PIX_FMT_NV16M</constant> and
-<constant>V4L2_PIX_FMT_NV61M</constant> are intended to be used only in drivers
-and applications that support the multi-planar API, described in
-<xref linkend="planar-apis"/>. </para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV16M</constant> 4 &times; 4 pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>02</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>12</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>22</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;12:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>32</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv24.xml b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml
deleted file mode 100644 (file)
index fb255f2..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV24 ('NV24'), V4L2_PIX_FMT_NV42 ('NV42')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV24"><constant>V4L2_PIX_FMT_NV24</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV42"><constant>V4L2_PIX_FMT_NV42</constant></refname>
-       <refpurpose>Formats with full horizontal and vertical
-chroma resolutions, also known as YUV 4:4:4. One luminance and one
-chrominance plane with alternating chroma samples as opposed to
-<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are two-plane versions of the YUV 4:4:4 format. The three
-       components are separated into two sub-images or planes. The Y plane is
-       first, with each Y sample stored in one byte per pixel. For
-       <constant>V4L2_PIX_FMT_NV24</constant>, a combined CbCr plane
-       immediately follows the Y plane in memory. The CbCr plane has the same
-       width and height, in pixels, as the Y plane (and the image). Each line
-       contains one CbCr pair per pixel, with each Cb and Cr sample stored in
-       one byte. <constant>V4L2_PIX_FMT_NV42</constant> is the same except that
-       the Cb and Cr samples are swapped, the CrCb plane starts with a Cr
-       sample.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the CbCr plane
-       has twice as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV24</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>03</subscript></entry>
-                     <entry>Cr<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>13</subscript></entry>
-                     <entry>Cr<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;32:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>23</subscript></entry>
-                     <entry>Cr<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;40:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>33</subscript></entry>
-                     <entry>Cr<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
deleted file mode 100644 (file)
index b60fb93..0000000
+++ /dev/null
@@ -1,937 +0,0 @@
-<refentry id="packed-rgb">
-  <refmeta>
-    <refentrytitle>Packed RGB formats</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname>Packed RGB formats</refname>
-    <refpurpose>Packed RGB formats</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>These formats are designed to match the pixel formats of
-typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits
-per pixel. These are all packed-pixel formats, meaning all the data
-for a pixel lie next to each other in memory.</para>
-
-    <table pgwide="1" frame="none" id="rgb-formats">
-      <title>Packed RGB Image Formats</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-RGB332">
-           <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
-           <entry>'RGB1'</entry>
-           <entry></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ARGB444">
-           <entry><constant>V4L2_PIX_FMT_ARGB444</constant></entry>
-           <entry>'AR12'</entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XRGB444">
-           <entry><constant>V4L2_PIX_FMT_XRGB444</constant></entry>
-           <entry>'XR12'</entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ARGB555">
-           <entry><constant>V4L2_PIX_FMT_ARGB555</constant></entry>
-           <entry>'AR15'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XRGB555">
-           <entry><constant>V4L2_PIX_FMT_XRGB555</constant></entry>
-           <entry>'XR15'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB565">
-           <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
-           <entry>'RGBP'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ARGB555X">
-           <entry><constant>V4L2_PIX_FMT_ARGB555X</constant></entry>
-           <entry>'AR15' | (1 &lt;&lt; 31)</entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XRGB555X">
-           <entry><constant>V4L2_PIX_FMT_XRGB555X</constant></entry>
-           <entry>'XR15' | (1 &lt;&lt; 31)</entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB565X">
-           <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
-           <entry>'RGBR'</entry>
-           <entry></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR24">
-           <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
-           <entry>'BGR3'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB24">
-           <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
-           <entry>'RGB3'</entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR666">
-           <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
-           <entry>'BGRH'</entry>
-           <entry></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ABGR32">
-           <entry><constant>V4L2_PIX_FMT_ABGR32</constant></entry>
-           <entry>'AR24'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XBGR32">
-           <entry><constant>V4L2_PIX_FMT_XBGR32</constant></entry>
-           <entry>'XR24'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ARGB32">
-           <entry><constant>V4L2_PIX_FMT_ARGB32</constant></entry>
-           <entry>'BA24'</entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XRGB32">
-           <entry><constant>V4L2_PIX_FMT_XRGB32</constant></entry>
-           <entry>'BX24'</entry>
-           <entry></entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry>-</entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Bit 7 is the most significant bit.</para>
-
-    <para>The usage and value of the alpha bits (a) in the ARGB and ABGR formats
-    (collectively referred to as alpha formats) depend on the device type and
-    hardware operation. <link linkend="capture">Capture</link> devices
-    (including capture queues of mem-to-mem devices) fill the alpha component in
-    memory. When the device outputs an alpha channel the alpha component will
-    have a meaningful value. Otherwise, when the device doesn't output an alpha
-    channel but can set the alpha bit to a user-configurable value, the <link
-    linkend="v4l2-alpha-component"><constant>V4L2_CID_ALPHA_COMPONENT</constant>
-    </link> control is used to specify that alpha value, and the alpha component
-    of all pixels will be set to the value specified by that control. Otherwise
-    a corresponding format without an alpha component (XRGB or XBGR) must be
-    used instead of an alpha format.</para>
-
-    <para><link linkend="output">Output</link> devices (including output queues
-    of mem-to-mem devices and <link linkend="osd">video output overlay</link>
-    devices) read the alpha component from memory. When the device processes the
-    alpha channel the alpha component must be filled with meaningful values by
-    applications. Otherwise a corresponding format without an alpha component
-    (XRGB or XBGR) must be used instead of an alpha format.</para>
-
-    <para>The XRGB and XBGR formats contain undefined bits (-). Applications,
-    devices and drivers must ignore those bits, for both <link
-    linkend="capture">capture</link> and <link linkend="output">output</link>
-    devices.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 &times; 4 pixel
-image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-             <informaltable frame="none">
-           <tgroup cols="13" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00</subscript></entry>
-                 <entry>G<subscript>00</subscript></entry>
-                 <entry>R<subscript>00</subscript></entry>
-                 <entry>B<subscript>01</subscript></entry>
-                 <entry>G<subscript>01</subscript></entry>
-                 <entry>R<subscript>01</subscript></entry>
-                 <entry>B<subscript>02</subscript></entry>
-                 <entry>G<subscript>02</subscript></entry>
-                 <entry>R<subscript>02</subscript></entry>
-                 <entry>B<subscript>03</subscript></entry>
-                 <entry>G<subscript>03</subscript></entry>
-                 <entry>R<subscript>03</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;12:</entry>
-                 <entry>B<subscript>10</subscript></entry>
-                 <entry>G<subscript>10</subscript></entry>
-                 <entry>R<subscript>10</subscript></entry>
-                 <entry>B<subscript>11</subscript></entry>
-                 <entry>G<subscript>11</subscript></entry>
-                 <entry>R<subscript>11</subscript></entry>
-                 <entry>B<subscript>12</subscript></entry>
-                 <entry>G<subscript>12</subscript></entry>
-                 <entry>R<subscript>12</subscript></entry>
-                 <entry>B<subscript>13</subscript></entry>
-                 <entry>G<subscript>13</subscript></entry>
-                 <entry>R<subscript>13</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>B<subscript>20</subscript></entry>
-                 <entry>G<subscript>20</subscript></entry>
-                 <entry>R<subscript>20</subscript></entry>
-                 <entry>B<subscript>21</subscript></entry>
-                 <entry>G<subscript>21</subscript></entry>
-                 <entry>R<subscript>21</subscript></entry>
-                 <entry>B<subscript>22</subscript></entry>
-                 <entry>G<subscript>22</subscript></entry>
-                 <entry>R<subscript>22</subscript></entry>
-                 <entry>B<subscript>23</subscript></entry>
-                 <entry>G<subscript>23</subscript></entry>
-                 <entry>R<subscript>23</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;36:</entry>
-                 <entry>B<subscript>30</subscript></entry>
-                 <entry>G<subscript>30</subscript></entry>
-                 <entry>R<subscript>30</subscript></entry>
-                 <entry>B<subscript>31</subscript></entry>
-                 <entry>G<subscript>31</subscript></entry>
-                 <entry>R<subscript>31</subscript></entry>
-                 <entry>B<subscript>32</subscript></entry>
-                 <entry>G<subscript>32</subscript></entry>
-                 <entry>R<subscript>32</subscript></entry>
-                 <entry>B<subscript>33</subscript></entry>
-                 <entry>G<subscript>33</subscript></entry>
-                 <entry>R<subscript>33</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-             </informaltable>
-           </para>
-      </formalpara>
-    </example>
-
-    <para>Formats defined in <xref linkend="rgb-formats-deprecated"/> are
-    deprecated and must not be used by new drivers. They are documented here for
-    reference. The meaning of their alpha bits (a) is ill-defined and
-    interpreted as in either the corresponding ARGB or XRGB format, depending on
-    the driver.</para>
-
-    <table pgwide="1" frame="none" id="rgb-formats-deprecated">
-      <title>Deprecated Packed RGB Image Formats</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody>
-         <row id="V4L2-PIX-FMT-RGB444">
-           <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
-           <entry>'R444'</entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB555">
-           <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
-           <entry>'RGBO'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB555X">
-           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
-           <entry>'RGBQ'</entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR32">
-           <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-           <entry>'BGR4'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB32">
-           <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-           <entry>'RGB4'</entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>A test utility to determine which RGB formats a driver
-actually supports is available from the LinuxTV v4l-dvb repository.
-See &v4l-dvb; for access instructions.</para>
-
-  </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml
deleted file mode 100644 (file)
index 33fa5a4..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-<refentry id="packed-yuv">
-  <refmeta>
-    <refentrytitle>Packed YUV formats</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname>Packed YUV formats</refname>
-    <refpurpose>Packed YUV formats</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>Similar to the packed RGB formats these formats store
-the Y, Cb and Cr component of each pixel in one 16 or 32 bit
-word.</para>
-
-    <table pgwide="1" frame="none">
-      <title>Packed YUV Image Formats</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-YUV444">
-           <entry><constant>V4L2_PIX_FMT_YUV444</constant></entry>
-           <entry>'Y444'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV555">
-           <entry><constant>V4L2_PIX_FMT_YUV555</constant></entry>
-           <entry>'YUVO'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV565">
-           <entry><constant>V4L2_PIX_FMT_YUV565</constant></entry>
-           <entry>'YUVP'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry>Cb<subscript>5</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV32">
-           <entry><constant>V4L2_PIX_FMT_YUV32</constant></entry>
-           <entry>'YUV4'</entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Y'<subscript>7</subscript></entry>
-           <entry>Y'<subscript>6</subscript></entry>
-           <entry>Y'<subscript>5</subscript></entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Cb<subscript>7</subscript></entry>
-           <entry>Cb<subscript>6</subscript></entry>
-           <entry>Cb<subscript>5</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Cr<subscript>7</subscript></entry>
-           <entry>Cr<subscript>6</subscript></entry>
-           <entry>Cr<subscript>5</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Bit 7 is the most significant bit. The value of a = alpha
-bits is undefined when reading from the driver, ignored when writing
-to the driver, except when alpha blending has been negotiated for a
-<link linkend="overlay">Video Overlay</link> or <link
-linkend="osd">Video Output Overlay</link>.</para>
-
-  </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml
deleted file mode 100644 (file)
index 6494b05..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<refentry id="V4L2-PIX-FMT-SBGGR16">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_SBGGR16 ('BYR2')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_SBGGR16</constant></refname>
-    <refpurpose>Bayer RGB format</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This format is similar to <link
-linkend="V4L2-PIX-FMT-SBGGR8">
-<constant>V4L2_PIX_FMT_SBGGR8</constant></link>, except each pixel has
-a depth of 16 bits. The least significant byte is stored at lower
-memory addresses (little-endian). Note the actual sampling precision
-may be lower than 16 bits, for example 10 bits per pixel with values
-in range 0 to 1023.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR16</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml
deleted file mode 100644 (file)
index 5eaf2b4..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SBGGR8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SBGGR8 ('BA81')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SBGGR8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a blue and green value, the second row of a green and
-red value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SBGGR8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>B<subscript>00</subscript></entry>
-                     <entry>G<subscript>01</subscript></entry>
-                     <entry>B<subscript>02</subscript></entry>
-                     <entry>G<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>G<subscript>10</subscript></entry>
-                     <entry>R<subscript>11</subscript></entry>
-                     <entry>G<subscript>12</subscript></entry>
-                     <entry>R<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>B<subscript>20</subscript></entry>
-                     <entry>G<subscript>21</subscript></entry>
-                     <entry>B<subscript>22</subscript></entry>
-                     <entry>G<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>G<subscript>30</subscript></entry>
-                     <entry>R<subscript>31</subscript></entry>
-                     <entry>G<subscript>32</subscript></entry>
-                     <entry>R<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml
deleted file mode 100644 (file)
index 6118d8f..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<refentry id="V4L2-SDR-FMT-CS08">
-  <refmeta>
-    <refentrytitle>V4L2_SDR_FMT_CS8 ('CS08')</refentrytitle>
-    &manvol;
-  </refmeta>
-    <refnamediv>
-      <refname>
-        <constant>V4L2_SDR_FMT_CS8</constant>
-      </refname>
-      <refpurpose>Complex signed 8-bit IQ sample</refpurpose>
-    </refnamediv>
-    <refsect1>
-      <title>Description</title>
-      <para>
-This format contains sequence of complex number samples. Each complex number
-consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
-represented as a 8 bit signed number. I value comes first and Q value after
-that.
-      </para>
-    <example>
-      <title><constant>V4L2_SDR_FMT_CS8</constant> 1 sample</title>
-      <formalpara>
-        <title>Byte Order.</title>
-        <para>Each cell is one byte.
-          <informaltable frame="none">
-            <tgroup cols="2" align="center">
-              <colspec align="left" colwidth="2*" />
-              <tbody valign="top">
-                <row>
-                  <entry>start&nbsp;+&nbsp;0:</entry>
-                  <entry>I'<subscript>0</subscript></entry>
-                </row>
-                <row>
-                  <entry>start&nbsp;+&nbsp;1:</entry>
-                  <entry>Q'<subscript>0</subscript></entry>
-                </row>
-              </tbody>
-            </tgroup>
-          </informaltable>
-        </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml
deleted file mode 100644 (file)
index e4b494c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<refentry id="V4L2-SDR-FMT-CS14LE">
-  <refmeta>
-    <refentrytitle>V4L2_SDR_FMT_CS14LE ('CS14')</refentrytitle>
-    &manvol;
-  </refmeta>
-    <refnamediv>
-      <refname>
-        <constant>V4L2_SDR_FMT_CS14LE</constant>
-      </refname>
-      <refpurpose>Complex signed 14-bit little endian IQ sample</refpurpose>
-    </refnamediv>
-    <refsect1>
-      <title>Description</title>
-      <para>
-This format contains sequence of complex number samples. Each complex number
-consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
-represented as a 14 bit signed little endian number. I value comes first
-and Q value after that. 14 bit value is stored in 16 bit space with unused
-high bits padded with 0.
-      </para>
-    <example>
-      <title><constant>V4L2_SDR_FMT_CS14LE</constant> 1 sample</title>
-      <formalpara>
-        <title>Byte Order.</title>
-        <para>Each cell is one byte.
-          <informaltable frame="none">
-            <tgroup cols="3" align="center">
-              <colspec align="left" colwidth="2*" />
-              <tbody valign="top">
-                <row>
-                  <entry>start&nbsp;+&nbsp;0:</entry>
-                  <entry>I'<subscript>0[7:0]</subscript></entry>
-                  <entry>I'<subscript>0[13:8]</subscript></entry>
-                </row>
-                <row>
-                  <entry>start&nbsp;+&nbsp;2:</entry>
-                  <entry>Q'<subscript>0[7:0]</subscript></entry>
-                  <entry>Q'<subscript>0[13:8]</subscript></entry>
-                </row>
-              </tbody>
-            </tgroup>
-          </informaltable>
-        </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu08.xml
deleted file mode 100644 (file)
index 2d80104..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-<refentry id="V4L2-SDR-FMT-CU08">
-  <refmeta>
-    <refentrytitle>V4L2_SDR_FMT_CU8 ('CU08')</refentrytitle>
-    &manvol;
-  </refmeta>
-    <refnamediv>
-      <refname>
-        <constant>V4L2_SDR_FMT_CU8</constant>
-      </refname>
-      <refpurpose>Complex unsigned 8-bit IQ sample</refpurpose>
-    </refnamediv>
-    <refsect1>
-      <title>Description</title>
-      <para>
-This format contains sequence of complex number samples. Each complex number
-consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
-represented as a 8 bit unsigned number. I value comes first and Q value after
-that.
-      </para>
-    <example>
-      <title><constant>V4L2_SDR_FMT_CU8</constant> 1 sample</title>
-      <formalpara>
-        <title>Byte Order.</title>
-        <para>Each cell is one byte.
-          <informaltable frame="none">
-            <tgroup cols="2" align="center">
-              <colspec align="left" colwidth="2*" />
-              <tbody valign="top">
-                <row>
-                  <entry>start&nbsp;+&nbsp;0:</entry>
-                  <entry>I'<subscript>0</subscript></entry>
-                </row>
-                <row>
-                  <entry>start&nbsp;+&nbsp;1:</entry>
-                  <entry>Q'<subscript>0</subscript></entry>
-                </row>
-              </tbody>
-            </tgroup>
-          </informaltable>
-        </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cu16le.xml
deleted file mode 100644 (file)
index 26288ff..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<refentry id="V4L2-SDR-FMT-CU16LE">
-  <refmeta>
-    <refentrytitle>V4L2_SDR_FMT_CU16LE ('CU16')</refentrytitle>
-    &manvol;
-  </refmeta>
-    <refnamediv>
-      <refname>
-        <constant>V4L2_SDR_FMT_CU16LE</constant>
-      </refname>
-      <refpurpose>Complex unsigned 16-bit little endian IQ sample</refpurpose>
-    </refnamediv>
-    <refsect1>
-      <title>Description</title>
-      <para>
-This format contains sequence of complex number samples. Each complex number
-consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
-represented as a 16 bit unsigned little endian number. I value comes first
-and Q value after that.
-      </para>
-    <example>
-      <title><constant>V4L2_SDR_FMT_CU16LE</constant> 1 sample</title>
-      <formalpara>
-        <title>Byte Order.</title>
-        <para>Each cell is one byte.
-          <informaltable frame="none">
-            <tgroup cols="3" align="center">
-              <colspec align="left" colwidth="2*" />
-              <tbody valign="top">
-                <row>
-                  <entry>start&nbsp;+&nbsp;0:</entry>
-                  <entry>I'<subscript>0[7:0]</subscript></entry>
-                  <entry>I'<subscript>0[15:8]</subscript></entry>
-                </row>
-                <row>
-                  <entry>start&nbsp;+&nbsp;2:</entry>
-                  <entry>Q'<subscript>0[7:0]</subscript></entry>
-                  <entry>Q'<subscript>0[15:8]</subscript></entry>
-                </row>
-              </tbody>
-            </tgroup>
-          </informaltable>
-        </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml
deleted file mode 100644 (file)
index 3df076b..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<refentry id="V4L2-SDR-FMT-RU12LE">
-  <refmeta>
-    <refentrytitle>V4L2_SDR_FMT_RU12LE ('RU12')</refentrytitle>
-    &manvol;
-  </refmeta>
-    <refnamediv>
-      <refname>
-        <constant>V4L2_SDR_FMT_RU12LE</constant>
-      </refname>
-      <refpurpose>Real unsigned 12-bit little endian sample</refpurpose>
-    </refnamediv>
-    <refsect1>
-      <title>Description</title>
-      <para>
-This format contains sequence of real number samples. Each sample is
-represented as a 12 bit unsigned little endian number. Sample is stored
-in 16 bit space with unused high bits padded with 0.
-      </para>
-    <example>
-      <title><constant>V4L2_SDR_FMT_RU12LE</constant> 1 sample</title>
-      <formalpara>
-        <title>Byte Order.</title>
-        <para>Each cell is one byte.
-          <informaltable frame="none">
-            <tgroup cols="3" align="center">
-              <colspec align="left" colwidth="2*" />
-              <tbody valign="top">
-                <row>
-                  <entry>start&nbsp;+&nbsp;0:</entry>
-                  <entry>I'<subscript>0[7:0]</subscript></entry>
-                  <entry>I'<subscript>0[11:8]</subscript></entry>
-                </row>
-              </tbody>
-            </tgroup>
-          </informaltable>
-        </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml
deleted file mode 100644 (file)
index fee65dc..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SGBRG8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SGBRG8 ('GBRG')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SGBRG8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a green and blue value, the second row of a red and
-green value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SGBRG8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>G<subscript>00</subscript></entry>
-                     <entry>B<subscript>01</subscript></entry>
-                     <entry>G<subscript>02</subscript></entry>
-                     <entry>B<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>R<subscript>10</subscript></entry>
-                     <entry>G<subscript>11</subscript></entry>
-                     <entry>R<subscript>12</subscript></entry>
-                     <entry>G<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>G<subscript>20</subscript></entry>
-                     <entry>B<subscript>21</subscript></entry>
-                     <entry>G<subscript>22</subscript></entry>
-                     <entry>B<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>R<subscript>30</subscript></entry>
-                     <entry>G<subscript>31</subscript></entry>
-                     <entry>R<subscript>32</subscript></entry>
-                     <entry>G<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml
deleted file mode 100644 (file)
index 7803b8c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SGRBG8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SGRBG8 ('GRBG')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SGRBG8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a green and blue value, the second row of a red and
-green value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SGRBG8</constant> 4 &times;
-4 pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>G<subscript>00</subscript></entry>
-                     <entry>R<subscript>01</subscript></entry>
-                     <entry>G<subscript>02</subscript></entry>
-                     <entry>R<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>B<subscript>10</subscript></entry>
-                     <entry>G<subscript>11</subscript></entry>
-                     <entry>B<subscript>12</subscript></entry>
-                     <entry>G<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>G<subscript>20</subscript></entry>
-                     <entry>R<subscript>21</subscript></entry>
-                     <entry>G<subscript>22</subscript></entry>
-                     <entry>R<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>B<subscript>30</subscript></entry>
-                     <entry>G<subscript>31</subscript></entry>
-                     <entry>B<subscript>32</subscript></entry>
-                     <entry>G<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
deleted file mode 100644 (file)
index f34d03e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-    <refentry id="pixfmt-srggb10">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
-        V4L2_PIX_FMT_SGRBG10 ('BA10'),
-        V4L2_PIX_FMT_SGBRG10 ('GB10'),
-        V4L2_PIX_FMT_SBGGR10 ('BG10'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SRGGB10"><constant>V4L2_PIX_FMT_SRGGB10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG10"><constant>V4L2_PIX_FMT_SGRBG10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG10"><constant>V4L2_PIX_FMT_SGBRG10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SBGGR10"><constant>V4L2_PIX_FMT_SBGGR10</constant></refname>
-       <refpurpose>10-bit Bayer formats expanded to 16 bits</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These four pixel formats are raw sRGB / Bayer formats with
-10 bits per colour. Each colour component is stored in a 16-bit word, with 6
-unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
-and n/2 blue or red samples, with alternating red and blue rows. Bytes are
-stored in memory in little endian order. They are conventionally described
-as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
-formats</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR10</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte, high 6 bits in high bytes are 0.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml
deleted file mode 100644 (file)
index d2e5845..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-       <refentry>
-         <refmeta>
-           <refentrytitle>
-             V4L2_PIX_FMT_SBGGR10ALAW8 ('aBA8'),
-             V4L2_PIX_FMT_SGBRG10ALAW8 ('aGA8'),
-             V4L2_PIX_FMT_SGRBG10ALAW8 ('agA8'),
-             V4L2_PIX_FMT_SRGGB10ALAW8 ('aRA8'),
-           </refentrytitle>
-           &manvol;
-         </refmeta>
-         <refnamediv>
-           <refname id="V4L2-PIX-FMT-SBGGR10ALAW8">
-             <constant>V4L2_PIX_FMT_SBGGR10ALAW8</constant>
-           </refname>
-           <refname id="V4L2-PIX-FMT-SGBRG10ALAW8">
-             <constant>V4L2_PIX_FMT_SGBRG10ALAW8</constant>
-           </refname>
-           <refname id="V4L2-PIX-FMT-SGRBG10ALAW8">
-             <constant>V4L2_PIX_FMT_SGRBG10ALAW8</constant>
-           </refname>
-           <refname id="V4L2-PIX-FMT-SRGGB10ALAW8">
-             <constant>V4L2_PIX_FMT_SRGGB10ALAW8</constant>
-           </refname>
-           <refpurpose>10-bit Bayer formats compressed to 8 bits</refpurpose>
-         </refnamediv>
-         <refsect1>
-           <title>Description</title>
-           <para>These four pixel formats are raw sRGB / Bayer
-           formats with 10 bits per color compressed to 8 bits each,
-           using the A-LAW algorithm. Each color component consumes 8
-           bits of memory. In other respects this format is similar to
-           <xref linkend="V4L2-PIX-FMT-SRGGB8"></xref>.</para>
-         </refsect1>
-       </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
deleted file mode 100644 (file)
index bde8987..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-    <refentry id="pixfmt-srggb10dpcm8">
-      <refmeta>
-       <refentrytitle>
-        V4L2_PIX_FMT_SBGGR10DPCM8 ('bBA8'),
-        V4L2_PIX_FMT_SGBRG10DPCM8 ('bGA8'),
-        V4L2_PIX_FMT_SGRBG10DPCM8 ('BD10'),
-        V4L2_PIX_FMT_SRGGB10DPCM8 ('bRA8'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SBGGR10DPCM8"><constant>V4L2_PIX_FMT_SBGGR10DPCM8</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG10DPCM8"><constant>V4L2_PIX_FMT_SGBRG10DPCM8</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG10DPCM8"><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></refname>
-       <refname id="V4L2-PIX-FMT-SRGGB10DPCM8"><constant>V4L2_PIX_FMT_SRGGB10DPCM8</constant></refname>
-       <refpurpose>10-bit Bayer formats compressed to 8 bits</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These four pixel formats are raw sRGB / Bayer formats
-       with 10 bits per colour compressed to 8 bits each, using DPCM
-       compression. DPCM, differential pulse-code modulation, is lossy.
-       Each colour component consumes 8 bits of memory. In other respects
-       this format is similar to <xref linkend="pixfmt-srggb10" />.</para>
-
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml
deleted file mode 100644 (file)
index a8cc102..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-    <refentry id="pixfmt-srggb10p">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB10P ('pRAA'),
-        V4L2_PIX_FMT_SGRBG10P ('pgAA'),
-        V4L2_PIX_FMT_SGBRG10P ('pGAA'),
-        V4L2_PIX_FMT_SBGGR10P ('pBAA'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SRGGB10P"><constant>V4L2_PIX_FMT_SRGGB10P</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG10P"><constant>V4L2_PIX_FMT_SGRBG10P</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG10P"><constant>V4L2_PIX_FMT_SGBRG10P</constant></refname>
-       <refname id="V4L2-PIX-FMT-SBGGR10P"><constant>V4L2_PIX_FMT_SBGGR10P</constant></refname>
-       <refpurpose>10-bit packed Bayer formats</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These four pixel formats are packed raw sRGB /
-       Bayer formats with 10 bits per colour. Every four consecutive
-       colour components are packed into 5 bytes. Each of the first 4
-       bytes contain the 8 high order bits of the pixels, and the
-       fifth byte contains the two least significants bits of each
-       pixel, in the same order.</para>
-
-       <para>Each n-pixel row contains n/2 green samples and n/2 blue
-       or red samples, with alternating green-red and green-blue
-       rows. They are conventionally described as GRGR... BGBG...,
-       RGRG... GBGB..., etc. Below is an example of one of these
-       formats:</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR10P</constant> 4 &times; 4
-      pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="topbot" colsep="1" rowsep="1">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-                 <entry>B<subscript>00low</subscript>(bits 7--6)
-                        G<subscript>01low</subscript>(bits 5--4)
-                        B<subscript>02low</subscript>(bits 3--2)
-                        G<subscript>03low</subscript>(bits 1--0)
-                 </entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;5:</entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-                 <entry>G<subscript>10low</subscript>(bits 7--6)
-                        R<subscript>11low</subscript>(bits 5--4)
-                        G<subscript>12low</subscript>(bits 3--2)
-                        R<subscript>13low</subscript>(bits 1--0)
-                 </entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;10:</entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-                 <entry>B<subscript>20low</subscript>(bits 7--6)
-                        G<subscript>21low</subscript>(bits 5--4)
-                        B<subscript>22low</subscript>(bits 3--2)
-                        G<subscript>23low</subscript>(bits 1--0)
-                 </entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;15:</entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-                 <entry>G<subscript>30low</subscript>(bits 7--6)
-                        R<subscript>31low</subscript>(bits 5--4)
-                        G<subscript>32low</subscript>(bits 3--2)
-                        R<subscript>33low</subscript>(bits 1--0)
-                 </entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
deleted file mode 100644 (file)
index 0c8e4ad..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB12 ('RG12'),
-        V4L2_PIX_FMT_SGRBG12 ('BA12'),
-        V4L2_PIX_FMT_SGBRG12 ('GB12'),
-        V4L2_PIX_FMT_SBGGR12 ('BG12'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SRGGB12"><constant>V4L2_PIX_FMT_SRGGB12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG12"><constant>V4L2_PIX_FMT_SGRBG12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG12"><constant>V4L2_PIX_FMT_SGBRG12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SBGGR12"><constant>V4L2_PIX_FMT_SBGGR12</constant></refname>
-       <refpurpose>12-bit Bayer formats expanded to 16 bits</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These four pixel formats are raw sRGB / Bayer formats with
-12 bits per colour. Each colour component is stored in a 16-bit word, with 4
-unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
-and n/2 blue or red samples, with alternating red and blue rows. Bytes are
-stored in memory in little endian order. They are conventionally described
-as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
-formats</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR12</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte, high 6 bits in high bytes are 0.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb8.xml
deleted file mode 100644 (file)
index 2570e3b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SRGGB8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB8 ('RGGB')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SRGGB8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a red and green value, the second row of a green and
-blue value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SRGGB8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>R<subscript>00</subscript></entry>
-                     <entry>G<subscript>01</subscript></entry>
-                     <entry>R<subscript>02</subscript></entry>
-                     <entry>G<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>G<subscript>10</subscript></entry>
-                     <entry>B<subscript>11</subscript></entry>
-                     <entry>G<subscript>12</subscript></entry>
-                     <entry>B<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>R<subscript>20</subscript></entry>
-                     <entry>G<subscript>21</subscript></entry>
-                     <entry>R<subscript>22</subscript></entry>
-                     <entry>G<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>G<subscript>30</subscript></entry>
-                     <entry>B<subscript>31</subscript></entry>
-                     <entry>G<subscript>32</subscript></entry>
-                     <entry>B<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-uv8.xml b/Documentation/DocBook/media/v4l/pixfmt-uv8.xml
deleted file mode 100644 (file)
index c507c1f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-       <refentry id="V4L2-PIX-FMT-UV8">
-         <refmeta>
-           <refentrytitle>V4L2_PIX_FMT_UV8  ('UV8')</refentrytitle>
-           &manvol;
-         </refmeta>
-         <refnamediv>
-           <refname><constant>V4L2_PIX_FMT_UV8</constant></refname>
-           <refpurpose>UV plane interleaved</refpurpose>
-         </refnamediv>
-         <refsect1>
-           <title>Description</title>
-           <para>In this format there is no Y plane, Only CbCr plane. ie
-           (UV interleaved)</para>
-           <example>
-           <title>
-             <constant>V4L2_PIX_FMT_UV8</constant>
-              pixel image
-           </title>
-
-           <formalpara>
-             <title>Byte Order.</title>
-             <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-             </formalpara>
-           </example>
-         </refsect1>
-       </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml b/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml
deleted file mode 100644 (file)
index b1f6801..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-UYVY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_UYVY ('UYVY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_UYVY</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_UYVY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml b/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml
deleted file mode 100644 (file)
index 8280340..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-VYUY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_VYUY ('VYUY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_VYUY</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_VYUY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y10.xml b/Documentation/DocBook/media/v4l/pixfmt-y10.xml
deleted file mode 100644 (file)
index d065043..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y10">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y10 ('Y10 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y10</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 10 bits per pixel. Pixels
-are stored in 16-bit words with unused high bits padded with 0. The least
-significant byte is stored at lower memory addresses (little-endian).</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y10</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y10b.xml b/Documentation/DocBook/media/v4l/pixfmt-y10b.xml
deleted file mode 100644 (file)
index adb0ad8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y10BPACK">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
-    <refpurpose>Grey-scale image as a bit-packed array</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a packed grey-scale image format with a depth of 10 bits per
-      pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
-      with no padding between them and with the most significant bits coming
-      first from the left.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
-
-      <formalpara>
-       <title>Bit-packed representation</title>
-       <para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
-          pixels.
-         <informaltable frame="all">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>Y'<subscript>00[9:2]</subscript></entry>
-                 <entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
-                 <entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
-                 <entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
-                 <entry>Y'<subscript>03[7:0]</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y12.xml b/Documentation/DocBook/media/v4l/pixfmt-y12.xml
deleted file mode 100644 (file)
index ff417b8..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y12">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y12 ('Y12 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y12</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 12 bits per pixel. Pixels
-are stored in 16-bit words with unused high bits padded with 0. The least
-significant byte is stored at lower memory addresses (little-endian).</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y12</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y12i.xml b/Documentation/DocBook/media/v4l/pixfmt-y12i.xml
deleted file mode 100644 (file)
index 4a2d1e5..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y12I">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y12I ('Y12I')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y12I</constant></refname>
-    <refpurpose>Interleaved grey-scale image, e.g. from a stereo-pair</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 12 bits per pixel, but with
-pixels from 2 sources interleaved and bit-packed. Each pixel is stored in a
-24-bit word in the little-endian order. On a little-endian machine these pixels
-can be deinterlaced using</para>
-
-<para>
-<programlisting>
-__u8 *buf;
-left0 = 0xfff &amp; *(__u16 *)buf;
-right0 = *(__u16 *)(buf + 1) >> 4;
-</programlisting>
-</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y12I</constant> 2 pixel data stream taking 3 bytes</title>
-
-      <formalpara>
-       <title>Bit-packed representation</title>
-       <para>pixels cross the byte boundary and have a ratio of 3 bytes for each
-          interleaved pixel.
-         <informaltable frame="all">
-           <tgroup cols="3" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>Y'<subscript>0left[7:0]</subscript></entry>
-                 <entry>Y'<subscript>0right[3:0]</subscript>Y'<subscript>0left[11:8]</subscript></entry>
-                 <entry>Y'<subscript>0right[11:4]</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y16-be.xml b/Documentation/DocBook/media/v4l/pixfmt-y16-be.xml
deleted file mode 100644 (file)
index cea53e1..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y16-BE">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y16_BE ('Y16 ' | (1 &lt;&lt; 31))</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y16_BE</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 16 bits per
-pixel. The most significant byte is stored at lower memory addresses
-(big-endian). Note the actual sampling precision may be lower than
-16 bits, for example 10 bits per pixel with values in range 0 to
-1023.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y16_BE</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y16.xml b/Documentation/DocBook/media/v4l/pixfmt-y16.xml
deleted file mode 100644 (file)
index ff4f727..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y16">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y16 ('Y16 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y16</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 16 bits per
-pixel. The least significant byte is stored at lower memory addresses
-(little-endian). Note the actual sampling precision may be lower than
-16 bits, for example 10 bits per pixel with values in range 0 to
-1023.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y16</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y41p.xml b/Documentation/DocBook/media/v4l/pixfmt-y41p.xml
deleted file mode 100644 (file)
index 98dcb91..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-Y41P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_Y41P ('Y41P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_Y41P</constant></refname>
-       <refpurpose>Format with &frac14; horizontal chroma
-resolution, also known as YUV 4:1:1</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each 12 bytes is eight pixels. In the
-twelve bytes are two CbCr pairs and eight Y's. The first CbCr pair
-goes with the first four Y's, and the second CbCr pair goes with the
-other four Y's. The Cb and Cr components have one fourth the
-horizontal resolution of the Y component.</para>
-
-       <para>Do not confuse this format with <link
-linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link>.
-Y41P is derived from "YUV 4:1:1 <emphasis>packed</emphasis>", while
-YUV411P stands for "YUV 4:1:1 <emphasis>planar</emphasis>".</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_Y41P</constant> 8 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="13" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Y'<subscript>04</subscript></entry>
-                     <entry>Y'<subscript>05</subscript></entry>
-                     <entry>Y'<subscript>06</subscript></entry>
-                     <entry>Y'<subscript>07</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Y'<subscript>14</subscript></entry>
-                     <entry>Y'<subscript>15</subscript></entry>
-                     <entry>Y'<subscript>16</subscript></entry>
-                     <entry>Y'<subscript>17</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Y'<subscript>24</subscript></entry>
-                     <entry>Y'<subscript>25</subscript></entry>
-                     <entry>Y'<subscript>26</subscript></entry>
-                     <entry>Y'<subscript>27</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;36:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Y'<subscript>34</subscript></entry>
-                     <entry>Y'<subscript>35</subscript></entry>
-                     <entry>Y'<subscript>36</subscript></entry>
-                     <entry>Y'<subscript>37</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable></para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="15" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry><entry></entry>
-                     <entry>4</entry><entry></entry><entry>5</entry><entry></entry>
-                     <entry>6</entry><entry></entry><entry>7</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y8i.xml b/Documentation/DocBook/media/v4l/pixfmt-y8i.xml
deleted file mode 100644 (file)
index 99f389d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y8I">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y8I ('Y8I ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y8I</constant></refname>
-    <refpurpose>Interleaved grey-scale image, e.g. from a stereo-pair</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 8 bits per pixel, but with
-pixels from 2 sources interleaved. Each pixel is stored in a 16-bit word. E.g.
-the R200 RealSense camera stores pixel from the left sensor in lower and from
-the right sensor in the higher 8 bits.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y8I</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00left</subscript></entry>
-                 <entry>Y'<subscript>00right</subscript></entry>
-                 <entry>Y'<subscript>01left</subscript></entry>
-                 <entry>Y'<subscript>01right</subscript></entry>
-                 <entry>Y'<subscript>02left</subscript></entry>
-                 <entry>Y'<subscript>02right</subscript></entry>
-                 <entry>Y'<subscript>03left</subscript></entry>
-                 <entry>Y'<subscript>03right</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10left</subscript></entry>
-                 <entry>Y'<subscript>10right</subscript></entry>
-                 <entry>Y'<subscript>11left</subscript></entry>
-                 <entry>Y'<subscript>11right</subscript></entry>
-                 <entry>Y'<subscript>12left</subscript></entry>
-                 <entry>Y'<subscript>12right</subscript></entry>
-                 <entry>Y'<subscript>13left</subscript></entry>
-                 <entry>Y'<subscript>13right</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20left</subscript></entry>
-                 <entry>Y'<subscript>20right</subscript></entry>
-                 <entry>Y'<subscript>21left</subscript></entry>
-                 <entry>Y'<subscript>21right</subscript></entry>
-                 <entry>Y'<subscript>22left</subscript></entry>
-                 <entry>Y'<subscript>22right</subscript></entry>
-                 <entry>Y'<subscript>23left</subscript></entry>
-                 <entry>Y'<subscript>23right</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30left</subscript></entry>
-                 <entry>Y'<subscript>30right</subscript></entry>
-                 <entry>Y'<subscript>31left</subscript></entry>
-                 <entry>Y'<subscript>31right</subscript></entry>
-                 <entry>Y'<subscript>32left</subscript></entry>
-                 <entry>Y'<subscript>32right</subscript></entry>
-                 <entry>Y'<subscript>33left</subscript></entry>
-                 <entry>Y'<subscript>33right</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml
deleted file mode 100644 (file)
index 0869dce..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></refname>
-       <refname id="V4L2-PIX-FMT-YUV410"><constant>V4L2_PIX_FMT_YUV410</constant></refname>
-       <refpurpose>Planar formats with &frac14; horizontal and
-vertical chroma resolution, also known as YUV 4:1:0</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are planar formats, as opposed to a packed format.
-The three components are separated into three sub-images or planes.
-The Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_YVU410</constant>, the Cr plane immediately
-follows the Y plane in memory. The Cr plane is &frac14; the width and
-&frac14; the height of the Y plane (and of the image). Each Cr belongs
-to 16 pixels, a four-by-four square of the image. Following the Cr
-plane is the Cb plane, just like the Cr plane.
-<constant>V4L2_PIX_FMT_YUV410</constant> is the same, except the Cb
-plane comes first, then the Cr plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have &frac14; as many pad bytes after their rows. In
-other words, four Cx rows (including padding) are exactly as long as
-one Y row (including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVU410</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;17:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry></entry><entry></entry><entry>C</entry>
-                     <entry></entry><entry></entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml
deleted file mode 100644 (file)
index 086dc73..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUV411P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV411P ('411P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUV411P</constant></refname>
-       <refpurpose>Format with &frac14; horizontal chroma resolution,
-also known as YUV 4:1:1. Planar layout as opposed to
-<constant>V4L2_PIX_FMT_Y41P</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This format is not commonly used. This is a planar
-format similar to the 4:2:2 planar format except with half as many
-chroma. The three components are separated into three sub-images or
-planes. The Y plane is first. The Y plane has one byte per pixel. The
-Cb plane immediately follows the Y plane in memory. The Cb plane is
-&frac14; the width of the Y plane (and of the image). Each Cb belongs
-to 4 pixels all on the same row. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>02</subscript> and
-Y'<subscript>03</subscript>. Following the Cb plane is the Cr plane,
-just like the Cb plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have &frac14; as many pad bytes after their rows. In
-other words, four C x rows (including padding) is exactly as long as
-one Y row (including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV411P</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;17:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;19:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;21:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;23:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml
deleted file mode 100644 (file)
index 48649fa..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')</refentrytitle>
-       &manvol;
-     </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></refname>
-       <refname id="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></refname>
-       <refpurpose>Planar formats with &frac12; horizontal and
-vertical chroma resolution, also known as YUV 4:2:0</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are planar formats, as opposed to a packed format.
-The three components are separated into three sub- images or planes.
-The Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_YVU420</constant>, the Cr plane immediately
-follows the Y plane in memory. The Cr plane is half the width and half
-the height of the Y plane (and of the image). Each Cr belongs to four
-pixels, a two-by-two square of the image. For example,
-Cr<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
-Y'<subscript>11</subscript>. Following the Cr plane is the Cb plane,
-just like the Cr plane. <constant>V4L2_PIX_FMT_YUV420</constant> is
-the same except the Cb plane comes first, then the Cr plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVU420</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml
deleted file mode 100644 (file)
index 7d13fe9..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV420M ('YM12'), V4L2_PIX_FMT_YVU420M ('YM21')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YUV420M"><constant>V4L2_PIX_FMT_YUV420M</constant></refname>
-       <refname id="V4L2-PIX-FMT-YVU420M"><constant>V4L2_PIX_FMT_YVU420M</constant></refname>
-       <refpurpose>Variation of <constant>V4L2_PIX_FMT_YUV420</constant> and
-         <constant>V4L2_PIX_FMT_YVU420</constant> with planes non contiguous
-         in memory.</refpurpose>
-      </refnamediv>
-
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar format, as opposed to a packed format.
-The three components are separated into three sub-images or planes.</para>
-
-       <para>The Y plane is first. The Y plane has one byte per pixel.
-For <constant>V4L2_PIX_FMT_YUV420M</constant> the Cb data
-constitutes the second plane which is half the width and half
-the height of the Y plane (and of the image). Each Cb belongs to four
-pixels, a two-by-two square of the image. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
-Y'<subscript>11</subscript>. The Cr data, just like the Cb plane, is
-in the third plane.</para>
-
-       <para><constant>V4L2_PIX_FMT_YVU420M</constant> is the same except
-the Cr data is stored in the second plane and the Cb data in the third plane.
-</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cb
-and Cr planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <para><constant>V4L2_PIX_FMT_YUV420M</constant> and
-<constant>V4L2_PIX_FMT_YVU420M</constant> are intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV420M</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;2:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;2:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv422m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv422m.xml
deleted file mode 100644 (file)
index dd50280..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV422M ('YM16'), V4L2_PIX_FMT_YVU422M ('YM61')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YUV422M"><constant>V4L2_PIX_FMT_YUV422M</constant></refname>
-       <refname id="V4L2-PIX-FMT-YVU422M"><constant>V4L2_PIX_FMT_YVU422M</constant></refname>
-       <refpurpose>Planar formats with &frac12; horizontal resolution, also
-       known as YUV and YVU 4:2:2</refpurpose>
-      </refnamediv>
-
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar format, as opposed to a packed format.
-The three components are separated into three sub-images or planes.</para>
-
-       <para>The Y plane is first. The Y plane has one byte per pixel.
-For <constant>V4L2_PIX_FMT_YUV422M</constant> the Cb data
-constitutes the second plane which is half the width of the Y plane (and of the
-image). Each Cb belongs to two pixels. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>. The Cr data, just like the Cb plane, is
-in the third plane. </para>
-
-       <para><constant>V4L2_PIX_FMT_YVU422M</constant> is the same except
-the Cr data is stored in the second plane and the Cb data in the third plane.
-</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cb
-and Cr planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <para><constant>V4L2_PIX_FMT_YUV422M</constant> and
-<constant>V4L2_PIX_FMT_YVU422M</constant> are intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV422M</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;2:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;6:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;2:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;4:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;6:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml
deleted file mode 100644 (file)
index 4ce6463..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUV422P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV422P ('422P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUV422P</constant></refname>
-       <refpurpose>Format with &frac12; horizontal chroma resolution,
-also known as YUV 4:2:2. Planar layout as opposed to
-<constant>V4L2_PIX_FMT_YUYV</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This format is not commonly used. This is a planar
-version of the YUYV format. The three components are separated into
-three sub-images or planes. The Y plane is first. The Y plane has one
-byte per pixel. The Cb plane immediately follows the Y plane in
-memory. The Cb plane is half the width of the Y plane (and of the
-image). Each Cb belongs to two pixels. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>. Following the Cb plane is the Cr plane,
-just like the Cb plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV422P</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;26:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;28:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;30:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv444m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv444m.xml
deleted file mode 100644 (file)
index 1b73359..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV444M ('YM24'), V4L2_PIX_FMT_YVU444M ('YM42')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YUV444M"><constant>V4L2_PIX_FMT_YUV444M</constant></refname>
-       <refname id="V4L2-PIX-FMT-YVU444M"><constant>V4L2_PIX_FMT_YVU444M</constant></refname>
-       <refpurpose>Planar formats with full horizontal resolution, also
-       known as YUV and YVU 4:4:4</refpurpose>
-      </refnamediv>
-
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar format, as opposed to a packed format.
-The three components are separated into three sub-images or planes.</para>
-
-       <para>The Y plane is first. The Y plane has one byte per pixel.
-For <constant>V4L2_PIX_FMT_YUV444M</constant> the Cb data
-constitutes the second plane which is the same width and height as the Y plane
-(and as the image). The Cr data, just like the Cb plane, is in the third plane.
-</para>
-
-       <para><constant>V4L2_PIX_FMT_YVU444M</constant> is the same except
-the Cr data is stored in the second plane and the Cb data in the third plane.
-</para>
-       <para>If the Y plane has pad bytes after each row, then the Cb
-and Cr planes have the same number of pad bytes after their rows.</para>
-
-       <para><constant>V4L2_PIX_FMT_YUV444M</constant> and
-<constant>V4L2_PIX_FMT_YUV444M</constant> are intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV444M</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;12:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>33</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;4:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;8:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;12:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry><entry></entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry><entry></entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry><entry></entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry><entry></entry>
-                     <entry>YC</entry><entry></entry><entry>YC</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml b/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml
deleted file mode 100644 (file)
index 5838409..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUYV">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUYV ('YUYV')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUYV</constant></refname>
-       <refpurpose>Packed format with &frac12; horizontal chroma
-resolution, also known as YUV 4:2:2</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y component.
-<constant>V4L2_PIX_FMT_YUYV </constant> is known in the Windows
-environment as YUY2.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUYV</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml b/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml
deleted file mode 100644 (file)
index bfffdc7..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YVYU">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVYU ('YVYU')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YVYU</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVYU</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-z16.xml b/Documentation/DocBook/media/v4l/pixfmt-z16.xml
deleted file mode 100644 (file)
index 1d9cb16..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Z16">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Z16 ('Z16 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Z16</constant></refname>
-    <refpurpose>16-bit depth data with distance values at each pixel</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a 16-bit format, representing depth data. Each pixel is a
-distance to the respective point in the image coordinates. Distance unit can
-vary and has to be negotiated with the device separately. Each pixel is stored
-in a 16-bit word in the little endian byte order.
-</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Z16</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Z<subscript>00low</subscript></entry>
-                 <entry>Z<subscript>00high</subscript></entry>
-                 <entry>Z<subscript>01low</subscript></entry>
-                 <entry>Z<subscript>01high</subscript></entry>
-                 <entry>Z<subscript>02low</subscript></entry>
-                 <entry>Z<subscript>02high</subscript></entry>
-                 <entry>Z<subscript>03low</subscript></entry>
-                 <entry>Z<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Z<subscript>10low</subscript></entry>
-                 <entry>Z<subscript>10high</subscript></entry>
-                 <entry>Z<subscript>11low</subscript></entry>
-                 <entry>Z<subscript>11high</subscript></entry>
-                 <entry>Z<subscript>12low</subscript></entry>
-                 <entry>Z<subscript>12high</subscript></entry>
-                 <entry>Z<subscript>13low</subscript></entry>
-                 <entry>Z<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Z<subscript>20low</subscript></entry>
-                 <entry>Z<subscript>20high</subscript></entry>
-                 <entry>Z<subscript>21low</subscript></entry>
-                 <entry>Z<subscript>21high</subscript></entry>
-                 <entry>Z<subscript>22low</subscript></entry>
-                 <entry>Z<subscript>22high</subscript></entry>
-                 <entry>Z<subscript>23low</subscript></entry>
-                 <entry>Z<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Z<subscript>30low</subscript></entry>
-                 <entry>Z<subscript>30high</subscript></entry>
-                 <entry>Z<subscript>31low</subscript></entry>
-                 <entry>Z<subscript>31high</subscript></entry>
-                 <entry>Z<subscript>32low</subscript></entry>
-                 <entry>Z<subscript>32high</subscript></entry>
-                 <entry>Z<subscript>33low</subscript></entry>
-                 <entry>Z<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
deleted file mode 100644 (file)
index 5a08aee..0000000
+++ /dev/null
@@ -1,2003 +0,0 @@
-  <title>Image Formats</title>
-
-  <para>The V4L2 API was primarily designed for devices exchanging
-image data with applications. The
-<structname>v4l2_pix_format</structname> and <structname>v4l2_pix_format_mplane
-</structname> structures define the format and layout of an image in memory.
-The former is used with the single-planar API, while the latter is used with the
-multi-planar version (see <xref linkend="planar-apis"/>). Image formats are
-negotiated with the &VIDIOC-S-FMT; ioctl. (The explanations here focus on video
-capturing and output, for overlay frame buffer formats see also
-&VIDIOC-G-FBUF;.)</para>
-
-<section>
-  <title>Single-planar format structure</title>
-  <table pgwide="1" frame="none" id="v4l2-pix-format">
-    <title>struct <structname>v4l2_pix_format</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>width</structfield></entry>
-         <entry>Image width in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>height</structfield></entry>
-         <entry>Image height in pixels. If <structfield>field</structfield> is
-         one of <constant>V4L2_FIELD_TOP</constant>, <constant>V4L2_FIELD_BOTTOM</constant>
-         or <constant>V4L2_FIELD_ALTERNATE</constant> then height refers to the
-         number of lines in the field, otherwise it refers to the number of
-         lines in the frame (which is twice the field height for interlaced
-         formats).</entry>
-       </row>
-       <row>
-         <entry spanname="hspan">Applications set these fields to
-request an image size, drivers return the closest possible values. In
-case of planar formats the <structfield>width</structfield> and
-<structfield>height</structfield> applies to the largest plane. To
-avoid ambiguities drivers must return values rounded up to a multiple
-of the scale factor of any smaller planes. For example when the image
-format is YUV 4:2:0, <structfield>width</structfield> and
-<structfield>height</structfield> must be multiples of two.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>pixelformat</structfield></entry>
-         <entry>The pixel format or type of compression, set by the
-application. This is a little endian <link
-linkend="v4l2-fourcc">four character code</link>. V4L2 defines
-standard RGB formats in <xref linkend="rgb-formats" />, YUV formats in <xref
-linkend="yuv-formats" />, and reserved codes in <xref
-linkend="reserved-formats" /></entry>
-       </row>
-       <row>
-         <entry>&v4l2-field;</entry>
-         <entry><structfield>field</structfield></entry>
-         <entry>Video images are typically interlaced. Applications
-can request to capture or output only the top or bottom field, or both
-fields interlaced or sequentially stored in one buffer or alternating
-in separate buffers. Drivers return the actual field order selected.
-For more details on fields see <xref linkend="field-order" />.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>bytesperline</structfield></entry>
-         <entry>Distance in bytes between the leftmost pixels in two
-adjacent lines.</entry>
-       </row>
-       <row>
-         <entry spanname="hspan"><para>Both applications and drivers
-can set this field to request padding bytes at the end of each line.
-Drivers however may ignore the value requested by the application,
-returning <structfield>width</structfield> times bytes per pixel or a
-larger value required by the hardware. That implies applications can
-just set this field to zero to get a reasonable
-default.</para><para>Video hardware may access padding bytes,
-therefore they must reside in accessible memory. Consider cases where
-padding bytes after the last line of an image cross a system page
-boundary. Input devices may write padding bytes, the value is
-undefined. Output devices ignore the contents of padding
-bytes.</para><para>When the image format is planar the
-<structfield>bytesperline</structfield> value applies to the first
-plane and is divided by the same factor as the
-<structfield>width</structfield> field for the other planes. For
-example the Cb and Cr planes of a YUV 4:2:0 image have half as many
-padding bytes following each line as the Y plane. To avoid ambiguities
-drivers must return a <structfield>bytesperline</structfield> value
-rounded up to a multiple of the scale factor.</para>
-<para>For compressed formats the <structfield>bytesperline</structfield>
-value makes no sense. Applications and drivers must set this to 0 in
-that case.</para></entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>sizeimage</structfield></entry>
-         <entry>Size in bytes of the buffer to hold a complete image,
-set by the driver. Usually this is
-<structfield>bytesperline</structfield> times
-<structfield>height</structfield>. When the image consists of variable
-length compressed data this is the maximum number of bytes required to
-hold an image.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-colorspace;</entry>
-         <entry><structfield>colorspace</structfield></entry>
-         <entry>This information supplements the
-<structfield>pixelformat</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>priv</structfield></entry>
-         <entry><para>This field indicates whether the remaining fields of the
-<structname>v4l2_pix_format</structname> structure, also called the extended
-fields, are valid. When set to <constant>V4L2_PIX_FMT_PRIV_MAGIC</constant>, it
-indicates that the extended fields have been correctly initialized. When set to
-any other value it indicates that the extended fields contain undefined values.
-</para>
-<para>Applications that wish to use the pixel format extended fields must first
-ensure that the feature is supported by querying the device for the
-<link linkend="querycap"><constant>V4L2_CAP_EXT_PIX_FORMAT</constant></link>
-capability. If the capability isn't set the pixel format extended fields are not
-supported and using the extended fields will lead to undefined results.</para>
-<para>To use the extended fields, applications must set the
-<structfield>priv</structfield> field to
-<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant>, initialize all the extended fields
-and zero the unused bytes of the <structname>v4l2_format</structname>
-<structfield>raw_data</structfield> field.</para>
-<para>When the <structfield>priv</structfield> field isn't set to
-<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant> drivers must act as if all the
-extended fields were set to zero. On return drivers must set the
-<structfield>priv</structfield> field to
-<constant>V4L2_PIX_FMT_PRIV_MAGIC</constant> and all the extended fields to
-applicable values.</para></entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>flags</structfield></entry>
-         <entry>Flags set by the application or driver, see <xref
-linkend="format-flags" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-ycbcr-encoding;</entry>
-         <entry><structfield>ycbcr_enc</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-quantization;</entry>
-         <entry><structfield>quantization</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-xfer-func;</entry>
-         <entry><structfield>xfer_func</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-      </tbody>
-    </tgroup>
-  </table>
-</section>
-
-<section>
-  <title>Multi-planar format structures</title>
-  <para>The <structname>v4l2_plane_pix_format</structname> structures define
-    size and layout for each of the planes in a multi-planar format.
-    The <structname>v4l2_pix_format_mplane</structname> structure contains
-    information common to all planes (such as image width and height) and
-    an array of <structname>v4l2_plane_pix_format</structname> structures,
-    describing all planes of that format.</para>
-  <table pgwide="1" frame="none" id="v4l2-plane-pix-format">
-    <title>struct <structname>v4l2_plane_pix_format</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>sizeimage</structfield></entry>
-          <entry>Maximum size in bytes required for image data in this plane.
-          </entry>
-        </row>
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>bytesperline</structfield></entry>
-          <entry>Distance in bytes between the leftmost pixels in two adjacent
-            lines. See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>__u16</entry>
-          <entry><structfield>reserved[6]</structfield></entry>
-          <entry>Reserved for future extensions. Should be zeroed by drivers and
-           applications.</entry>
-        </row>
-      </tbody>
-    </tgroup>
-  </table>
-  <table pgwide="1" frame="none" id="v4l2-pix-format-mplane">
-    <title>struct <structname>v4l2_pix_format_mplane</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>width</structfield></entry>
-          <entry>Image width in pixels. See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>height</structfield></entry>
-          <entry>Image height in pixels. See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>pixelformat</structfield></entry>
-          <entry>The pixel format. Both single- and multi-planar four character
-codes can be used.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-field;</entry>
-          <entry><structfield>field</structfield></entry>
-          <entry>See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-colorspace;</entry>
-          <entry><structfield>colorspace</structfield></entry>
-          <entry>See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-plane-pix-format;</entry>
-          <entry><structfield>plane_fmt[VIDEO_MAX_PLANES]</structfield></entry>
-          <entry>An array of structures describing format of each plane this
-          pixel format consists of. The number of valid entries in this array
-          has to be put in the <structfield>num_planes</structfield>
-          field.</entry>
-        </row>
-        <row>
-          <entry>__u8</entry>
-          <entry><structfield>num_planes</structfield></entry>
-          <entry>Number of planes (i.e. separate memory buffers) for this format
-          and the number of valid entries in the
-          <structfield>plane_fmt</structfield> array.</entry>
-        </row>
-       <row>
-         <entry>__u8</entry>
-         <entry><structfield>flags</structfield></entry>
-         <entry>Flags set by the application or driver, see <xref
-linkend="format-flags" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-ycbcr-encoding;</entry>
-         <entry><structfield>ycbcr_enc</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-quantization;</entry>
-         <entry><structfield>quantization</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-xfer-func;</entry>
-         <entry><structfield>xfer_func</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-        <row>
-          <entry>__u8</entry>
-          <entry><structfield>reserved[7]</structfield></entry>
-          <entry>Reserved for future extensions. Should be zeroed by drivers
-           and applications.</entry>
-        </row>
-      </tbody>
-    </tgroup>
-  </table>
-</section>
-
-  <section>
-    <title>Standard Image Formats</title>
-
-    <para>In order to exchange images between drivers and
-applications, it is necessary to have standard image data formats
-which both sides will interpret the same way. V4L2 includes several
-such formats, and this section is intended to be an unambiguous
-specification of the standard image data formats in V4L2.</para>
-
-    <para>V4L2 drivers are not limited to these formats, however.
-Driver-specific formats are possible. In that case the application may
-depend on a codec to convert images to one of the standard formats
-when needed. But the data can still be stored and retrieved in the
-proprietary format. For example, a device may support a proprietary
-compressed format. Applications can still capture and save the data in
-the compressed format, saving much disk space, and later use a codec
-to convert the images to the X Windows screen format when the video is
-to be displayed.</para>
-
-    <para>Even so, ultimately, some standard formats are needed, so
-the V4L2 specification would not be complete without well-defined
-standard formats.</para>
-
-    <para>The V4L2 standard formats are mainly uncompressed formats. The
-pixels are always arranged in memory from left to right, and from top
-to bottom. The first byte of data in the image buffer is always for
-the leftmost pixel of the topmost row. Following that is the pixel
-immediately to its right, and so on until the end of the top row of
-pixels. Following the rightmost pixel of the row there may be zero or
-more bytes of padding to guarantee that each row of pixel data has a
-certain alignment. Following the pad bytes, if any, is data for the
-leftmost pixel of the second row from the top, and so on. The last row
-has just as many pad bytes after it as the other rows.</para>
-
-    <para>In V4L2 each format has an identifier which looks like
-<constant>PIX_FMT_XXX</constant>, defined in the <link
-linkend="videodev">videodev2.h</link> header file. These identifiers
-represent <link linkend="v4l2-fourcc">four character (FourCC) codes</link>
-which are also listed below, however they are not the same as those
-used in the Windows world.</para>
-
-    <para>For some formats, data is stored in separate, discontiguous
-memory buffers. Those formats are identified by a separate set of FourCC codes
-and are referred to as "multi-planar formats". For example, a YUV422 frame is
-normally stored in one memory buffer, but it can also be placed in two or three
-separate buffers, with Y component in one buffer and CbCr components in another
-in the 2-planar version or with each component in its own buffer in the
-3-planar case. Those sub-buffers are referred to as "planes".</para>
-  </section>
-
-  <section id="colorspaces">
-    <title>Colorspaces</title>
-
-    <para>'Color' is a very complex concept and depends on physics, chemistry and
-biology. Just because you have three numbers that describe the 'red', 'green'
-and 'blue' components of the color of a pixel does not mean that you can accurately
-display that color. A colorspace defines what it actually <emphasis>means</emphasis>
-to have an RGB value of e.g. (255,&nbsp;0,&nbsp;0). That is, which color should be
-reproduced on the screen in a perfectly calibrated environment.</para>
-
-    <para>In order to do that we first need to have a good definition of
-color, i.e. some way to uniquely and unambiguously define a color so that someone
-else can reproduce it. Human color vision is trichromatic since the human eye has
-color receptors that are sensitive to three different wavelengths of light. Hence
-the need to use three numbers to describe color. Be glad you are not a mantis shrimp
-as those are sensitive to 12 different wavelengths, so instead of RGB we would be
-using the ABCDEFGHIJKL colorspace...</para>
-
-    <para>Color exists only in the eye and brain and is the result of how strongly
-color receptors are stimulated. This is based on the Spectral
-Power Distribution (SPD) which is a graph showing the intensity (radiant power)
-of the light at wavelengths covering the visible spectrum as it enters the eye.
-The science of colorimetry is about the relationship between the SPD and color as
-perceived by the human brain.</para>
-
-    <para>Since the human eye has only three color receptors it is perfectly
-possible that different SPDs will result in the same stimulation of those receptors
-and are perceived as the same color, even though the SPD of the light is
-different.</para>
-
-   <para>In the 1920s experiments were devised to determine the relationship
-between SPDs and the perceived color and that resulted in the CIE 1931 standard
-that defines spectral weighting functions that model the perception of color.
-Specifically that standard defines functions that can take an SPD and calculate
-the stimulus for each color receptor. After some further mathematical transforms
-these stimuli are known as the <emphasis>CIE XYZ tristimulus</emphasis> values
-and these X, Y and Z values describe a color as perceived by a human unambiguously.
-These X, Y and Z values are all in the range [0&hellip;1].</para>
-
-   <para>The Y value in the CIE XYZ colorspace corresponds to luminance. Often
-the CIE XYZ colorspace is transformed to the normalized CIE xyY colorspace:</para>
-
-   <para>x = X / (X + Y + Z)</para>
-   <para>y = Y / (X + Y + Z)</para>
-
-   <para>The x and y values are the chromaticity coordinates and can be used to
-define a color without the luminance component Y. It is very confusing to
-have such similar names for these colorspaces. Just be aware that if colors
-are specified with lower case 'x' and 'y', then the CIE xyY colorspace is
-used. Upper case 'X' and 'Y' refer to the CIE XYZ colorspace. Also, y has nothing
-to do with luminance. Together x and y specify a color, and Y the luminance.
-That is really all you need to remember from a practical point of view. At
-the end of this section you will find reading resources that go into much more
-detail if you are interested.
-</para>
-
-   <para>A monitor or TV will reproduce colors by emitting light at three
-different wavelengths, the combination of which will stimulate the color receptors
-in the eye and thus cause the perception of color. Historically these wavelengths
-were defined by the red, green and blue phosphors used in the displays. These
-<emphasis>color primaries</emphasis> are part of what defines a colorspace.</para>
-
-    <para>Different display devices will have different primaries and some
-primaries are more suitable for some display technologies than others. This has
-resulted in a variety of colorspaces that are used for different display
-technologies or uses. To define a colorspace you need to define the three
-color primaries (these are typically defined as x,&nbsp;y chromaticity coordinates
-from the CIE xyY colorspace) but also the white reference: that is the color obtained
-when all three primaries are at maximum power. This determines the relative power
-or energy of the primaries. This is usually chosen to be close to daylight which has
-been defined as the CIE D65 Illuminant.</para>
-
-    <para>To recapitulate: the CIE XYZ colorspace uniquely identifies colors.
-Other colorspaces are defined by three chromaticity coordinates defined in the
-CIE xyY colorspace. Based on those a 3x3 matrix can be constructed that
-transforms CIE XYZ colors to colors in the new colorspace.
-</para>
-
-    <para>Both the CIE XYZ and the RGB colorspace that are derived from the
-specific chromaticity primaries are linear colorspaces. But neither the eye,
-nor display technology is linear. Doubling the values of all components in
-the linear colorspace will not be perceived as twice the intensity of the color.
-So each colorspace also defines a transfer function that takes a linear color
-component value and transforms it to the non-linear component value, which is a
-closer match to the non-linear performance of both the eye and displays. Linear
-component values are denoted RGB, non-linear are denoted as R'G'B'. In general
-colors used in graphics are all R'G'B', except in openGL which uses linear RGB.
-Special care should be taken when dealing with openGL to provide linear RGB colors
-or to use the built-in openGL support to apply the inverse transfer function.</para>
-
-    <para>The final piece that defines a colorspace is a function that
-transforms non-linear R'G'B' to non-linear Y'CbCr. This function is determined
-by the so-called luma coefficients. There may be multiple possible Y'CbCr
-encodings allowed for the same colorspace. Many encodings of color
-prefer to use luma (Y') and chroma (CbCr) instead of R'G'B'. Since the human
-eye is more sensitive to differences in luminance than in color this encoding
-allows one to reduce the amount of color information compared to the luma
-data. Note that the luma (Y') is unrelated to the Y in the CIE XYZ colorspace.
-Also note that Y'CbCr is often called YCbCr or YUV even though these are
-strictly speaking wrong.</para>
-
-    <para>Sometimes people confuse Y'CbCr as being a colorspace. This is not
-correct, it is just an encoding of an R'G'B' color into luma and chroma
-values. The underlying colorspace that is associated with the R'G'B' color
-is also associated with the Y'CbCr color.</para>
-
-    <para>The final step is how the RGB, R'G'B' or Y'CbCr values are
-quantized. The CIE XYZ colorspace where X, Y and Z are in the range
-[0&hellip;1] describes all colors that humans can perceive, but the transform to
-another colorspace will produce colors that are outside the [0&hellip;1] range.
-Once clamped to the [0&hellip;1] range those colors can no longer be reproduced
-in that colorspace. This clamping is what reduces the extent or gamut of the
-colorspace. How the range of [0&hellip;1] is translated to integer values in the
-range of [0&hellip;255] (or higher, depending on the color depth) is called the
-quantization. This is <emphasis>not</emphasis> part of the colorspace
-definition. In practice RGB or R'G'B' values are full range, i.e. they
-use the full [0&hellip;255] range. Y'CbCr values on the other hand are limited
-range with Y' using [16&hellip;235] and Cb and Cr using [16&hellip;240].</para>
-
-    <para>Unfortunately, in some cases limited range RGB is also used
-where the components use the range [16&hellip;235]. And full range Y'CbCr also exists
-using the [0&hellip;255] range.</para>
-
-    <para>In order to correctly interpret a color you need to know the
-quantization range, whether it is R'G'B' or Y'CbCr, the used Y'CbCr encoding
-and the colorspace.
-From that information you can calculate the corresponding CIE XYZ color
-and map that again to whatever colorspace your display device uses.</para>
-
-    <para>The colorspace definition itself consists of the three
-chromaticity primaries, the white reference chromaticity, a transfer
-function and the luma coefficients needed to transform R'G'B' to Y'CbCr. While
-some colorspace standards correctly define all four, quite often the colorspace
-standard only defines some, and you have to rely on other standards for
-the missing pieces. The fact that colorspaces are often a mix of different
-standards also led to very confusing naming conventions where the name of
-a standard was used to name a colorspace when in fact that standard was
-part of various other colorspaces as well.</para>
-
-    <para>If you want to read more about colors and colorspaces, then the
-following resources are useful: <xref linkend="poynton" /> is a good practical
-book for video engineers, <xref linkend="colimg" /> has a much broader scope and
-describes many more aspects of color (physics, chemistry, biology, etc.).
-The <ulink url="http://www.brucelindbloom.com">http://www.brucelindbloom.com</ulink>
-website is an excellent resource, especially with respect to the mathematics behind
-colorspace conversions. The wikipedia <ulink url="http://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space">CIE 1931 colorspace</ulink> article
-is also very useful.</para>
-  </section>
-
-  <section>
-    <title>Defining Colorspaces in V4L2</title>
-    <para>In V4L2 colorspaces are defined by four values. The first is the colorspace
-identifier (&v4l2-colorspace;) which defines the chromaticities, the default transfer
-function, the default Y'CbCr encoding and the default quantization method. The second
-is the transfer function identifier (&v4l2-xfer-func;) to specify non-standard
-transfer functions. The third is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;)
-to specify non-standard Y'CbCr encodings and the fourth is the quantization identifier
-(&v4l2-quantization;) to specify non-standard quantization methods. Most of the time
-only the colorspace field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to
-be filled in. Note that the default R'G'B' quantization is full range for all
-colorspaces except for BT.2020 which uses limited range R'G'B' quantization.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-colorspace">
-      <title>V4L2 Colorspaces</title>
-      <tgroup cols="2" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_COLORSPACE_DEFAULT</constant></entry>
-           <entry>The default colorspace. This can be used by applications to let the
-           driver fill in the colorspace.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SMPTE170M</constant></entry>
-           <entry>See <xref linkend="col-smpte-170m" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_REC709</constant></entry>
-           <entry>See <xref linkend="col-rec709" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SRGB</constant></entry>
-           <entry>See <xref linkend="col-srgb" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_ADOBERGB</constant></entry>
-           <entry>See <xref linkend="col-adobergb" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_BT2020</constant></entry>
-           <entry>See <xref linkend="col-bt2020" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_DCI_P3</constant></entry>
-           <entry>See <xref linkend="col-dcip3" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SMPTE240M</constant></entry>
-           <entry>See <xref linkend="col-smpte-240m" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_M</constant></entry>
-           <entry>See <xref linkend="col-sysm" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant></entry>
-           <entry>See <xref linkend="col-sysbg" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_JPEG</constant></entry>
-           <entry>See <xref linkend="col-jpeg" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_RAW</constant></entry>
-           <entry>The raw colorspace. This is used for raw image capture where
-           the image is minimally processed and is using the internal colorspace
-           of the device. The software that processes an image using this
-           'colorspace' will have to know the internals of the capture device.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-xfer-func">
-      <title>V4L2 Transfer Function</title>
-      <tgroup cols="2" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_DEFAULT</constant></entry>
-           <entry>Use the default transfer function as defined by the colorspace.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_709</constant></entry>
-           <entry>Use the Rec. 709 transfer function.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_SRGB</constant></entry>
-           <entry>Use the sRGB transfer function.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_ADOBERGB</constant></entry>
-           <entry>Use the AdobeRGB transfer function.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_SMPTE240M</constant></entry>
-           <entry>Use the SMPTE 240M transfer function.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_NONE</constant></entry>
-           <entry>Do not use a transfer function (i.e. use linear RGB values).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_DCI_P3</constant></entry>
-           <entry>Use the DCI-P3 transfer function.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_XFER_FUNC_SMPTE2084</constant></entry>
-           <entry>Use the SMPTE 2084 transfer function.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-ycbcr-encoding">
-      <title>V4L2 Y'CbCr Encodings</title>
-      <tgroup cols="2" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_DEFAULT</constant></entry>
-           <entry>Use the default Y'CbCr encoding as defined by the colorspace.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_601</constant></entry>
-           <entry>Use the BT.601 Y'CbCr encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_709</constant></entry>
-           <entry>Use the Rec. 709 Y'CbCr encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_XV601</constant></entry>
-           <entry>Use the extended gamut xvYCC BT.601 encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_XV709</constant></entry>
-           <entry>Use the extended gamut xvYCC Rec. 709 encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_SYCC</constant></entry>
-           <entry>Use the extended gamut sYCC encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_BT2020</constant></entry>
-           <entry>Use the default non-constant luminance BT.2020 Y'CbCr encoding.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_YCBCR_ENC_BT2020_CONST_LUM</constant></entry>
-           <entry>Use the constant luminance BT.2020 Yc'CbcCrc encoding.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-quantization">
-      <title>V4L2 Quantization Methods</title>
-      <tgroup cols="2" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_QUANTIZATION_DEFAULT</constant></entry>
-           <entry>Use the default quantization encoding as defined by the colorspace.
-This is always full range for R'G'B' (except for the BT.2020 colorspace) and usually
-limited range for Y'CbCr.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_QUANTIZATION_FULL_RANGE</constant></entry>
-           <entry>Use the full range quantization encoding. I.e. the range [0&hellip;1]
-is mapped to [0&hellip;255] (with possible clipping to [1&hellip;254] to avoid the
-0x00 and 0xff values). Cb and Cr are mapped from [-0.5&hellip;0.5] to [0&hellip;255]
-(with possible clipping to [1&hellip;254] to avoid the 0x00 and 0xff values).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_QUANTIZATION_LIM_RANGE</constant></entry>
-           <entry>Use the limited range quantization encoding. I.e. the range [0&hellip;1]
-is mapped to [16&hellip;235]. Cb and Cr are mapped from [-0.5&hellip;0.5] to [16&hellip;240].
-</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section>
-    <title>Detailed Colorspace Descriptions</title>
-    <section id="col-smpte-170m">
-      <title>Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>)</title>
-      <para>The <xref linkend="smpte170m" /> standard defines the colorspace used by NTSC and PAL and by SDTV
-in general. The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
-The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and
-the white reference are:</para>
-      <table frame="none">
-        <title>SMPTE 170M Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.630</entry>
-              <entry>0.340</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.310</entry>
-              <entry>0.595</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.155</entry>
-              <entry>0.070</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <para>The red, green and blue chromaticities are also often referred to
-as the SMPTE C set, so this colorspace is sometimes called SMPTE C as well.</para>
-      <variablelist>
-       <varlistentry>
-          <term>The transfer function defined for SMPTE 170M is the same as the
-one defined in Rec. 709.</term>
-         <listitem>
-            <para>L' = -1.099(-L)<superscript>0.45</superscript>&nbsp;+&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&le;&nbsp;-0.018</para>
-            <para>L' = 4.5L&nbsp;for&nbsp;-0.018&nbsp;&lt;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
-            <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&ge;&nbsp;0.018</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = -((L'&nbsp;-&nbsp;0.099)&nbsp;/&nbsp;-1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&le;&nbsp;-0.081</para>
-            <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;-0.081&nbsp;&lt;&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with
-the following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5]. This conversion to Y'CbCr is identical to the one
-defined in the <xref linkend="itu601" /> standard and this colorspace is sometimes called BT.601 as well, even
-though BT.601 does not mention any color primaries.</para>
-      <para>The default quantization is limited range, but full range is possible although
-rarely seen.</para>
-    </section>
-
-    <section id="col-rec709">
-      <title>Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>)</title>
-      <para>The <xref linkend="itu709" /> standard defines the colorspace used by HDTV in general.
-The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>. The default
-Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_709</constant>. The default Y'CbCr quantization is
-limited range. The chromaticities of the primary colors and the white reference are:</para>
-      <table frame="none">
-        <title>Rec. 709 Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.640</entry>
-              <entry>0.330</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.300</entry>
-              <entry>0.600</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.150</entry>
-              <entry>0.060</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <para>The full name of this standard is Rec. ITU-R BT.709-5.</para>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function. Normally L is in the range [0&hellip;1], but for the extended
-gamut xvYCC encoding values outside that range are allowed.</term>
-         <listitem>
-            <para>L' = -1.099(-L)<superscript>0.45</superscript>&nbsp;+&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&le;&nbsp;-0.018</para>
-            <para>L' = 4.5L&nbsp;for&nbsp;-0.018&nbsp;&lt;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
-            <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&ge;&nbsp;0.018</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = -((L'&nbsp;-&nbsp;0.099)&nbsp;/&nbsp;-1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&le;&nbsp;-0.081</para>
-            <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;-0.081&nbsp;&lt;&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the following
-<constant>V4L2_YCBCR_ENC_709</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.2126R'&nbsp;+&nbsp;0.7152G'&nbsp;+&nbsp;0.0722B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.1146R'&nbsp;-&nbsp;0.3854G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4542G'&nbsp;-&nbsp;0.0458B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5].</para>
-      <para>The default quantization is limited range, but full range is possible although
-rarely seen.</para>
-      <para>The <constant>V4L2_YCBCR_ENC_709</constant> encoding described above is the default
-for this colorspace, but it can be overridden with <constant>V4L2_YCBCR_ENC_601</constant>, in which
-case the BT.601 Y'CbCr encoding is used.</para>
-      <para>Two additional extended gamut Y'CbCr encodings are also possible with this colorspace:</para>
-      <variablelist>
-       <varlistentry>
-         <term>The xvYCC 709 encoding (<constant>V4L2_YCBCR_ENC_XV709</constant>, <xref linkend="xvycc" />)
-is similar to the Rec. 709 encoding, but it allows for R', G' and B' values that are outside the range
-[0&hellip;1]. The resulting Y', Cb and Cr values are scaled and offset:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;(219&nbsp;/&nbsp;256)&nbsp;*&nbsp;(0.2126R'&nbsp;+&nbsp;0.7152G'&nbsp;+&nbsp;0.0722B')&nbsp;+&nbsp;(16&nbsp;/&nbsp;256)</para>
-            <para>Cb&nbsp;=&nbsp;(224&nbsp;/&nbsp;256)&nbsp;*&nbsp;(-0.1146R'&nbsp;-&nbsp;0.3854G'&nbsp;+&nbsp;0.5B')</para>
-            <para>Cr&nbsp;=&nbsp;(224&nbsp;/&nbsp;256)&nbsp;*&nbsp;(0.5R'&nbsp;-&nbsp;0.4542G'&nbsp;-&nbsp;0.0458B')</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The xvYCC 601 encoding (<constant>V4L2_YCBCR_ENC_XV601</constant>, <xref linkend="xvycc" />) is similar
-to the BT.601 encoding, but it allows for R', G' and B' values that are outside the range
-[0&hellip;1]. The resulting Y', Cb and Cr values are scaled and offset:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;(219&nbsp;/&nbsp;256)&nbsp;*&nbsp;(0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B')&nbsp;+&nbsp;(16&nbsp;/&nbsp;256)</para>
-            <para>Cb&nbsp;=&nbsp;(224&nbsp;/&nbsp;256)&nbsp;*&nbsp;(-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B')</para>
-            <para>Cr&nbsp;=&nbsp;(224&nbsp;/&nbsp;256)&nbsp;*&nbsp;(0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B')</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are clamped
-to the range [-0.5&hellip;0.5]. The non-standard xvYCC 709 or xvYCC 601 encodings can be used by
-selecting <constant>V4L2_YCBCR_ENC_XV709</constant> or <constant>V4L2_YCBCR_ENC_XV601</constant>.
-The xvYCC encodings always use full range quantization.</para>
-    </section>
-
-    <section id="col-srgb">
-      <title>Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>)</title>
-      <para>The <xref linkend="srgb" /> standard defines the colorspace used by most webcams
-and computer graphics. The default transfer function is <constant>V4L2_XFER_FUNC_SRGB</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SYCC</constant>. The default Y'CbCr
-quantization is full range. The chromaticities of the primary colors and the white
-reference are:</para>
-      <table frame="none">
-        <title>sRGB Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.640</entry>
-              <entry>0.330</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.300</entry>
-              <entry>0.600</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.150</entry>
-              <entry>0.060</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <para>These chromaticities are identical to the Rec. 709 colorspace.</para>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function. Note that negative values for L are only used by the Y'CbCr conversion.</term>
-         <listitem>
-            <para>L' = -1.055(-L)<superscript>1/2.4</superscript>&nbsp;+&nbsp;0.055&nbsp;for&nbsp;L&nbsp;&lt;&nbsp;-0.0031308</para>
-            <para>L' = 12.92L&nbsp;for&nbsp;-0.0031308&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;0.0031308</para>
-            <para>L' = 1.055L<superscript>1/2.4</superscript>&nbsp;-&nbsp;0.055&nbsp;for&nbsp;0.0031308&nbsp;&lt;&nbsp;L&nbsp;&le;&nbsp;1</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = -((-L'&nbsp;+&nbsp;0.055)&nbsp;/&nbsp;1.055)<superscript>2.4</superscript>&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;-0.04045</para>
-            <para>L = L'&nbsp;/&nbsp;12.92&nbsp;for&nbsp;-0.04045&nbsp;&le;&nbsp;L'&nbsp;&le;&nbsp;0.04045</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.055)&nbsp;/&nbsp;1.055)<superscript>2.4</superscript>&nbsp;for&nbsp;L'&nbsp;&gt;&nbsp;0.04045</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the following
-<constant>V4L2_YCBCR_ENC_SYCC</constant> encoding as defined by <xref linkend="sycc" />:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.2990R'&nbsp;+&nbsp;0.5870G'&nbsp;+&nbsp;0.1140B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.1687R'&nbsp;-&nbsp;0.3313G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4187G'&nbsp;-&nbsp;0.0813B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are clamped
-to the range [-0.5&hellip;0.5]. The <constant>V4L2_YCBCR_ENC_SYCC</constant> quantization is always
-full range. Although this Y'CbCr encoding looks very similar to the <constant>V4L2_YCBCR_ENC_XV601</constant>
-encoding, it is not. The <constant>V4L2_YCBCR_ENC_XV601</constant> scales and offsets the Y'CbCr
-values before quantization, but this encoding does not do that.</para>
-    </section>
-
-    <section id="col-adobergb">
-      <title>Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>)</title>
-      <para>The <xref linkend="adobergb" /> standard defines the colorspace used by computer graphics
-that use the AdobeRGB colorspace. This is also known as the <xref linkend="oprgb" /> standard.
-The default transfer function is <constant>V4L2_XFER_FUNC_ADOBERGB</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr
-quantization is limited range. The chromaticities of the primary colors and the white reference
-are:</para>
-      <table frame="none">
-        <title>Adobe RGB Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.6400</entry>
-              <entry>0.3300</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.2100</entry>
-              <entry>0.7100</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.1500</entry>
-              <entry>0.0600</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function:</term>
-         <listitem>
-            <para>L' = L<superscript>1/2.19921875</superscript></para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'<superscript>2.19921875</superscript></para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
-following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5]. This transform is identical to one defined in
-SMPTE 170M/BT.601. The Y'CbCr quantization is limited range.</para>
-    </section>
-
-    <section id="col-bt2020">
-      <title>Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>)</title>
-      <para>The <xref linkend="itu2020" /> standard defines the colorspace used by Ultra-high definition
-television (UHDTV). The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_BT2020</constant>.
-The default R'G'B' quantization is limited range (!), and so is the default Y'CbCr quantization.
-The chromaticities of the primary colors and the white reference are:</para>
-      <table frame="none">
-        <title>BT.2020 Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.708</entry>
-              <entry>0.292</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.170</entry>
-              <entry>0.797</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.131</entry>
-              <entry>0.046</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function (same as Rec. 709):</term>
-         <listitem>
-            <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
-            <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
-following <constant>V4L2_YCBCR_ENC_BT2020</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.2627R'&nbsp;+&nbsp;0.6780G'&nbsp;+&nbsp;0.0593B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.1396R'&nbsp;-&nbsp;0.3604G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4598G'&nbsp;-&nbsp;0.0402B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.</para>
-      <para>There is also an alternate constant luminance R'G'B' to Yc'CbcCrc
-(<constant>V4L2_YCBCR_ENC_BT2020_CONST_LUM</constant>) encoding:</para>
-      <variablelist>
-       <varlistentry>
-         <term>Luma:</term>
-         <listitem>
-            <para>Yc'&nbsp;=&nbsp;(0.2627R&nbsp;+&nbsp;0.6780G&nbsp;+&nbsp;0.0593B)'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>B'&nbsp;-&nbsp;Yc'&nbsp;&le;&nbsp;0:</term>
-         <listitem>
-            <para>Cbc&nbsp;=&nbsp;(B'&nbsp;-&nbsp;Yc')&nbsp;/&nbsp;1.9404</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>B'&nbsp;-&nbsp;Yc'&nbsp;&gt;&nbsp;0:</term>
-         <listitem>
-            <para>Cbc&nbsp;=&nbsp;(B'&nbsp;-&nbsp;Yc')&nbsp;/&nbsp;1.5816</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>R'&nbsp;-&nbsp;Yc'&nbsp;&le;&nbsp;0:</term>
-         <listitem>
-            <para>Crc&nbsp;=&nbsp;(R'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;1.7184</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>R'&nbsp;-&nbsp;Yc'&nbsp;&gt;&nbsp;0:</term>
-         <listitem>
-            <para>Crc&nbsp;=&nbsp;(R'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;0.9936</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Yc' is clamped to the range [0&hellip;1] and Cbc and Crc are
-clamped to the range [-0.5&hellip;0.5]. The Yc'CbcCrc quantization is limited range.</para>
-    </section>
-
-    <section id="col-dcip3">
-      <title>Colorspace DCI-P3 (<constant>V4L2_COLORSPACE_DCI_P3</constant>)</title>
-      <para>The <xref linkend="smpte431" /> standard defines the colorspace used by cinema
-projectors that use the DCI-P3 colorspace.
-The default transfer function is <constant>V4L2_XFER_FUNC_DCI_P3</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_709</constant>. Note that this
-colorspace does not specify a Y'CbCr encoding since it is not meant to be encoded
-to Y'CbCr. So this default Y'CbCr encoding was picked because it is the HDTV
-encoding. The default Y'CbCr quantization is limited range. The chromaticities of
-the primary colors and the white reference are:</para>
-      <table frame="none">
-        <title>DCI-P3 Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.6800</entry>
-              <entry>0.3200</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.2650</entry>
-              <entry>0.6900</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.1500</entry>
-              <entry>0.0600</entry>
-            </row>
-            <row>
-              <entry>White Reference</entry>
-              <entry>0.3140</entry>
-              <entry>0.3510</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function:</term>
-         <listitem>
-            <para>L' = L<superscript>1/2.6</superscript></para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'<superscript>2.6</superscript></para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y'CbCr encoding is not specified. V4L2 defaults to Rec. 709.</para>
-    </section>
-
-    <section id="col-smpte-240m">
-      <title>Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>)</title>
-      <para>The <xref linkend="smpte240m" /> standard was an interim standard used during
-the early days of HDTV (1988-1998).  It has been superseded by Rec. 709.
-The default transfer function is <constant>V4L2_XFER_FUNC_SMPTE240M</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SMPTE240M</constant>.
-The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the
-white reference are:</para>
-      <table frame="none">
-        <title>SMPTE 240M Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.630</entry>
-              <entry>0.340</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.310</entry>
-              <entry>0.595</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.155</entry>
-              <entry>0.070</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <para>These chromaticities are identical to the SMPTE 170M colorspace.</para>
-      <variablelist>
-       <varlistentry>
-          <term>Transfer function:</term>
-         <listitem>
-            <para>L' = 4L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.0228</para>
-            <para>L' = 1.1115L<superscript>0.45</superscript>&nbsp;-&nbsp;0.1115&nbsp;for&nbsp;0.0228&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'&nbsp;/&nbsp;4&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L'&nbsp;&lt;&nbsp;0.0913</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.1115)&nbsp;/&nbsp;1.1115)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.0913</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
-following <constant>V4L2_YCBCR_ENC_SMPTE240M</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.2122R'&nbsp;+&nbsp;0.7013G'&nbsp;+&nbsp;0.0865B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.1161R'&nbsp;-&nbsp;0.3839G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4451G'&nbsp;-&nbsp;0.0549B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Yc' is clamped to the range [0&hellip;1] and Cbc and Crc are
-clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.</para>
-    </section>
-
-    <section id="col-sysm">
-      <title>Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>)</title>
-      <para>This standard defines the colorspace used by NTSC in 1953. In practice this
-colorspace is obsolete and SMPTE 170M should be used instead.
-The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
-The default Y'CbCr quantization is limited range.
-The chromaticities of the primary colors and the white reference are:</para>
-      <table frame="none">
-        <title>NTSC 1953 Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.67</entry>
-              <entry>0.33</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.21</entry>
-              <entry>0.71</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.14</entry>
-              <entry>0.08</entry>
-            </row>
-            <row>
-              <entry>White Reference (C)</entry>
-              <entry>0.310</entry>
-              <entry>0.316</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <para>Note that this colorspace uses Illuminant C instead of D65 as the
-white reference. To correctly convert an image in this colorspace to another
-that uses D65 you need to apply a chromatic adaptation algorithm such as the
-Bradford method.</para>
-      <variablelist>
-       <varlistentry>
-          <term>The transfer function was never properly defined for NTSC 1953. The
-Rec. 709 transfer function is recommended in the literature:</term>
-         <listitem>
-            <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
-            <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
-following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.
-This transform is identical to one defined in SMPTE 170M/BT.601.</para>
-    </section>
-
-    <section id="col-sysbg">
-      <title>Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>)</title>
-      <para>The <xref linkend="tech3213" /> standard defines the colorspace used by PAL/SECAM in 1975. In practice this
-colorspace is obsolete and SMPTE 170M should be used instead.
-The default transfer function is <constant>V4L2_XFER_FUNC_709</constant>.
-The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
-The default Y'CbCr quantization is limited range.
-The chromaticities of the primary colors and the white reference are:</para>
-      <table frame="none">
-        <title>EBU Tech. 3213 Chromaticities</title>
-        <tgroup cols="3" align="left">
-          &cs-str;
-       <thead>
-         <row>
-           <entry>Color</entry>
-           <entry>x</entry>
-           <entry>y</entry>
-         </row>
-       </thead>
-          <tbody valign="top">
-            <row>
-              <entry>Red</entry>
-              <entry>0.64</entry>
-              <entry>0.33</entry>
-            </row>
-            <row>
-              <entry>Green</entry>
-              <entry>0.29</entry>
-              <entry>0.60</entry>
-            </row>
-            <row>
-              <entry>Blue</entry>
-              <entry>0.15</entry>
-              <entry>0.06</entry>
-            </row>
-            <row>
-              <entry>White Reference (D65)</entry>
-              <entry>0.3127</entry>
-              <entry>0.3290</entry>
-            </row>
-          </tbody>
-        </tgroup>
-      </table>
-      <variablelist>
-       <varlistentry>
-          <term>The transfer function was never properly defined for this colorspace.
-The Rec. 709 transfer function is recommended in the literature:</term>
-         <listitem>
-            <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
-            <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
-            <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-         <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
-following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
-         <listitem>
-            <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
-            <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
-            <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
-clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.
-This transform is identical to one defined in SMPTE 170M/BT.601.</para>
-    </section>
-
-    <section id="col-jpeg">
-      <title>Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>)</title>
-      <para>This colorspace defines the colorspace used by most (Motion-)JPEG formats. The chromaticities
-of the primary colors and the white reference are identical to sRGB. The transfer
-function use is <constant>V4L2_XFER_FUNC_SRGB</constant>. The Y'CbCr encoding is
-<constant>V4L2_YCBCR_ENC_601</constant> with full range quantization where
-Y' is scaled to [0&hellip;255] and Cb/Cr are scaled to [-128&hellip;128] and
-then clipped to [-128&hellip;127].</para>
-      <para>Note that the JPEG standard does not actually store colorspace information.
-So if something other than sRGB is used, then the driver will have to set that information
-explicitly. Effectively <constant>V4L2_COLORSPACE_JPEG</constant> can be considered to be
-an abbreviation for <constant>V4L2_COLORSPACE_SRGB</constant>, <constant>V4L2_YCBCR_ENC_601</constant>
-and <constant>V4L2_QUANTIZATION_FULL_RANGE</constant>.</para>
-    </section>
-
-  </section>
-
-  <section>
-    <title>Detailed Transfer Function Descriptions</title>
-    <section id="xf-smpte-2084">
-      <title>Transfer Function SMPTE 2084 (<constant>V4L2_XFER_FUNC_SMPTE2084</constant>)</title>
-      <para>The <xref linkend="smpte2084" /> standard defines the transfer function used by
-High Dynamic Range content.</para>
-      <variablelist>
-       <varlistentry>
-          <term>Constants:</term>
-         <listitem>
-            <para>m1 = (2610 / 4096) / 4</para>
-            <para>m2 = (2523 / 4096) * 128</para>
-            <para>c1 = 3424 / 4096</para>
-            <para>c2 = (2413 / 4096) * 32</para>
-            <para>c3 = (2392 / 4096) * 32</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-          <term>Transfer function:</term>
-         <listitem>
-            <para>L' = ((c1 + c2 * L<superscript>m1</superscript>) / (1 + c3 * L<superscript>m1</superscript>))<superscript>m2</superscript></para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-      <variablelist>
-       <varlistentry>
-          <term>Inverse Transfer function:</term>
-         <listitem>
-            <para>L = (max(L'<superscript>1/m2</superscript> - c1, 0) / (c2 - c3 * L'<superscript>1/m2</superscript>))<superscript>1/m1</superscript></para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-    </section>
-  </section>
-
-  <section id="pixfmt-indexed">
-    <title>Indexed Format</title>
-
-    <para>In this format each pixel is represented by an 8 bit index
-into a 256 entry ARGB palette. It is intended for <link
-linkend="osd">Video Output Overlays</link> only. There are no ioctls to
-access the palette, this must be done with ioctls of the Linux framebuffer API.</para>
-
-    <table pgwide="0" frame="none">
-      <title>Indexed Image Format</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-PAL8">
-           <entry><constant>V4L2_PIX_FMT_PAL8</constant></entry>
-           <entry>'PAL8'</entry>
-           <entry></entry>
-           <entry>i<subscript>7</subscript></entry>
-           <entry>i<subscript>6</subscript></entry>
-           <entry>i<subscript>5</subscript></entry>
-           <entry>i<subscript>4</subscript></entry>
-           <entry>i<subscript>3</subscript></entry>
-           <entry>i<subscript>2</subscript></entry>
-           <entry>i<subscript>1</subscript></entry>
-           <entry>i<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="pixfmt-rgb">
-    <title>RGB Formats</title>
-
-    &sub-packed-rgb;
-    &sub-sbggr8;
-    &sub-sgbrg8;
-    &sub-sgrbg8;
-    &sub-srggb8;
-    &sub-sbggr16;
-    &sub-srggb10;
-    &sub-srggb10p;
-    &sub-srggb10alaw8;
-    &sub-srggb10dpcm8;
-    &sub-srggb12;
-  </section>
-
-  <section id="yuv-formats">
-    <title>YUV Formats</title>
-
-    <para>YUV is the format native to TV broadcast and composite video
-signals. It separates the brightness information (Y) from the color
-information (U and V or Cb and Cr). The color information consists of
-red and blue <emphasis>color difference</emphasis> signals, this way
-the green component can be reconstructed by subtracting from the
-brightness component. See <xref linkend="colorspaces" /> for conversion
-examples. YUV was chosen because early television would only transmit
-brightness information. To add color in a way compatible with existing
-receivers a new signal carrier was added to transmit the color
-difference signals. Secondary in the YUV format the U and V components
-usually have lower resolution than the Y component. This is an analog
-video compression technique taking advantage of a property of the
-human visual system, being more sensitive to brightness
-information.</para>
-
-    &sub-packed-yuv;
-    &sub-grey;
-    &sub-y10;
-    &sub-y12;
-    &sub-y10b;
-    &sub-y16;
-    &sub-y16-be;
-    &sub-y8i;
-    &sub-y12i;
-    &sub-uv8;
-    &sub-yuyv;
-    &sub-uyvy;
-    &sub-yvyu;
-    &sub-vyuy;
-    &sub-y41p;
-    &sub-yuv420;
-    &sub-yuv420m;
-    &sub-yuv422m;
-    &sub-yuv444m;
-    &sub-yuv410;
-    &sub-yuv422p;
-    &sub-yuv411p;
-    &sub-nv12;
-    &sub-nv12m;
-    &sub-nv12mt;
-    &sub-nv16;
-    &sub-nv16m;
-    &sub-nv24;
-    &sub-m420;
-  </section>
-
-  <section id="depth-formats">
-    <title>Depth Formats</title>
-    <para>Depth data provides distance to points, mapped onto the image plane
-    </para>
-
-    &sub-z16;
-  </section>
-
-  <section>
-    <title>Compressed Formats</title>
-
-    <table pgwide="1" frame="none" id="compressed-formats">
-      <title>Compressed Image Formats</title>
-      <tgroup cols="3" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-        <row id="V4L2-PIX-FMT-JPEG">
-           <entry><constant>V4L2_PIX_FMT_JPEG</constant></entry>
-           <entry>'JPEG'</entry>
-           <entry>TBD. See also &VIDIOC-G-JPEGCOMP;,
-           &VIDIOC-S-JPEGCOMP;.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MPEG">
-           <entry><constant>V4L2_PIX_FMT_MPEG</constant></entry>
-           <entry>'MPEG'</entry>
-           <entry>MPEG multiplexed stream. The actual format is determined by
-extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
-<xref linkend="mpeg-control-id" />.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-H264">
-               <entry><constant>V4L2_PIX_FMT_H264</constant></entry>
-               <entry>'H264'</entry>
-               <entry>H264 video elementary stream with start codes.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-H264-NO-SC">
-               <entry><constant>V4L2_PIX_FMT_H264_NO_SC</constant></entry>
-               <entry>'AVC1'</entry>
-               <entry>H264 video elementary stream without start codes.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-H264-MVC">
-               <entry><constant>V4L2_PIX_FMT_H264_MVC</constant></entry>
-               <entry>'M264'</entry>
-               <entry>H264 MVC video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-H263">
-               <entry><constant>V4L2_PIX_FMT_H263</constant></entry>
-               <entry>'H263'</entry>
-               <entry>H263 video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MPEG1">
-               <entry><constant>V4L2_PIX_FMT_MPEG1</constant></entry>
-               <entry>'MPG1'</entry>
-               <entry>MPEG1 video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MPEG2">
-               <entry><constant>V4L2_PIX_FMT_MPEG2</constant></entry>
-               <entry>'MPG2'</entry>
-               <entry>MPEG2 video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MPEG4">
-               <entry><constant>V4L2_PIX_FMT_MPEG4</constant></entry>
-               <entry>'MPG4'</entry>
-               <entry>MPEG4 video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-XVID">
-               <entry><constant>V4L2_PIX_FMT_XVID</constant></entry>
-               <entry>'XVID'</entry>
-               <entry>Xvid video elementary stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-VC1-ANNEX-G">
-               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_G</constant></entry>
-               <entry>'VC1G'</entry>
-               <entry>VC1, SMPTE 421M Annex G compliant stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-VC1-ANNEX-L">
-               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_L</constant></entry>
-               <entry>'VC1L'</entry>
-               <entry>VC1, SMPTE 421M Annex L compliant stream.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-VP8">
-               <entry><constant>V4L2_PIX_FMT_VP8</constant></entry>
-               <entry>'VP80'</entry>
-               <entry>VP8 video elementary stream.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="sdr-formats">
-    <title>SDR Formats</title>
-
-    <para>These formats are used for <link linkend="sdr">SDR</link>
-interface only.</para>
-
-    &sub-sdr-cu08;
-    &sub-sdr-cu16le;
-    &sub-sdr-cs08;
-    &sub-sdr-cs14le;
-    &sub-sdr-ru12le;
-
-  </section>
-
-  <section id="pixfmt-reserved">
-    <title>Reserved Format Identifiers</title>
-
-    <para>These formats are not defined by this specification, they
-are just listed for reference and to avoid naming conflicts. If you
-want to register your own format, send an e-mail to the linux-media mailing
-list &v4l-ml; for inclusion in the <filename>videodev2.h</filename>
-file. If you want to share your format with other developers add a
-link to your documentation and send a copy to the linux-media mailing list
-for inclusion in this section. If you think your format should be listed
-in a standard format section please make a proposal on the linux-media mailing
-list.</para>
-
-    <table pgwide="1" frame="none" id="reserved-formats">
-      <title>Reserved Image Formats</title>
-      <tgroup cols="3" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-DV">
-           <entry><constant>V4L2_PIX_FMT_DV</constant></entry>
-           <entry>'dvsd'</entry>
-           <entry>unknown</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ET61X251">
-           <entry><constant>V4L2_PIX_FMT_ET61X251</constant></entry>
-           <entry>'E625'</entry>
-           <entry>Compressed format of the ET61X251 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-HI240">
-           <entry><constant>V4L2_PIX_FMT_HI240</constant></entry>
-           <entry>'HI24'</entry>
-           <entry><para>8 bit RGB format used by the BTTV driver.</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-HM12">
-           <entry><constant>V4L2_PIX_FMT_HM12</constant></entry>
-           <entry>'HM12'</entry>
-           <entry><para>YUV 4:2:0 format used by the
-IVTV driver, <ulink url="http://www.ivtvdriver.org/">
-http://www.ivtvdriver.org/</ulink></para><para>The format is documented in the
-kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm12</filename>
-</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-CPIA1">
-           <entry><constant>V4L2_PIX_FMT_CPIA1</constant></entry>
-           <entry>'CPIA'</entry>
-           <entry>YUV format used by the gspca cpia1 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-JPGL">
-           <entry><constant>V4L2_PIX_FMT_JPGL</constant></entry>
-           <entry>'JPGL'</entry>
-           <entry>JPEG-Light format (Pegasus Lossless JPEG)
-                       used in Divio webcams NW 80x.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA501">
-           <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
-           <entry>'S501'</entry>
-           <entry>YUYV per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA505">
-           <entry><constant>V4L2_PIX_FMT_SPCA505</constant></entry>
-           <entry>'S505'</entry>
-           <entry>YYUV per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA508">
-           <entry><constant>V4L2_PIX_FMT_SPCA508</constant></entry>
-           <entry>'S508'</entry>
-           <entry>YUVY per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA561">
-           <entry><constant>V4L2_PIX_FMT_SPCA561</constant></entry>
-           <entry>'S561'</entry>
-           <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PAC207">
-           <entry><constant>V4L2_PIX_FMT_PAC207</constant></entry>
-           <entry>'P207'</entry>
-           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MR97310A">
-           <entry><constant>V4L2_PIX_FMT_MR97310A</constant></entry>
-           <entry>'M310'</entry>
-           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-JL2005BCD">
-           <entry><constant>V4L2_PIX_FMT_JL2005BCD</constant></entry>
-           <entry>'JL20'</entry>
-           <entry>JPEG compressed RGGB Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-OV511">
-           <entry><constant>V4L2_PIX_FMT_OV511</constant></entry>
-           <entry>'O511'</entry>
-           <entry>OV511 JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-OV518">
-           <entry><constant>V4L2_PIX_FMT_OV518</constant></entry>
-           <entry>'O518'</entry>
-           <entry>OV518 JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PJPG">
-           <entry><constant>V4L2_PIX_FMT_PJPG</constant></entry>
-           <entry>'PJPG'</entry>
-           <entry>Pixart 73xx JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SE401">
-           <entry><constant>V4L2_PIX_FMT_SE401</constant></entry>
-           <entry>'S401'</entry>
-           <entry>Compressed RGB format used by the gspca se401 driver</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SQ905C">
-           <entry><constant>V4L2_PIX_FMT_SQ905C</constant></entry>
-           <entry>'905C'</entry>
-           <entry>Compressed RGGB bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MJPEG">
-           <entry><constant>V4L2_PIX_FMT_MJPEG</constant></entry>
-           <entry>'MJPG'</entry>
-           <entry>Compressed format used by the Zoran driver</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PWC1">
-           <entry><constant>V4L2_PIX_FMT_PWC1</constant></entry>
-           <entry>'PWC1'</entry>
-           <entry>Compressed format of the PWC driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PWC2">
-           <entry><constant>V4L2_PIX_FMT_PWC2</constant></entry>
-           <entry>'PWC2'</entry>
-           <entry>Compressed format of the PWC driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C10X">
-           <entry><constant>V4L2_PIX_FMT_SN9C10X</constant></entry>
-           <entry>'S910'</entry>
-           <entry>Compressed format of the SN9C102 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C20X-I420">
-           <entry><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></entry>
-           <entry>'S920'</entry>
-           <entry>YUV 4:2:0 format of the gspca sn9c20x driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C2028">
-           <entry><constant>V4L2_PIX_FMT_SN9C2028</constant></entry>
-           <entry>'SONX'</entry>
-           <entry>Compressed GBRG bayer format of the gspca sn9c2028 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-STV0680">
-           <entry><constant>V4L2_PIX_FMT_STV0680</constant></entry>
-           <entry>'S680'</entry>
-           <entry>Bayer format of the gspca stv0680 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-WNVA">
-           <entry><constant>V4L2_PIX_FMT_WNVA</constant></entry>
-           <entry>'WNVA'</entry>
-           <entry><para>Used by the Winnov Videum driver, <ulink
-url="http://www.thedirks.org/winnov/">
-http://www.thedirks.org/winnov/</ulink></para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-TM6000">
-           <entry><constant>V4L2_PIX_FMT_TM6000</constant></entry>
-           <entry>'TM60'</entry>
-           <entry><para>Used by Trident tm6000</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-CIT-YYVYUY">
-           <entry><constant>V4L2_PIX_FMT_CIT_YYVYUY</constant></entry>
-           <entry>'CITV'</entry>
-           <entry><para>Used by xirlink CIT, found at IBM webcams.</para>
-                  <para>Uses one line of Y then 1 line of VYUY</para>
-           </entry>
-         </row>
-         <row id="V4L2-PIX-FMT-KONICA420">
-           <entry><constant>V4L2_PIX_FMT_KONICA420</constant></entry>
-           <entry>'KONI'</entry>
-           <entry><para>Used by Konica webcams.</para>
-                  <para>YUV420 planar in blocks of 256 pixels.</para>
-           </entry>
-         </row>
-         <row id="V4L2-PIX-FMT-YYUV">
-           <entry><constant>V4L2_PIX_FMT_YYUV</constant></entry>
-           <entry>'YYUV'</entry>
-           <entry>unknown</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-Y4">
-           <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
-           <entry>'Y04 '</entry>
-           <entry>Old 4-bit greyscale format. Only the most significant 4 bits of each byte are used,
-the other bits are set to 0.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-Y6">
-           <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
-           <entry>'Y06 '</entry>
-           <entry>Old 6-bit greyscale format. Only the most significant 6 bits of each byte are used,
-the other bits are set to 0.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-S5C-UYVY-JPG">
-           <entry><constant>V4L2_PIX_FMT_S5C_UYVY_JPG</constant></entry>
-           <entry>'S5CI'</entry>
-           <entry>Two-planar format used by Samsung S5C73MX cameras. The
-first plane contains interleaved JPEG and UYVY image data, followed by meta data
-in form of an array of offsets to the UYVY data blocks. The actual pointer array
-follows immediately the interleaved JPEG/UYVY data, the number of entries in
-this array equals the height of the UYVY image. Each entry is a 4-byte unsigned
-integer in big endian order and it's an offset to a single pixel line of the
-UYVY image. The first plane can start either with JPEG or UYVY data chunk. The
-size of a single UYVY block equals the UYVY image's width multiplied by 2. The
-size of a JPEG chunk depends on the image and can vary with each line.
-<para>The second plane, at an offset of 4084 bytes, contains a 4-byte offset to
-the pointer array in the first plane. This offset is followed by a 4-byte value
-indicating size of the pointer array. All numbers in the second plane are also
-in big endian order. Remaining data in the second plane is undefined. The
-information in the second plane allows to easily find location of the pointer
-array, which can be different for each frame. The size of the pointer array is
-constant for given UYVY image height.</para>
-<para>In order to extract UYVY and JPEG frames an application can initially set
-a data pointer to the start of first plane and then add an offset from the first
-entry of the pointers table. Such a pointer indicates start of an UYVY image
-pixel line. Whole UYVY line can be copied to a separate buffer. These steps
-should be repeated for each line, i.e. the number of entries in the pointer
-array. Anything what's in between the UYVY lines is JPEG data and should be
-concatenated to form the JPEG stream. </para>
-</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="format-flags">
-      <title>Format Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_PIX_FMT_FLAG_PREMUL_ALPHA</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>The color values are premultiplied by the alpha channel
-value. For example, if a light blue pixel with 50% transparency was described by
-RGBA values (128, 192, 255, 128), the same pixel described with premultiplied
-colors would be described by RGBA values (64, 96, 128, 128) </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
diff --git a/Documentation/DocBook/media/v4l/planar-apis.xml b/Documentation/DocBook/media/v4l/planar-apis.xml
deleted file mode 100644 (file)
index 878ce20..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<section id="planar-apis">
-  <title>Single- and multi-planar APIs</title>
-
-  <para>Some devices require data for each input or output video frame
-  to be placed in discontiguous memory buffers. In such cases, one
-  video frame has to be addressed using more than one memory address, i.e. one
-  pointer per "plane". A plane is a sub-buffer of the current frame. For
-  examples of such formats see <xref linkend="pixfmt" />.</para>
-
-  <para>Initially, V4L2 API did not support multi-planar buffers and a set of
-  extensions has been introduced to handle them. Those extensions constitute
-  what is being referred to as the "multi-planar API".</para>
-
-  <para>Some of the V4L2 API calls and structures are interpreted differently,
-  depending on whether single- or multi-planar API is being used. An application
-  can choose whether to use one or the other by passing a corresponding buffer
-  type to its ioctl calls. Multi-planar versions of buffer types are suffixed
-  with an `_MPLANE' string. For a list of available multi-planar buffer types
-  see &v4l2-buf-type;.
-  </para>
-
-  <section>
-    <title>Multi-planar formats</title>
-    <para>Multi-planar API introduces new multi-planar formats. Those formats
-    use a separate set of FourCC codes. It is important to distinguish between
-    the multi-planar API and a multi-planar format. Multi-planar API calls can
-    handle all single-planar formats as well (as long as they are passed in
-    multi-planar API structures), while the single-planar API cannot
-    handle multi-planar formats.</para>
-  </section>
-
-  <section>
-    <title>Calls that distinguish between single and multi-planar APIs</title>
-    <variablelist>
-      <varlistentry>
-        <term>&VIDIOC-QUERYCAP;</term>
-        <listitem><para>Two additional multi-planar capabilities are added. They can
-        be set together with non-multi-planar ones for devices that handle
-        both single- and multi-planar formats.</para></listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-G-FMT;, &VIDIOC-S-FMT;, &VIDIOC-TRY-FMT;</term>
-        <listitem><para>New structures for describing multi-planar formats are added:
-        &v4l2-pix-format-mplane; and &v4l2-plane-pix-format;. Drivers may
-        define new multi-planar formats, which have distinct FourCC codes from
-        the existing single-planar ones.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-QBUF;, &VIDIOC-DQBUF;, &VIDIOC-QUERYBUF;</term>
-        <listitem><para>A new &v4l2-plane; structure for describing planes is added.
-        Arrays of this structure are passed in the new
-        <structfield>m.planes</structfield> field of &v4l2-buffer;.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-REQBUFS;</term>
-        <listitem><para>Will allocate multi-planar buffers as requested.</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </section>
-</section>
diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml
deleted file mode 100644 (file)
index b86844e..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-<partinfo>
-<authorgroup>
-<author>
-<firstname>Mauro</firstname>
-<surname>Chehab</surname>
-<othername role="mi">Carvalho</othername>
-<affiliation><address><email>m.chehab@samsung.com</email></address></affiliation>
-<contrib>Initial version.</contrib>
-</author>
-</authorgroup>
-<copyright>
-       <year>2009-2014</year>
-        <holder>Mauro Carvalho Chehab</holder>
-</copyright>
-
-<revhistory>
-<!-- Put document revisions here, newest first. -->
-<revision>
-<revnumber>3.15</revnumber>
-<date>2014-02-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Added the interface description and the RC sysfs class description.</revremark>
-</revision>
-<revision>
-<revnumber>1.0</revnumber>
-<date>2009-09-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Initial revision</revremark>
-</revision>
-</revhistory>
-</partinfo>
-
- <title>Remote Controller API</title>
- <chapter id="remote_controllers">
-
-<title>Remote Controllers</title>
-
-<section id="Remote_controllers_Intro">
-<title>Introduction</title>
-
-<para>Currently, most analog and digital devices have a Infrared input for remote controllers. Each
-manufacturer has their own type of control. It is not rare for the same manufacturer to ship different
-types of controls, depending on the device.</para>
-<para>A Remote Controller interface is mapped as a normal evdev/input interface, just like a keyboard or a mouse.
-So, it uses all ioctls already defined for any other input devices.</para>
-<para>However, remove controllers are more flexible than a normal input device, as the IR
-receiver (and/or transmitter) can be used in conjunction with a wide variety of different IR remotes.</para>
-<para>In order to allow flexibility, the Remote Controller subsystem allows controlling the
-RC-specific attributes via <link linkend="remote_controllers_sysfs_nodes">the sysfs class nodes</link>.</para>
-</section>
-
-<section id="remote_controllers_sysfs_nodes">
-<title>Remote Controller's sysfs nodes</title>
-<para>As defined at <constant>Documentation/ABI/testing/sysfs-class-rc</constant>, those are the sysfs nodes that control the Remote Controllers:</para>
-
-<section id="sys_class_rc">
-<title>/sys/class/rc/</title>
-<para>The <constant>/sys/class/rc/</constant> class sub-directory belongs to the Remote Controller
-core and provides a sysfs interface for configuring infrared remote controller receivers.
-</para>
-
-</section>
-<section id="sys_class_rc_rcN">
-<title>/sys/class/rc/rcN/</title>
-<para>A <constant>/sys/class/rc/rcN</constant> directory is created for each remote
-  control receiver device where N is the number of the receiver.</para>
-
-</section>
-<section id="sys_class_rc_rcN_protocols">
-<title>/sys/class/rc/rcN/protocols</title>
-<para>Reading this file returns a list of available protocols, something like:</para>
-<para><constant>rc5 [rc6] nec jvc [sony]</constant></para>
-<para>Enabled protocols are shown in [] brackets.</para>
-<para>Writing "+proto" will add a protocol to the list of enabled protocols.</para>
-<para>Writing "-proto" will remove a protocol from the list of enabled protocols.</para>
-<para>Writing "proto" will enable only "proto".</para>
-<para>Writing "none" will disable all protocols.</para>
-<para>Write fails with EINVAL if an invalid protocol combination or unknown protocol name is used.</para>
-
-</section>
-<section id="sys_class_rc_rcN_filter">
-<title>/sys/class/rc/rcN/filter</title>
-<para>Sets the scancode filter expected value.</para>
-<para>Use in combination with <constant>/sys/class/rc/rcN/filter_mask</constant> to set the
-expected value of the bits set in the filter mask.
-If the hardware supports it then scancodes which do not match
-the filter will be ignored. Otherwise the write will fail with
-an error.</para>
-<para>This value may be reset to 0 if the current protocol is altered.</para>
-
-</section>
-<section id="sys_class_rc_rcN_filter_mask">
-<title>/sys/class/rc/rcN/filter_mask</title>
-<para>Sets the scancode filter mask of bits to compare.
-Use in combination with <constant>/sys/class/rc/rcN/filter</constant> to set the bits
-of the scancode which should be compared against the expected
-value. A value of 0 disables the filter to allow all valid
-scancodes to be processed.</para>
-<para>If the hardware supports it then scancodes which do not match
-the filter will be ignored. Otherwise the write will fail with
-an error.</para>
-<para>This value may be reset to 0 if the current protocol is altered.</para>
-
-</section>
-<section id="sys_class_rc_rcN_wakeup_protocols">
-<title>/sys/class/rc/rcN/wakeup_protocols</title>
-<para>Reading this file returns a list of available protocols to use for the
-wakeup filter, something like:</para>
-<para><constant>rc5 rc6 nec jvc [sony]</constant></para>
-<para>The enabled wakeup protocol is shown in [] brackets.</para>
-<para>Writing "+proto" will add a protocol to the list of enabled wakeup
-protocols.</para>
-<para>Writing "-proto" will remove a protocol from the list of enabled wakeup
-protocols.</para>
-<para>Writing "proto" will use "proto" for wakeup events.</para>
-<para>Writing "none" will disable wakeup.</para>
-<para>Write fails with EINVAL if an invalid protocol combination or unknown
-protocol name is used, or if wakeup is not supported by the hardware.</para>
-
-</section>
-<section id="sys_class_rc_rcN_wakeup_filter">
-<title>/sys/class/rc/rcN/wakeup_filter</title>
-<para>Sets the scancode wakeup filter expected value.
-Use in combination with <constant>/sys/class/rc/rcN/wakeup_filter_mask</constant> to
-set the expected value of the bits set in the wakeup filter mask
-to trigger a system wake event.</para>
-<para>If the hardware supports it and wakeup_filter_mask is not 0 then
-scancodes which match the filter will wake the system from e.g.
-suspend to RAM or power off.
-Otherwise the write will fail with an error.</para>
-<para>This value may be reset to 0 if the wakeup protocol is altered.</para>
-
-</section>
-<section id="sys_class_rc_rcN_wakeup_filter_mask">
-<title>/sys/class/rc/rcN/wakeup_filter_mask</title>
-<para>Sets the scancode wakeup filter mask of bits to compare.
-Use in combination with <constant>/sys/class/rc/rcN/wakeup_filter</constant> to set
-the bits of the scancode which should be compared against the
-expected value to trigger a system wake event.</para>
-<para>If the hardware supports it and wakeup_filter_mask is not 0 then
-scancodes which match the filter will wake the system from e.g.
-suspend to RAM or power off.
-Otherwise the write will fail with an error.</para>
-<para>This value may be reset to 0 if the wakeup protocol is altered.</para>
-</section>
-</section>
-
-<section id="Remote_controllers_tables">
-<title>Remote controller tables</title>
-<para>Unfortunately, for several years, there was no effort to create uniform IR keycodes for
-different devices.  This caused the same IR keyname to be mapped completely differently on
-different IR devices. This resulted that the same IR keyname to be mapped completely different on
-different IR's. Due to that, V4L2 API now specifies a standard for mapping Media keys on IR.</para>
-<para>This standard should be used by both V4L/DVB drivers and userspace applications</para>
-<para>The modules register the remote as keyboard within the linux input layer. This means that the IR key strokes will look like normal keyboard key strokes (if CONFIG_INPUT_KEYBOARD is enabled). Using the event devices (CONFIG_INPUT_EVDEV) it is possible for applications to access the remote via /dev/input/event devices.</para>
-
-<table pgwide="1" frame="none" id="rc_standard_keymap">
-<title>IR default keymapping</title>
-<tgroup cols="3">
-&cs-str;
-<tbody valign="top">
-<row>
-<entry>Key code</entry>
-<entry>Meaning</entry>
-<entry>Key examples on IR</entry>
-</row>
-
-<row><entry><emphasis role="bold">Numeric keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_0</constant></entry><entry>Keyboard digit 0</entry><entry>0</entry></row>
-<row><entry><constant>KEY_1</constant></entry><entry>Keyboard digit 1</entry><entry>1</entry></row>
-<row><entry><constant>KEY_2</constant></entry><entry>Keyboard digit 2</entry><entry>2</entry></row>
-<row><entry><constant>KEY_3</constant></entry><entry>Keyboard digit 3</entry><entry>3</entry></row>
-<row><entry><constant>KEY_4</constant></entry><entry>Keyboard digit 4</entry><entry>4</entry></row>
-<row><entry><constant>KEY_5</constant></entry><entry>Keyboard digit 5</entry><entry>5</entry></row>
-<row><entry><constant>KEY_6</constant></entry><entry>Keyboard digit 6</entry><entry>6</entry></row>
-<row><entry><constant>KEY_7</constant></entry><entry>Keyboard digit 7</entry><entry>7</entry></row>
-<row><entry><constant>KEY_8</constant></entry><entry>Keyboard digit 8</entry><entry>8</entry></row>
-<row><entry><constant>KEY_9</constant></entry><entry>Keyboard digit 9</entry><entry>9</entry></row>
-
-<row><entry><emphasis role="bold">Movie play control</emphasis></entry></row>
-
-<row><entry><constant>KEY_FORWARD</constant></entry><entry>Instantly advance in time</entry><entry>&gt;&gt; / FORWARD</entry></row>
-<row><entry><constant>KEY_BACK</constant></entry><entry>Instantly go back in time</entry><entry>&lt;&lt;&lt; / BACK</entry></row>
-<row><entry><constant>KEY_FASTFORWARD</constant></entry><entry>Play movie faster</entry><entry>&gt;&gt;&gt; / FORWARD</entry></row>
-<row><entry><constant>KEY_REWIND</constant></entry><entry>Play movie back</entry><entry>REWIND / BACKWARD</entry></row>
-<row><entry><constant>KEY_NEXT</constant></entry><entry>Select next chapter / sub-chapter / interval</entry><entry>NEXT / SKIP</entry></row>
-<row><entry><constant>KEY_PREVIOUS</constant></entry><entry>Select previous chapter / sub-chapter / interval</entry><entry>&lt;&lt; /  PREV / PREVIOUS</entry></row>
-<row><entry><constant>KEY_AGAIN</constant></entry><entry>Repeat the video or a video interval</entry><entry>REPEAT / LOOP / RECALL</entry></row>
-<row><entry><constant>KEY_PAUSE</constant></entry><entry>Pause sroweam</entry><entry>PAUSE / FREEZE</entry></row>
-<row><entry><constant>KEY_PLAY</constant></entry><entry>Play movie at the normal timeshift</entry><entry>NORMAL TIMESHIFT / LIVE / &gt;</entry></row>
-<row><entry><constant>KEY_PLAYPAUSE</constant></entry><entry>Alternate between play and pause</entry><entry>PLAY / PAUSE</entry></row>
-<row><entry><constant>KEY_STOP</constant></entry><entry>Stop sroweam</entry><entry>STOP</entry></row>
-<row><entry><constant>KEY_RECORD</constant></entry><entry>Start/stop recording sroweam</entry><entry>CAPTURE / REC / RECORD/PAUSE</entry></row>
-<row><entry><constant>KEY_CAMERA</constant></entry><entry>Take a picture of the image</entry><entry>CAMERA ICON / CAPTURE / SNAPSHOT</entry></row>
-<row><entry><constant>KEY_SHUFFLE</constant></entry><entry>Enable shuffle mode</entry><entry>SHUFFLE</entry></row>
-<row><entry><constant>KEY_TIME</constant></entry><entry>Activate time shift mode</entry><entry>TIME SHIFT</entry></row>
-<row><entry><constant>KEY_TITLE</constant></entry><entry>Allow changing the chapter</entry><entry>CHAPTER</entry></row>
-<row><entry><constant>KEY_SUBTITLE</constant></entry><entry>Allow changing the subtitle</entry><entry>SUBTITLE</entry></row>
-
-<row><entry><emphasis role="bold">Image control</emphasis></entry></row>
-
-<row><entry><constant>KEY_BRIGHTNESSDOWN</constant></entry><entry>Decrease Brightness</entry><entry>BRIGHTNESS DECREASE</entry></row>
-<row><entry><constant>KEY_BRIGHTNESSUP</constant></entry><entry>Increase Brightness</entry><entry>BRIGHTNESS INCREASE</entry></row>
-
-<row><entry><constant>KEY_ANGLE</constant></entry><entry>Switch video camera angle (on videos with more than one angle stored)</entry><entry>ANGLE / SWAP</entry></row>
-<row><entry><constant>KEY_EPG</constant></entry><entry>Open the Elecrowonic Play Guide (EPG)</entry><entry>EPG / GUIDE</entry></row>
-<row><entry><constant>KEY_TEXT</constant></entry><entry>Activate/change closed caption mode</entry><entry>CLOSED CAPTION/TELETEXT / DVD TEXT / TELETEXT / TTX</entry></row>
-
-<row><entry><emphasis role="bold">Audio control</emphasis></entry></row>
-
-<row><entry><constant>KEY_AUDIO</constant></entry><entry>Change audio source</entry><entry>AUDIO SOURCE / AUDIO / MUSIC</entry></row>
-<row><entry><constant>KEY_MUTE</constant></entry><entry>Mute/unmute audio</entry><entry>MUTE / DEMUTE / UNMUTE</entry></row>
-<row><entry><constant>KEY_VOLUMEDOWN</constant></entry><entry>Decrease volume</entry><entry>VOLUME- / VOLUME DOWN</entry></row>
-<row><entry><constant>KEY_VOLUMEUP</constant></entry><entry>Increase volume</entry><entry>VOLUME+ / VOLUME UP</entry></row>
-<row><entry><constant>KEY_MODE</constant></entry><entry>Change sound mode</entry><entry>MONO/STEREO</entry></row>
-<row><entry><constant>KEY_LANGUAGE</constant></entry><entry>Select Language</entry><entry>1ST / 2ND LANGUAGE / DVD LANG / MTS/SAP / MTS SEL</entry></row>
-
-<row><entry><emphasis role="bold">Channel control</emphasis></entry></row>
-
-<row><entry><constant>KEY_CHANNEL</constant></entry><entry>Go to the next favorite channel</entry><entry>ALT / CHANNEL / CH SURFING / SURF / FAV</entry></row>
-<row><entry><constant>KEY_CHANNELDOWN</constant></entry><entry>Decrease channel sequencially</entry><entry>CHANNEL - / CHANNEL DOWN / DOWN</entry></row>
-<row><entry><constant>KEY_CHANNELUP</constant></entry><entry>Increase channel sequencially</entry><entry>CHANNEL + / CHANNEL UP / UP</entry></row>
-<row><entry><constant>KEY_DIGITS</constant></entry><entry>Use more than one digit for channel</entry><entry>PLUS / 100/ 1xx / xxx /  -/--  / Single Double Triple Digit</entry></row>
-<row><entry><constant>KEY_SEARCH</constant></entry><entry>Start channel autoscan</entry><entry>SCAN / AUTOSCAN</entry></row>
-
-<row><entry><emphasis role="bold">Colored keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_BLUE</constant></entry><entry>IR Blue key</entry><entry>BLUE</entry></row>
-<row><entry><constant>KEY_GREEN</constant></entry><entry>IR Green Key</entry><entry>GREEN</entry></row>
-<row><entry><constant>KEY_RED</constant></entry><entry>IR Red key</entry><entry>RED</entry></row>
-<row><entry><constant>KEY_YELLOW</constant></entry><entry>IR Yellow key</entry><entry> YELLOW</entry></row>
-
-<row><entry><emphasis role="bold">Media selection</emphasis></entry></row>
-
-<row><entry><constant>KEY_CD</constant></entry><entry>Change input source to Compact Disc</entry><entry>CD</entry></row>
-<row><entry><constant>KEY_DVD</constant></entry><entry>Change input to DVD</entry><entry>DVD / DVD MENU</entry></row>
-<row><entry><constant>KEY_EJECTCLOSECD</constant></entry><entry>Open/close the CD/DVD player</entry><entry>-&gt; ) / CLOSE / OPEN</entry></row>
-
-<row><entry><constant>KEY_MEDIA</constant></entry><entry>Turn on/off Media application</entry><entry>PC/TV /  TURN ON/OFF APP</entry></row>
-<row><entry><constant>KEY_PC</constant></entry><entry>Selects from TV to PC</entry><entry>PC</entry></row>
-<row><entry><constant>KEY_RADIO</constant></entry><entry>Put into AM/FM radio mode</entry><entry>RADIO / TV/FM / TV/RADIO / FM / FM/RADIO</entry></row>
-<row><entry><constant>KEY_TV</constant></entry><entry>Select tv mode</entry><entry>TV / LIVE TV</entry></row>
-<row><entry><constant>KEY_TV2</constant></entry><entry>Select Cable mode</entry><entry>AIR/CBL</entry></row>
-<row><entry><constant>KEY_VCR</constant></entry><entry>Select VCR mode</entry><entry>VCR MODE / DTR</entry></row>
-<row><entry><constant>KEY_VIDEO</constant></entry><entry>Alternate between input modes</entry><entry>SOURCE / SELECT / DISPLAY / SWITCH INPUTS / VIDEO</entry></row>
-
-<row><entry><emphasis role="bold">Power control</emphasis></entry></row>
-
-<row><entry><constant>KEY_POWER</constant></entry><entry>Turn on/off computer</entry><entry>SYSTEM POWER / COMPUTER POWER</entry></row>
-<row><entry><constant>KEY_POWER2</constant></entry><entry>Turn on/off application</entry><entry>TV ON/OFF / POWER</entry></row>
-<row><entry><constant>KEY_SLEEP</constant></entry><entry>Activate sleep timer</entry><entry>SLEEP / SLEEP TIMER</entry></row>
-<row><entry><constant>KEY_SUSPEND</constant></entry><entry>Put computer into suspend mode</entry><entry>STANDBY / SUSPEND</entry></row>
-
-<row><entry><emphasis role="bold">Window control</emphasis></entry></row>
-
-<row><entry><constant>KEY_CLEAR</constant></entry><entry>Stop sroweam and return to default input video/audio</entry><entry>CLEAR / RESET / BOSS KEY</entry></row>
-<row><entry><constant>KEY_CYCLEWINDOWS</constant></entry><entry>Minimize windows and move to the next one</entry><entry>ALT-TAB / MINIMIZE / DESKTOP</entry></row>
-<row><entry><constant>KEY_FAVORITES</constant></entry><entry>Open the favorites sroweam window</entry><entry>TV WALL / Favorites</entry></row>
-<row><entry><constant>KEY_MENU</constant></entry><entry>Call application menu</entry><entry>2ND CONTROLS (USA: MENU) / DVD/MENU / SHOW/HIDE CTRL</entry></row>
-<row><entry><constant>KEY_NEW</constant></entry><entry>Open/Close Picture in Picture</entry><entry>PIP</entry></row>
-<row><entry><constant>KEY_OK</constant></entry><entry>Send a confirmation code to application</entry><entry>OK / ENTER / RETURN</entry></row>
-<row><entry><constant>KEY_SCREEN</constant></entry><entry>Select screen aspect ratio</entry><entry>4:3 16:9 SELECT</entry></row>
-<row><entry><constant>KEY_ZOOM</constant></entry><entry>Put device into zoom/full screen mode</entry><entry>ZOOM / FULL SCREEN / ZOOM+ / HIDE PANNEL / SWITCH</entry></row>
-
-<row><entry><emphasis role="bold">Navigation keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_ESC</constant></entry><entry>Cancel current operation</entry><entry>CANCEL / BACK</entry></row>
-<row><entry><constant>KEY_HELP</constant></entry><entry>Open a Help window</entry><entry>HELP</entry></row>
-<row><entry><constant>KEY_HOMEPAGE</constant></entry><entry>Navigate to Homepage</entry><entry>HOME</entry></row>
-<row><entry><constant>KEY_INFO</constant></entry><entry>Open On Screen Display</entry><entry>DISPLAY INFORMATION / OSD</entry></row>
-<row><entry><constant>KEY_WWW</constant></entry><entry>Open the default browser</entry><entry>WEB</entry></row>
-<row><entry><constant>KEY_UP</constant></entry><entry>Up key</entry><entry>UP</entry></row>
-<row><entry><constant>KEY_DOWN</constant></entry><entry>Down key</entry><entry>DOWN</entry></row>
-<row><entry><constant>KEY_LEFT</constant></entry><entry>Left key</entry><entry>LEFT</entry></row>
-<row><entry><constant>KEY_RIGHT</constant></entry><entry>Right key</entry><entry>RIGHT</entry></row>
-
-<row><entry><emphasis role="bold">Miscellaneous keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_DOT</constant></entry><entry>Return a dot</entry><entry>.</entry></row>
-<row><entry><constant>KEY_FN</constant></entry><entry>Select a function</entry><entry>FUNCTION</entry></row>
-
-</tbody>
-</tgroup>
-</table>
-
-<para>It should be noted that, sometimes, there some fundamental missing keys at some cheaper IR's. Due to that, it is recommended to:</para>
-
-<table pgwide="1" frame="none" id="rc_keymap_notes">
-<title>Notes</title>
-<tgroup cols="1">
-&cs-str;
-<tbody valign="top">
-<row>
-<entry>On simpler IR's, without separate channel keys, you need to map UP as <constant>KEY_CHANNELUP</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate channel keys, you need to map DOWN as <constant>KEY_CHANNELDOWN</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate volume keys, you need to map LEFT as <constant>KEY_VOLUMEDOWN</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate volume keys, you need to map RIGHT as <constant>KEY_VOLUMEUP</constant></entry>
-</row>
-</tbody>
-</tgroup>
-</table>
-
-</section>
-
-<section id="Remote_controllers_table_change">
-<title>Changing default Remote Controller mappings</title>
-<para>The event interface provides two ioctls to be used against
-the /dev/input/event device, to allow changing the default
-keymapping.</para>
-
-<para>This program demonstrates how to replace the keymap tables.</para>
-&sub-keytable-c;
-</section>
-
-&sub-lirc_device_interface;
-</chapter>
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
deleted file mode 100644 (file)
index b764cba..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-<section id="selection-api">
-
-  <title>API for cropping, composing and scaling</title>
-
-  <section>
-    <title>Introduction</title>
-
-<para>Some video capture devices can sample a subsection of a picture and
-shrink or enlarge it to an image of arbitrary size. Next, the devices can
-insert the image into larger one. Some video output devices can crop part of an
-input image, scale it up or down and insert it at an arbitrary scan line and
-horizontal offset into a video signal. We call these abilities cropping,
-scaling and composing.</para>
-
-<para>On a video <emphasis>capture</emphasis> device the source is a video
-signal, and the cropping target determine the area actually sampled. The sink
-is an image stored in a memory buffer.  The composing area specifies which part
-of the buffer is actually written to by the hardware. </para>
-
-<para>On a video <emphasis>output</emphasis> device the source is an image in a
-memory buffer, and the cropping target is a part of an image to be shown on a
-display. The sink is the display or the graphics screen. The application may
-select the part of display where the image should be displayed. The size and
-position of such a window is controlled by the compose target.</para>
-
-<para>Rectangles for all cropping and composing targets are defined even if the
-device does supports neither cropping nor composing. Their size and position
-will be fixed in such a case. If the device does not support scaling then the
-cropping and composing rectangles have the same size.</para>
-
-  </section>
-
-    <section>
-      <title>Selection targets</title>
-
-      <para>
-      <figure id="sel-targets-capture">
-       <title>Cropping and composing targets</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="selection.png" format="PNG" />
-         </imageobject>
-         <textobject>
-           <phrase>Targets used by a cropping, composing and scaling
-            process</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-      </para>
-
-      <para>See <xref linkend="v4l2-selection-targets" /> for more
-    information.</para>
-    </section>
-
-  <section>
-
-  <title>Configuration</title>
-
-<para>Applications can use the <link linkend="vidioc-g-selection">selection
-API</link> to select an area in a video signal or a buffer, and to query for
-default settings and hardware limits.</para>
-
-<para>Video hardware can have various cropping, composing and scaling
-limitations. It may only scale up or down, support only discrete scaling
-factors, or have different scaling abilities in the horizontal and vertical
-directions. Also it may not support scaling at all. At the same time the
-cropping/composing rectangles may have to be aligned, and both the source and
-the sink may have arbitrary upper and lower size limits. Therefore, as usual,
-drivers are expected to adjust the requested parameters and return the actual
-values selected. An application can control the rounding behaviour using <link
-linkend="v4l2-selection-flags"> constraint flags </link>.</para>
-
-   <section>
-
-   <title>Configuration of video capture</title>
-
-<para>See figure <xref linkend="sel-targets-capture" /> for examples of the
-selection targets available for a video capture device.  It is recommended to
-configure the cropping targets before to the composing targets.</para>
-
-<para>The range of coordinates of the top left corner, width and height of
-areas that can be sampled is given by the <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>
-target. It is recommended for the driver developers to put the
-top/left corner at position <constant>(0,0)</constant>.  The rectangle's
-coordinates are expressed in pixels.</para>
-
-<para>The top left corner, width and height of the source rectangle, that is
-the area actually sampled, is given by the <constant>V4L2_SEL_TGT_CROP</constant>
-target. It uses the same coordinate system as <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>.
-The active cropping area must lie completely inside the capture boundaries. The
-driver may further adjust the requested size and/or position according to hardware
-limitations.</para>
-
-<para>Each capture device has a default source rectangle, given by the
-<constant>V4L2_SEL_TGT_CROP_DEFAULT</constant> target. This rectangle shall
-over what the driver writer considers the complete picture.  Drivers shall set
-the active crop rectangle to the default when the driver is first loaded, but
-not later.</para>
-
-<para>The composing targets refer to a memory buffer. The limits of composing
-coordinates are obtained using <constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant>.
-All coordinates are expressed in pixels. The rectangle's top/left
-corner must be located at position <constant>(0,0)</constant>. The width and
-height are equal to the image size set by <constant>VIDIOC_S_FMT</constant>.
-</para>
-
-<para>The part of a buffer into which the image is inserted by the hardware is
-controlled by the <constant>V4L2_SEL_TGT_COMPOSE</constant> target.
-The rectangle's coordinates are also expressed in the same coordinate system as
-the bounds rectangle. The composing rectangle must lie completely inside bounds
-rectangle. The driver must adjust the composing rectangle to fit to the
-bounding limits. Moreover, the driver can perform other adjustments according
-to hardware limitations. The application can control rounding behaviour using
-<link linkend="v4l2-selection-flags"> constraint flags</link>.</para>
-
-<para>For capture devices the default composing rectangle is queried using
-<constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant>. It is usually equal to the
-bounding rectangle.</para>
-
-<para>The part of a buffer that is modified by the hardware is given by
-<constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant>. It contains all pixels
-defined using <constant>V4L2_SEL_TGT_COMPOSE</constant> plus all
-padding data modified by hardware during insertion process. All pixels outside
-this rectangle <emphasis>must not</emphasis> be changed by the hardware. The
-content of pixels that lie inside the padded area but outside active area is
-undefined. The application can use the padded and active rectangles to detect
-where the rubbish pixels are located and remove them if needed.</para>
-
-   </section>
-
-   <section>
-
-   <title>Configuration of video output</title>
-
-<para>For output devices targets and ioctls are used similarly to the video
-capture case. The <emphasis>composing</emphasis> rectangle refers to the
-insertion of an image into a video signal. The cropping rectangles refer to a
-memory buffer. It is recommended to configure the composing targets before to
-the cropping targets.</para>
-
-<para>The cropping targets refer to the memory buffer that contains an image to
-be inserted into a video signal or graphical screen. The limits of cropping
-coordinates are obtained using <constant>V4L2_SEL_TGT_CROP_BOUNDS</constant>.
-All coordinates are expressed in pixels. The top/left corner is always point
-<constant>(0,0)</constant>.  The width and height is equal to the image size
-specified using <constant>VIDIOC_S_FMT</constant> ioctl.</para>
-
-<para>The top left corner, width and height of the source rectangle, that is
-the area from which image date are processed by the hardware, is given by the
-<constant>V4L2_SEL_TGT_CROP</constant>. Its coordinates are expressed
-in in the same coordinate system as the bounds rectangle. The active cropping
-area must lie completely inside the crop boundaries and the driver may further
-adjust the requested size and/or position according to hardware
-limitations.</para>
-
-<para>For output devices the default cropping rectangle is queried using
-<constant>V4L2_SEL_TGT_CROP_DEFAULT</constant>. It is usually equal to the
-bounding rectangle.</para>
-
-<para>The part of a video signal or graphics display where the image is
-inserted by the hardware is controlled by <constant>V4L2_SEL_TGT_COMPOSE</constant>
-target.  The rectangle's coordinates are expressed in pixels. The composing
-rectangle must lie completely inside the bounds rectangle.  The driver must
-adjust the area to fit to the bounding limits.  Moreover, the driver can
-perform other adjustments according to hardware limitations.</para>
-
-<para>The device has a default composing rectangle, given by the
-<constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant> target. This rectangle shall cover what
-the driver writer considers the complete picture. It is recommended for the
-driver developers to put the top/left corner at position <constant>(0,0)</constant>.
-Drivers shall set the active composing rectangle to the default
-one when the driver is first loaded.</para>
-
-<para>The devices may introduce additional content to video signal other than
-an image from memory buffers.  It includes borders around an image. However,
-such a padded area is driver-dependent feature not covered by this document.
-Driver developers are encouraged to keep padded rectangle equal to active one.
-The padded target is accessed by the <constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant>
-identifier.  It must contain all pixels from the <constant>V4L2_SEL_TGT_COMPOSE</constant>
-target.</para>
-
-   </section>
-
-   <section>
-
-     <title>Scaling control</title>
-
-<para>An application can detect if scaling is performed by comparing the width
-and the height of rectangles obtained using <constant>V4L2_SEL_TGT_CROP</constant>
-and <constant>V4L2_SEL_TGT_COMPOSE</constant> targets. If
-these are not equal then the scaling is applied. The application can compute
-the scaling ratios using these values.</para>
-
-   </section>
-
-  </section>
-
-  <section>
-
-    <title>Comparison with old cropping API</title>
-
-<para>The selection API was introduced to cope with deficiencies of previous
-<link linkend="crop"> API</link>, that was designed to control simple capture
-devices. Later the cropping API was adopted by video output drivers. The ioctls
-are used to select a part of the display were the video signal is inserted. It
-should be considered as an API abuse because the described operation is
-actually the composing.  The selection API makes a clear distinction between
-composing and cropping operations by setting the appropriate targets.  The V4L2
-API lacks any support for composing to and cropping from an image inside a
-memory buffer.  The application could configure a capture device to fill only a
-part of an image by abusing V4L2 API.  Cropping a smaller image from a larger
-one is achieved by setting the field
-&v4l2-pix-format;<structfield>::bytesperline</structfield>.  Introducing an image offsets
-could be done by modifying field &v4l2-buffer;<structfield>::m_userptr</structfield>
-before calling <constant>VIDIOC_QBUF</constant>. Those
-operations should be avoided because they are not portable (endianness), and do
-not work for macroblock and Bayer formats and mmap buffers.  The selection API
-deals with configuration of buffer cropping/composing in a clear, intuitive and
-portable way.  Next, with the selection API the concepts of the padded target
-and constraints flags are introduced.  Finally, &v4l2-crop; and &v4l2-cropcap;
-have no reserved fields. Therefore there is no way to extend their functionality.
-The new &v4l2-selection; provides a lot of place for future
-extensions.  Driver developers are encouraged to implement only selection API.
-The former cropping API would be simulated using the new one.</para>
-
-  </section>
-
-   <section>
-      <title>Examples</title>
-      <example>
-       <title>Resetting the cropping parameters</title>
-
-       <para>(A video capture device is assumed; change
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> for other devices; change target to
-<constant>V4L2_SEL_TGT_COMPOSE_*</constant> family to configure composing
-area)</para>
-
-       <programlisting>
-
-       &v4l2-selection; sel = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-               .target = V4L2_SEL_TGT_CROP_DEFAULT,
-       };
-       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
-       if (ret)
-               exit(-1);
-       sel.target = V4L2_SEL_TGT_CROP;
-       ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
-       if (ret)
-               exit(-1);
-
-        </programlisting>
-      </example>
-
-      <example>
-       <title>Simple downscaling</title>
-       <para>Setting a composing area on output of size of <emphasis> at most
-</emphasis> half of limit placed at a center of a display.</para>
-       <programlisting>
-
-       &v4l2-selection; sel = {
-               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               .target = V4L2_SEL_TGT_COMPOSE_BOUNDS,
-       };
-       struct v4l2_rect r;
-
-       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;sel);
-       if (ret)
-               exit(-1);
-       /* setting smaller compose rectangle */
-       r.width = sel.r.width / 2;
-       r.height = sel.r.height / 2;
-       r.left = sel.r.width / 4;
-       r.top = sel.r.height / 4;
-       sel.r = r;
-       sel.target = V4L2_SEL_TGT_COMPOSE;
-       sel.flags = V4L2_SEL_FLAG_LE;
-       ret = ioctl(fd, &VIDIOC-S-SELECTION;, &amp;sel);
-       if (ret)
-               exit(-1);
-
-        </programlisting>
-      </example>
-
-      <example>
-       <title>Querying for scaling factors</title>
-       <para>A video output device is assumed; change
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> for other devices</para>
-       <programlisting>
-
-       &v4l2-selection; compose = {
-               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               .target = V4L2_SEL_TGT_COMPOSE,
-       };
-       &v4l2-selection; crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               .target = V4L2_SEL_TGT_CROP,
-       };
-       double hscale, vscale;
-
-       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;compose);
-       if (ret)
-               exit(-1);
-       ret = ioctl(fd, &VIDIOC-G-SELECTION;, &amp;crop);
-       if (ret)
-               exit(-1);
-
-       /* computing scaling factors */
-       hscale = (double)compose.r.width / crop.r.width;
-       vscale = (double)compose.r.height / crop.r.height;
-
-       </programlisting>
-      </example>
-
-   </section>
-
-</section>
diff --git a/Documentation/DocBook/media/v4l/selections-common.xml b/Documentation/DocBook/media/v4l/selections-common.xml
deleted file mode 100644 (file)
index d6d56fb..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<section id="v4l2-selections-common">
-
-  <title>Common selection definitions</title>
-
-  <para>While the <link linkend="selection-api">V4L2 selection
-  API</link> and <link linkend="v4l2-subdev-selections">V4L2 subdev
-  selection APIs</link> are very similar, there's one fundamental
-  difference between the two. On sub-device API, the selection
-  rectangle refers to the media bus format, and is bound to a
-  sub-device's pad. On the V4L2 interface the selection rectangles
-  refer to the in-memory pixel format.</para>
-
-  <para>This section defines the common definitions of the
-  selection interfaces on the two APIs.</para>
-
-  <section id="v4l2-selection-targets">
-
-    <title>Selection targets</title>
-
-    <para>The precise meaning of the selection targets may be
-    dependent on which of the two interfaces they are used.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-selection-targets-table">
-    <title>Selection target definitions</title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       &cs-def;
-       <thead>
-         <row rowsep="1">
-           <entry align="left">Target name</entry>
-           <entry align="left">id</entry>
-           <entry align="left">Definition</entry>
-           <entry align="left">Valid for V4L2</entry>
-           <entry align="left">Valid for V4L2 subdev</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SEL_TGT_CROP</constant></entry>
-           <entry>0x0000</entry>
-           <entry>Crop rectangle. Defines the cropped area.</entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry>
-           <entry>0x0001</entry>
-           <entry>Suggested cropping rectangle that covers the "whole picture".</entry>
-           <entry>Yes</entry>
-           <entry>No</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry>
-           <entry>0x0002</entry>
-           <entry>Bounds of the crop rectangle. All valid crop
-           rectangles fit inside the crop bounds rectangle.
-           </entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_NATIVE_SIZE</constant></entry>
-           <entry>0x0003</entry>
-           <entry>The native size of the device, e.g. a sensor's
-           pixel array. <structfield>left</structfield> and
-           <structfield>top</structfield> fields are zero for this
-           target. Setting the native size will generally only make
-           sense for memory to memory devices where the software can
-           create a canvas of a given size in which for example a
-           video frame can be composed. In that case
-           V4L2_SEL_TGT_NATIVE_SIZE can be used to configure the size
-           of that canvas.
-           </entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_COMPOSE</constant></entry>
-           <entry>0x0100</entry>
-           <entry>Compose rectangle. Used to configure scaling
-           and composition.</entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry>
-           <entry>0x0101</entry>
-           <entry>Suggested composition rectangle that covers the "whole picture".</entry>
-           <entry>Yes</entry>
-           <entry>No</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
-           <entry>0x0102</entry>
-           <entry>Bounds of the compose rectangle. All valid compose
-           rectangles fit inside the compose bounds rectangle.</entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
-           <entry>0x0103</entry>
-           <entry>The active area and all padding pixels that are inserted or
-           modified by hardware.</entry>
-           <entry>Yes</entry>
-           <entry>No</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </section>
-
-  <section id="v4l2-selection-flags">
-
-    <title>Selection flags</title>
-
-    <table pgwide="1" frame="none" id="v4l2-selection-flags-table">
-    <title>Selection flag definitions</title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       &cs-def;
-       <thead>
-       <row rowsep="1">
-           <entry align="left">Flag name</entry>
-           <entry align="left">id</entry>
-           <entry align="left">Definition</entry>
-           <entry align="left">Valid for V4L2</entry>
-           <entry align="left">Valid for V4L2 subdev</entry>
-       </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
-           <entry>(1 &lt;&lt; 0)</entry>
-           <entry>Suggest the driver it should choose greater or
-           equal rectangle (in size) than was requested. Albeit the
-           driver may choose a lesser size, it will only do so due to
-           hardware limitations. Without this flag (and
-           <constant>V4L2_SEL_FLAG_LE</constant>) the
-           behaviour is to choose the closest possible
-           rectangle.</entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_FLAG_LE</constant></entry>
-           <entry>(1 &lt;&lt; 1)</entry>
-           <entry>Suggest the driver it
-           should choose lesser or equal rectangle (in size) than was
-           requested. Albeit the driver may choose a greater size, it
-           will only do so due to hardware limitations.</entry>
-           <entry>Yes</entry>
-           <entry>Yes</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SEL_FLAG_KEEP_CONFIG</constant></entry>
-           <entry>(1 &lt;&lt; 2)</entry>
-           <entry>The configuration must not be propagated to any
-           further processing steps. If this flag is not given, the
-           configuration is propagated inside the subdevice to all
-           further processing steps.</entry>
-           <entry>No</entry>
-           <entry>Yes</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </section>
-
-</section>
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
deleted file mode 100644 (file)
index 199c84e..0000000
+++ /dev/null
@@ -1,4040 +0,0 @@
-<section id="v4l2-mbus-format">
-  <title>Media Bus Formats</title>
-
-  <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
-    <title>struct <structname>v4l2_mbus_framefmt</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>width</structfield></entry>
-         <entry>Image width, in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>height</structfield></entry>
-         <entry>Image height, in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>code</structfield></entry>
-         <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>field</structfield></entry>
-         <entry>Field order, from &v4l2-field;. See
-         <xref linkend="field-order" /> for details.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>colorspace</structfield></entry>
-         <entry>Image colorspace, from &v4l2-colorspace;. See
-         <xref linkend="colorspaces" /> for details.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-ycbcr-encoding;</entry>
-         <entry><structfield>ycbcr_enc</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-quantization;</entry>
-         <entry><structfield>quantization</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-xfer-func;</entry>
-         <entry><structfield>xfer_func</structfield></entry>
-         <entry>This information supplements the
-<structfield>colorspace</structfield> and must be set by the driver for
-capture streams and by the application for output streams,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>__u16</entry>
-         <entry><structfield>reserved</structfield>[11]</entry>
-         <entry>Reserved for future extensions. Applications and drivers must
-         set the array to zero.</entry>
-       </row>
-      </tbody>
-    </tgroup>
-  </table>
-
-  <section id="v4l2-mbus-pixelcode">
-    <title>Media Bus Pixel Codes</title>
-
-    <para>The media bus pixel codes describe image formats as flowing over
-    physical busses (both between separate physical components and inside SoC
-    devices). This should not be confused with the V4L2 pixel formats that
-    describe, using four character codes, image formats as stored in memory.
-    </para>
-
-    <para>While there is a relationship between image formats on busses and
-    image formats in memory (a raw Bayer image won't be magically converted to
-    JPEG just by storing it to memory), there is no one-to-one correspondance
-    between them.</para>
-
-    <section>
-      <title>Packed RGB Formats</title>
-
-      <para>Those formats transfer pixel data as red, green and blue components.
-      The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The red, green and blue components order code, as encoded in a
-       pixel sample. Possible values are RGB and BGR.</para></listitem>
-       <listitem><para>The number of bits per component, for each component. The values
-       can be different for all components. Common values are 555 and 565.</para>
-       </listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1 and 2.</para></listitem>
-       <listitem><para>The bus width.</para></listitem>
-       <listitem><para>For formats where the total number of bits per pixel is smaller
-       than the number of bus samples per pixel times the bus width, a padding
-       value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO). A "C" prefix is used for component-wise
-       padding in the most high order bits (CPADHI) or low order bits (CPADLO)
-       of each separate component.</para></listitem>
-       <listitem><para>For formats where the number of bus samples per pixel is larger
-       than 1, an endianness value stating if the pixel is transferred MSB first
-       (BE) or LSB first (LE).</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
-      green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
-      samples per pixel with the most significant bits (padding, red and half of
-      the green value) transferred first will be named
-      <constant>MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE</constant>.
-      </para>
-
-      <para>The following tables list existing packed RGB formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
-       <title>RGB formats</title>
-       <tgroup cols="27">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b31" align="center" />
-         <colspec colnum="5" colname="b20" align="center" />
-         <colspec colnum="6" colname="b29" align="center" />
-         <colspec colnum="7" colname="b28" align="center" />
-         <colspec colnum="8" colname="b27" align="center" />
-         <colspec colnum="9" colname="b26" align="center" />
-         <colspec colnum="10" colname="b25" align="center" />
-         <colspec colnum="11" colname="b24" align="center" />
-         <colspec colnum="12" colname="b23" align="center" />
-         <colspec colnum="13" colname="b22" align="center" />
-         <colspec colnum="14" colname="b21" align="center" />
-         <colspec colnum="15" colname="b20" align="center" />
-         <colspec colnum="16" colname="b19" align="center" />
-         <colspec colnum="17" colname="b18" align="center" />
-         <colspec colnum="18" colname="b17" align="center" />
-         <colspec colnum="19" colname="b16" align="center" />
-         <colspec colnum="20" colname="b15" align="center" />
-         <colspec colnum="21" colname="b14" align="center" />
-         <colspec colnum="22" colname="b13" align="center" />
-         <colspec colnum="23" colname="b12" align="center" />
-         <colspec colnum="24" colname="b11" align="center" />
-         <colspec colnum="25" colname="b10" align="center" />
-         <colspec colnum="26" colname="b09" align="center" />
-         <colspec colnum="27" colname="b08" align="center" />
-         <colspec colnum="28" colname="b07" align="center" />
-         <colspec colnum="29" colname="b06" align="center" />
-         <colspec colnum="30" colname="b05" align="center" />
-         <colspec colnum="31" colname="b04" align="center" />
-         <colspec colnum="32" colname="b03" align="center" />
-         <colspec colnum="33" colname="b02" align="center" />
-         <colspec colnum="34" colname="b01" align="center" />
-         <colspec colnum="35" colname="b00" align="center" />
-         <spanspec namest="b31" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>31</entry>
-             <entry>30</entry>
-             <entry>29</entry>
-             <entry>28</entry>
-             <entry>27</entry>
-             <entry>26</entry>
-             <entry>25</entry>
-             <entry>24</entry>
-             <entry>23</entry>
-             <entry>22</entry>
-             <entry>21</entry>
-             <entry>20</entry>
-             <entry>19</entry>
-             <entry>18</entry>
-             <entry>17</entry>
-             <entry>16</entry>
-             <entry>15</entry>
-             <entry>14</entry>
-             <entry>13</entry>
-             <entry>12</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-RGB444-1X12">
-             <entry>MEDIA_BUS_FMT_RGB444_1X12</entry>
-             <entry>0x1016</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-BE">
-             <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE</entry>
-             <entry>0x1001</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-LE">
-             <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE</entry>
-             <entry>0x1002</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB555-2X8-PADHI-BE">
-             <entry>MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE</entry>
-             <entry>0x1003</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>0</entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB555-2X8-PADHI-LE">
-             <entry>MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE</entry>
-             <entry>0x1004</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>0</entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB565-1X16">
-             <entry>MEDIA_BUS_FMT_RGB565_1X16</entry>
-             <entry>0x1017</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-BGR565-2X8-BE">
-             <entry>MEDIA_BUS_FMT_BGR565_2X8_BE</entry>
-             <entry>0x1005</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-BGR565-2X8-LE">
-             <entry>MEDIA_BUS_FMT_BGR565_2X8_LE</entry>
-             <entry>0x1006</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB565-2X8-BE">
-             <entry>MEDIA_BUS_FMT_RGB565_2X8_BE</entry>
-             <entry>0x1007</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB565-2X8-LE">
-             <entry>MEDIA_BUS_FMT_RGB565_2X8_LE</entry>
-             <entry>0x1008</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB666-1X18">
-             <entry>MEDIA_BUS_FMT_RGB666_1X18</entry>
-             <entry>0x1009</entry>
-             <entry></entry>
-             &dash-ent-14;
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RBG888-1X24">
-             <entry>MEDIA_BUS_FMT_RBG888_1X24</entry>
-             <entry>0x100e</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB666-1X24_CPADHI">
-             <entry>MEDIA_BUS_FMT_RGB666_1X24_CPADHI</entry>
-             <entry>0x1015</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-BGR888-1X24">
-             <entry>MEDIA_BUS_FMT_BGR888_1X24</entry>
-             <entry>0x1013</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-GBR888-1X24">
-             <entry>MEDIA_BUS_FMT_GBR888_1X24</entry>
-             <entry>0x1014</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-1X24">
-             <entry>MEDIA_BUS_FMT_RGB888_1X24</entry>
-             <entry>0x100a</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-2X12-BE">
-             <entry>MEDIA_BUS_FMT_RGB888_2X12_BE</entry>
-             <entry>0x100b</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-2X12-LE">
-             <entry>MEDIA_BUS_FMT_RGB888_2X12_LE</entry>
-             <entry>0x100c</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-ARGB888-1X32">
-             <entry>MEDIA_BUS_FMT_ARGB888_1X32</entry>
-             <entry>0x100d</entry>
-             <entry></entry>
-             <entry>a<subscript>7</subscript></entry>
-             <entry>a<subscript>6</subscript></entry>
-             <entry>a<subscript>5</subscript></entry>
-             <entry>a<subscript>4</subscript></entry>
-             <entry>a<subscript>3</subscript></entry>
-             <entry>a<subscript>2</subscript></entry>
-             <entry>a<subscript>1</subscript></entry>
-             <entry>a<subscript>0</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-1X32-PADHI">
-             <entry>MEDIA_BUS_FMT_RGB888_1X32_PADHI</entry>
-             <entry>0x100f</entry>
-             <entry></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <para>On LVDS buses, usually each sample is transferred serialized in
-      seven time slots per pixel clock, on three (18-bit) or four (24-bit)
-      differential data pairs at the same time. The remaining bits are used for
-      control signals as defined by SPWG/PSWG/VESA or JEIDA standards.
-      The 24-bit RGB format serialized in seven time slots on four lanes using
-      JEIDA defined bit mapping will be named
-      <constant>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</constant>, for example.
-      </para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb-lvds">
-       <title>LVDS RGB formats</title>
-       <tgroup cols="8">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center" />
-         <colspec colname="slot" align="center" />
-         <colspec colname="lane" />
-         <colspec colnum="5" colname="l03" align="center" />
-         <colspec colnum="6" colname="l02" align="center" />
-         <colspec colnum="7" colname="l01" align="center" />
-         <colspec colnum="8" colname="l00" align="center" />
-         <spanspec namest="l03" nameend="l00" spanname="l0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry></entry>
-             <entry spanname="l0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Timeslot</entry>
-             <entry>Lane</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-RGB666-1X7X3-SPWG">
-             <entry>MEDIA_BUS_FMT_RGB666_1X7X3_SPWG</entry>
-             <entry>0x1010</entry>
-             <entry>0</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>d</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>1</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>d</entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>2</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>d</entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>3</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>4</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>5</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>6</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-1X7X4-SPWG">
-             <entry>MEDIA_BUS_FMT_RGB888_1X7X4_SPWG</entry>
-             <entry>0x1011</entry>
-             <entry>0</entry>
-             <entry></entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>1</entry>
-             <entry></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>d</entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>2</entry>
-             <entry></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>d</entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>3</entry>
-             <entry></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>4</entry>
-             <entry></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>5</entry>
-             <entry></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>6</entry>
-             <entry></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-RGB888-1X7X4-JEIDA">
-             <entry>MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA</entry>
-             <entry>0x1012</entry>
-             <entry>0</entry>
-             <entry></entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>1</entry>
-             <entry></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>d</entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>2</entry>
-             <entry></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>d</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>3</entry>
-             <entry></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>4</entry>
-             <entry></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>5</entry>
-             <entry></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>6</entry>
-             <entry></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>Bayer Formats</title>
-
-      <para>Those formats transfer pixel data as red, green and blue components.
-      The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The red, green and blue components order code, as encoded in a
-       pixel sample. The possible values are shown in <xref
-       linkend="bayer-patterns" />.</para></listitem>
-       <listitem><para>The number of bits per pixel component. All components are
-       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
-       </listitem>
-       <listitem><para>The compression (optional). If the pixel components are
-       ALAW- or DPCM-compressed, a mention of the compression scheme and the
-       number of bits per compressed pixel component.</para></listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1 and 2.</para></listitem>
-       <listitem><para>The bus width.</para></listitem>
-       <listitem><para>For formats where the total number of bits per pixel is smaller
-       than the number of bus samples per pixel times the bus width, a padding
-       value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO).</para></listitem>
-       <listitem><para>For formats where the number of bus samples per pixel is larger
-       than 1, an endianness value stating if the pixel is transferred MSB first
-       (BE) or LSB first (LE).</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format with uncompressed 10-bit Bayer components
-      arranged in a red, green, green, blue pattern transferred as 2 8-bit
-      samples per pixel with the least significant bits transferred first will
-      be named <constant>MEDIA_BUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
-      </para>
-
-      <figure id="bayer-patterns">
-       <title>Bayer Patterns</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="bayer.png" format="PNG" />
-         </imageobject>
-         <textobject>
-           <phrase>Bayer filter color patterns</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <para>The following table lists existing packed Bayer formats. The data
-      organization is given as an example for the first pixel only.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
-       <title>Bayer Formats</title>
-       <tgroup cols="15">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b11" align="center" />
-         <colspec colnum="5" colname="b10" align="center" />
-         <colspec colnum="6" colname="b09" align="center" />
-         <colspec colnum="7" colname="b08" align="center" />
-         <colspec colnum="8" colname="b07" align="center" />
-         <colspec colnum="9" colname="b06" align="center" />
-         <colspec colnum="10" colname="b05" align="center" />
-         <colspec colnum="11" colname="b04" align="center" />
-         <colspec colnum="12" colname="b03" align="center" />
-         <colspec colnum="13" colname="b02" align="center" />
-         <colspec colnum="14" colname="b01" align="center" />
-         <colspec colnum="15" colname="b00" align="center" />
-         <spanspec namest="b11" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-SBGGR8-1X8">
-             <entry>MEDIA_BUS_FMT_SBGGR8_1X8</entry>
-             <entry>0x3001</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGBRG8-1X8">
-             <entry>MEDIA_BUS_FMT_SGBRG8_1X8</entry>
-             <entry>0x3013</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGRBG8-1X8">
-             <entry>MEDIA_BUS_FMT_SGRBG8_1X8</entry>
-             <entry>0x3002</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SRGGB8-1X8">
-             <entry>MEDIA_BUS_FMT_SRGGB8_1X8</entry>
-             <entry>0x3014</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-ALAW8-1X8">
-             <entry>MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8</entry>
-             <entry>0x3015</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGBRG10-ALAW8-1X8">
-             <entry>MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8</entry>
-             <entry>0x3016</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGRBG10-ALAW8-1X8">
-             <entry>MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8</entry>
-             <entry>0x3017</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SRGGB10-ALAW8-1X8">
-             <entry>MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8</entry>
-             <entry>0x3018</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-DPCM8-1X8">
-             <entry>MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8</entry>
-             <entry>0x300b</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGBRG10-DPCM8-1X8">
-             <entry>MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8</entry>
-             <entry>0x300c</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGRBG10-DPCM8-1X8">
-             <entry>MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8</entry>
-             <entry>0x3009</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SRGGB10-DPCM8-1X8">
-             <entry>MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8</entry>
-             <entry>0x300d</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADHI-BE">
-             <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
-             <entry>0x3003</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADHI-LE">
-             <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
-             <entry>0x3004</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADLO-BE">
-             <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
-             <entry>0x3005</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADLO-LE">
-             <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
-             <entry>0x3006</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR10-1X10">
-             <entry>MEDIA_BUS_FMT_SBGGR10_1X10</entry>
-             <entry>0x3007</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGBRG10-1X10">
-             <entry>MEDIA_BUS_FMT_SGBRG10_1X10</entry>
-             <entry>0x300e</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGRBG10-1X10">
-             <entry>MEDIA_BUS_FMT_SGRBG10_1X10</entry>
-             <entry>0x300a</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SRGGB10-1X10">
-             <entry>MEDIA_BUS_FMT_SRGGB10_1X10</entry>
-             <entry>0x300f</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>9</subscript></entry>
-             <entry>r<subscript>8</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SBGGR12-1X12">
-             <entry>MEDIA_BUS_FMT_SBGGR12_1X12</entry>
-             <entry>0x3008</entry>
-             <entry></entry>
-             <entry>b<subscript>11</subscript></entry>
-             <entry>b<subscript>10</subscript></entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGBRG12-1X12">
-             <entry>MEDIA_BUS_FMT_SGBRG12_1X12</entry>
-             <entry>0x3010</entry>
-             <entry></entry>
-             <entry>g<subscript>11</subscript></entry>
-             <entry>g<subscript>10</subscript></entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SGRBG12-1X12">
-             <entry>MEDIA_BUS_FMT_SGRBG12_1X12</entry>
-             <entry>0x3011</entry>
-             <entry></entry>
-             <entry>g<subscript>11</subscript></entry>
-             <entry>g<subscript>10</subscript></entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-SRGGB12-1X12">
-             <entry>MEDIA_BUS_FMT_SRGGB12_1X12</entry>
-             <entry>0x3012</entry>
-             <entry></entry>
-             <entry>r<subscript>11</subscript></entry>
-             <entry>r<subscript>10</subscript></entry>
-             <entry>r<subscript>9</subscript></entry>
-             <entry>r<subscript>8</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>Packed YUV Formats</title>
-
-      <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
-      and V components. Some formats include dummy bits in some of their samples
-      and are collectively referred to as "YDYC" (Y-Dummy-Y-Chroma) formats.
-      One cannot rely on the values of these dummy bits as those are undefined.
-      </para>
-      <para>The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The Y, U and V components order code, as transferred on the
-       bus. Possible values are YUYV, UYVY, YVYU and VYUY for formats with no
-       dummy bit, and YDYUYDYV, YDYVYDYU, YUYDYVYD and YVYDYUYD for YDYC formats.
-       </para></listitem>
-       <listitem><para>The number of bits per pixel component. All components are
-       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
-       </listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1, 1.5 (encoded as 1_5) and 2.</para></listitem>
-       <listitem><para>The bus width. When the bus width is larger than the number of
-       bits per pixel component, several components are packed in a single bus
-       sample. The components are ordered as specified by the order code, with
-       components on the left of the code transferred in the high order bits.
-       Common values are 8 and 16.</para>
-       </listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format where pixels are encoded as 8-bit YUV values
-      downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
-      U, Y, V, Y order will be named <constant>MEDIA_BUS_FMT_UYVY8_2X8</constant>.
-      </para>
-
-       <para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> lists existing packed YUV
-       formats and describes the organization of each pixel data in each sample.
-       When a format pattern is split across multiple samples each of the samples
-       in the pattern is described.</para>
-
-       <para>The role of each bit transferred over the bus is identified by one
-       of the following codes.</para>
-
-       <itemizedlist>
-          <listitem><para>y<subscript>x</subscript> for luma component bit number x</para></listitem>
-          <listitem><para>u<subscript>x</subscript> for blue chroma component bit number x</para></listitem>
-          <listitem><para>v<subscript>x</subscript> for red chroma component bit number x</para></listitem>
-          <listitem><para>a<subscript>x</subscript> for alpha component bit number x</para></listitem>
-          <listitem><para>- for non-available bits (for positions higher than the bus width)</para></listitem>
-          <listitem><para>d for dummy bits</para></listitem>
-       </itemizedlist>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
-       <title>YUV Formats</title>
-       <tgroup cols="23">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b31" align="center" />
-         <colspec colnum="5" colname="b20" align="center" />
-         <colspec colnum="6" colname="b29" align="center" />
-         <colspec colnum="7" colname="b28" align="center" />
-         <colspec colnum="8" colname="b27" align="center" />
-         <colspec colnum="9" colname="b26" align="center" />
-         <colspec colnum="10" colname="b25" align="center" />
-         <colspec colnum="11" colname="b24" align="center" />
-         <colspec colnum="12" colname="b23" align="center" />
-         <colspec colnum="13" colname="b22" align="center" />
-         <colspec colnum="14" colname="b21" align="center" />
-         <colspec colnum="15" colname="b20" align="center" />
-         <colspec colnum="16" colname="b19" align="center" />
-         <colspec colnum="17" colname="b18" align="center" />
-         <colspec colnum="18" colname="b17" align="center" />
-         <colspec colnum="19" colname="b16" align="center" />
-         <colspec colnum="20" colname="b15" align="center" />
-         <colspec colnum="21" colname="b14" align="center" />
-         <colspec colnum="22" colname="b13" align="center" />
-         <colspec colnum="23" colname="b12" align="center" />
-         <colspec colnum="24" colname="b11" align="center" />
-         <colspec colnum="25" colname="b10" align="center" />
-         <colspec colnum="26" colname="b09" align="center" />
-         <colspec colnum="27" colname="b08" align="center" />
-         <colspec colnum="28" colname="b07" align="center" />
-         <colspec colnum="29" colname="b06" align="center" />
-         <colspec colnum="30" colname="b05" align="center" />
-         <colspec colnum="31" colname="b04" align="center" />
-         <colspec colnum="32" colname="b03" align="center" />
-         <colspec colnum="33" colname="b02" align="center" />
-         <colspec colnum="34" colname="b01" align="center" />
-         <colspec colnum="35" colname="b00" align="center" />
-         <spanspec namest="b31" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>31</entry>
-             <entry>30</entry>
-             <entry>29</entry>
-             <entry>28</entry>
-             <entry>27</entry>
-             <entry>26</entry>
-             <entry>25</entry>
-             <entry>24</entry>
-             <entry>23</entry>
-             <entry>22</entry>
-             <entry>21</entry>
-             <entry>10</entry>
-             <entry>19</entry>
-             <entry>18</entry>
-             <entry>17</entry>
-             <entry>16</entry>
-             <entry>15</entry>
-             <entry>14</entry>
-             <entry>13</entry>
-             <entry>12</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-Y8-1X8">
-             <entry>MEDIA_BUS_FMT_Y8_1X8</entry>
-             <entry>0x2001</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UV8-1X8">
-             <entry>MEDIA_BUS_FMT_UV8_1X8</entry>
-             <entry>0x2015</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY8-1_5X8">
-             <entry>MEDIA_BUS_FMT_UYVY8_1_5X8</entry>
-             <entry>0x2002</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY8-1_5X8">
-             <entry>MEDIA_BUS_FMT_VYUY8_1_5X8</entry>
-             <entry>0x2003</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV8-1_5X8">
-             <entry>MEDIA_BUS_FMT_YUYV8_1_5X8</entry>
-             <entry>0x2004</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU8-1_5X8">
-             <entry>MEDIA_BUS_FMT_YVYU8_1_5X8</entry>
-             <entry>0x2005</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY8-2X8">
-             <entry>MEDIA_BUS_FMT_UYVY8_2X8</entry>
-             <entry>0x2006</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY8-2X8">
-             <entry>MEDIA_BUS_FMT_VYUY8_2X8</entry>
-             <entry>0x2007</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV8-2X8">
-             <entry>MEDIA_BUS_FMT_YUYV8_2X8</entry>
-             <entry>0x2008</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU8-2X8">
-             <entry>MEDIA_BUS_FMT_YVYU8_2X8</entry>
-             <entry>0x2009</entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-24;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-Y10-1X10">
-             <entry>MEDIA_BUS_FMT_Y10_1X10</entry>
-             <entry>0x200a</entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY10-2X10">
-             <entry>MEDIA_BUS_FMT_UYVY10_2X10</entry>
-             <entry>0x2018</entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY10-2X10">
-             <entry>MEDIA_BUS_FMT_VYUY10_2X10</entry>
-             <entry>0x2019</entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV10-2X10">
-             <entry>MEDIA_BUS_FMT_YUYV10_2X10</entry>
-             <entry>0x200b</entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU10-2X10">
-             <entry>MEDIA_BUS_FMT_YVYU10_2X10</entry>
-             <entry>0x200c</entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-22;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-Y12-1X12">
-             <entry>MEDIA_BUS_FMT_Y12_1X12</entry>
-             <entry>0x2013</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY12-2X12">
-             <entry>MEDIA_BUS_FMT_UYVY12_2X12</entry>
-             <entry>0x201c</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY12-2X12">
-             <entry>MEDIA_BUS_FMT_VYUY12_2X12</entry>
-             <entry>0x201d</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV12-2X12">
-             <entry>MEDIA_BUS_FMT_YUYV12_2X12</entry>
-             <entry>0x201e</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU12-2X12">
-             <entry>MEDIA_BUS_FMT_YVYU12_2X12</entry>
-             <entry>0x201f</entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-20;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY8-1X16">
-             <entry>MEDIA_BUS_FMT_UYVY8_1X16</entry>
-             <entry>0x200f</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY8-1X16">
-             <entry>MEDIA_BUS_FMT_VYUY8_1X16</entry>
-             <entry>0x2010</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV8-1X16">
-             <entry>MEDIA_BUS_FMT_YUYV8_1X16</entry>
-             <entry>0x2011</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU8-1X16">
-             <entry>MEDIA_BUS_FMT_YVYU8_1X16</entry>
-             <entry>0x2012</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YDYUYDYV8-1X16">
-             <entry>MEDIA_BUS_FMT_YDYUYDYV8_1X16</entry>
-             <entry>0x2014</entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-             <entry>d</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-16;
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY10-1X20">
-             <entry>MEDIA_BUS_FMT_UYVY10_1X20</entry>
-             <entry>0x201a</entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY10-1X20">
-             <entry>MEDIA_BUS_FMT_VYUY10_1X20</entry>
-             <entry>0x201b</entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV10-1X20">
-             <entry>MEDIA_BUS_FMT_YUYV10_1X20</entry>
-             <entry>0x200d</entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU10-1X20">
-             <entry>MEDIA_BUS_FMT_YVYU10_1X20</entry>
-             <entry>0x200e</entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-12;
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VUY8-1X24">
-             <entry>MEDIA_BUS_FMT_VUY8_1X24</entry>
-             <entry>0x201a</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUV8-1X24">
-             <entry>MEDIA_BUS_FMT_YUV8_1X24</entry>
-             <entry>0x2025</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-UYVY12-1X24">
-             <entry>MEDIA_BUS_FMT_UYVY12_1X24</entry>
-             <entry>0x2020</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-VYUY12-1X24">
-             <entry>MEDIA_BUS_FMT_VYUY12_1X24</entry>
-             <entry>0x2021</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUYV12-1X24">
-             <entry>MEDIA_BUS_FMT_YUYV12_1X24</entry>
-             <entry>0x2022</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YVYU12-1X24">
-             <entry>MEDIA_BUS_FMT_YVYU12_1X24</entry>
-             <entry>0x2023</entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>11</subscript></entry>
-             <entry>v<subscript>10</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             &dash-ent-8;
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>11</subscript></entry>
-             <entry>u<subscript>10</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-YUV10-1X30">
-             <entry>MEDIA_BUS_FMT_YUV10_1X30</entry>
-             <entry>0x2016</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="MEDIA-BUS-FMT-AYUV8-1X32">
-             <entry>MEDIA_BUS_FMT_AYUV8_1X32</entry>
-             <entry>0x2017</entry>
-             <entry></entry>
-             <entry>a<subscript>7</subscript></entry>
-             <entry>a<subscript>6</subscript></entry>
-             <entry>a<subscript>5</subscript></entry>
-             <entry>a<subscript>4</subscript></entry>
-             <entry>a<subscript>3</subscript></entry>
-             <entry>a<subscript>2</subscript></entry>
-             <entry>a<subscript>1</subscript></entry>
-             <entry>a<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>HSV/HSL Formats</title>
-
-      <para>Those formats transfer pixel data as RGB values in a cylindrical-coordinate
-      system using Hue-Saturation-Value or Hue-Saturation-Lightness components. The
-      format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The hue, saturation, value or lightness and optional alpha
-       components order code, as encoded in a pixel sample. The only currently
-       supported value is AHSV.
-       </para></listitem>
-       <listitem><para>The number of bits per component, for each component. The values
-       can be different for all components. The only currently supported value is 8888.
-       </para></listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. The only currently
-       supported value is 1.</para></listitem>
-       <listitem><para>The bus width.</para></listitem>
-       <listitem><para>For formats where the total number of bits per pixel is smaller
-       than the number of bus samples per pixel times the bus width, a padding
-       value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO).</para></listitem>
-       <listitem><para>For formats where the number of bus samples per pixel is larger
-       than 1, an endianness value stating if the pixel is transferred MSB first
-       (BE) or LSB first (LE).</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>The following table lists existing HSV/HSL formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-hsv">
-       <title>HSV/HSL formats</title>
-       <tgroup cols="27">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b31" align="center" />
-         <colspec colnum="5" colname="b20" align="center" />
-         <colspec colnum="6" colname="b29" align="center" />
-         <colspec colnum="7" colname="b28" align="center" />
-         <colspec colnum="8" colname="b27" align="center" />
-         <colspec colnum="9" colname="b26" align="center" />
-         <colspec colnum="10" colname="b25" align="center" />
-         <colspec colnum="11" colname="b24" align="center" />
-         <colspec colnum="12" colname="b23" align="center" />
-         <colspec colnum="13" colname="b22" align="center" />
-         <colspec colnum="14" colname="b21" align="center" />
-         <colspec colnum="15" colname="b20" align="center" />
-         <colspec colnum="16" colname="b19" align="center" />
-         <colspec colnum="17" colname="b18" align="center" />
-         <colspec colnum="18" colname="b17" align="center" />
-         <colspec colnum="19" colname="b16" align="center" />
-         <colspec colnum="20" colname="b15" align="center" />
-         <colspec colnum="21" colname="b14" align="center" />
-         <colspec colnum="22" colname="b13" align="center" />
-         <colspec colnum="23" colname="b12" align="center" />
-         <colspec colnum="24" colname="b11" align="center" />
-         <colspec colnum="25" colname="b10" align="center" />
-         <colspec colnum="26" colname="b09" align="center" />
-         <colspec colnum="27" colname="b08" align="center" />
-         <colspec colnum="28" colname="b07" align="center" />
-         <colspec colnum="29" colname="b06" align="center" />
-         <colspec colnum="30" colname="b05" align="center" />
-         <colspec colnum="31" colname="b04" align="center" />
-         <colspec colnum="32" colname="b03" align="center" />
-         <colspec colnum="33" colname="b02" align="center" />
-         <colspec colnum="34" colname="b01" align="center" />
-         <colspec colnum="35" colname="b00" align="center" />
-         <spanspec namest="b31" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>31</entry>
-             <entry>30</entry>
-             <entry>29</entry>
-             <entry>28</entry>
-             <entry>27</entry>
-             <entry>26</entry>
-             <entry>25</entry>
-             <entry>24</entry>
-             <entry>23</entry>
-             <entry>22</entry>
-             <entry>21</entry>
-             <entry>20</entry>
-             <entry>19</entry>
-             <entry>18</entry>
-             <entry>17</entry>
-             <entry>16</entry>
-             <entry>15</entry>
-             <entry>14</entry>
-             <entry>13</entry>
-             <entry>12</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-AHSV8888-1X32">
-             <entry>MEDIA_BUS_FMT_AHSV8888_1X32</entry>
-             <entry>0x6001</entry>
-             <entry></entry>
-             <entry>a<subscript>7</subscript></entry>
-             <entry>a<subscript>6</subscript></entry>
-             <entry>a<subscript>5</subscript></entry>
-             <entry>a<subscript>4</subscript></entry>
-             <entry>a<subscript>3</subscript></entry>
-             <entry>a<subscript>2</subscript></entry>
-             <entry>a<subscript>1</subscript></entry>
-             <entry>a<subscript>0</subscript></entry>
-             <entry>h<subscript>7</subscript></entry>
-             <entry>h<subscript>6</subscript></entry>
-             <entry>h<subscript>5</subscript></entry>
-             <entry>h<subscript>4</subscript></entry>
-             <entry>h<subscript>3</subscript></entry>
-             <entry>h<subscript>2</subscript></entry>
-             <entry>h<subscript>1</subscript></entry>
-             <entry>h<subscript>0</subscript></entry>
-             <entry>s<subscript>7</subscript></entry>
-             <entry>s<subscript>6</subscript></entry>
-             <entry>s<subscript>5</subscript></entry>
-             <entry>s<subscript>4</subscript></entry>
-             <entry>s<subscript>3</subscript></entry>
-             <entry>s<subscript>2</subscript></entry>
-             <entry>s<subscript>1</subscript></entry>
-             <entry>s<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>JPEG Compressed Formats</title>
-
-      <para>Those data formats consist of an ordered sequence of 8-bit bytes
-       obtained from JPEG compression process. Additionally to the
-       <constant>_JPEG</constant> postfix the format code is made of
-       the following information.
-       <itemizedlist>
-         <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
-         <listitem><para>The bus width.</para></listitem>
-       </itemizedlist>
-      </para>
-
-      <para>For instance, for a JPEG baseline process and an 8-bit bus width
-        the format will be named <constant>MEDIA_BUS_FMT_JPEG_1X8</constant>.
-      </para>
-
-      <para>The following table lists existing JPEG compressed formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
-       <title>JPEG Formats</title>
-       <tgroup cols="3">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="left"/>
-         <colspec colname="remarks" align="left"/>
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry>Remarks</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-JPEG-1X8">
-             <entry>MEDIA_BUS_FMT_JPEG_1X8</entry>
-             <entry>0x4001</entry>
-             <entry>Besides of its usage for the parallel bus this format is
-               recommended for transmission of JPEG data over MIPI CSI bus
-               using the User Defined 8-bit Data types.
-             </entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section id="v4l2-mbus-vendor-spec-fmts">
-      <title>Vendor and Device Specific Formats</title>
-
-      <para>This section lists complex data formats that are either vendor or
-       device specific.
-      </para>
-
-      <para>The following table lists the existing vendor and device specific
-       formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-vendor-specific">
-       <title>Vendor and device specific formats</title>
-       <tgroup cols="3">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="left"/>
-         <colspec colname="remarks" align="left"/>
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry>Comments</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="MEDIA-BUS-FMT-S5C-UYVY-JPEG-1X8">
-             <entry>MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8</entry>
-             <entry>0x5001</entry>
-             <entry>
-               Interleaved raw UYVY and JPEG image format with embedded
-               meta-data used by Samsung S3C73MX camera sensors.
-             </entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-  </section>
-</section>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia
deleted file mode 100644 (file)
index e32ba53..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
-  <dia:diagramdata>
-    <dia:attribute name="background">
-      <dia:color val="#ffffff"/>
-    </dia:attribute>
-    <dia:attribute name="pagebreak">
-      <dia:color val="#000099"/>
-    </dia:attribute>
-    <dia:attribute name="paper">
-      <dia:composite type="paper">
-        <dia:attribute name="name">
-          <dia:string>#A4#</dia:string>
-        </dia:attribute>
-        <dia:attribute name="tmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="bmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="lmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="rmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="is_portrait">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-        <dia:attribute name="scaling">
-          <dia:real val="0.49000000953674316"/>
-        </dia:attribute>
-        <dia:attribute name="fitto">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="grid">
-      <dia:composite type="grid">
-        <dia:attribute name="width_x">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="width_y">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_x">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_y">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:composite type="color"/>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="color">
-      <dia:color val="#d8e5e5"/>
-    </dia:attribute>
-    <dia:attribute name="guides">
-      <dia:composite type="guides">
-        <dia:attribute name="hguides"/>
-        <dia:attribute name="vguides"/>
-      </dia:composite>
-    </dia:attribute>
-  </dia:diagramdata>
-  <dia:layer name="Background" visible="true" active="true">
-    <dia:object type="Standard - Box" version="0" id="O0">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-0.4,6.5"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-0.45,6.45;23.1387,16.2"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-0.4,6.5"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="23.48871579904775"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="9.6500000000000004"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O1">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.225,9.45"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.175,9.4;8.225,14.7"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="0.225,9.45"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="7.9499999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="5.1999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a52a2a"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O2">
-      <dia:attribute name="obj_pos">
-        <dia:point val="3.175,10.55"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.125,10.5;7.925,14.45"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="3.175,10.55"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="4.6999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.8499999999999979"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O3">
-      <dia:attribute name="obj_pos">
-        <dia:point val="3.725,11.3875"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.725,10.7925;6.6025,13.14"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink
-crop
-selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="3.725,11.3875"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#0000ff"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O4">
-      <dia:attribute name="obj_pos">
-        <dia:point val="1.475,7.9"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>##</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="1.475,7.9"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O5">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.426918,7.89569"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="0.426918,7.89569"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#a52a2a"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O6">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.4887,7.75"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="17.4887,7.155;21.8112,8.7025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#source media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="17.4887,7.75"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#8b6914"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O7">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.5244,9.5417"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="17.4744,9.4917;22.2387,13.35"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="17.5244,9.5417"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="4.6643157990477508"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.758300000000002"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#8b6914"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O8">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.5244,13.3"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.12132,13.2463;17.5781,14.4537"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="17.5244,13.3"/>
-        <dia:point val="3.175,14.4"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O7" connection="5"/>
-        <dia:connection handle="1" to="O2" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O9">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.5244,9.5417"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.12162,9.48832;17.5778,10.6034"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="17.5244,9.5417"/>
-        <dia:point val="3.175,10.55"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O7" connection="0"/>
-        <dia:connection handle="1" to="O2" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O10">
-      <dia:attribute name="obj_pos">
-        <dia:point val="22.1887,13.3"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.82132,13.2463;22.2424,14.4537"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="22.1887,13.3"/>
-        <dia:point val="7.875,14.4"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O7" connection="7"/>
-        <dia:connection handle="1" to="O2" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O11">
-      <dia:attribute name="obj_pos">
-        <dia:point val="22.1887,9.5417"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.82161,9.48831;22.2421,10.6034"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="22.1887,9.5417"/>
-        <dia:point val="7.875,10.55"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O7" connection="2"/>
-        <dia:connection handle="1" to="O2" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O12">
-      <dia:attribute name="obj_pos">
-        <dia:point val="23.23,10.5742"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="23.18,10.5242;24.13,11.4742"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="23.23,10.5742"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O13">
-      <dia:attribute name="obj_pos">
-        <dia:point val="24.08,10.9992"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.03,10.6388;32.4953,11.3624"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="24.08,10.9992"/>
-        <dia:point val="32.3835,11.0007"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O12" connection="3"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O14">
-      <dia:attribute name="obj_pos">
-        <dia:point val="25.3454,10.49"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.3454,9.895;29.9904,10.6425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 1 (source)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="25.3454,10.49"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O15">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-1.44491,11.6506"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-1.44491,11.6506"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O16">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-9.61991,12.09"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="-9.61991,12.09"/>
-        <dia:point val="-1.44491,12.0756"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O15" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O17">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-7.39291,11.49"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 0 (sink)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="-7.39291,11.49"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-  </dia:layer>
-</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg
deleted file mode 100644 (file)
index 18b0f5d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
-<svg width="43cm" height="10cm" viewBox="-194 128 844 196" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="469.774" height="193"/>
-  <g>
-    <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
-  </g>
-  <g>
-    <rect style="fill: #ffffff" x="63.5" y="211" width="94" height="77"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="63.5" y="211" width="94" height="77"/>
-  </g>
-  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="74.5" y="227.75">
-    <tspan x="74.5" y="227.75">sink</tspan>
-    <tspan x="74.5" y="243.75">crop</tspan>
-    <tspan x="74.5" y="259.75">selection</tspan>
-  </text>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
-    <tspan x="29.5" y="158"></tspan>
-  </text>
-  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
-    <tspan x="8.53836" y="157.914">sink media</tspan>
-    <tspan x="8.53836" y="173.914">bus format</tspan>
-  </text>
-  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="349.774" y="155">
-    <tspan x="349.774" y="155">source media</tspan>
-    <tspan x="349.774" y="171">bus format</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="350.488" y="190.834" width="93.2863" height="75.166"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="350.488" y="190.834" width="93.2863" height="75.166"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="266" x2="63.5" y2="288"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="190.834" x2="63.5" y2="211"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="266" x2="157.5" y2="288"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="190.834" x2="157.5" y2="211"/>
-  <g>
-    <ellipse style="fill: #ffffff" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="481.6" y1="219.984" x2="637.934" y2="220.012"/>
-    <polygon style="fill: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="506.908" y="209.8">
-    <tspan x="506.908" y="209.8">pad 1 (source)</tspan>
-  </text>
-  <g>
-    <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
-    <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
-    <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
-  </text>
-</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia
deleted file mode 100644 (file)
index a0d7829..0000000
+++ /dev/null
@@ -1,1588 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
-  <dia:diagramdata>
-    <dia:attribute name="background">
-      <dia:color val="#ffffff"/>
-    </dia:attribute>
-    <dia:attribute name="pagebreak">
-      <dia:color val="#000099"/>
-    </dia:attribute>
-    <dia:attribute name="paper">
-      <dia:composite type="paper">
-        <dia:attribute name="name">
-          <dia:string>#A4#</dia:string>
-        </dia:attribute>
-        <dia:attribute name="tmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="bmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="lmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="rmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="is_portrait">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-        <dia:attribute name="scaling">
-          <dia:real val="0.49000000953674316"/>
-        </dia:attribute>
-        <dia:attribute name="fitto">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="grid">
-      <dia:composite type="grid">
-        <dia:attribute name="width_x">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="width_y">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_x">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_y">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:composite type="color"/>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="color">
-      <dia:color val="#d8e5e5"/>
-    </dia:attribute>
-    <dia:attribute name="guides">
-      <dia:composite type="guides">
-        <dia:attribute name="hguides"/>
-        <dia:attribute name="vguides"/>
-      </dia:composite>
-    </dia:attribute>
-  </dia:diagramdata>
-  <dia:layer name="Background" visible="true" active="true">
-    <dia:object type="Standard - Box" version="0" id="O0">
-      <dia:attribute name="obj_pos">
-        <dia:point val="15.945,6.45"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="15.895,6.4;26.4,18.95"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="15.945,6.45"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="10.404999999254942"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="12.449999999999992"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#ff765a"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O1">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-0.1,3.65"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-0.15,3.6;40.25,20.85"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-0.1,3.65"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="40.300000000000004"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="17.149999999999999"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O2">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-1.05,7.9106"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-1.1,7.8606;-0.15,8.8106"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-1.05,7.9106"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O3">
-      <dia:attribute name="obj_pos">
-        <dia:point val="40.3366,9.8342"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="40.2866,9.7842;41.2366,10.7342"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="40.3366,9.8342"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O4">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-9.225,8.35"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-9.27509,7.97487;-0.938197,8.69848"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="-9.225,8.35"/>
-        <dia:point val="-1.05,8.3356"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O2" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O5">
-      <dia:attribute name="obj_pos">
-        <dia:point val="41.1866,10.2592"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="41.1366,9.89879;49.6019,10.6224"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="41.1866,10.2592"/>
-        <dia:point val="49.4901,10.2607"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O3" connection="3"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O6">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-6.998,7.75"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-6.998,7.155;-3.193,7.9025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 0 (sink)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="-6.998,7.75"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O7">
-      <dia:attribute name="obj_pos">
-        <dia:point val="42.452,9.75"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="42.452,9.155;47.097,9.9025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 2 (source)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="42.452,9.75"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O8">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.275,6"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.225,5.95;8.275,11.25"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="0.275,6"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="7.9499999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="5.1999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a52a2a"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O9">
-      <dia:attribute name="obj_pos">
-        <dia:point val="3.125,6.8"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.075,6.75;7.875,10.7"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="3.125,6.8"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="4.6999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.8499999999999979"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O10">
-      <dia:attribute name="obj_pos">
-        <dia:point val="1.525,4.45"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="1.525,3.855;1.525,4.6025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>##</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="1.525,4.45"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O11">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.476918,4.44569"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.476918,3.85069;3.95942,5.39819"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="0.476918,4.44569"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#a52a2a"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O12">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="8.2600228398861297"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="8.6238900617957164"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#00ff00"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O13">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,17.9064"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.05732,10.5823;16.7499,17.9741"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="16.6822,17.9064"/>
-        <dia:point val="3.125,10.65"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O12" connection="5"/>
-        <dia:connection handle="1" to="O9" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O14">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3.06681,6.74181;16.7404,9.3407"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="16.6822,9.28251"/>
-        <dia:point val="3.125,6.8"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O12" connection="0"/>
-        <dia:connection handle="1" to="O9" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O15">
-      <dia:attribute name="obj_pos">
-        <dia:point val="24.9422,17.9064"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.75945,10.5845;25.0077,17.9719"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="24.9422,17.9064"/>
-        <dia:point val="7.825,10.65"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O12" connection="7"/>
-        <dia:connection handle="1" to="O9" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O16">
-      <dia:attribute name="obj_pos">
-        <dia:point val="24.9422,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.76834,6.74334;24.9989,9.33917"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="24.9422,9.28251"/>
-        <dia:point val="7.825,6.8"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O12" connection="2"/>
-        <dia:connection handle="1" to="O9" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O17">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.7352,7.47209"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink compose
-selection (scaling)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="16.7352,7.47209"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#00ff00"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O18">
-      <dia:attribute name="obj_pos">
-        <dia:point val="20.4661,9.72825"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="20.4161,9.67825;25.5254,13.3509"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="20.4661,9.72825"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O19">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.475,5.2564"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.475,4.6614;38.7975,6.2089"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#source media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="34.475,5.2564"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#8b6914"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O20">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4244,8.6917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.3744,8.6417;39.4837,12.3143"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="34.4244,8.6917"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#8b6914"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O21">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4244,12.2643"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="20.4125,12.2107;34.478,13.3545"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.4244,12.2643"/>
-        <dia:point val="20.4661,13.3009"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O20" connection="5"/>
-        <dia:connection handle="1" to="O18" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O22">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4244,8.6917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="20.4125,8.63813;34.478,9.78182"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.4244,8.6917"/>
-        <dia:point val="20.4661,9.72825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O20" connection="0"/>
-        <dia:connection handle="1" to="O18" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O23">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.4337,12.2643"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.4218,12.2107;39.4873,13.3545"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.4337,12.2643"/>
-        <dia:point val="25.4754,13.3009"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O20" connection="7"/>
-        <dia:connection handle="1" to="O18" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O24">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.4337,8.6917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.4218,8.63813;39.4873,9.78182"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.4337,8.6917"/>
-        <dia:point val="25.4754,9.72825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O20" connection="2"/>
-        <dia:connection handle="1" to="O18" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O25">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.25,5.15"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="16.25,4.555;21.68,6.1025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink compose
-bounds selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="16.25,5.15"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#ff765a"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O26">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-1.02991,16.6506"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-1.07991,16.6006;-0.12991,17.5506"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-1.02991,16.6506"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O27">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-9.20491,17.09"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-9.255,16.7149;-0.918107,17.4385"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="-9.20491,17.09"/>
-        <dia:point val="-1.02991,17.0756"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O26" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O28">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-6.95,16.45"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-6.95,15.855;-3.145,16.6025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 1 (sink)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="-6.95,16.45"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O29">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.390412,14.64"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.340412,14.59;6.045,18.8"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="0.390412,14.64"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.604587512785236"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="4.1099999999999994"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a52a2a"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O30">
-      <dia:attribute name="obj_pos">
-        <dia:point val="2.645,15.74"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.595,15.69;5.6,18.3"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="2.645,15.74"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="2.904999999254942"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="2.5100000000000016"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O31">
-      <dia:attribute name="obj_pos">
-        <dia:point val="1.595,12.99"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="1.595,12.395;1.595,13.1425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>##</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="1.595,12.99"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O32">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.945,12.595"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.58596,12.536;18.004,15.799"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="17.945,12.595"/>
-        <dia:point val="2.645,15.74"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O36" connection="0"/>
-        <dia:connection handle="1" to="O30" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O33">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.945,15.8"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.58772,15.7427;18.0023,18.3073"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="17.945,15.8"/>
-        <dia:point val="2.645,18.25"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O36" connection="5"/>
-        <dia:connection handle="1" to="O30" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O34">
-      <dia:attribute name="obj_pos">
-        <dia:point val="21.7,15.8"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="5.49307,15.7431;21.7569,18.3069"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="21.7,15.8"/>
-        <dia:point val="5.55,18.25"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O36" connection="7"/>
-        <dia:connection handle="1" to="O30" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O35">
-      <dia:attribute name="obj_pos">
-        <dia:point val="21.7,12.595"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="5.49136,12.5364;21.7586,15.7986"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="21.7,12.595"/>
-        <dia:point val="5.55,15.74"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O36" connection="2"/>
-        <dia:connection handle="1" to="O30" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O36">
-      <dia:attribute name="obj_pos">
-        <dia:point val="17.945,12.595"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="17.895,12.545;21.75,15.85"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="17.945,12.595"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="3.7549999992549452"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.2049999992549427"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#00ff00"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O37">
-      <dia:attribute name="obj_pos">
-        <dia:point val="22.1631,14.2233"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="22.1131,14.1733;25.45,16.7"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="22.1631,14.2233"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="3.2369000000000021"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="2.4267000000000003"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O38">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.6714,16.2367"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.6214,16.1867;37.9,18.75"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="34.6714,16.2367"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="3.178600000000003"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="2.4632999999999967"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#8b6914"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O39">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.6714,18.7"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="22.1057,16.5926;34.7288,18.7574"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.6714,18.7"/>
-        <dia:point val="22.1631,16.65"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O38" connection="5"/>
-        <dia:connection handle="1" to="O37" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O40">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.6714,16.2367"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="22.1058,14.166;34.7287,16.294"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.6714,16.2367"/>
-        <dia:point val="22.1631,14.2233"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O38" connection="0"/>
-        <dia:connection handle="1" to="O37" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O41">
-      <dia:attribute name="obj_pos">
-        <dia:point val="37.85,18.7"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.3425,16.5925;37.9075,18.7575"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="37.85,18.7"/>
-        <dia:point val="25.4,16.65"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O38" connection="7"/>
-        <dia:connection handle="1" to="O37" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O42">
-      <dia:attribute name="obj_pos">
-        <dia:point val="37.85,16.2367"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.3427,14.166;37.9073,16.294"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="37.85,16.2367"/>
-        <dia:point val="25.4,14.2233"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O38" connection="2"/>
-        <dia:connection handle="1" to="O37" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O43">
-      <dia:attribute name="obj_pos">
-        <dia:point val="40.347,16.7742"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="40.297,16.7242;41.247,17.6742"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="40.347,16.7742"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O44">
-      <dia:attribute name="obj_pos">
-        <dia:point val="41.197,17.1992"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="41.147,16.8388;49.6123,17.5624"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="41.197,17.1992"/>
-        <dia:point val="49.5005,17.2007"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O43" connection="3"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O45">
-      <dia:attribute name="obj_pos">
-        <dia:point val="42.4624,16.69"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="42.4624,16.095;47.1074,16.8425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 3 (source)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="42.4624,16.69"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O46">
-      <dia:attribute name="obj_pos">
-        <dia:point val="9.85,4.55"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="9.85,3.955;12.7275,6.3025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink
-crop
-selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="9.85,4.55"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#0000ff"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O47">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.65,4.75"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="27.65,4.155;30.5275,6.5025"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#source
-crop
-selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="27.65,4.75"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#a020f0"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O48">
-      <dia:attribute name="obj_pos">
-        <dia:point val="10.55,6.6"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.7135,6.39438;10.6035,7.11605"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="10.55,6.6"/>
-        <dia:point val="7.825,6.8"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O9" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O49">
-      <dia:attribute name="obj_pos">
-        <dia:point val="10.45,6.55"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="5.48029,6.48236;10.5176,15.8387"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="10.45,6.55"/>
-        <dia:point val="5.55,15.74"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O30" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O50">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.5246,6.66071"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.406,6.59136;27.594,9.82122"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="27.5246,6.66071"/>
-        <dia:point val="25.4754,9.72825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O18" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O51">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.5036,6.68935"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="25.2161,6.62775;27.5652,14.331"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="27.5036,6.68935"/>
-        <dia:point val="25.4,14.2233"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O37" connection="2"/>
-      </dia:connections>
-    </dia:object>
-  </dia:layer>
-</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg
deleted file mode 100644 (file)
index 3322cf4..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
-<svg width="59cm" height="18cm" viewBox="-186 71 1178 346" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <g>
-    <rect style="fill: #ffffff" x="318.9" y="129" width="208.1" height="249"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #ff765a" x="318.9" y="129" width="208.1" height="249"/>
-  </g>
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-2" y="73" width="806" height="343"/>
-  <g>
-    <ellipse style="fill: #ffffff" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <ellipse style="fill: #ffffff" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.5" y1="167" x2="-30.7361" y2="166.729"/>
-    <polygon style="fill: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.732" y1="205.184" x2="980.066" y2="205.212"/>
-    <polygon style="fill: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139.96" y="155">
-    <tspan x="-139.96" y="155">pad 0 (sink)</tspan>
-  </text>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.04" y="195">
-    <tspan x="849.04" y="195">pad 2 (source)</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="5.5" y="120" width="159" height="104"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="5.5" y="120" width="159" height="104"/>
-  </g>
-  <g>
-    <rect style="fill: #ffffff" x="62.5" y="136" width="94" height="77"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="62.5" y="136" width="94" height="77"/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="30.5" y="89">
-    <tspan x="30.5" y="89"></tspan>
-  </text>
-  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="9.53836" y="88.9138">
-    <tspan x="9.53836" y="88.9138">sink media</tspan>
-    <tspan x="9.53836" y="104.914">bus format</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="62.5" y2="213"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="62.5" y2="136"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="156.5" y2="213"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="156.5" y2="136"/>
-  <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
-    <tspan x="334.704" y="149.442">sink compose</tspan>
-    <tspan x="334.704" y="165.442">selection (scaling)</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="409.322" y="194.565" width="100.186" height="71.4523"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="409.322" y="194.565" width="100.186" height="71.4523"/>
-  </g>
-  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="689.5" y="105.128">
-    <tspan x="689.5" y="105.128">source media</tspan>
-    <tspan x="689.5" y="121.128">bus format</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="688.488" y="173.834" width="100.186" height="71.4523"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="688.488" y="173.834" width="100.186" height="71.4523"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="245.286" x2="409.322" y2="266.018"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="173.834" x2="409.322" y2="194.565"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="245.286" x2="509.508" y2="266.018"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="173.834" x2="509.508" y2="194.565"/>
-  <text style="fill: #ff765a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="325" y="103">
-    <tspan x="325" y="103">sink compose</tspan>
-    <tspan x="325" y="119">bounds selection</tspan>
-  </text>
-  <g>
-    <ellipse style="fill: #ffffff" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.098" y1="341.8" x2="-30.3343" y2="341.529"/>
-    <polygon style="fill: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139" y="329">
-    <tspan x="-139" y="329">pad 1 (sink)</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="7.80824" y="292.8" width="112.092" height="82.2"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="7.80824" y="292.8" width="112.092" height="82.2"/>
-  </g>
-  <g>
-    <rect style="fill: #ffffff" x="52.9" y="314.8" width="58.1" height="50.2"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="52.9" y="314.8" width="58.1" height="50.2"/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="31.9" y="259.8">
-    <tspan x="31.9" y="259.8"></tspan>
-  </text>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="251.9" x2="52.9" y2="314.8"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="316" x2="52.9" y2="365"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="316" x2="111" y2="365"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="251.9" x2="111" y2="314.8"/>
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="358.9" y="251.9" width="75.1" height="64.1"/>
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="443.262" y="284.466" width="64.738" height="48.534"/>
-  <g>
-    <rect style="fill: #ffffff" x="693.428" y="324.734" width="63.572" height="49.266"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="693.428" y="324.734" width="63.572" height="49.266"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="374" x2="443.262" y2="333"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="324.734" x2="443.262" y2="284.466"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="374" x2="508" y2="333"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="324.734" x2="508" y2="284.466"/>
-  <g>
-    <ellipse style="fill: #ffffff" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.94" y1="343.984" x2="980.274" y2="344.012"/>
-    <polygon style="fill: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.248" y="333.8">
-    <tspan x="849.248" y="333.8">pad 3 (source)</tspan>
-  </text>
-  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="197" y="91">
-    <tspan x="197" y="91">sink</tspan>
-    <tspan x="197" y="107">crop</tspan>
-    <tspan x="197" y="123">selection</tspan>
-  </text>
-  <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="553" y="95">
-    <tspan x="553" y="95">source</tspan>
-    <tspan x="553" y="111">crop</tspan>
-    <tspan x="553" y="127">selection</tspan>
-  </text>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="211" y1="132" x2="166.21" y2="135.287"/>
-    <polygon style="fill: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="209" y1="131" x2="115.581" y2="306.209"/>
-    <polygon style="fill: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.492" y1="133.214" x2="514.916" y2="186.469"/>
-    <polygon style="fill: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.072" y1="133.787" x2="510.618" y2="275.089"/>
-    <polygon style="fill: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
-  </g>
-</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia
deleted file mode 100644 (file)
index 0cd50a7..0000000
+++ /dev/null
@@ -1,1152 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
-  <dia:diagramdata>
-    <dia:attribute name="background">
-      <dia:color val="#ffffff"/>
-    </dia:attribute>
-    <dia:attribute name="pagebreak">
-      <dia:color val="#000099"/>
-    </dia:attribute>
-    <dia:attribute name="paper">
-      <dia:composite type="paper">
-        <dia:attribute name="name">
-          <dia:string>#A4#</dia:string>
-        </dia:attribute>
-        <dia:attribute name="tmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="bmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="lmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="rmargin">
-          <dia:real val="2.8222000598907471"/>
-        </dia:attribute>
-        <dia:attribute name="is_portrait">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-        <dia:attribute name="scaling">
-          <dia:real val="0.49000000953674316"/>
-        </dia:attribute>
-        <dia:attribute name="fitto">
-          <dia:boolean val="false"/>
-        </dia:attribute>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="grid">
-      <dia:composite type="grid">
-        <dia:attribute name="width_x">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="width_y">
-          <dia:real val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_x">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:attribute name="visible_y">
-          <dia:int val="1"/>
-        </dia:attribute>
-        <dia:composite type="color"/>
-      </dia:composite>
-    </dia:attribute>
-    <dia:attribute name="color">
-      <dia:color val="#d8e5e5"/>
-    </dia:attribute>
-    <dia:attribute name="guides">
-      <dia:composite type="guides">
-        <dia:attribute name="hguides"/>
-        <dia:attribute name="vguides"/>
-      </dia:composite>
-    </dia:attribute>
-  </dia:diagramdata>
-  <dia:layer name="Background" visible="true" active="true">
-    <dia:object type="Standard - Box" version="0" id="O0">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-0.4,6.5"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-0.45,6.45;39.95,22.9"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-0.4,6.5"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="40.299999999999997"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="16.349999999999998"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O1">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.225,9.45"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.175,9.4;8.225,14.7"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="0.225,9.45"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="7.9499999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="5.1999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a52a2a"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O2">
-      <dia:attribute name="obj_pos">
-        <dia:point val="2.475,10.2"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.425,10.15;7.225,14.1"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="2.475,10.2"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="4.6999999999999975"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.8499999999999979"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#0000ff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O3">
-      <dia:attribute name="obj_pos">
-        <dia:point val="3,11.2"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="3,10.605;5.8775,12.9525"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink
-crop
-selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="3,11.2"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#0000ff"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O4">
-      <dia:attribute name="obj_pos">
-        <dia:point val="1.475,7.9"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>##</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="1.475,7.9"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O5">
-      <dia:attribute name="obj_pos">
-        <dia:point val="0.426918,7.89569"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="0.426918,7.89569"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#a52a2a"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O6">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="8.2600228398861297"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="8.6238900617957164"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#00ff00"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O7">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,17.9064"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.41365,13.9886;16.7436,17.9678"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="16.6822,17.9064"/>
-        <dia:point val="2.475,14.05"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O6" connection="5"/>
-        <dia:connection handle="1" to="O2" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O8">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.6822,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="2.42188,9.22939;16.7353,10.2531"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="16.6822,9.28251"/>
-        <dia:point val="2.475,10.2"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O6" connection="0"/>
-        <dia:connection handle="1" to="O2" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O9">
-      <dia:attribute name="obj_pos">
-        <dia:point val="24.9422,17.9064"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.11553,13.9905;25.0017,17.9659"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="24.9422,17.9064"/>
-        <dia:point val="7.175,14.05"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O6" connection="7"/>
-        <dia:connection handle="1" to="O2" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O10">
-      <dia:attribute name="obj_pos">
-        <dia:point val="24.9422,9.28251"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="7.12249,9.23;24.9947,10.2525"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="24.9422,9.28251"/>
-        <dia:point val="7.175,10.2"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O6" connection="2"/>
-        <dia:connection handle="1" to="O2" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O11">
-      <dia:attribute name="obj_pos">
-        <dia:point val="16.7352,7.47209"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#sink compose
-selection (scaling)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="16.7352,7.47209"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#00ff00"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O12">
-      <dia:attribute name="obj_pos">
-        <dia:point val="19.1161,9.97825"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.0661,9.92825;24.1754,13.6009"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="19.1161,9.97825"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O13">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.1661,7.47209"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="27.1661,6.87709;30.0436,9.22459"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#source
-crop
-selection#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="27.1661,7.47209"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#a020f0"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O14">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.575,7.8564"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.575,7.2614;38.8975,8.8089"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#source media
-bus format#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="34.575,7.8564"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#8b6914"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O15">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.5244,11.2917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.4744,11.2417;39.5837,14.9143"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="34.5244,11.2917"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#8b6914"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O16">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.5244,14.8643"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.062,13.4968;34.5785,14.9184"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.5244,14.8643"/>
-        <dia:point val="19.1161,13.5509"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O15" connection="5"/>
-        <dia:connection handle="1" to="O12" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O17">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.5244,11.2917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.062,9.92418;34.5785,11.3458"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.5244,11.2917"/>
-        <dia:point val="19.1161,9.97825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O15" connection="0"/>
-        <dia:connection handle="1" to="O12" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O18">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.5337,14.8643"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.0713,13.4968;39.5878,14.9184"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.5337,14.8643"/>
-        <dia:point val="24.1254,13.5509"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O15" connection="7"/>
-        <dia:connection handle="1" to="O12" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O19">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.5337,11.2917"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.0713,9.92418;39.5878,11.3458"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.5337,11.2917"/>
-        <dia:point val="24.1254,9.97825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O15" connection="2"/>
-        <dia:connection handle="1" to="O12" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O20">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.98,12.0742"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="39.93,12.0242;40.88,12.9742"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="39.98,12.0742"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O21">
-      <dia:attribute name="obj_pos">
-        <dia:point val="40.83,12.4992"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="40.78,12.1388;49.2453,12.8624"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="40.83,12.4992"/>
-        <dia:point val="49.1335,12.5007"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O20" connection="3"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O22">
-      <dia:attribute name="obj_pos">
-        <dia:point val="42.0954,11.99"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="42.0954,11.395;46.7404,12.1425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 1 (source)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="42.0954,11.99"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O23">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-1.44491,11.6506"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="-1.44491,11.6506"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O24">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-9.61991,12.09"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="-9.61991,12.09"/>
-        <dia:point val="-1.44491,12.0756"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O23" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O25">
-      <dia:attribute name="obj_pos">
-        <dia:point val="-7.39291,11.49"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 0 (sink)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="-7.39291,11.49"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O26">
-      <dia:attribute name="obj_pos">
-        <dia:point val="19.4911,13.8333"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.4411,13.7833;24.5504,17.4559"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="19.4911,13.8333"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Box" version="0" id="O27">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4994,17.2967"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="34.4494,17.2467;39.5587,20.9193"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="34.4994,17.2967"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="5.009308462554376"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="3.5726155970598077"/>
-      </dia:attribute>
-      <dia:attribute name="border_width">
-        <dia:real val="0.10000000149011612"/>
-      </dia:attribute>
-      <dia:attribute name="border_color">
-        <dia:color val="#8b6914"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O28">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4994,20.8693"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.4311,17.3459;34.5594,20.9293"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.4994,20.8693"/>
-        <dia:point val="19.4911,17.4059"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O27" connection="5"/>
-        <dia:connection handle="1" to="O26" connection="5"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O29">
-      <dia:attribute name="obj_pos">
-        <dia:point val="34.4994,17.2967"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="19.4311,13.7733;34.5594,17.3567"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="34.4994,17.2967"/>
-        <dia:point val="19.4911,13.8333"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O27" connection="0"/>
-        <dia:connection handle="1" to="O26" connection="0"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O30">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.5087,20.8693"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.4404,17.3459;39.5687,20.9293"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.5087,20.8693"/>
-        <dia:point val="24.5004,17.4059"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O27" connection="7"/>
-        <dia:connection handle="1" to="O26" connection="7"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O31">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.5087,17.2967"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.4404,13.7733;39.5687,17.3567"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="39.5087,17.2967"/>
-        <dia:point val="24.5004,13.8333"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#e60505"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="4"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O27" connection="2"/>
-        <dia:connection handle="1" to="O26" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Geometric - Perfect Circle" version="1" id="O32">
-      <dia:attribute name="obj_pos">
-        <dia:point val="39.855,18.7792"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="39.805,18.7292;40.755,19.6792"/>
-      </dia:attribute>
-      <dia:attribute name="meta">
-        <dia:composite type="dict"/>
-      </dia:attribute>
-      <dia:attribute name="elem_corner">
-        <dia:point val="39.855,18.7792"/>
-      </dia:attribute>
-      <dia:attribute name="elem_width">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="elem_height">
-        <dia:real val="0.84999999999999787"/>
-      </dia:attribute>
-      <dia:attribute name="line_width">
-        <dia:real val="0.10000000000000001"/>
-      </dia:attribute>
-      <dia:attribute name="line_colour">
-        <dia:color val="#000000"/>
-      </dia:attribute>
-      <dia:attribute name="fill_colour">
-        <dia:color val="#ffffff"/>
-      </dia:attribute>
-      <dia:attribute name="show_background">
-        <dia:boolean val="true"/>
-      </dia:attribute>
-      <dia:attribute name="line_style">
-        <dia:enum val="0"/>
-        <dia:real val="1"/>
-      </dia:attribute>
-      <dia:attribute name="flip_horizontal">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="flip_vertical">
-        <dia:boolean val="false"/>
-      </dia:attribute>
-      <dia:attribute name="subscale">
-        <dia:real val="1"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O33">
-      <dia:attribute name="obj_pos">
-        <dia:point val="40.705,19.2042"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="40.655,18.8438;49.1203,19.5674"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="40.705,19.2042"/>
-        <dia:point val="49.0085,19.2057"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="0" to="O32" connection="3"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Text" version="1" id="O34">
-      <dia:attribute name="obj_pos">
-        <dia:point val="41.9704,18.695"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="41.9704,18.1;46.6154,18.8475"/>
-      </dia:attribute>
-      <dia:attribute name="text">
-        <dia:composite type="text">
-          <dia:attribute name="string">
-            <dia:string>#pad 2 (source)#</dia:string>
-          </dia:attribute>
-          <dia:attribute name="font">
-            <dia:font family="sans" style="0" name="Helvetica"/>
-          </dia:attribute>
-          <dia:attribute name="height">
-            <dia:real val="0.80000000000000004"/>
-          </dia:attribute>
-          <dia:attribute name="pos">
-            <dia:point val="41.9704,18.695"/>
-          </dia:attribute>
-          <dia:attribute name="color">
-            <dia:color val="#000000"/>
-          </dia:attribute>
-          <dia:attribute name="alignment">
-            <dia:enum val="0"/>
-          </dia:attribute>
-        </dia:composite>
-      </dia:attribute>
-      <dia:attribute name="valign">
-        <dia:enum val="3"/>
-      </dia:attribute>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O35">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.3,9.55"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.0146,9.49376;27.3562,10.255"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="27.3,9.55"/>
-        <dia:point val="24.1254,9.97825"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O12" connection="2"/>
-      </dia:connections>
-    </dia:object>
-    <dia:object type="Standard - Line" version="0" id="O36">
-      <dia:attribute name="obj_pos">
-        <dia:point val="27.3454,9.53624"/>
-      </dia:attribute>
-      <dia:attribute name="obj_bb">
-        <dia:rectangle val="24.4311,9.46695;27.4147,13.9265"/>
-      </dia:attribute>
-      <dia:attribute name="conn_endpoints">
-        <dia:point val="27.3454,9.53624"/>
-        <dia:point val="24.5004,13.8333"/>
-      </dia:attribute>
-      <dia:attribute name="numcp">
-        <dia:int val="1"/>
-      </dia:attribute>
-      <dia:attribute name="line_color">
-        <dia:color val="#a020f0"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow">
-        <dia:enum val="22"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_length">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:attribute name="end_arrow_width">
-        <dia:real val="0.5"/>
-      </dia:attribute>
-      <dia:connections>
-        <dia:connection handle="1" to="O26" connection="2"/>
-      </dia:connections>
-    </dia:object>
-  </dia:layer>
-</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg
deleted file mode 100644 (file)
index 2340c0f..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
-<svg width="59cm" height="17cm" viewBox="-194 128 1179 330" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="806" height="327"/>
-  <g>
-    <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
-  </g>
-  <g>
-    <rect style="fill: #ffffff" x="49.5" y="204" width="94" height="77"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="49.5" y="204" width="94" height="77"/>
-  </g>
-  <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="60" y="224">
-    <tspan x="60" y="224">sink</tspan>
-    <tspan x="60" y="240">crop</tspan>
-    <tspan x="60" y="256">selection</tspan>
-  </text>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
-    <tspan x="29.5" y="158"></tspan>
-  </text>
-  <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
-    <tspan x="8.53836" y="157.914">sink media</tspan>
-    <tspan x="8.53836" y="173.914">bus format</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="49.5" y2="281"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="49.5" y2="204"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="143.5" y2="281"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="143.5" y2="204"/>
-  <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
-    <tspan x="334.704" y="149.442">sink compose</tspan>
-    <tspan x="334.704" y="165.442">selection (scaling)</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="382.322" y="199.565" width="100.186" height="71.4523"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="382.322" y="199.565" width="100.186" height="71.4523"/>
-  </g>
-  <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="543.322" y="149.442">
-    <tspan x="543.322" y="149.442">source</tspan>
-    <tspan x="543.322" y="165.442">crop</tspan>
-    <tspan x="543.322" y="181.442">selection</tspan>
-  </text>
-  <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="691.5" y="157.128">
-    <tspan x="691.5" y="157.128">source media</tspan>
-    <tspan x="691.5" y="173.128">bus format</tspan>
-  </text>
-  <g>
-    <rect style="fill: #ffffff" x="690.488" y="225.834" width="100.186" height="71.4523"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="690.488" y="225.834" width="100.186" height="71.4523"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="297.286" x2="382.322" y2="271.018"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="225.834" x2="382.322" y2="199.565"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="297.286" x2="482.508" y2="271.018"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="225.834" x2="482.508" y2="199.565"/>
-  <g>
-    <ellipse style="fill: #ffffff" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="816.6" y1="249.984" x2="972.934" y2="250.012"/>
-    <polygon style="fill: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="841.908" y="239.8">
-    <tspan x="841.908" y="239.8">pad 1 (source)</tspan>
-  </text>
-  <g>
-    <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
-    <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
-    <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
-  </text>
-  <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="389.822" y="276.666" width="100.186" height="71.4523"/>
-  <g>
-    <rect style="fill: #ffffff" x="689.988" y="345.934" width="100.186" height="71.4523"/>
-    <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="689.988" y="345.934" width="100.186" height="71.4523"/>
-  </g>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="417.386" x2="389.822" y2="348.118"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="345.934" x2="389.822" y2="276.666"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="417.386" x2="490.008" y2="348.118"/>
-  <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="345.934" x2="490.008" y2="276.666"/>
-  <g>
-    <ellipse style="fill: #ffffff" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
-    <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="814.1" y1="384.084" x2="970.434" y2="384.112"/>
-    <polygon style="fill: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
-  </g>
-  <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="839.408" y="373.9">
-    <tspan x="839.408" y="373.9">pad 2 (source)</tspan>
-  </text>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546" y1="191" x2="492.157" y2="198.263"/>
-    <polygon style="fill: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
-  </g>
-  <g>
-    <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546.908" y1="190.725" x2="495.383" y2="268.548"/>
-    <polygon style="fill: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
-    <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
-  </g>
-</svg>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
deleted file mode 100644 (file)
index 42e626d..0000000
+++ /dev/null
@@ -1,728 +0,0 @@
- <partinfo>
-    <authorgroup>
-      <author>
-       <firstname>Michael</firstname>
-       <surname>Schimek</surname>
-       <othername role="mi">H</othername>
-       <affiliation>
-         <address>
-           <email>mschimek@gmx.at</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Bill</firstname>
-       <surname>Dirks</surname>
-       <!-- Commented until Bill opts in to be spammed.
-       <affiliation>
-         <address>
-           <email>bill@thedirks.org</email>
-         </address>
-       </affiliation> -->
-       <contrib>Original author of the V4L2 API and
-documentation.</contrib>
-      </author>
-
-      <author>
-       <firstname>Hans</firstname>
-       <surname>Verkuil</surname>
-       <contrib>Designed and documented the VIDIOC_LOG_STATUS ioctl,
-the extended control ioctls, major parts of the sliced VBI API, the
-MPEG encoder and decoder APIs and the DV Timings API.</contrib>
-       <affiliation>
-         <address>
-           <email>hverkuil@xs4all.nl</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Martin</firstname>
-       <surname>Rubli</surname>
-       <!--
-       <affiliation>
-         <address>
-           <email>martin_rubli@logitech.com</email>
-         </address>
-       </affiliation> -->
-       <contrib>Designed and documented the VIDIOC_ENUM_FRAMESIZES
-and VIDIOC_ENUM_FRAMEINTERVALS ioctls.</contrib>
-      </author>
-
-      <author>
-       <firstname>Andy</firstname>
-       <surname>Walls</surname>
-       <contrib>Documented the fielded V4L2_MPEG_STREAM_VBI_FMT_IVTV
-MPEG stream embedded, sliced VBI data format in this specification.
-</contrib>
-       <affiliation>
-         <address>
-           <email>awalls@md.metrocast.net</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Mauro</firstname>
-       <surname>Carvalho Chehab</surname>
-       <contrib>Documented libv4l, designed and added v4l2grab example,
-Remote Controller chapter.</contrib>
-       <affiliation>
-         <address>
-           <email>m.chehab@samsung.com</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Muralidharan</firstname>
-       <surname>Karicheri</surname>
-       <contrib>Documented the Digital Video timings API.</contrib>
-       <affiliation>
-         <address>
-           <email>m-karicheri2@ti.com</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Pawel</firstname>
-       <surname>Osciak</surname>
-       <contrib>Designed and documented the multi-planar API.</contrib>
-       <affiliation>
-         <address>
-           <email>pawel AT osciak.com</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Sakari</firstname>
-       <surname>Ailus</surname>
-       <contrib>Subdev selections API.</contrib>
-       <affiliation>
-         <address>
-           <email>sakari.ailus@iki.fi</email>
-         </address>
-       </affiliation>
-      </author>
-      <author>
-       <firstname>Antti</firstname>
-       <surname>Palosaari</surname>
-       <contrib>SDR API.</contrib>
-       <affiliation>
-         <address>
-           <email>crope@iki.fi</email>
-         </address>
-       </affiliation>
-      </author>
-    </authorgroup>
-
-    <copyright>
-      <year>1999</year>
-      <year>2000</year>
-      <year>2001</year>
-      <year>2002</year>
-      <year>2003</year>
-      <year>2004</year>
-      <year>2005</year>
-      <year>2006</year>
-      <year>2007</year>
-      <year>2008</year>
-      <year>2009</year>
-      <year>2010</year>
-      <year>2011</year>
-      <year>2012</year>
-      <year>2013</year>
-      <year>2014</year>
-      <year>2015</year>
-      <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
-Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
-       Pawel Osciak</holder>
-    </copyright>
-    <legalnotice>
-    <para>Except when explicitly stated as GPL, programming examples within
-           this part can be used and distributed without restrictions.</para>
-    </legalnotice>
-    <revhistory>
-      <!-- Put document revisions here, newest first. -->
-      <!-- API revisions (changes and additions of defines, enums,
-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>4.5</revnumber>
-       <date>2015-10-29</date>
-       <authorinitials>rr</authorinitials>
-       <revremark>Extend vidioc-g-ext-ctrls;. Replace ctrl_class with a new
-union with ctrl_class and which. Which is used to select the current value of
-the control or the default value.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>4.4</revnumber>
-       <date>2015-05-26</date>
-       <authorinitials>ap</authorinitials>
-       <revremark>Renamed V4L2_TUNER_ADC to V4L2_TUNER_SDR.
-Added V4L2_CID_RF_TUNER_RF_GAIN control.
-Added transmitter support for Software Defined Radio (SDR) Interface.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>4.1</revnumber>
-       <date>2015-02-13</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>Fix documentation for media controller device nodes and add support for DVB device nodes.
-Add support for Tuner sub-device.
-       </revremark>
-      </revision>
-      <revision>
-       <revnumber>3.19</revnumber>
-       <date>2014-12-05</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Rewrote Colorspace chapter, added new &v4l2-ycbcr-encoding; and &v4l2-quantization; fields
-to &v4l2-pix-format;, &v4l2-pix-format-mplane; and &v4l2-mbus-framefmt;.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.17</revnumber>
-       <date>2014-08-04</date>
-       <authorinitials>lp, hv</authorinitials>
-       <revremark>Extended &v4l2-pix-format;. Added format flags. Added compound control types
-and VIDIOC_QUERY_EXT_CTRL.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.15</revnumber>
-       <date>2014-02-03</date>
-       <authorinitials>hv, ap</authorinitials>
-       <revremark>Update several sections of "Common API Elements": "Opening and Closing Devices"
-"Querying Capabilities", "Application Priority", "Video Inputs and Outputs", "Audio Inputs and Outputs"
-"Tuners and Modulators", "Video Standards" and "Digital Video (DV) Timings". Added SDR API.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.14</revnumber>
-       <date>2013-11-25</date>
-       <authorinitials>rr</authorinitials>
-       <revremark>Set width and height as unsigned on v4l2_rect.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.11</revnumber>
-       <date>2013-05-26</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Remove obsolete VIDIOC_DBG_G_CHIP_IDENT ioctl.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.10</revnumber>
-       <date>2013-03-25</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Remove obsolete and unused DV_PRESET ioctls:
-       VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and
-       VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability
-       flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_INFO.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.9</revnumber>
-       <date>2012-12-03</date>
-       <authorinitials>sa, sn</authorinitials>
-       <revremark>Added timestamp types to v4l2_buffer.
-       Added V4L2_EVENT_CTRL_CH_RANGE control event changes flag.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.6</revnumber>
-       <date>2012-07-02</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added VIDIOC_ENUM_FREQ_BANDS.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.5</revnumber>
-       <date>2012-05-07</date>
-       <authorinitials>sa, sn, hv</authorinitials>
-       <revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
-           selections API. Improved the description of V4L2_CID_COLORFX
-           control, added V4L2_CID_COLORFX_CBCR control.
-           Added camera controls V4L2_CID_AUTO_EXPOSURE_BIAS,
-           V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_IMAGE_STABILIZATION,
-           V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO,
-           V4L2_CID_EXPOSURE_METERING, V4L2_CID_SCENE_MODE,
-           V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
-           V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
-           and V4L2_CID_AUTO_FOCUS_RANGE.
-           Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
-           VIDIOC_DV_TIMINGS_CAP.
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.4</revnumber>
-       <date>2012-01-25</date>
-       <authorinitials>sn</authorinitials>
-       <revremark>Added <link linkend="jpeg-controls">JPEG compression
-           control class.</link>
-       </revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.3</revnumber>
-       <date>2012-01-11</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added device_caps field to struct v4l2_capabilities.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.2</revnumber>
-       <date>2011-08-26</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added V4L2_CTRL_FLAG_VOLATILE.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>3.1</revnumber>
-       <date>2011-06-27</date>
-       <authorinitials>mcc, po, hv</authorinitials>
-       <revremark>Documented that VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.
-                  Standardize an error code for invalid ioctl.
-                  Added V4L2_CTRL_TYPE_BITMASK.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.39</revnumber>
-       <date>2011-03-01</date>
-       <authorinitials>mcc, po</authorinitials>
-       <revremark>Removed VIDIOC_*_OLD from videodev2.h header and update it to reflect latest changes. Added the <link linkend="planar-apis">multi-planar API</link>.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.37</revnumber>
-       <date>2010-08-06</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Removed obsolete vtx (videotext) API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.33</revnumber>
-       <date>2009-12-03</date>
-       <authorinitials>mk</authorinitials>
-       <revremark>Added documentation for the Digital Video timings API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.32</revnumber>
-       <date>2009-08-31</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>Now, revisions will match the kernel version where
-the V4L2 API changes will be used by the Linux Kernel.
-Also added Remote Controller chapter.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.29</revnumber>
-       <date>2009-08-26</date>
-       <authorinitials>ev</authorinitials>
-       <revremark>Added documentation for string controls and for FM Transmitter controls.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.28</revnumber>
-       <date>2009-08-26</date>
-       <authorinitials>gl</authorinitials>
-       <revremark>Added V4L2_CID_BAND_STOP_FILTER documentation.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.27</revnumber>
-       <date>2009-08-15</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>Added libv4l and Remote Controller documentation;
-added v4l2grab and keytable application examples.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.26</revnumber>
-       <date>2009-07-23</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Finalized the RDS capture API. Added modulator and RDS encoder
-capabilities. Added support for string controls.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.25</revnumber>
-       <date>2009-01-18</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added pixel formats VYUY, NV16 and NV61, and changed
-the debug ioctls VIDIOC_DBG_G/S_REGISTER and VIDIOC_DBG_G_CHIP_IDENT.
-Added camera controls V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_RELATIVE,
-V4L2_CID_ZOOM_CONTINUOUS and V4L2_CID_PRIVACY.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.24</revnumber>
-       <date>2008-03-04</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added pixel formats Y16 and SBGGR16, new controls
-and a camera controls class. Removed VIDIOC_G/S_MPEGCOMP.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.23</revnumber>
-       <date>2007-08-30</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed a typo in VIDIOC_DBG_G/S_REGISTER.
-Clarified the byte order of packed pixel formats.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.22</revnumber>
-       <date>2007-08-29</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added the Video Output Overlay interface, new MPEG
-controls, V4L2_FIELD_INTERLACED_TB and V4L2_FIELD_INTERLACED_BT,
-VIDIOC_DBG_G/S_REGISTER, VIDIOC_(TRY_)ENCODER_CMD,
-VIDIOC_G_CHIP_IDENT, VIDIOC_G_ENC_INDEX, new pixel formats.
-Clarifications in the cropping chapter, about RGB pixel formats, the
-mmap(), poll(), select(), read() and write() functions. Typographical
-fixes.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.21</revnumber>
-       <date>2006-12-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed a link in the VIDIOC_G_EXT_CTRLS section.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.20</revnumber>
-       <date>2006-11-24</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Clarified the purpose of the audioset field in
-struct v4l2_input and v4l2_output.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.19</revnumber>
-       <date>2006-10-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Documented V4L2_PIX_FMT_RGB444.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.18</revnumber>
-       <date>2006-10-18</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added the description of extended controls by Hans
-Verkuil. Linked V4L2_PIX_FMT_MPEG to V4L2_CID_MPEG_STREAM_TYPE.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.17</revnumber>
-       <date>2006-10-12</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected V4L2_PIX_FMT_HM12 description.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.16</revnumber>
-       <date>2006-10-08</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>VIDIOC_ENUM_FRAMESIZES and
-VIDIOC_ENUM_FRAMEINTERVALS are now part of the API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.15</revnumber>
-       <date>2006-09-23</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Cleaned up the bibliography, added BT.653 and
-BT.1119. capture.c/start_capturing() for user pointer I/O did not
-initialize the buffer index. Documented the V4L MPEG and MJPEG
-VID_TYPEs and V4L2_PIX_FMT_SBGGR8. Updated the list of reserved pixel
-formats. See the history chapter for API changes.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.14</revnumber>
-       <date>2006-09-14</date>
-       <authorinitials>mr</authorinitials>
-       <revremark>Added VIDIOC_ENUM_FRAMESIZES and
-VIDIOC_ENUM_FRAMEINTERVALS proposal for frame format enumeration of
-digital devices.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.13</revnumber>
-       <date>2006-04-07</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected the description of struct v4l2_window
-clips. New V4L2_STD_ and V4L2_TUNER_MODE_LANG1_LANG2
-defines.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.12</revnumber>
-       <date>2006-02-03</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected the description of struct
-v4l2_captureparm and v4l2_outputparm.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.11</revnumber>
-       <date>2006-01-27</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Improved the description of struct
-v4l2_tuner.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.10</revnumber>
-       <date>2006-01-10</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>VIDIOC_G_INPUT and VIDIOC_S_PARM
-clarifications.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.9</revnumber>
-       <date>2005-11-27</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Improved the 525 line numbering diagram. Hans
-Verkuil and I rewrote the sliced VBI section. He also contributed a
-VIDIOC_LOG_STATUS page. Fixed VIDIOC_S_STD call in the video standard
-selection example. Various updates.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.8</revnumber>
-       <date>2004-10-04</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Somehow a piece of junk slipped into the capture
-example, removed.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.7</revnumber>
-       <date>2004-09-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed video standard selection, control
-enumeration, downscaling and aspect example. Added read and user
-pointer i/o to video capture example.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.6</revnumber>
-       <date>2004-08-01</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>v4l2_buffer changes, added video capture example,
-various corrections.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.5</revnumber>
-       <date>2003-11-05</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Pixel format erratum.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.4</revnumber>
-       <date>2003-09-17</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected source and Makefile to generate a PDF.
-SGML fixes. Added latest API changes. Closed gaps in the history
-chapter.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.3</revnumber>
-       <date>2003-02-05</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Another draft, more corrections.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.2</revnumber>
-       <date>2003-01-15</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Second draft, with corrections pointed out by Gerd
-Knorr.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.1</revnumber>
-       <date>2002-12-01</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>First draft, based on documentation by Bill Dirks
-and discussions on the V4L mailing list.</revremark>
-      </revision>
-    </revhistory>
-</partinfo>
-
-<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 4.4</subtitle>
-
-  <chapter id="common">
-    &sub-common;
-  </chapter>
-
-  <chapter id="pixfmt">
-    &sub-pixfmt;
-  </chapter>
-
-  <chapter id="io">
-    &sub-io;
-  </chapter>
-
-  <chapter id="devices">
-    <title>Interfaces</title>
-
-    <section id="capture"> &sub-dev-capture; </section>
-    <section id="overlay"> &sub-dev-overlay; </section>
-    <section id="output"> &sub-dev-output; </section>
-    <section id="osd"> &sub-dev-osd; </section>
-    <section id="codec"> &sub-dev-codec; </section>
-    <section id="effect"> &sub-dev-effect; </section>
-    <section id="raw-vbi"> &sub-dev-raw-vbi; </section>
-    <section id="sliced"> &sub-dev-sliced-vbi; </section>
-    <section id="ttx"> &sub-dev-teletext; </section>
-    <section id="radio"> &sub-dev-radio; </section>
-    <section id="rds"> &sub-dev-rds; </section>
-    <section id="sdr"> &sub-dev-sdr; </section>
-    <section id="event"> &sub-dev-event; </section>
-    <section id="subdev"> &sub-dev-subdev; </section>
-  </chapter>
-
-  <chapter id="driver">
-         &sub-driver;
-  </chapter>
-
-  <chapter id="libv4l">
-         &sub-libv4l;
-  </chapter>
-
-  <chapter id="compat">
-         &sub-compat;
-  </chapter>
-
-  <appendix id="user-func">
-  <title>Function Reference</title>
-
-    <!-- Keep this alphabetically sorted. -->
-
-    &sub-close;
-    &sub-ioctl;
-    <!-- All ioctls go here. -->
-    &sub-create-bufs;
-    &sub-cropcap;
-    &sub-dbg-g-chip-info;
-    &sub-dbg-g-register;
-    &sub-decoder-cmd;
-    &sub-dqevent;
-    &sub-dv-timings-cap;
-    &sub-encoder-cmd;
-    &sub-enumaudio;
-    &sub-enumaudioout;
-    &sub-enum-dv-timings;
-    &sub-enum-fmt;
-    &sub-enum-framesizes;
-    &sub-enum-frameintervals;
-    &sub-enum-freq-bands;
-    &sub-enuminput;
-    &sub-enumoutput;
-    &sub-enumstd;
-    &sub-expbuf;
-    &sub-g-audio;
-    &sub-g-audioout;
-    &sub-g-crop;
-    &sub-g-ctrl;
-    &sub-g-dv-timings;
-    &sub-g-edid;
-    &sub-g-enc-index;
-    &sub-g-ext-ctrls;
-    &sub-g-fbuf;
-    &sub-g-fmt;
-    &sub-g-frequency;
-    &sub-g-input;
-    &sub-g-jpegcomp;
-    &sub-g-modulator;
-    &sub-g-output;
-    &sub-g-parm;
-    &sub-g-priority;
-    &sub-g-selection;
-    &sub-g-sliced-vbi-cap;
-    &sub-g-std;
-    &sub-g-tuner;
-    &sub-log-status;
-    &sub-overlay;
-    &sub-prepare-buf;
-    &sub-qbuf;
-    &sub-querybuf;
-    &sub-querycap;
-    &sub-queryctrl;
-    &sub-query-dv-timings;
-    &sub-querystd;
-    &sub-reqbufs;
-    &sub-s-hw-freq-seek;
-    &sub-streamon;
-    &sub-subdev-enum-frame-interval;
-    &sub-subdev-enum-frame-size;
-    &sub-subdev-enum-mbus-code;
-    &sub-subdev-g-crop;
-    &sub-subdev-g-fmt;
-    &sub-subdev-g-frame-interval;
-    &sub-subdev-g-selection;
-    &sub-subscribe-event;
-    <!-- End of ioctls. -->
-    &sub-mmap;
-    &sub-munmap;
-    &sub-open;
-    &sub-poll;
-    &sub-read;
-    &sub-select;
-    &sub-write;
-  </appendix>
-
-  <appendix>
-    <title>Common definitions for V4L2 and V4L2 subdev interfaces</title>
-      &sub-selections-common;
-  </appendix>
-
-  <appendix id="videodev">
-    <title>Video For Linux Two Header File</title>
-    &sub-videodev2-h;
-  </appendix>
-
-  <appendix id="capture-example">
-    <title>Video Capture Example</title>
-    &sub-capture-c;
-  </appendix>
-
-  <appendix id="v4l2grab-example">
-    <title>Video Grabber example using libv4l</title>
-    <para>This program demonstrates how to grab V4L2 images in ppm format by
-using libv4l handlers. The advantage is that this grabber can potentially work
-with any V4L2 driver.</para>
-    &sub-v4l2grab-c;
-  </appendix>
-
-  &sub-media-indices;
-
-  &sub-biblio;
-
diff --git a/Documentation/DocBook/media/v4l/v4l2grab.c.xml b/Documentation/DocBook/media/v4l/v4l2grab.c.xml
deleted file mode 100644 (file)
index bed12e4..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-<programlisting>
-/* V4L2 video picture grabber
-   Copyright (C) 2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
- */
-
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;sys/ioctl.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;sys/time.h&gt;
-#include &lt;sys/mman.h&gt;
-#include &lt;linux/videodev2.h&gt;
-#include "../libv4l/include/libv4l2.h"
-
-#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
-
-struct buffer {
-        void   *start;
-        size_t length;
-};
-
-static void xioctl(int fh, int request, void *arg)
-{
-        int r;
-
-        do {
-                r = v4l2_ioctl(fh, request, arg);
-        } while (r == -1 &amp;&amp; ((errno == EINTR) || (errno == EAGAIN)));
-
-        if (r == -1) {
-                fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-}
-
-int main(int argc, char **argv)
-{
-        struct <link linkend="v4l2-format">v4l2_format</link>              fmt;
-        struct <link linkend="v4l2-buffer">v4l2_buffer</link>              buf;
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link>      req;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>              type;
-        fd_set                          fds;
-        struct timeval                  tv;
-        int                             r, fd = -1;
-        unsigned int                    i, n_buffers;
-        char                            *dev_name = "/dev/video0";
-        char                            out_name[256];
-        FILE                            *fout;
-        struct buffer                   *buffers;
-
-        fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
-        if (fd &lt; 0) {
-                perror("Cannot open device");
-                exit(EXIT_FAILURE);
-        }
-
-        CLEAR(fmt);
-        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        fmt.fmt.pix.width       = 640;
-        fmt.fmt.pix.height      = 480;
-        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
-        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
-        xioctl(fd, VIDIOC_S_FMT, &amp;fmt);
-        if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
-                printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
-                exit(EXIT_FAILURE);
-        }
-        if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480))
-                printf("Warning: driver is sending image at %dx%d\n",
-                        fmt.fmt.pix.width, fmt.fmt.pix.height);
-
-        CLEAR(req);
-        req.count = 2;
-        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_MMAP;
-        xioctl(fd, VIDIOC_REQBUFS, &amp;req);
-
-        buffers = calloc(req.count, sizeof(*buffers));
-        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
-                CLEAR(buf);
-
-                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory      = V4L2_MEMORY_MMAP;
-                buf.index       = n_buffers;
-
-                xioctl(fd, VIDIOC_QUERYBUF, &amp;buf);
-
-                buffers[n_buffers].length = buf.length;
-                buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
-                              PROT_READ | PROT_WRITE, MAP_SHARED,
-                              fd, buf.m.offset);
-
-                if (MAP_FAILED == buffers[n_buffers].start) {
-                        perror("mmap");
-                        exit(EXIT_FAILURE);
-                }
-        }
-
-        for (i = 0; i &lt; n_buffers; ++i) {
-                CLEAR(buf);
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-                buf.index = i;
-                xioctl(fd, VIDIOC_QBUF, &amp;buf);
-        }
-        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-        xioctl(fd, VIDIOC_STREAMON, &amp;type);
-        for (i = 0; i &lt; 20; i++) {
-                do {
-                        FD_ZERO(&amp;fds);
-                        FD_SET(fd, &amp;fds);
-
-                        /* Timeout. */
-                        tv.tv_sec = 2;
-                        tv.tv_usec = 0;
-
-                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
-                } while ((r == -1 &amp;&amp; (errno = EINTR)));
-                if (r == -1) {
-                        perror("select");
-                        return errno;
-                }
-
-                CLEAR(buf);
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-                xioctl(fd, VIDIOC_DQBUF, &amp;buf);
-
-                sprintf(out_name, "out%03d.ppm", i);
-                fout = fopen(out_name, "w");
-                if (!fout) {
-                        perror("Cannot open image");
-                        exit(EXIT_FAILURE);
-                }
-                fprintf(fout, "P6\n%d %d 255\n",
-                        fmt.fmt.pix.width, fmt.fmt.pix.height);
-                fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
-                fclose(fout);
-
-                xioctl(fd, VIDIOC_QBUF, &amp;buf);
-        }
-
-        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        xioctl(fd, VIDIOC_STREAMOFF, &amp;type);
-        for (i = 0; i &lt; n_buffers; ++i)
-                v4l2_munmap(buffers[i].start, buffers[i].length);
-        v4l2_close(fd);
-
-        return 0;
-}
-</programlisting>
diff --git a/Documentation/DocBook/media/v4l/vbi_525.pdf b/Documentation/DocBook/media/v4l/vbi_525.pdf
deleted file mode 100644 (file)
index 9e72c25..0000000
Binary files a/Documentation/DocBook/media/v4l/vbi_525.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/vbi_625.pdf b/Documentation/DocBook/media/v4l/vbi_625.pdf
deleted file mode 100644 (file)
index 765235e..0000000
Binary files a/Documentation/DocBook/media/v4l/vbi_625.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/vbi_hsync.pdf b/Documentation/DocBook/media/v4l/vbi_hsync.pdf
deleted file mode 100644 (file)
index 200b668..0000000
Binary files a/Documentation/DocBook/media/v4l/vbi_hsync.pdf and /dev/null differ
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
deleted file mode 100644 (file)
index 6528e97..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-<refentry id="vidioc-create-bufs">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_CREATE_BUFS</refname>
-    <refpurpose>Create buffers for Memory Mapped or User Pointer or DMA Buffer
-    I/O</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_create_buffers *<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_CREATE_BUFS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
-mapped</link> or <link linkend="userp">user pointer</link> or <link
-linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
-addition to the &VIDIOC-REQBUFS; ioctl, when a tighter
-control over buffers is required. This ioctl can be called multiple times to
-create buffers of different sizes.</para>
-
-    <para>To allocate the device buffers applications must initialize the
-relevant fields of the <structname>v4l2_create_buffers</structname> structure.
-The <structfield>count</structfield> field must be set to the number of
-requested buffers, the <structfield>memory</structfield> field specifies the
-requested I/O method and the <structfield>reserved</structfield> array must be
-zeroed.</para>
-
-    <para>The <structfield>format</structfield> field specifies the image format
-that the buffers must be able to handle. The application has to fill in this
-&v4l2-format;. Usually this will be done using the &VIDIOC-TRY-FMT; or &VIDIOC-G-FMT; ioctls
-to ensure that the requested format is supported by the driver.
-Based on the format's <structfield>type</structfield> field the requested buffer
-size (for single-planar) or plane sizes (for multi-planar formats) will be
-used for the allocated buffers. The driver may return an error if the size(s)
-are not supported by the hardware (usually because they are too small).</para>
-
-    <para>The buffers created by this ioctl will have as minimum size the size
-defined by the <structfield>format.pix.sizeimage</structfield> field (or the
-corresponding fields for other format types). Usually if the
-<structfield>format.pix.sizeimage</structfield> field is less than the minimum
-required for the given format, then an error will be returned since drivers will
-typically not allow this. If it is larger, then the value will be used as-is.
-In other words, the driver may reject the requested size, but if it is accepted
-the driver will use it unchanged.</para>
-
-    <para>When the ioctl is called with a pointer to this structure the driver
-will attempt to allocate up to the requested number of buffers and store the
-actual number allocated and the starting index in the
-<structfield>count</structfield> and the <structfield>index</structfield> fields
-respectively. On return <structfield>count</structfield> can be smaller than
-the number requested.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-create-buffers">
-      <title>struct <structname>v4l2_create_buffers</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>The starting buffer index, returned by the driver.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>count</structfield></entry>
-           <entry>The number of buffers requested or granted. If count == 0, then
-           <constant>VIDIOC_CREATE_BUFS</constant> will set <structfield>index</structfield>
-           to the current number of created buffers, and it will check the validity of
-           <structfield>memory</structfield> and <structfield>format.type</structfield>.
-           If those are invalid -1 is returned and errno is set to &EINVAL;,
-           otherwise <constant>VIDIOC_CREATE_BUFS</constant> returns 0. It will
-           never set errno to &EBUSY; in this particular case.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>memory</structfield></entry>
-           <entry>Applications set this field to
-<constant>V4L2_MEMORY_MMAP</constant>,
-<constant>V4L2_MEMORY_DMABUF</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
-/></entry>
-         </row>
-         <row>
-           <entry>&v4l2-format;</entry>
-           <entry><structfield>format</structfield></entry>
-           <entry>Filled in by the application, preserved by the driver.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>A place holder for future extensions. Drivers and applications
-must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>No memory to allocate buffers for <link linkend="mmap">memory
-mapped</link> I/O.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer type (<structfield>format.type</structfield> field),
-requested I/O method (<structfield>memory</structfield>) or format
-(<structfield>format</structfield> field) is not valid.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
deleted file mode 100644 (file)
index 50cb940..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<refentry id="vidioc-cropcap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_CROPCAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_CROPCAP</refname>
-    <refpurpose>Information about the video cropping and scaling abilities</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_cropcap
-*<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_CROPCAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications use this function to query the cropping
-limits, the pixel aspect of images and to calculate scale factors.
-They set the <structfield>type</structfield> field of a v4l2_cropcap
-structure to the respective buffer (stream) type and call the
-<constant>VIDIOC_CROPCAP</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure. The results are
-constant except when switching the video standard. Remember this
-switch can occur implicit when switching the video input or
-output.</para>
-
-<para>Do not use the multiplanar buffer types.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
-instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
-and use <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.</para>
-
-    <para>This ioctl must be implemented for video capture or output devices that
-support cropping and/or scaling and/or have non-square pixels, and for overlay devices.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-cropcap">
-      <title>struct <structname>v4l2_cropcap</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here:
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> and
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>. See <xref linkend="v4l2-buf-type" />.</entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
-           <entry><structfield>bounds</structfield></entry>
-           <entry>Defines the window within capturing or output is
-possible, this may exclude for example the horizontal and vertical
-blanking areas. The cropping rectangle cannot exceed these limits.
-Width and height are defined in pixels, the driver writer is free to
-choose origin and units of the coordinate system in the analog
-domain.</entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
-           <entry><structfield>defrect</structfield></entry>
-           <entry>Default cropping rectangle, it shall cover the
-"whole picture". Assuming pixel aspect 1/1 this could be for example a
-640&nbsp;&times;&nbsp;480 rectangle for NTSC, a
-768&nbsp;&times;&nbsp;576 rectangle for PAL and SECAM centered over
-the active picture area. The same co-ordinate system as for
-           <structfield>bounds</structfield> is used.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>pixelaspect</structfield></entry>
-           <entry><para>This is the pixel aspect (y / x) when no
-scaling is applied, the ratio of the actual sampling
-frequency and the frequency required to get square
-pixels.</para><para>When cropping coordinates refer to square pixels,
-the driver sets <structfield>pixelaspect</structfield> to 1/1. Other
-common values are 54/59 for PAL and SECAM, 11/10 for NTSC sampled
-according to [<xref linkend="itu601" />].</para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- NB this table is duplicated in the overlay chapter. -->
-
-    <table pgwide="1" frame="none" id="v4l2-rect-crop">
-      <title>struct <structname>v4l2_rect</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>left</structfield></entry>
-           <entry>Horizontal offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>top</structfield></entry>
-           <entry>Vertical offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-cropcap; <structfield>type</structfield> is
-invalid.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
deleted file mode 100644 (file)
index f14a3bb..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-<refentry id="vidioc-dbg-g-chip-info">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DBG_G_CHIP_INFO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DBG_G_CHIP_INFO</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_info
-*<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_INFO</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>Additionally the Linux kernel must be compiled with the
-<constant>CONFIG_VIDEO_ADV_DEBUG</constant> option to enable this ioctl.</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-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.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_BRIDGE</constant>,
-<structfield>match.addr</structfield> selects the nth bridge '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_INFO</constant> fails with an &EINVAL;.
-The number zero always selects the bridge chip itself, &eg; the chip
-connected to the PCI or USB bus. Non-zero numbers identify specific
-parts of the bridge chip such as an AC97 register block.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_SUBDEV</constant>,
-<structfield>match.addr</structfield> selects the nth sub-device. This
-allows you to enumerate over all sub-devices.</para>
-
-    <para>On success, the <structfield>name</structfield> field will
-contain a chip name and the <structfield>flags</structfield> field will
-contain <constant>V4L2_CHIP_FL_READABLE</constant> if the driver supports
-reading registers from the device or <constant>V4L2_CHIP_FL_WRITABLE</constant>
-if the driver supports writing registers to the device.</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="https://linuxtv.org/repo/">https://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="name-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="name-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. Currently unused.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dbg-chip-info">
-      <title>struct <structname>v4l2_dbg_chip_info</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="name-v4l2-dbg-match" />.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name[32]</structfield></entry>
-           <entry>The name of the chip.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Set by the driver. If <constant>V4L2_CHIP_FL_READABLE</constant>
-is set, then the driver supports reading registers from the device. If
-<constant>V4L2_CHIP_FL_WRITABLE</constant> is set, then it supports writing registers.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[8]</structfield></entry>
-           <entry>Reserved fields, both application and driver must set these to 0.</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="name-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_SUBDEV</constant></entry>
-           <entry>4</entry>
-           <entry>Match the nth sub-device.</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 or
-no device could be matched.</para>
-       </listitem>
-      </varlistentry>
-     </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
deleted file mode 100644 (file)
index 5877f68..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-<refentry id="vidioc-dbg-g-register">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DBG_G_REGISTER</refname>
-    <refname>VIDIOC_DBG_S_REGISTER</refname>
-    <refpurpose>Read or write hardware registers</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_register *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_dbg_register
-*<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_REGISTER, VIDIOC_DBG_S_REGISTER</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 these ioctls allow test
-applications to access hardware registers directly. Regular
-applications must not use them.</para>
-
-    <para>Since writing or even reading registers can jeopardize the
-system security, its stability and damage the hardware, both ioctls
-require superuser privileges. Additionally the Linux kernel must be
-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; 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>
-fields select a chip on the TV
-card, the <structfield>reg</structfield> field specifies a register
-number and the <structfield>val</structfield> field the value to be
-written into the register.</para>
-
-    <para>To read a register applications must initialize the
-<structfield>match.type</structfield>,
-<structfield>match.addr</structfield> or <structfield>match.name</structfield> and
-<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 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>,
-<structfield>match.addr</structfield> selects the nth non-sub-device chip
-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_SUBDEV</constant>,
-<structfield>match.addr</structfield> selects the nth sub-device.</para>
-
-    <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
-<constant>VIDIOC_DBG_G_CHIP_INFO</constant> but not these ioctls.</para>
-
-    <para><constant>VIDIOC_DBG_G_REGISTER</constant> and
-<constant>VIDIOC_DBG_S_REGISTER</constant> were introduced in Linux
-2.6.21, but their API was changed to the one described here in kernel 2.6.29.</para>
-
-    <para>We recommended the <application>v4l2-dbg</application>
-utility over calling these ioctls directly. It is available from the
-LinuxTV v4l-dvb repository; see <ulink
-url="https://linuxtv.org/repo/">https://linuxtv.org/repo/</ulink> for
-access instructions.</para>
-
-    <!-- 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>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>See <xref linkend="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. Currently unused.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-
-    <table pgwide="1" frame="none" id="v4l2-dbg-register">
-      <title>struct <structname>v4l2_dbg_register</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>struct v4l2_dbg_match</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>
-           <entry>A register number.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>val</structfield></entry>
-           <entry>The value read from, or to be written into the
-register.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- 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>
-      <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_SUBDEV</constant></entry>
-           <entry>4</entry>
-           <entry>Match the nth sub-device.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para>Insufficient permissions. Root privileges are required
-to execute these ioctls.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
deleted file mode 100644 (file)
index 73eb5cf..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-<refentry id="vidioc-decoder-cmd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DECODER_CMD</refname>
-    <refname>VIDIOC_TRY_DECODER_CMD</refname>
-    <refpurpose>Execute an decoder command</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_decoder_cmd *<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_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls control an audio/video (usually MPEG-) decoder.
-<constant>VIDIOC_DECODER_CMD</constant> sends a command to the
-decoder, <constant>VIDIOC_TRY_DECODER_CMD</constant> can be used to
-try a command without actually executing it. To send a command applications
-must initialize all fields of a &v4l2-decoder-cmd; and call
-<constant>VIDIOC_DECODER_CMD</constant> or <constant>VIDIOC_TRY_DECODER_CMD</constant>
-with a pointer to this structure.</para>
-
-    <para>The <structfield>cmd</structfield> field must contain the
-command code. Some commands use the <structfield>flags</structfield> field for
-additional information.
-</para>
-
-    <para>A <function>write</function>() or &VIDIOC-STREAMON; call sends an implicit
-START command to the decoder if it has not been started yet.
-</para>
-
-    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
-file descriptor sends an implicit immediate STOP command to the decoder, and all
-buffered data is discarded.</para>
-
-    <para>These ioctls are optional, not all drivers may support
-them. They were introduced in Linux 3.3.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-decoder-cmd">
-      <title>struct <structname>v4l2_decoder_cmd</structname></title>
-      <tgroup cols="5">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>cmd</structfield></entry>
-            <entry></entry>
-            <entry></entry>
-           <entry>The decoder command, see <xref linkend="decoder-cmds" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-            <entry></entry>
-            <entry></entry>
-           <entry>Flags to go with the command. If no flags are defined for
-this command, drivers and applications must set this field to zero.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-            <entry></entry>
-           <entry></entry>
-            <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-            <entry><structfield>start</structfield></entry>
-            <entry></entry>
-            <entry>Structure containing additional data for the
-<constant>V4L2_DEC_CMD_START</constant> command.</entry>
-         </row>
-         <row>
-            <entry></entry>
-            <entry></entry>
-           <entry>__s32</entry>
-           <entry><structfield>speed</structfield></entry>
-            <entry>Playback speed and direction. The playback speed is defined as
-<structfield>speed</structfield>/1000 of the normal speed. So 1000 is normal playback.
-Negative numbers denote reverse playback, so -1000 does reverse playback at normal
-speed. Speeds -1, 0 and 1 have special meanings: speed 0 is shorthand for 1000
-(normal playback). A speed of 1 steps just one frame forward, a speed of -1 steps
-just one frame back.
-           </entry>
-         </row>
-         <row>
-            <entry></entry>
-            <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>format</structfield></entry>
-            <entry>Format restrictions. This field is set by the driver, not the
-application. Possible values are <constant>V4L2_DEC_START_FMT_NONE</constant> if
-there are no format restrictions or <constant>V4L2_DEC_START_FMT_GOP</constant>
-if the decoder operates on full GOPs (<wordasword>Group Of Pictures</wordasword>).
-This is usually the case for reverse playback: the decoder needs full GOPs, which
-it can then play in reverse order. So to implement reverse playback the application
-must feed the decoder the last GOP in the video file, then the GOP before that, etc. etc.
-           </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-            <entry><structfield>stop</structfield></entry>
-            <entry></entry>
-            <entry>Structure containing additional data for the
-<constant>V4L2_DEC_CMD_STOP</constant> command.</entry>
-         </row>
-         <row>
-            <entry></entry>
-            <entry></entry>
-           <entry>__u64</entry>
-           <entry><structfield>pts</structfield></entry>
-            <entry>Stop playback at this <structfield>pts</structfield> or immediately
-if the playback is already past that timestamp. Leave to 0 if you want to stop after the
-last frame was decoded.
-           </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-            <entry><structfield>raw</structfield></entry>
-            <entry></entry>
-            <entry></entry>
-         </row>
-         <row>
-            <entry></entry>
-            <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>data</structfield>[16]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="decoder-cmds">
-      <title>Decoder Commands</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_DEC_CMD_START</constant></entry>
-           <entry>0</entry>
-           <entry>Start the decoder. When the decoder is already
-running or paused, this command will just change the playback speed.
-That means that calling <constant>V4L2_DEC_CMD_START</constant> when
-the decoder was paused will <emphasis>not</emphasis> resume the decoder.
-You have to explicitly call <constant>V4L2_DEC_CMD_RESUME</constant> for that.
-This command has one flag:
-<constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant>. If set, then audio will
-be muted when playing back at a non-standard speed.
-            </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_DEC_CMD_STOP</constant></entry>
-           <entry>1</entry>
-           <entry>Stop the decoder. When the decoder is already stopped,
-this command does nothing. This command has two flags:
-if <constant>V4L2_DEC_CMD_STOP_TO_BLACK</constant> is set, then the decoder will
-set the picture to black after it stopped decoding. Otherwise the last image will
-repeat. mem2mem decoders will stop producing new frames altogether. They will send
-a <constant>V4L2_EVENT_EOS</constant> event when the last frame has been decoded
-and all frames are ready to be dequeued and will set the
-<constant>V4L2_BUF_FLAG_LAST</constant> buffer flag on the last buffer of the
-capture queue to indicate there will be no new buffers produced to dequeue. This
-buffer may be empty, indicated by the driver setting the
-<structfield>bytesused</structfield> field to 0. Once the
-<constant>V4L2_BUF_FLAG_LAST</constant> flag was set, the
-<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl will not block anymore,
-but return an &EPIPE;.
-If <constant>V4L2_DEC_CMD_STOP_IMMEDIATELY</constant> is set, then the decoder
-stops immediately (ignoring the <structfield>pts</structfield> value), otherwise it
-will keep decoding until timestamp >= pts or until the last of the pending data from
-its internal buffers was decoded.
-</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_DEC_CMD_PAUSE</constant></entry>
-           <entry>2</entry>
-           <entry>Pause the decoder. When the decoder has not been
-started yet, the driver will return an &EPERM;. When the decoder is
-already paused, this command does nothing. This command has one flag:
-if <constant>V4L2_DEC_CMD_PAUSE_TO_BLACK</constant> is set, then set the
-decoder output to black when paused.
-</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_DEC_CMD_RESUME</constant></entry>
-           <entry>3</entry>
-           <entry>Resume decoding after a PAUSE command. When the
-decoder has not been started yet, the driver will return an &EPERM;.
-When the decoder is already running, this command does nothing. No
-flags are defined for this command.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>cmd</structfield> field is invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para>The application sent a PAUSE or RESUME command when
-the decoder was not running.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
deleted file mode 100644 (file)
index c9c3c77..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-<refentry id="vidioc-dqevent">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DQEVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DQEVENT</refname>
-    <refpurpose>Dequeue event</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_event
-*<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_DQEVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Dequeue an event from a video device. No input is required
-    for this ioctl. All the fields of the &v4l2-event; structure are
-    filled by the driver. The file handle will also receive exceptions
-    which the application may get by e.g. using the select system
-    call.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-event">
-      <title>struct <structname>v4l2_event</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-            <entry></entry>
-           <entry>Type of the event, see <xref linkend="event-type" />.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>u</structfield></entry>
-            <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-vsync;</entry>
-            <entry><structfield>vsync</structfield></entry>
-           <entry>Event data for event <constant>V4L2_EVENT_VSYNC</constant>.
-            </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-ctrl;</entry>
-            <entry><structfield>ctrl</structfield></entry>
-           <entry>Event data for event <constant>V4L2_EVENT_CTRL</constant>.
-            </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-frame-sync;</entry>
-            <entry><structfield>frame_sync</structfield></entry>
-           <entry>Event data for event
-           <constant>V4L2_EVENT_FRAME_SYNC</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-motion-det;</entry>
-            <entry><structfield>motion_det</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_MOTION_DET.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-src-change;</entry>
-            <entry><structfield>src_change</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_SOURCE_CHANGE.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-            <entry><structfield>data</structfield>[64]</entry>
-           <entry>Event data. Defined by the event type. The union
-            should be used to define easily accessible type for
-            events.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pending</structfield></entry>
-            <entry></entry>
-           <entry>Number of pending events excluding this one.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sequence</structfield></entry>
-            <entry></entry>
-           <entry>Event sequence number. The sequence number is
-           incremented for every subscribed event that takes place.
-           If sequence numbers are not contiguous it means that
-           events have been lost.
-           </entry>
-         </row>
-         <row>
-           <entry>struct timespec</entry>
-           <entry><structfield>timestamp</structfield></entry>
-            <entry></entry>
-           <entry>Event timestamp. The timestamp has been taken from the
-           <constant>CLOCK_MONOTONIC</constant> clock. To access the
-           same clock outside V4L2, use <function>clock_gettime(2)</function>.
-           </entry>
-         </row>
-         <row>
-           <entry>u32</entry>
-           <entry><structfield>id</structfield></entry>
-            <entry></entry>
-           <entry>The ID associated with the event source. If the event does not
-               have an associated ID (this depends on the event type), then this
-               is 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-            <entry></entry>
-           <entry>Reserved for future extensions. Drivers must set
-           the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="event-type">
-      <title>Event Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_ALL</constant></entry>
-           <entry>0</entry>
-           <entry>All events. V4L2_EVENT_ALL is valid only for
-           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
-           <entry>1</entry>
-           <entry>This event is triggered on the vertical sync.
-           This event has a &v4l2-event-vsync; associated with it.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_EOS</constant></entry>
-           <entry>2</entry>
-           <entry>This event is triggered when the end of a stream is reached.
-           This is typically used with MPEG decoders to report to the application
-           when the last of the MPEG stream has been decoded.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL</constant></entry>
-           <entry>3</entry>
-           <entry><para>This event requires that the <structfield>id</structfield>
-               matches the control ID from which you want to receive events.
-               This event is triggered if the control's value changes, if a
-               button control is pressed or if the control's flags change.
-               This event has a &v4l2-event-ctrl; associated with it. This struct
-               contains much of the same information as &v4l2-queryctrl; and
-               &v4l2-control;.</para>
-
-               <para>If the event is generated due to a call to &VIDIOC-S-CTRL; or
-               &VIDIOC-S-EXT-CTRLS;, then the event will <emphasis>not</emphasis> be sent to
-               the file handle that called the ioctl function. This prevents
-               nasty feedback loops. If you <emphasis>do</emphasis> want to get the
-               event, then set the <constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant>
-               flag.
-               </para>
-
-               <para>This event type will ensure that no information is lost when
-               more events are raised than there is room internally. In that
-               case the &v4l2-event-ctrl; of the second-oldest event is kept,
-               but the <structfield>changes</structfield> field of the
-               second-oldest event is ORed with the <structfield>changes</structfield>
-               field of the oldest event.</para>
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_FRAME_SYNC</constant></entry>
-           <entry>4</entry>
-           <entry>
-             <para>Triggered immediately when the reception of a
-             frame has begun. This event has a
-             &v4l2-event-frame-sync; associated with it.</para>
-
-             <para>If the hardware needs to be stopped in the case of a
-             buffer underrun it might not be able to generate this event.
-             In such cases the <structfield>frame_sequence</structfield>
-             field in &v4l2-event-frame-sync; will not be incremented. This
-             causes two consecutive frame sequence numbers to have n times
-             frame interval in between them.</para>
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_SOURCE_CHANGE</constant></entry>
-           <entry>5</entry>
-           <entry>
-             <para>This event is triggered when a source parameter change is
-              detected during runtime by the video device. It can be a
-              runtime resolution change triggered by a video decoder or the
-              format change happening on an input connector.
-              This event requires that the <structfield>id</structfield>
-              matches the input index (when used with a video device node)
-              or the pad index (when used with a subdevice node) from which
-              you want to receive events.</para>
-
-              <para>This event has a &v4l2-event-src-change; associated
-             with it. The <structfield>changes</structfield> bitfield denotes
-             what has changed for the subscribed pad. If multiple events
-             occurred before application could dequeue them, then the changes
-             will have the ORed value of all the events generated.</para>
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry>
-           <entry>6</entry>
-           <entry>
-             <para>Triggered whenever the motion detection state for one or more of the regions
-             changes. This event has a &v4l2-event-motion-det; associated with it.</para>
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
-           <entry>0x08000000</entry>
-           <entry>Base event number for driver-private events.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-vsync">
-      <title>struct <structname>v4l2_event_vsync</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The upcoming field. See &v4l2-field;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-ctrl">
-      <title>struct <structname>v4l2_event_ctrl</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>changes</structfield></entry>
-           <entry></entry>
-           <entry>A bitmask that tells what has changed. See <xref linkend="ctrl-changes-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>The type of the control. See &v4l2-ctrl-type;.</entry>
-         </row>
-         <row>
-           <entry>union (anonymous)</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>The 32-bit value of the control for 32-bit control types.
-               This is 0 for string controls since the value of a string
-               cannot be passed using &VIDIOC-DQEVENT;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s64</entry>
-           <entry><structfield>value64</structfield></entry>
-           <entry>The 64-bit value of the control for 64-bit control types.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>The control flags. See <xref linkend="control-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry></entry>
-           <entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry></entry>
-           <entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry></entry>
-           <entry>The step value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>default_value</structfield></entry>
-           <entry></entry>
-           <entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-frame-sync">
-      <title>struct <structname>v4l2_event_frame_sync</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>frame_sequence</structfield></entry>
-           <entry>
-             The sequence number of the frame being received.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-src-change">
-      <title>struct <structname>v4l2_event_src_change</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>changes</structfield></entry>
-           <entry>
-             A bitmask that tells what has changed. See <xref linkend="src-changes-flags" />.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-motion-det">
-      <title>struct <structname>v4l2_event_motion_det</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>
-             Currently only one flag is available: if <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant>
-             is set, then the <structfield>frame_sequence</structfield> field is valid,
-             otherwise that field should be ignored.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>frame_sequence</structfield></entry>
-           <entry>
-             The sequence number of the frame being received. Only valid if the
-             <constant>V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ</constant> flag was set.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>region_mask</structfield></entry>
-           <entry>
-             The bitmask of the regions that reported motion. There is at least one
-             region. If this field is 0, then no motion was detected at all.
-             If there is no <constant>V4L2_CID_DETECT_MD_REGION_GRID</constant> control
-             (see <xref linkend="detect-controls" />) to assign a different region
-             to each cell in the motion detection grid, then that all cells
-             are automatically assigned to the default region 0.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="ctrl-changes-flags">
-      <title>Control Changes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This control event was triggered because the value of the control
-               changed. Special cases: Volatile controls do no generate this event;
-               If a control has the <constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant>
-               flag set, then this event is sent as well, regardless its value.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This control event was triggered because the control flags
-               changed.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_CTRL_CH_RANGE</constant></entry>
-           <entry>0x0004</entry>
-           <entry>This control event was triggered because the minimum,
-           maximum, step or the default value of the control changed.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="src-changes-flags">
-      <title>Source Changes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_SRC_CH_RESOLUTION</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This event gets triggered when a resolution change is
-           detected at an input. This can come from an input connector or
-           from a video decoder.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
deleted file mode 100644 (file)
index ca9ffce..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-<refentry id="vidioc-dv-timings-cap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DV_TIMINGS_CAP, VIDIOC_SUBDEV_DV_TIMINGS_CAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DV_TIMINGS_CAP</refname>
-    <refname>VIDIOC_SUBDEV_DV_TIMINGS_CAP</refname>
-    <refpurpose>The capabilities of the Digital Video receiver/transmitter</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_dv_timings_cap *<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_DV_TIMINGS_CAP, VIDIOC_SUBDEV_DV_TIMINGS_CAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the capabilities of the DV receiver/transmitter applications initialize the
-<structfield>pad</structfield> field to 0, zero the reserved array of &v4l2-dv-timings-cap;
-and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node
-and the driver will fill in the structure. Note that drivers may return
-different values after switching the video input or output.</para>
-
-    <para>When implemented by the driver DV capabilities of subdevices can be
-queried by calling the <constant>VIDIOC_SUBDEV_DV_TIMINGS_CAP</constant> ioctl
-directly on a subdevice node. The capabilities are specific to inputs (for DV
-receivers) or outputs (for DV transmitters), applications must specify the
-desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield>
-field and zero the <structfield>reserved</structfield> array. Attempts to query
-capabilities on a pad that doesn't support them will return an &EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-bt-timings-cap">
-      <title>struct <structname>v4l2_bt_timings_cap</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_width</structfield></entry>
-           <entry>Minimum width of the active video in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_width</structfield></entry>
-           <entry>Maximum width of the active video in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_height</structfield></entry>
-           <entry>Minimum height of the active video in lines.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_height</structfield></entry>
-           <entry>Maximum height of the active video in lines.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>min_pixelclock</structfield></entry>
-           <entry>Minimum pixelclock frequency in Hz.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>max_pixelclock</structfield></entry>
-           <entry>Maximum pixelclock frequency in Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>standards</structfield></entry>
-           <entry>The video standard(s) supported by the hardware.
-           See <xref linkend="dv-bt-standards"/> for a list of standards.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>Several flags giving more information about the capabilities.
-           See <xref linkend="dv-bt-cap-capabilities"/> for a description of the flags.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[16]</entry>
-           <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-timings-cap">
-      <title>struct <structname>v4l2_dv_timings_cap</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API. This field
-           is only used when operating on a subdevice node. When operating on a
-           video node applications must set this field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield></structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-bt-timings-cap;</entry>
-           <entry><structfield>bt</structfield></entry>
-           <entry>BT.656/1120 timings capabilities of the hardware.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>raw_data</structfield>[32]</entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="dv-bt-cap-capabilities">
-      <title>DV BT Timing capabilities</title>
-      <tgroup cols="2">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Flag</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_CAP_INTERLACED</entry>
-           <entry>Interlaced formats are supported.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_CAP_PROGRESSIVE</entry>
-           <entry>Progressive formats are supported.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_CAP_REDUCED_BLANKING</entry>
-           <entry>CVT/GTF specific: the timings can make use of reduced blanking (CVT)
-or the 'Secondary GTF' curve (GTF).
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_CAP_CUSTOM</entry>
-           <entry>Can support non-standard timings, i.e. timings not belonging to the
-standards set in the <structfield>standards</structfield> field.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
deleted file mode 100644 (file)
index 70a4a08..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-<refentry id="vidioc-encoder-cmd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENCODER_CMD</refname>
-    <refname>VIDIOC_TRY_ENCODER_CMD</refname>
-    <refpurpose>Execute an encoder command</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_encoder_cmd *<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_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls control an audio/video (usually MPEG-) encoder.
-<constant>VIDIOC_ENCODER_CMD</constant> sends a command to the
-encoder, <constant>VIDIOC_TRY_ENCODER_CMD</constant> can be used to
-try a command without actually executing it.</para>
-
-    <para>To send a command applications must initialize all fields of a
-    &v4l2-encoder-cmd; and call
-    <constant>VIDIOC_ENCODER_CMD</constant> or
-    <constant>VIDIOC_TRY_ENCODER_CMD</constant> with a pointer to this
-    structure.</para>
-
-    <para>The <structfield>cmd</structfield> field must contain the
-command code. The <structfield>flags</structfield> field is currently
-only used by the STOP command and contains one bit: If the
-<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
-encoding will continue until the end of the current <wordasword>Group
-Of Pictures</wordasword>, otherwise it will stop immediately.</para>
-
-    <para>A <function>read</function>() or &VIDIOC-STREAMON; call sends an implicit
-START command to the encoder if it has not been started yet. After a STOP command,
-<function>read</function>() calls will read the remaining data
-buffered by the driver. When the buffer is empty,
-<function>read</function>() will return zero and the next
-<function>read</function>() call will restart the encoder.</para>
-
-    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
-file descriptor sends an implicit immediate STOP to the encoder, and all buffered
-data is discarded.</para>
-
-    <para>These ioctls are optional, not all drivers may support
-them. They were introduced in Linux 2.6.21.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-encoder-cmd">
-      <title>struct <structname>v4l2_encoder_cmd</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>cmd</structfield></entry>
-           <entry>The encoder command, see <xref linkend="encoder-cmds" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags to go with the command, see <xref
-               linkend="encoder-flags" />. If no flags are defined for
-this command, drivers and applications must set this field to
-zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>data</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="encoder-cmds">
-      <title>Encoder Commands</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_CMD_START</constant></entry>
-           <entry>0</entry>
-           <entry>Start the encoder. When the encoder is already
-running or paused, this command does nothing. No flags are defined for
-this command.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_STOP</constant></entry>
-           <entry>1</entry>
-           <entry>Stop the encoder. When the
-<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
-encoding will continue until the end of the current <wordasword>Group
-Of Pictures</wordasword>, otherwise encoding will stop immediately.
-When the encoder is already stopped, this command does
-nothing. mem2mem encoders will send a <constant>V4L2_EVENT_EOS</constant> event
-when the last frame has been encoded and all frames are ready to be dequeued and
-will set the <constant>V4L2_BUF_FLAG_LAST</constant> buffer flag on the last
-buffer of the capture queue to indicate there will be no new buffers produced to
-dequeue. This buffer may be empty, indicated by the driver setting the
-<structfield>bytesused</structfield> field to 0. Once the
-<constant>V4L2_BUF_FLAG_LAST</constant> flag was set, the
-<link linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl will not block anymore,
-but return an &EPIPE;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_PAUSE</constant></entry>
-           <entry>2</entry>
-           <entry>Pause the encoder. When the encoder has not been
-started yet, the driver will return an &EPERM;. When the encoder is
-already paused, this command does nothing. No flags are defined for
-this command.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_RESUME</constant></entry>
-           <entry>3</entry>
-           <entry>Resume encoding after a PAUSE command. When the
-encoder has not been started yet, the driver will return an &EPERM;.
-When the encoder is already running, this command does nothing. No
-flags are defined for this command.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="encoder-flags">
-      <title>Encoder Command Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant></entry>
-           <entry>0x0001</entry>
-           <entry>Stop encoding at the end of the current <wordasword>Group Of
-Pictures</wordasword>, rather than immediately.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>cmd</structfield> field is invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para>The application sent a PAUSE or RESUME command when
-the encoder was not running.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
deleted file mode 100644 (file)
index 9b3d420..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<refentry id="vidioc-enum-dv-timings">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_DV_TIMINGS, VIDIOC_SUBDEV_ENUM_DV_TIMINGS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_DV_TIMINGS</refname>
-    <refname>VIDIOC_SUBDEV_ENUM_DV_TIMINGS</refname>
-    <refpurpose>Enumerate supported Digital Video timings</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_enum_dv_timings *<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_ENUM_DV_TIMINGS, VIDIOC_SUBDEV_ENUM_DV_TIMINGS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>While some DV receivers or transmitters support a wide range of timings, others
-support only a limited number of timings. With this ioctl applications can enumerate a list
-of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other
-standards or even custom timings that are not in this list.</para>
-
-    <para>To query the available timings, applications initialize the
-<structfield>index</structfield> field, set the <structfield>pad</structfield> field to 0,
-zero the reserved array of &v4l2-enum-dv-timings; and call the
-<constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a
-pointer to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>. Note that drivers may enumerate a
-different set of DV timings after switching the video input or
-output.</para>
-
-    <para>When implemented by the driver DV timings of subdevices can be queried
-by calling the <constant>VIDIOC_SUBDEV_ENUM_DV_TIMINGS</constant> ioctl directly
-on a subdevice node. The DV timings are specific to inputs (for DV receivers) or
-outputs (for DV transmitters), applications must specify the desired pad number
-in the &v4l2-enum-dv-timings; <structfield>pad</structfield> field. Attempts to
-enumerate timings on a pad that doesn't support them will return an &EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-enum-dv-timings">
-      <title>struct <structname>v4l2_enum_dv_timings</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the DV timings, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API. This field
-           is only used when operating on a subdevice node. When operating on a
-           video node applications must set this field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-dv-timings;</entry>
-           <entry><structfield>timings</structfield></entry>
-           <entry>The timings.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-enum-dv-timings; <structfield>index</structfield>
-is out of bounds or the <structfield>pad</structfield> number is invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Digital video presets are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
deleted file mode 100644 (file)
index f8dfeed..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<refentry id="vidioc-enum-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FMT</refname>
-    <refpurpose>Enumerate image formats</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_fmtdesc
-*<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_ENUM_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To enumerate image formats applications initialize the
-<structfield>type</structfield> and <structfield>index</structfield>
-field of &v4l2-fmtdesc; and call the
-<constant>VIDIOC_ENUM_FMT</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL;. All formats are enumerable by beginning at index zero and
-incrementing by one until <errorcode>EINVAL</errorcode> is
-returned.</para>
-
-    <para>Note that after switching input or output the list of enumerated image
-formats may be different.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-fmtdesc">
-      <title>struct <structname>v4l2_fmtdesc</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by
-the application. This is in no way related to the <structfield>
-pixelformat</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here:
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>. See <xref linkend="v4l2-buf-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>See <xref linkend="fmtdesc-flags" /></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>description</structfield>[32]</entry>
-           <entry>Description of the format, a NUL-terminated ASCII
-string. This information is intended for the user, for example: "YUV
-4:2:2".</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixelformat</structfield></entry>
-           <entry>The image format identifier. This is a
-four character code as computed by the v4l2_fourcc()
-macro:</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para><programlisting id="v4l2-fourcc">
-#define v4l2_fourcc(a,b,c,d) (((__u32)(a)&lt;&lt;0)|((__u32)(b)&lt;&lt;8)|((__u32)(c)&lt;&lt;16)|((__u32)(d)&lt;&lt;24))
-</programlisting></para><para>Several image formats are already
-defined by this specification in <xref linkend="pixfmt" />. Note these
-codes are not the same as those used in the Windows world.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="fmtdesc-flags">
-      <title>Image Format Description Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FMT_FLAG_COMPRESSED</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This is a compressed format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FMT_FLAG_EMULATED</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This format is not native to the device but emulated
-through software (usually libv4l2), where possible try to use a native format
-instead for better performance.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-fmtdesc; <structfield>type</structfield>
-is not supported or the <structfield>index</structfield> is out of
-bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml
deleted file mode 100644 (file)
index 7c839ab..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-<refentry id="vidioc-enum-frameintervals">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FRAMEINTERVALS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FRAMEINTERVALS</refname>
-    <refpurpose>Enumerate frame intervals</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_frmivalenum *<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_ENUM_FRAMEINTERVALS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a &v4l2-frmivalenum; structure that
-contains a pixel format and size and receives a frame interval.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl allows applications to enumerate all frame
-intervals that the device supports for the given pixel format and
-frame size.</para>
-    <para>The supported pixel formats and frame sizes can be obtained
-by using the &VIDIOC-ENUM-FMT; and &VIDIOC-ENUM-FRAMESIZES;
-functions.</para>
-    <para>The return value and the content of the
-<structfield>v4l2_frmivalenum.type</structfield> field depend on the
-type of frame intervals the device supports. Here are the semantics of
-the function for the different cases:</para>
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Discrete:</emphasis> The function
-returns success if the given index value (zero-based) is valid. The
-application should increase the index by one for each call until
-<constant>EINVAL</constant> is returned. The `v4l2_frmivalenum.type`
-field is set to `V4L2_FRMIVAL_TYPE_DISCRETE` by the driver. Of the
-union only the `discrete` member is valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Step-wise:</emphasis> The function
-returns success if the given index value is zero and
-<constant>EINVAL</constant> for any other index value. The
-<structfield>v4l2_frmivalenum.type</structfield> field is set to
-<constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant> by the driver. Of the
-union only the <structfield>stepwise</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Continuous:</emphasis> This is a
-special case of the step-wise type above. The function returns success
-if the given index value is zero and <constant>EINVAL</constant> for
-any other index value. The
-<structfield>v4l2_frmivalenum.type</structfield> field is set to
-<constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant> by the driver. Of
-the union only the <structfield>stepwise</structfield> member is valid
-and the <structfield>step</structfield> value is set to 1.</para>
-      </listitem>
-    </itemizedlist>
-
-    <para>When the application calls the function with index zero, it
-must check the <structfield>type</structfield> field to determine the
-type of frame interval enumeration the device supports. Only for the
-<constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant> type does it make
-sense to increase the index value to receive more frame
-intervals.</para>
-    <para>Note that the order in which the frame intervals are
-returned has no special meaning. In particular does it not say
-anything about potential default frame intervals.</para>
-    <para>Applications can assume that the enumeration data does not
-change without any interaction from the application itself. This means
-that the enumeration data is consistent if the application does not
-perform any other ioctl calls while it runs the frame interval
-enumeration.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Notes</title>
-
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Frame intervals and frame
-rates:</emphasis> The V4L2 API uses frame intervals instead of frame
-rates. Given the frame interval the frame rate can be computed as
-follows:<screen>frame_rate = 1 / frame_interval</screen></para>
-      </listitem>
-    </itemizedlist>
-
-  </refsect1>
-
-  <refsect1>
-    <title>Structs</title>
-
-    <para>In the structs below, <emphasis>IN</emphasis> denotes a
-value that has to be filled in by the application,
-<emphasis>OUT</emphasis> denotes values that the driver fills in. The
-application should zero out all members except for the
-<emphasis>IN</emphasis> fields.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frmival-stepwise">
-      <title>struct <structname>v4l2_frmival_stepwise</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>min</structfield></entry>
-           <entry>Minimum frame interval [s].</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>max</structfield></entry>
-           <entry>Maximum frame interval [s].</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry>Frame interval step size [s].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmivalenum">
-      <title>struct <structname>v4l2_frmivalenum</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>IN: Index of the given frame interval in the
-enumeration.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixel_format</structfield></entry>
-           <entry></entry>
-           <entry>IN: Pixel format for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry></entry>
-           <entry>IN: Frame width for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry></entry>
-           <entry>IN: Frame height for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>OUT: Frame interval type the device supports.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>OUT: Frame interval with the given index.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>discrete</structfield></entry>
-           <entry>Frame interval [s].</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmival-stepwise;</entry>
-           <entry><structfield>stepwise</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[2]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved space for future use. Must be zeroed by drivers and
-           applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    <title>Enums</title>
-
-    <table pgwide="1" frame="none" id="v4l2-frmivaltypes">
-      <title>enum <structname>v4l2_frmivaltypes</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant></entry>
-           <entry>1</entry>
-           <entry>Discrete frame interval.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant></entry>
-           <entry>2</entry>
-           <entry>Continuous frame interval.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant></entry>
-           <entry>3</entry>
-           <entry>Step-wise defined frame interval.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml
deleted file mode 100644 (file)
index 9ed68ac..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-<refentry id="vidioc-enum-framesizes">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FRAMESIZES</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FRAMESIZES</refname>
-    <refpurpose>Enumerate frame sizes</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_frmsizeenum *<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_ENUM_FRAMESIZES</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a &v4l2-frmsizeenum; that contains an index
-and pixel format and receives a frame width and height.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl allows applications to enumerate all frame sizes
-(&ie; width and height in pixels) that the device supports for the
-given pixel format.</para>
-    <para>The supported pixel formats can be obtained by using the
-&VIDIOC-ENUM-FMT; function.</para>
-    <para>The return value and the content of the
-<structfield>v4l2_frmsizeenum.type</structfield> field depend on the
-type of frame sizes the device supports. Here are the semantics of the
-function for the different cases:</para>
-
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Discrete:</emphasis> The function
-returns success if the given index value (zero-based) is valid. The
-application should increase the index by one for each call until
-<constant>EINVAL</constant> is returned. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> by the driver. Of the
-union only the <structfield>discrete</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Step-wise:</emphasis> The function
-returns success if the given index value is zero and
-<constant>EINVAL</constant> for any other index value. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant> by the driver. Of the
-union only the <structfield>stepwise</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Continuous:</emphasis> This is a
-special case of the step-wise type above. The function returns success
-if the given index value is zero and <constant>EINVAL</constant> for
-any other index value. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant> by the driver. Of
-the union only the <structfield>stepwise</structfield> member is valid
-and the <structfield>step_width</structfield> and
-<structfield>step_height</structfield> values are set to 1.</para>
-      </listitem>
-    </itemizedlist>
-
-    <para>When the application calls the function with index zero, it
-must check the <structfield>type</structfield> field to determine the
-type of frame size enumeration the device supports. Only for the
-<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> type does it make
-sense to increase the index value to receive more frame sizes.</para>
-    <para>Note that the order in which the frame sizes are returned
-has no special meaning. In particular does it not say anything about
-potential default format sizes.</para>
-    <para>Applications can assume that the enumeration data does not
-change without any interaction from the application itself. This means
-that the enumeration data is consistent if the application does not
-perform any other ioctl calls while it runs the frame size
-enumeration.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Structs</title>
-
-    <para>In the structs below, <emphasis>IN</emphasis> denotes a
-value that has to be filled in by the application,
-<emphasis>OUT</emphasis> denotes values that the driver fills in. The
-application should zero out all members except for the
-<emphasis>IN</emphasis> fields.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsize-discrete">
-      <title>struct <structname>v4l2_frmsize_discrete</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the frame [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the frame [pixel].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsize-stepwise">
-      <title>struct <structname>v4l2_frmsize_stepwise</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_width</structfield></entry>
-           <entry>Minimum frame width [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_width</structfield></entry>
-           <entry>Maximum frame width [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>step_width</structfield></entry>
-           <entry>Frame width step size [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_height</structfield></entry>
-           <entry>Minimum frame height [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_height</structfield></entry>
-           <entry>Maximum frame height [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>step_height</structfield></entry>
-           <entry>Frame height step size [pixel].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsizeenum">
-      <title>struct <structname>v4l2_frmsizeenum</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>IN: Index of the given frame size in the enumeration.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixel_format</structfield></entry>
-           <entry></entry>
-           <entry>IN: Pixel format for which the frame sizes are enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>OUT: Frame size type the device supports.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>OUT: Frame size with the given index.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmsize-discrete;</entry>
-           <entry><structfield>discrete</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmsize-stepwise;</entry>
-           <entry><structfield>stepwise</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[2]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved space for future use. Must be zeroed by drivers and
-           applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    <title>Enums</title>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsizetypes">
-      <title>enum <structname>v4l2_frmsizetypes</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant></entry>
-           <entry>1</entry>
-           <entry>Discrete frame size.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant></entry>
-           <entry>2</entry>
-           <entry>Continuous frame size.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant></entry>
-           <entry>3</entry>
-           <entry>Step-wise defined frame size.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml b/Documentation/DocBook/media/v4l/vidioc-enum-freq-bands.xml
deleted file mode 100644 (file)
index a0608ab..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<refentry id="vidioc-enum-freq-bands">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FREQ_BANDS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FREQ_BANDS</refname>
-    <refpurpose>Enumerate supported frequency bands</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_frequency_band
-*<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_ENUM_FREQ_BANDS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Enumerates the frequency bands that a tuner or modulator supports.
-To do this applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield> and <structfield>index</structfield> fields,
-and zero out the <structfield>reserved</structfield> array of a &v4l2-frequency-band; and
-call the <constant>VIDIOC_ENUM_FREQ_BANDS</constant> ioctl with a pointer
-to this structure.</para>
-
-    <para>This ioctl is supported if the <constant>V4L2_TUNER_CAP_FREQ_BANDS</constant> capability
-    of the corresponding tuner/modulator is set.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frequency-band">
-      <title>struct <structname>v4l2_frequency_band</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>The tuner or modulator index number. This is the
-same value as in the &v4l2-input; <structfield>tuner</structfield>
-field and the &v4l2-tuner; <structfield>index</structfield> field, or
-the &v4l2-output; <structfield>modulator</structfield> field and the
-&v4l2-modulator; <structfield>index</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The type must be set
-to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename>
-device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant>
-for all others. Set this field to <constant>V4L2_TUNER_RADIO</constant> for
-modulators (currently only radio modulators are supported).
-See <xref linkend="v4l2-tuner-type" /></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the frequency band, set by the application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry spanname="hspan">The tuner/modulator capability flags for
-this frequency band, see <xref linkend="tuner-capability" />. The <constant>V4L2_TUNER_CAP_LOW</constant>
-or <constant>V4L2_TUNER_CAP_1HZ</constant> capability must be the same for all frequency bands of the selected tuner/modulator.
-So either all bands have that capability set, or none of them have that capability.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry spanname="hspan">The lowest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, for this frequency band. A 1 Hz unit is used when the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry spanname="hspan">The highest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, for this frequency band. A 1 Hz unit is used when the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>modulation</structfield></entry>
-           <entry spanname="hspan">The supported modulation systems of this frequency band.
-           See <xref linkend="band-modulation" />. Note that currently only one
-           modulation system per frequency band is supported. More work will need to
-           be done if multiple modulation systems are possible. Contact the
-           linux-media mailing list (&v4l-ml;) if you need that functionality.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers
-           must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="band-modulation">
-      <title>Band Modulation Systems</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_BAND_MODULATION_VSB</constant></entry>
-           <entry>0x02</entry>
-           <entry>Vestigial Sideband modulation, used for analog TV.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BAND_MODULATION_FM</constant></entry>
-           <entry>0x04</entry>
-           <entry>Frequency Modulation, commonly used for analog radio.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BAND_MODULATION_AM</constant></entry>
-           <entry>0x08</entry>
-           <entry>Amplitude Modulation, commonly used for analog radio.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>tuner</structfield> or <structfield>index</structfield>
-is out of bounds or the <structfield>type</structfield> field is wrong.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml
deleted file mode 100644 (file)
index ea816ab..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<refentry id="vidioc-enumaudio">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMAUDIO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMAUDIO</refname>
-    <refpurpose>Enumerate audio inputs</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_audio *<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_ENUMAUDIO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of an audio input applications
-initialize the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-audio;
-and call the <constant>VIDIOC_ENUMAUDIO</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all audio
-inputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>See <xref linkend="vidioc-g-audio" /> for a description of
-&v4l2-audio;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the audio input is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml
deleted file mode 100644 (file)
index 2e87ced..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<refentry id="vidioc-enumaudioout">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMAUDOUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMAUDOUT</refname>
-    <refpurpose>Enumerate audio outputs</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_audioout *<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_ENUMAUDOUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of an audio output applications
-initialize the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-audioout; and
-call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all audio
-outputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Note connectors on a TV card to loop back the received audio
-signal to a sound card are not audio outputs in this sense.</para>
-
-    <para>See <xref linkend="vidioc-g-audioout" /> for a description of
-&v4l2-audioout;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the audio output is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
deleted file mode 100644 (file)
index 603fece..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-<refentry id="vidioc-enuminput">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMINPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMINPUT</refname>
-    <refpurpose>Enumerate video inputs</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_input
-*<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_ENUMINPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video input applications
-initialize the <structfield>index</structfield> field of &v4l2-input;
-and call the <constant>VIDIOC_ENUMINPUT</constant> ioctl with a
-pointer to this structure. Drivers fill the rest of the structure or
-return an &EINVAL; when the index is out of bounds. To enumerate all
-inputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-input">
-      <title>struct <structname>v4l2_input</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the input, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the video input, a NUL-terminated ASCII
-string, for example: "Vin (Composite 2)". This information is intended
-for the user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the input, see <xref
-               linkend="input-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audioset</structfield></entry>
-           <entry><para>Drivers can enumerate up to 32 video and
-audio inputs. This field shows which audio inputs were selectable as
-audio source if this was the currently selected video input. It is a
-bit mask. The LSB corresponds to audio input 0, the MSB to input 31.
-Any number of bits can be set, or none.</para><para>When the driver
-does not enumerate audio inputs no bits must be set. Applications
-shall not interpret this as lack of audio support. Some drivers
-automatically select audio sources and do not enumerate them since
-there is no choice anyway.</para><para>For details on audio inputs and
-how to select the current input see <xref
-                 linkend="audio" />.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>Capture devices can have zero or more tuners (RF
-demodulators). When the <structfield>type</structfield> is set to
-<constant>V4L2_INPUT_TYPE_TUNER</constant> this is an RF connector and
-this field identifies the tuner. It corresponds to
-&v4l2-tuner; field <structfield>index</structfield>. For details on
-tuners see <xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>std</structfield></entry>
-           <entry>Every video input supports one or more different
-video standards. This field is a set of all supported standards. For
-details on video standards and how to switch see <xref
-linkend="standard" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>status</structfield></entry>
-           <entry>This field provides status information about the
-input. See <xref linkend="input-status" /> for flags.
-With the exception of the sensor orientation bits <structfield>status</structfield> is only valid when this is the
-current input.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>This field provides capabilities for the
-input. See <xref linkend="input-capabilities" /> for flags.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="input-type">
-      <title>Input Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
-           <entry>1</entry>
-           <entry>This input uses a tuner (RF demodulator).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
-           <entry>2</entry>
-           <entry>Analog baseband input, for example CVBS /
-Composite Video, S-Video, RGB.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Status flags based on proposal by Mark McClelland,
-video4linux-list@redhat.com on 18 Oct 2002, subject "Re: [V4L] Re:
-v4l2 api". "Why are some of them inverted? So that the driver doesn't
-have to lie about the status in cases where it can't tell one way or
-the other. Plus, a status of zero would generally mean that everything
-is OK." -->
-
-    <table frame="none" pgwide="1" id="input-status">
-      <title>Input Status Flags</title>
-      <tgroup cols="3">
-       <colspec colname="c1" />
-       <colspec colname="c2" align="center" />
-       <colspec colname="c3" />
-       <spanspec namest="c1" nameend="c3" spanname="hspan"
-         align="left" />
-       <tbody valign="top">
-         <row>
-           <entry spanname="hspan">General</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_POWER</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>Attached device is off.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_SIGNAL</constant></entry>
-           <entry>0x00000002</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_COLOR</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>The hardware supports color decoding, but does not
-detect color modulation in the signal.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Sensor Orientation</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_HFLIP</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>The input is connected to a device that produces a signal
-that is flipped horizontally and does not correct this before passing the
-signal to userspace.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_VFLIP</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>The input is connected to a device that produces a signal
-that is flipped vertically and does not correct this before passing the
-signal to userspace. Note that a 180 degree rotation is the same as HFLIP | VFLIP</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Analog Video</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_H_LOCK</constant></entry>
-           <entry>0x00000100</entry>
-           <entry>No horizontal sync lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_COLOR_KILL</constant></entry>
-           <entry>0x00000200</entry>
-           <entry>A color killer circuit automatically disables color
-decoding when it detects no color modulation. When this flag is set
-the color killer is enabled <emphasis>and</emphasis> has shut off
-color decoding.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Digital Video</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_SYNC</constant></entry>
-           <entry>0x00010000</entry>
-           <entry>No synchronization lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_EQU</constant></entry>
-           <entry>0x00020000</entry>
-           <entry>No equalizer lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_CARRIER</constant></entry>
-           <entry>0x00040000</entry>
-           <entry>Carrier recovery failed.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">VCR and Set-Top Box</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_MACROVISION</constant></entry>
-           <entry>0x01000000</entry>
-           <entry>Macrovision is an analog copy prevention system
-mangling the video signal to confuse video recorders. When this
-flag is set Macrovision has been detected.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_ACCESS</constant></entry>
-           <entry>0x02000000</entry>
-           <entry>Conditional access denied.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_VTR</constant></entry>
-           <entry>0x04000000</entry>
-           <entry>VTR time constant. [?]</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Capability flags based on video timings RFC by Muralidharan
-Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
-input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
-       -->
-    <table frame="none" pgwide="1" id="input-capabilities">
-      <title>Input capabilities</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_IN_CAP_DV_TIMINGS</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>This input supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_CAP_STD</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_CAP_NATIVE_SIZE</constant></entry>
-           <entry>0x00000008</entry>
-           <entry>This input supports setting the native size using
-           the <constant>V4L2_SEL_TGT_NATIVE_SIZE</constant>
-           selection target, see <xref
-           linkend="v4l2-selections-common"/>.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-input; <structfield>index</structfield> is
-out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
deleted file mode 100644 (file)
index 773fb12..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-<refentry id="vidioc-enumoutput">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMOUTPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMOUTPUT</refname>
-    <refpurpose>Enumerate video outputs</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_output *<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_ENUMOUTPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video outputs applications
-initialize the <structfield>index</structfield> field of &v4l2-output;
-and call the <constant>VIDIOC_ENUMOUTPUT</constant> ioctl with a
-pointer to this structure. Drivers fill the rest of the structure or
-return an &EINVAL; when the index is out of bounds. To enumerate all
-outputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-output">
-      <title>struct <structname>v4l2_output</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the output, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the video output, a NUL-terminated ASCII
-string, for example: "Vout". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the output, see <xref
-               linkend="output-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audioset</structfield></entry>
-           <entry><para>Drivers can enumerate up to 32 video and
-audio outputs. This field shows which audio outputs were
-selectable as the current output if this was the currently selected
-video output. It is a bit mask. The LSB corresponds to audio output 0,
-the MSB to output 31. Any number of bits can be set, or
-none.</para><para>When the driver does not enumerate audio outputs no
-bits must be set. Applications shall not interpret this as lack of
-audio support. Drivers may automatically select audio outputs without
-enumerating them.</para><para>For details on audio outputs and how to
-select the current output see <xref linkend="audio" />.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>modulator</structfield></entry>
-           <entry>Output devices can have zero or more RF modulators.
-When the <structfield>type</structfield> is
-<constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> this is an RF
-connector and this field identifies the modulator. It corresponds to
-&v4l2-modulator; field <structfield>index</structfield>. For details
-on modulators see <xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>std</structfield></entry>
-           <entry>Every video output supports one or more different
-video standards. This field is a set of all supported standards. For
-details on video standards and how to switch see <xref
-               linkend="standard" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>This field provides capabilities for the
-output. See <xref linkend="output-capabilities" /> for flags.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="output-type">
-      <title>Output Type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_MODULATOR</constant></entry>
-           <entry>1</entry>
-           <entry>This output is an analog TV modulator.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_ANALOG</constant></entry>
-           <entry>2</entry>
-           <entry>Analog baseband output, for example Composite /
-CVBS, S-Video, RGB.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>[?]</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Capabilities flags based on video timings RFC by Muralidharan
-Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
-input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
-       -->
-    <table frame="none" pgwide="1" id="output-capabilities">
-      <title>Output capabilities</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_OUT_CAP_DV_TIMINGS</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>This output supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUT_CAP_STD</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUT_CAP_NATIVE_SIZE</constant></entry>
-           <entry>0x00000008</entry>
-           <entry>This output supports setting the native size using
-           the <constant>V4L2_SEL_TGT_NATIVE_SIZE</constant>
-           selection target, see <xref
-           linkend="v4l2-selections-common"/>.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-output; <structfield>index</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml
deleted file mode 100644 (file)
index f18454e..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-<refentry id="vidioc-enumstd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMSTD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMSTD</refname>
-    <refpurpose>Enumerate supported video standards</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_standard *<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_ENUMSTD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video standard,
-especially a custom (driver defined) one, applications initialize the
-<structfield>index</structfield> field of &v4l2-standard; and call the
-<constant>VIDIOC_ENUMSTD</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all standards
-applications shall begin  at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
-different set of standards after switching the video input or
-output.<footnote>
-       <para>The supported standards may overlap and we need an
-unambiguous set to find the current standard returned by
-<constant>VIDIOC_G_STD</constant>.</para>
-      </footnote></para>
-
-    <table pgwide="1" frame="none" id="v4l2-standard">
-      <title>struct <structname>v4l2_standard</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the video standard, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>The bits in this field identify the standard as
-one of the common standards listed in <xref linkend="v4l2-std-id" />,
-or if bits 32 to 63 are set as custom standards. Multiple bits can be
-set if the hardware does not distinguish between these standards,
-however separate indices do not indicate the opposite. The
-<structfield>id</structfield> must be unique. No other enumerated
-<structname>v4l2_standard</structname> structure, for this input or
-output anyway, can contain the same set of bits.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[24]</entry>
-           <entry>Name of the standard, a NUL-terminated ASCII
-string, for example: "PAL-B/G", "NTSC Japan". This information is
-intended for the user.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>frameperiod</structfield></entry>
-           <entry>The frame period (not field period) is numerator
-/ denominator. For example M/NTSC has a frame period of 1001 /
-30000 seconds.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>framelines</structfield></entry>
-           <entry>Total lines per frame including blanking,
-e.&nbsp;g. 625 for B/PAL.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-fract">
-      <title>struct <structname>v4l2_fract</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>numerator</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>denominator</structfield></entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-std-id">
-      <title>typedef <structname>v4l2_std_id</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>v4l2_std_id</structfield></entry>
-           <entry>This type is a set, each bit representing another
-video standard as listed below and in <xref
-linkend="video-standards" />. The 32 most significant bits are reserved
-for custom (driver defined) video standards.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para><programlisting>
-#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
-#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
-#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
-#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
-#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
-#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
-#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
-#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
-
-#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
-#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
-#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
-#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
-</programlisting></para><para><constant>V4L2_STD_PAL_60</constant> is
-a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color
-modulation with a 4.43 MHz color subcarrier. Some PAL video recorders
-can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic
-PAL TV.</para><para><programlisting>
-#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
-#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
-#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
-</programlisting></para><para><constant>V4L2_STD_NTSC_443</constant>
-is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC
-color modulation with a 4.43 MHz color
-subcarrier.</para><para><programlisting>
-#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
-
-#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
-#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
-#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
-#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
-#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
-#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
-#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
-#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
-
-/* ATSC/HDTV */
-#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
-#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
-</programlisting></para><para><!-- ATSC proposal by Mark McClelland,
-video4linux-list@redhat.com on 17 Oct 2002
---><constant>V4L2_STD_ATSC_8_VSB</constant> and
-<constant>V4L2_STD_ATSC_16_VSB</constant> are U.S. terrestrial digital
-TV standards. Presently the V4L2 API does not support digital TV. See
-also the Linux DVB API at <ulink
-url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
-<para><programlisting>
-#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
-                                V4L2_STD_PAL_B1        |\
-                                V4L2_STD_PAL_G)
-#define V4L2_STD_B              (V4L2_STD_PAL_B         |\
-                                V4L2_STD_PAL_B1        |\
-                                V4L2_STD_SECAM_B)
-#define V4L2_STD_GH             (V4L2_STD_PAL_G         |\
-                                V4L2_STD_PAL_H         |\
-                                V4L2_STD_SECAM_G       |\
-                                V4L2_STD_SECAM_H)
-#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
-                                V4L2_STD_PAL_D1        |\
-                                V4L2_STD_PAL_K)
-#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
-                                V4L2_STD_PAL_DK        |\
-                                V4L2_STD_PAL_H         |\
-                                V4L2_STD_PAL_I)
-#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
-                                V4L2_STD_NTSC_M_JP     |\
-                                V4L2_STD_NTSC_M_KR)
-#define V4L2_STD_MN             (V4L2_STD_PAL_M         |\
-                                V4L2_STD_PAL_N         |\
-                                V4L2_STD_PAL_Nc        |\
-                                V4L2_STD_NTSC)
-#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
-                                V4L2_STD_SECAM_K       |\
-                                V4L2_STD_SECAM_K1)
-#define V4L2_STD_DK             (V4L2_STD_PAL_DK        |\
-                                V4L2_STD_SECAM_DK)
-
-#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
-                                V4L2_STD_SECAM_G       |\
-                                V4L2_STD_SECAM_H       |\
-                                V4L2_STD_SECAM_DK      |\
-                                V4L2_STD_SECAM_L       |\
-                                V4L2_STD_SECAM_LC)
-
-#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
-                                V4L2_STD_PAL_60        |\
-                                V4L2_STD_NTSC          |\
-                                V4L2_STD_NTSC_443)
-#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
-                                V4L2_STD_PAL_N         |\
-                                V4L2_STD_PAL_Nc        |\
-                                V4L2_STD_SECAM)
-
-#define V4L2_STD_UNKNOWN        0
-#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
-                                V4L2_STD_625_50)
-</programlisting></para>
-
-    <table pgwide="1" id="video-standards" orient="land">
-      <title>Video Standards (based on [<xref linkend="itu470" />])</title>
-      <tgroup cols="12" colsep="1" rowsep="1" align="center">
-       <colspec colname="c1" align="left" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <colspec colnum="7" colname="c7" />
-       <colspec colnum="9" colname="c9" />
-       <colspec colnum="12" colname="c12" />
-       <spanspec namest="c2" nameend="c3" spanname="m" align="center" />
-       <spanspec namest="c4" nameend="c12" spanname="x" align="center" />
-       <spanspec namest="c5" nameend="c7" spanname="b" align="center" />
-       <spanspec namest="c9" nameend="c12" spanname="s" align="center" />
-       <thead>
-         <row>
-           <entry>Characteristics</entry>
-           <entry><para>M/NTSC<footnote><para>Japan uses a standard
-similar to M/NTSC
-(V4L2_STD_NTSC_M_JP).</para></footnote></para></entry>
-           <entry>M/PAL</entry>
-           <entry><para>N/PAL<footnote><para> The values in
-brackets apply to the combination N/PAL a.k.a.
-N<subscript>C</subscript> used in Argentina
-(V4L2_STD_PAL_Nc).</para></footnote></para></entry>
-           <entry align="center">B, B1, G/PAL</entry>
-           <entry align="center">D, D1, K/PAL</entry>
-           <entry align="center">H/PAL</entry>
-           <entry align="center">I/PAL</entry>
-           <entry align="center">B, G/SECAM</entry>
-           <entry align="center">D, K/SECAM</entry>
-           <entry align="center">K1/SECAM</entry>
-           <entry align="center">L/SECAM</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry>Frame lines</entry>
-           <entry spanname="m">525</entry>
-           <entry spanname="x">625</entry>
-         </row>
-         <row>
-           <entry>Frame period (s)</entry>
-           <entry spanname="m">1001/30000</entry>
-           <entry spanname="x">1/25</entry>
-         </row>
-         <row>
-           <entry>Chrominance sub-carrier frequency (Hz)</entry>
-           <entry>3579545 &plusmn;&nbsp;10</entry>
-           <entry>3579611.49 &plusmn;&nbsp;10</entry>
-           <entry>4433618.75 &plusmn;&nbsp;5 (3582056.25
-&plusmn;&nbsp;5)</entry>
-           <entry spanname="b">4433618.75 &plusmn;&nbsp;5</entry>
-           <entry>4433618.75 &plusmn;&nbsp;1</entry>
-           <entry spanname="s">f<subscript>OR</subscript>&nbsp;=
-4406250 &plusmn;&nbsp;2000, f<subscript>OB</subscript>&nbsp;= 4250000
-&plusmn;&nbsp;2000</entry>
-         </row>
-         <row>
-           <entry>Nominal radio-frequency channel bandwidth
-(MHz)</entry>
-           <entry>6</entry>
-           <entry>6</entry>
-           <entry>6</entry>
-           <entry>B: 7; B1, G: 8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-         </row>
-         <row>
-           <entry>Sound carrier relative to vision carrier
-(MHz)</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry><para>+&nbsp;5.5 &plusmn;&nbsp;0.001
-<footnote><para>In the Federal Republic of Germany, Austria, Italy,
-the Netherlands, Slovakia and Switzerland a system of two sound
-carriers is used, the frequency of the second carrier being
-242.1875&nbsp;kHz above the frequency of the first sound carrier. For
-stereophonic sound transmissions a similar system is used in
-Australia.</para></footnote> <footnote><para>New Zealand uses a sound
-carrier displaced 5.4996 &plusmn;&nbsp;0.0005 MHz from the vision
-carrier.</para></footnote> <footnote><para>In Denmark, Finland, New
-Zealand, Sweden and Spain a system of two sound carriers is used. In
-Iceland, Norway and Poland the same system is being introduced. The
-second carrier is 5.85&nbsp;MHz above the vision carrier and is DQPSK
-modulated with 728&nbsp;kbit/s sound and data multiplex. (NICAM
-system)</para></footnote> <footnote><para>In the United Kingdom, a
-system of two sound carriers is used. The second sound carrier is
-6.552&nbsp;MHz above the vision carrier and is DQPSK modulated with a
-728&nbsp;kbit/s sound and data multiplex able to carry two sound
-channels. (NICAM system)</para></footnote></para></entry>
-           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;5.5</entry>
-           <entry>+&nbsp;5.9996 &plusmn;&nbsp;0.0005</entry>
-           <entry>+&nbsp;5.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;6.5</entry>
-           <entry><para>+&nbsp;6.5 <footnote><para>In France, a
-digital carrier 5.85 MHz away from the vision carrier may be used in
-addition to the main sound carrier. It is modulated in differentially
-encoded QPSK with a 728 kbit/s sound and data multiplexer capable of
-carrying two sound channels. (NICAM
-system)</para></footnote></para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-standard; <structfield>index</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Standard video timings are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml
deleted file mode 100644 (file)
index a6558a6..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-<refentry id="vidioc-expbuf">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_EXPBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_EXPBUF</refname>
-    <refpurpose>Export a buffer as a DMABUF file descriptor.</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_exportbuffer *<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_EXPBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>This ioctl is an extension to the <link linkend="mmap">memory
-mapping</link> I/O method, therefore it is available only for
-<constant>V4L2_MEMORY_MMAP</constant> buffers.  It can be used to export a
-buffer as a DMABUF file at any time after buffers have been allocated with the
-&VIDIOC-REQBUFS; ioctl.</para>
-
-<para> To export a buffer, applications fill &v4l2-exportbuffer;.  The
-<structfield>type</structfield> field is set to the same buffer type as was
-previously used with &v4l2-requestbuffers; <structfield>type</structfield>.
-Applications must also set the <structfield>index</structfield> field. Valid
-index numbers range from zero to the number of buffers allocated with
-&VIDIOC-REQBUFS; (&v4l2-requestbuffers; <structfield>count</structfield>)
-minus one.  For the multi-planar API, applications set the <structfield>plane</structfield>
-field to the index of the plane to be exported. Valid planes
-range from zero to the maximal number of valid planes for the currently active
-format. For the single-planar API, applications must set <structfield>plane</structfield>
-to zero.  Additional flags may be posted in the <structfield>flags</structfield>
-field.  Refer to a manual for open() for details.
-Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, and O_RDWR are supported.  All
-other fields must be set to zero.
-In the case of multi-planar API, every plane is exported separately using
-multiple <constant>VIDIOC_EXPBUF</constant> calls.</para>
-
-<para>After calling <constant>VIDIOC_EXPBUF</constant> the <structfield>fd</structfield>
-field will be set by a driver.  This is a DMABUF file
-descriptor. The application may pass it to other DMABUF-aware devices. Refer to
-<link linkend="dmabuf">DMABUF importing</link> for details about importing
-DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it
-is no longer used to allow the associated memory to be reclaimed.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Examples</title>
-
-    <example>
-      <title>Exporting a buffer.</title>
-      <programlisting>
-int buffer_export(int v4lfd, &v4l2-buf-type; bt, int index, int *dmafd)
-{
-       &v4l2-exportbuffer; expbuf;
-
-       memset(&amp;expbuf, 0, sizeof(expbuf));
-       expbuf.type = bt;
-       expbuf.index = index;
-       if (ioctl(v4lfd, &VIDIOC-EXPBUF;, &amp;expbuf) == -1) {
-               perror("VIDIOC_EXPBUF");
-               return -1;
-       }
-
-       *dmafd = expbuf.fd;
-
-       return 0;
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Exporting a buffer using the multi-planar API.</title>
-      <programlisting>
-int buffer_export_mp(int v4lfd, &v4l2-buf-type; bt, int index,
-       int dmafd[], int n_planes)
-{
-       int i;
-
-       for (i = 0; i &lt; n_planes; ++i) {
-               &v4l2-exportbuffer; expbuf;
-
-               memset(&amp;expbuf, 0, sizeof(expbuf));
-               expbuf.type = bt;
-               expbuf.index = index;
-               expbuf.plane = i;
-               if (ioctl(v4lfd, &VIDIOC-EXPBUF;, &amp;expbuf) == -1) {
-                       perror("VIDIOC_EXPBUF");
-                       while (i)
-                               close(dmafd[--i]);
-                       return -1;
-               }
-               dmafd[i] = expbuf.fd;
-       }
-
-       return 0;
-}
-      </programlisting>
-    </example>
-
-    <table pgwide="1" frame="none" id="v4l2-exportbuffer">
-      <title>struct <structname>v4l2_exportbuffer</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the buffer, same as &v4l2-format;
-<structfield>type</structfield> or &v4l2-requestbuffers;
-<structfield>type</structfield>, set by the application. See <xref
-linkend="v4l2-buf-type" /></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the buffer, set by the application. This field is
-only used for <link linkend="mmap">memory mapping</link> I/O and can range from
-zero to the number of buffers allocated with the &VIDIOC-REQBUFS; and/or
-&VIDIOC-CREATE-BUFS; ioctls. </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>plane</structfield></entry>
-           <entry>Index of the plane to be exported when using the
-multi-planar API. Otherwise this value must be set to zero. </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags for the newly created file, currently only
-<constant>O_CLOEXEC</constant>, <constant>O_RDONLY</constant>, <constant>O_WRONLY</constant>,
-and <constant>O_RDWR</constant> are supported, refer to the manual
-of open() for more details.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>fd</structfield></entry>
-           <entry>The DMABUF file descriptor associated with a buffer. Set by
-               the driver.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[11]</structfield></entry>
-           <entry>Reserved field for future use. Drivers and applications must
-set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>A queue is not in MMAP mode or DMABUF exporting is not
-supported or <structfield>flags</structfield> or <structfield>type</structfield>
-or <structfield>index</structfield> or <structfield>plane</structfield> fields
-are invalid.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-audio.xml b/Documentation/DocBook/media/v4l/vidioc-g-audio.xml
deleted file mode 100644 (file)
index d7bb9b3..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<refentry id="vidioc-g-audio">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_AUDIO</refname>
-    <refname>VIDIOC_S_AUDIO</refname>
-    <refpurpose>Query or select the current audio input and its
-attributes</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_audio *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_audio *<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_G_AUDIO, VIDIOC_S_AUDIO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current audio input applications zero out the
-<structfield>reserved</structfield> array of a &v4l2-audio;
-and call the <constant>VIDIOC_G_AUDIO</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the device has no audio inputs, or none which combine
-with the current video input.</para>
-
-    <para>Audio inputs have one writable property, the audio mode. To
-select the current audio input <emphasis>and</emphasis> change the
-audio mode, applications initialize the
-<structfield>index</structfield> and <structfield>mode</structfield>
-fields, and the
-<structfield>reserved</structfield> array of a
-<structname>v4l2_audio</structname> structure and call the
-<constant>VIDIOC_S_AUDIO</constant> ioctl. Drivers may switch to a
-different audio mode if the request cannot be satisfied. However, this
-is a write-only ioctl, it does not return the actual new audio
-mode.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-audio">
-      <title>struct <structname>v4l2_audio</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the audio input, set by the
-driver or application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the audio input, a NUL-terminated ASCII
-string, for example: "Line In". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Audio capability flags, see <xref
-               linkend="audio-capability" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>mode</structfield></entry>
-           <entry>Audio mode flags set by drivers and applications (on
-           <constant>VIDIOC_S_AUDIO</constant> ioctl), see <xref linkend="audio-mode" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="audio-capability">
-      <title>Audio Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_AUDCAP_STEREO</constant></entry>
-           <entry>0x00001</entry>
-           <entry>This is a stereo input. The flag is intended to
-automatically disable stereo recording etc. when the signal is always
-monaural. The API provides no means to detect if stereo is
-<emphasis>received</emphasis>, unless the audio input belongs to a
-tuner.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_AUDCAP_AVL</constant></entry>
-           <entry>0x00002</entry>
-           <entry>Automatic Volume Level mode is supported.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="audio-mode">
-      <title>Audio Mode Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_AUDMODE_AVL</constant></entry>
-           <entry>0x00001</entry>
-           <entry>AVL mode is on.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>No audio inputs combine with the current video input,
-or the number of the selected audio input is out of bounds or it does
-not combine.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml b/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml
deleted file mode 100644 (file)
index 200a270..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<refentry id="vidioc-g-audioout">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_AUDOUT</refname>
-    <refname>VIDIOC_S_AUDOUT</refname>
-    <refpurpose>Query or select the current audio output</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_audioout *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_audioout *<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_G_AUDOUT, VIDIOC_S_AUDOUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current audio output applications zero out the
-<structfield>reserved</structfield> array of a &v4l2-audioout; and
-call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the device has no audio inputs, or none which combine
-with the current video output.</para>
-
-    <para>Audio outputs have no writable properties. Nevertheless, to
-select the current audio output applications can initialize the
-<structfield>index</structfield> field and
-<structfield>reserved</structfield> array (which in the future may
-contain writable properties) of a
-<structname>v4l2_audioout</structname> structure and call the
-<constant>VIDIOC_S_AUDOUT</constant> ioctl. Drivers switch to the
-requested output or return the &EINVAL; when the index is out of
-bounds. This is a write-only ioctl, it does not return the current
-audio output attributes as <constant>VIDIOC_G_AUDOUT</constant>
-does.</para>
-
-    <para>Note connectors on a TV card to loop back the received audio
-signal to a sound card are not audio outputs in this sense.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-audioout">
-      <title>struct <structname>v4l2_audioout</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the audio output, set by the
-driver or application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the audio output, a NUL-terminated ASCII
-string, for example: "Line Out". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Audio capability flags, none defined yet. Drivers
-must set this field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>mode</structfield></entry>
-           <entry>Audio mode, none defined yet. Drivers and
-applications (on <constant>VIDIOC_S_AUDOUT</constant>) must set this
-field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>No audio outputs combine with the current video
-output, or the number of the selected audio output is out of bounds or
-it does not combine.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
deleted file mode 100644 (file)
index e6c4efb..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-<refentry id="vidioc-g-crop">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_CROP, VIDIOC_S_CROP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_CROP</refname>
-    <refname>VIDIOC_S_CROP</refname>
-    <refpurpose>Get or set the current cropping rectangle</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_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_crop *<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_G_CROP, VIDIOC_S_CROP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the cropping rectangle size and position
-applications set the <structfield>type</structfield> field of a
-<structname>v4l2_crop</structname> structure to the respective buffer
-(stream) type and call the <constant>VIDIOC_G_CROP</constant> ioctl
-with a pointer to this structure. The driver fills the rest of the
-structure or returns the &EINVAL; if cropping is not supported.</para>
-
-    <para>To change the cropping rectangle applications initialize the
-<structfield>type</structfield> and &v4l2-rect; substructure named
-<structfield>c</structfield> of a v4l2_crop structure and call the
-<constant>VIDIOC_S_CROP</constant> ioctl with a pointer to this
-structure.</para>
-
-<para>Do not use the multiplanar buffer types.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
-instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
-and use <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.</para>
-
-    <para>The driver first adjusts the requested dimensions against
-hardware limits, &ie; the bounds given by the capture/output window,
-and it rounds to the closest possible values of horizontal and
-vertical offset, width and height. In particular the driver must round
-the vertical offset of the cropping rectangle to frame lines modulo
-two, such that the field order cannot be confused.</para>
-
-    <para>Second the driver adjusts the image size (the opposite
-rectangle of the scaling process, source or target depending on the
-data direction) to the closest size possible while maintaining the
-current horizontal and vertical scaling factor.</para>
-
-    <para>Finally the driver programs the hardware with the actual
-cropping and image parameters. <constant>VIDIOC_S_CROP</constant> is a
-write-only ioctl, it does not return the actual parameters. To query
-them applications must call <constant>VIDIOC_G_CROP</constant> and
-&VIDIOC-G-FMT;. When the parameters are unsuitable the application may
-modify the cropping or image parameters and repeat the cycle until
-satisfactory parameters have been negotiated.</para>
-
-    <para>When cropping is not supported then no parameters are
-changed and <constant>VIDIOC_S_CROP</constant> returns the
-&EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-crop">
-      <title>struct <structname>v4l2_crop</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> and
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>. See <xref linkend="v4l2-buf-type" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>c</structfield></entry>
-           <entry>Cropping rectangle. The same co-ordinate system as
-for &v4l2-cropcap; <structfield>bounds</structfield> is used.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
deleted file mode 100644 (file)
index ee2820d..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<refentry id="vidioc-g-ctrl">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_CTRL</refname>
-    <refname>VIDIOC_S_CTRL</refname>
-    <refpurpose>Get or set the value of a control</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_control
-*<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_G_CTRL, VIDIOC_S_CTRL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To get the current value of a control applications
-initialize the <structfield>id</structfield> field of a struct
-<structname>v4l2_control</structname> and call the
-<constant>VIDIOC_G_CTRL</constant> ioctl with a pointer to this
-structure. To change the value of a control applications initialize
-the <structfield>id</structfield> and <structfield>value</structfield>
-fields of a struct <structname>v4l2_control</structname> and call the
-<constant>VIDIOC_S_CTRL</constant> ioctl.</para>
-
-    <para>When the <structfield>id</structfield> is invalid drivers
-return an &EINVAL;. When the <structfield>value</structfield> is out
-of bounds drivers can choose to take the closest valid value or return
-an &ERANGE;, whatever seems more appropriate. However,
-<constant>VIDIOC_S_CTRL</constant> is a write-only ioctl, it does not
-return the actual new value. If the <structfield>value</structfield>
-is inappropriate for the control (e.g. if it refers to an unsupported
-menu index of a menu control), then &EINVAL; is returned as well.</para>
-
-    <para>These ioctls work only with user controls. For other
-control classes the &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS; or
-&VIDIOC-TRY-EXT-CTRLS; must be used.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-control">
-      <title>struct <structname>v4l2_control</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>New value or current value.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-control; <structfield>id</structfield> is
-invalid or the <structfield>value</structfield> is inappropriate for
-the given control (i.e. if a menu item is selected that is not supported
-by the driver according to &VIDIOC-QUERYMENU;).</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The &v4l2-control; <structfield>value</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The control is temporarily not changeable, possibly
-because another applications took over control of the device function
-this control belongs to.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>Attempt to set a read-only control or to get a
-         write-only control.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
deleted file mode 100644 (file)
index 06952d7..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-<refentry id="vidioc-g-dv-timings">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_DV_TIMINGS</refname>
-    <refname>VIDIOC_S_DV_TIMINGS</refname>
-    <refname>VIDIOC_SUBDEV_G_DV_TIMINGS</refname>
-    <refname>VIDIOC_SUBDEV_S_DV_TIMINGS</refname>
-    <refpurpose>Get or set DV timings for input or output</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_dv_timings *<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_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS, VIDIOC_SUBDEV_G_DV_TIMINGS, VIDIOC_SUBDEV_S_DV_TIMINGS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>To set DV timings for the input or output, applications use the
-<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current timings,
-applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
-information is filled in using the structure &v4l2-dv-timings;. These ioctls take
-a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
-or the timing values are not correct, the driver returns &EINVAL;.</para>
-<para>The <filename>linux/v4l2-dv-timings.h</filename> header can be used to get the
-timings of the formats in the <xref linkend="cea861" /> and <xref linkend="vesadmt" />
-standards. If the current input or output does not support DV timings (e.g. if
-&VIDIOC-ENUMINPUT; does not set the <constant>V4L2_IN_CAP_DV_TIMINGS</constant> flag), then
-&ENODATA; is returned.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_DV_TIMINGS</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Digital video timings are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not change the timings.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-
-    <table pgwide="1" frame="none" id="v4l2-bt-timings">
-      <title>struct <structname>v4l2_bt_timings</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the active video in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the active video frame in lines. So for interlaced formats the
-           height of the active video in each field is <structfield>height</structfield>/2.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>interlaced</structfield></entry>
-           <entry>Progressive (0) or interlaced (1)</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>polarities</structfield></entry>
-           <entry>This is a bit mask that defines polarities of sync signals.
-bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_HSYNC_POS_POL) is for horizontal sync polarity. If the bit is set
-(1) it is positive polarity and if is cleared (0), it is negative polarity.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>pixelclock</structfield></entry>
-           <entry>Pixel clock in Hz. Ex. 74.25MHz->74250000</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hfrontporch</structfield></entry>
-           <entry>Horizontal front porch in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hsync</structfield></entry>
-           <entry>Horizontal sync length in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hbackporch</structfield></entry>
-           <entry>Horizontal back porch in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vfrontporch</structfield></entry>
-           <entry>Vertical front porch in lines. For interlaced formats this refers to the
-           odd field (aka field 1).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vsync</structfield></entry>
-           <entry>Vertical sync length in lines. For interlaced formats this refers to the
-           odd field (aka field 1).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vbackporch</structfield></entry>
-           <entry>Vertical back porch in lines. For interlaced formats this refers to the
-           odd field (aka field 1).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vfrontporch</structfield></entry>
-           <entry>Vertical front porch in lines for the even field (aka field 2) of
-           interlaced field formats. Must be 0 for progressive formats.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vsync</structfield></entry>
-           <entry>Vertical sync length in lines for the even field (aka field 2) of
-           interlaced field formats. Must be 0 for progressive formats.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vbackporch</structfield></entry>
-           <entry>Vertical back porch in lines for the even field (aka field 2) of
-           interlaced field formats. Must be 0 for progressive formats.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>standards</structfield></entry>
-           <entry>The video standard(s) this format belongs to. This will be filled in by
-           the driver. Applications must set this to 0. See <xref linkend="dv-bt-standards"/>
-           for a list of standards.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Several flags giving more information about the format.
-           See <xref linkend="dv-bt-flags"/> for a description of the flags.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-timings">
-      <title>struct <structname>v4l2_dv_timings</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield></structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-bt-timings;</entry>
-           <entry><structfield>bt</structfield></entry>
-           <entry>Timings defined by BT.656/1120 specifications</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[32]</entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="dv-timing-types">
-      <title>DV Timing types</title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Timing type</entry>
-           <entry>value</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_656_1120</entry>
-           <entry>0</entry>
-           <entry>BT.656/1120 timings</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <table pgwide="1" frame="none" id="dv-bt-standards">
-      <title>DV BT Timing standards</title>
-      <tgroup cols="2">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Timing standard</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_STD_CEA861</entry>
-           <entry>The timings follow the CEA-861 Digital TV Profile standard</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_STD_DMT</entry>
-           <entry>The timings follow the VESA Discrete Monitor Timings standard</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_STD_CVT</entry>
-           <entry>The timings follow the VESA Coordinated Video Timings standard</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_STD_GTF</entry>
-           <entry>The timings follow the VESA Generalized Timings Formula standard</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <table pgwide="1" frame="none" id="dv-bt-flags">
-      <title>DV BT Timing flags</title>
-      <tgroup cols="2">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Flag</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_FL_REDUCED_BLANKING</entry>
-           <entry>CVT/GTF specific: the timings use reduced blanking (CVT) or the 'Secondary
-GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
-intervals are reduced, allowing a higher resolution over the same
-bandwidth. This is a read-only flag, applications must not set this.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_FL_CAN_REDUCE_FPS</entry>
-           <entry>CEA-861 specific: set for CEA-861 formats with a framerate that is a multiple
-of six. These formats can be optionally played at 1 / 1.001 speed to
-be compatible with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
-29.97 frames per second. If the transmitter can't generate such frequencies, then the
-flag will also be cleared. This is a read-only flag, applications must not set this.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_FL_REDUCED_FPS</entry>
-           <entry>CEA-861 specific: only valid for video transmitters, the flag is cleared
-by receivers. It is also only valid for formats with the V4L2_DV_FL_CAN_REDUCE_FPS flag
-set, for other formats the flag will be cleared by the driver.
-
-If the application sets this flag, then the pixelclock used to set up the transmitter is
-divided by 1.001 to make it compatible with NTSC framerates. If the transmitter
-can't generate such frequencies, then the flag will also be cleared.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_FL_HALF_LINE</entry>
-           <entry>Specific to interlaced formats: if set, then the vertical frontporch
-of field 1 (aka the odd field) is really one half-line longer and the vertical backporch
-of field 2 (aka the even field) is really one half-line shorter, so each field has exactly
-the same number of half-lines. Whether half-lines can be detected or used depends on
-the hardware.
-           </entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_FL_IS_CE_VIDEO</entry>
-           <entry>If set, then this is a Consumer Electronics (CE) video format.
-Such formats differ from other formats (commonly called IT formats) in that if
-R'G'B' encoding is used then by default the R'G'B' values use limited range
-(i.e. 16-235) as opposed to full range (i.e. 0-255). All formats defined in CEA-861
-except for the 640x480p59.94 format are CE formats.
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml
deleted file mode 100644 (file)
index b7602d3..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-<refentry id="vidioc-g-edid">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_EDID</refname>
-    <refname>VIDIOC_S_EDID</refname>
-    <refname>VIDIOC_SUBDEV_G_EDID</refname>
-    <refname>VIDIOC_SUBDEV_S_EDID</refname>
-    <refpurpose>Get or set the EDID of a video receiver/transmitter</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_edid *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_edid *<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_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>These ioctls can be used to get or set an EDID associated with an input
-    from a receiver or an output of a transmitter device. They can be
-    used with subdevice nodes (/dev/v4l-subdevX) or with video nodes (/dev/videoX).</para>
-
-    <para>When used with video nodes the <structfield>pad</structfield> field represents the
-    input (for video capture devices) or output (for video output devices) index as
-    is returned by &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively. When used
-    with subdevice nodes the <structfield>pad</structfield> field represents the
-    input or output pad of the subdevice. If there is no EDID support for the given
-    <structfield>pad</structfield> value, then the &EINVAL; will be returned.</para>
-
-    <para>To get the EDID data the application has to fill in the <structfield>pad</structfield>,
-    <structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield>
-    fields, zero the <structfield>reserved</structfield> array and call
-    <constant>VIDIOC_G_EDID</constant>. The current EDID from block
-    <structfield>start_block</structfield> and of size <structfield>blocks</structfield>
-    will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield>
-    pointer must point to memory at least <structfield>blocks</structfield>&nbsp;*&nbsp;128 bytes
-    large (the size of one block is 128 bytes).</para>
-
-    <para>If there are fewer blocks than specified, then the driver will set <structfield>blocks</structfield>
-    to the actual number of blocks. If there are no EDID blocks available at all, then the error code
-    ENODATA is set.</para>
-
-    <para>If blocks have to be retrieved from the sink, then this call will block until they
-    have been read.</para>
-
-    <para>If <structfield>start_block</structfield> and <structfield>blocks</structfield> are
-    both set to 0 when <constant>VIDIOC_G_EDID</constant> is called, then the driver will
-    set <structfield>blocks</structfield> to the total number of available EDID blocks
-    and it will return 0 without copying any data. This is an easy way to discover how many
-    EDID blocks there are. Note that if there are no EDID blocks available at all, then
-    the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para>
-
-    <para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>,
-    <structfield>blocks</structfield> and <structfield>edid</structfield> fields, set
-    <structfield>start_block</structfield> to 0 and zero the <structfield>reserved</structfield> array.
-    It is not possible to set part of an EDID,
-    it is always all or nothing. Setting the EDID data is only valid for receivers as it makes
-    no sense for a transmitter.</para>
-
-    <para>The driver assumes that the full EDID is passed in. If there are more EDID blocks than
-    the hardware can handle then the EDID is not written, but instead the error code E2BIG is set
-    and <structfield>blocks</structfield> is set to the maximum that the hardware supports.
-    If <structfield>start_block</structfield> is any
-    value other than 0 then the error code EINVAL is set.</para>
-
-    <para>To disable an EDID you set <structfield>blocks</structfield> to 0. Depending on the
-    hardware this will drive the hotplug pin low and/or block the source from reading the EDID
-    data in some way. In any case, the end result is the same: the EDID is no longer available.
-    </para>
-
-    <table pgwide="1" frame="none" id="v4l2-edid">
-      <title>struct <structname>v4l2_edid</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad for which to get/set the EDID blocks. When used with a video device
-           node the pad represents the input or output index as returned by
-           &VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; respectively.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>start_block</structfield></entry>
-           <entry>Read the EDID from starting with this block. Must be 0 when setting
-           the EDID.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>blocks</structfield></entry>
-           <entry>The number of blocks to get or set. Must be less or equal to 256 (the
-           maximum number of blocks as defined by the standard). When you set the EDID and
-           <structfield>blocks</structfield> is 0, then the EDID is disabled or erased.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[5]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>__u8&nbsp;*</entry>
-           <entry><structfield>edid</structfield></entry>
-           <entry>Pointer to memory that contains the EDID. The minimum size is
-           <structfield>blocks</structfield>&nbsp;*&nbsp;128.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>The EDID data is not available.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>E2BIG</errorcode></term>
-       <listitem>
-         <para>The EDID data you provided is more than the hardware can handle.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml b/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml
deleted file mode 100644 (file)
index be25029..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-<refentry id="vidioc-g-enc-index">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_ENC_INDEX</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_ENC_INDEX</refname>
-    <refpurpose>Get meta data about a compressed video stream</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_enc_idx *<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_G_ENC_INDEX</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <constant>VIDIOC_G_ENC_INDEX</constant> ioctl provides
-meta data about a compressed video stream the same or another
-application currently reads from the driver, which is useful for
-random access into the stream without decoding it.</para>
-
-    <para>To read the data applications must call
-<constant>VIDIOC_G_ENC_INDEX</constant> with a pointer to a
-&v4l2-enc-idx;. On success the driver fills the
-<structfield>entry</structfield> array, stores the number of elements
-written in the <structfield>entries</structfield> field, and
-initializes the <structfield>entries_cap</structfield> field.</para>
-
-    <para>Each element of the <structfield>entry</structfield> array
-contains meta data about one picture. A
-<constant>VIDIOC_G_ENC_INDEX</constant> call reads up to
-<constant>V4L2_ENC_IDX_ENTRIES</constant> entries from a driver
-buffer, which can hold up to <structfield>entries_cap</structfield>
-entries. This number can be lower or higher than
-<constant>V4L2_ENC_IDX_ENTRIES</constant>, but not zero. When the
-application fails to read the meta data in time the oldest entries
-will be lost. When the buffer is empty or no capturing/encoding is in
-progress, <structfield>entries</structfield> will be zero.</para>
-
-    <para>Currently this ioctl is only defined for MPEG-2 program
-streams and video elementary streams.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-enc-idx">
-      <title>struct <structname>v4l2_enc_idx</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entries</structfield></entry>
-           <entry>The number of entries the driver stored in the
-<structfield>entry</structfield> array.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entries_cap</structfield></entry>
-           <entry>The number of entries the driver can
-buffer. Must be greater than zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry spanname="hspan">Reserved for future extensions.
-Drivers must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-enc-idx-entry;</entry>
-           <entry><structfield>entry</structfield>[<constant>V4L2_ENC_IDX_ENTRIES</constant>]</entry>
-           <entry>Meta data about a compressed video stream. Each
-element of the array corresponds to one picture, sorted in ascending
-order by their <structfield>offset</structfield>.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-enc-idx-entry">
-      <title>struct <structname>v4l2_enc_idx_entry</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>offset</structfield></entry>
-           <entry>The offset in bytes from the beginning of the
-compressed video stream to the beginning of this picture, that is a
-<wordasword>PES packet header</wordasword> as defined in <xref
-           linkend="mpeg2part1" /> or a <wordasword>picture
-header</wordasword> as defined in <xref linkend="mpeg2part2" />. When
-the encoder is stopped, the driver resets the offset to zero.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>pts</structfield></entry>
-           <entry>The 33 bit <wordasword>Presentation Time
-Stamp</wordasword> of this picture as defined in <xref
-               linkend="mpeg2part1" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry>The length of this picture in bytes.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags containing the coding type of this picture, see <xref
-               linkend="enc-idx-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions.
-Drivers must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="enc-idx-flags">
-      <title>Index Entry Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_I</constant></entry>
-           <entry>0x00</entry>
-           <entry>This is an Intra-coded picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_P</constant></entry>
-           <entry>0x01</entry>
-           <entry>This is a Predictive-coded picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_B</constant></entry>
-           <entry>0x02</entry>
-           <entry>This is a Bidirectionally predictive-coded
-picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_MASK</constant></entry>
-           <entry>0x0F</entry>
-           <entry><wordasword>AND</wordasword> the flags field with
-this mask to obtain the picture coding type.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
deleted file mode 100644 (file)
index eb82f7e..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-<refentry id="vidioc-g-ext-ctrls">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
-VIDIOC_TRY_EXT_CTRLS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_EXT_CTRLS</refname>
-    <refname>VIDIOC_S_EXT_CTRLS</refname>
-    <refname>VIDIOC_TRY_EXT_CTRLS</refname>
-    <refpurpose>Get or set the value of several controls, try control
-values</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_ext_controls
-*<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_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
-VIDIOC_TRY_EXT_CTRLS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls allow the caller to get or set multiple
-controls atomically. Control IDs are grouped into control classes (see
-<xref linkend="ctrl-class" />) and all controls in the control array
-must belong to the same control class.</para>
-
-    <para>Applications must always fill in the
-<structfield>count</structfield>,
-<structfield>which</structfield>,
-<structfield>controls</structfield> and
-<structfield>reserved</structfield> fields of &v4l2-ext-controls;, and
-initialize the &v4l2-ext-control; array pointed to by the
-<structfield>controls</structfield> fields.</para>
-
-    <para>To get the current value of a set of controls applications
-initialize the <structfield>id</structfield>,
-<structfield>size</structfield> and <structfield>reserved2</structfield> fields
-of each &v4l2-ext-control; and call the
-<constant>VIDIOC_G_EXT_CTRLS</constant> ioctl. String controls controls
-must also set the <structfield>string</structfield> field. Controls
-of compound types (<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set)
-must set the <structfield>ptr</structfield> field.</para>
-
-    <para>If the <structfield>size</structfield> is too small to
-receive the control result (only relevant for pointer-type controls
-like strings), then the driver will set <structfield>size</structfield>
-to a valid value and return an &ENOSPC;. You should re-allocate the
-memory to this new size and try again. For the string type it is possible that
-the same issue occurs again if the string has grown in the meantime. It is
-recommended to call &VIDIOC-QUERYCTRL; first and use
-<structfield>maximum</structfield>+1 as the new <structfield>size</structfield>
-value. It is guaranteed that that is sufficient memory.
-</para>
-
-    <para>N-dimensional arrays are set and retrieved row-by-row. You cannot set a partial
-array, all elements have to be set or retrieved. The total size is calculated
-as <structfield>elems</structfield> * <structfield>elem_size</structfield>.
-These values can be obtained by calling &VIDIOC-QUERY-EXT-CTRL;.</para>
-
-    <para>To change the value of a set of controls applications
-initialize the <structfield>id</structfield>, <structfield>size</structfield>,
-<structfield>reserved2</structfield> and
-<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
-call the <constant>VIDIOC_S_EXT_CTRLS</constant> ioctl. The controls
-will only be set if <emphasis>all</emphasis> control values are
-valid.</para>
-
-    <para>To check if a set of controls have correct values applications
-initialize the <structfield>id</structfield>, <structfield>size</structfield>,
-<structfield>reserved2</structfield> and
-<structfield>value/value64/string/ptr</structfield> fields of each &v4l2-ext-control; and
-call the <constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctl. It is up to
-the driver whether wrong values are automatically adjusted to a valid
-value or if an error is returned.</para>
-
-    <para>When the <structfield>id</structfield> or
-<structfield>which</structfield> is invalid drivers return an
-&EINVAL;. When the value is out of bounds drivers can choose to take
-the closest valid value or return an &ERANGE;, whatever seems more
-appropriate. In the first case the new value is set in
-&v4l2-ext-control;. If the new control value is inappropriate (e.g. the
-given menu index is not supported by the menu control), then this will
-also result in an &EINVAL; error.</para>
-
-    <para>The driver will only set/get these controls if all control
-values are correct. This prevents the situation where only some of the
-controls were set/get. Only low-level errors (&eg; a failed i2c
-command) can still cause this situation.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-ext-control">
-      <title>struct <structname>v4l2_ext_control</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry>Identifies the control, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>size</structfield></entry>
-           <entry></entry>
-           <entry>The total size in bytes of the payload of this
-control. This is normally 0, but for pointer controls this should be
-set to the size of the memory containing the payload, or that will
-receive the payload. If <constant>VIDIOC_G_EXT_CTRLS</constant> finds
-that this value is less than is required to store
-the payload result, then it is set to a value large enough to store the
-payload result and ENOSPC is returned. Note that for string controls
-this <structfield>size</structfield> field should not be confused with the length of the string.
-This field refers to the size of the memory that contains the string.
-The actual <emphasis>length</emphasis> of the string may well be much smaller.
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved2</structfield>[1]</entry>
-           <entry></entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>New value or current value. Valid if this control is not of
-type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
-<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s64</entry>
-           <entry><structfield>value64</structfield></entry>
-           <entry>New value or current value. Valid if this control is of
-type <constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
-<constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is not set.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>char *</entry>
-           <entry><structfield>string</structfield></entry>
-           <entry>A pointer to a string. Valid if this control is of
-type <constant>V4L2_CTRL_TYPE_STRING</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8 *</entry>
-           <entry><structfield>p_u8</structfield></entry>
-           <entry>A pointer to a matrix control of unsigned 8-bit values.
-Valid if this control is of type <constant>V4L2_CTRL_TYPE_U8</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u16 *</entry>
-           <entry><structfield>p_u16</structfield></entry>
-           <entry>A pointer to a matrix control of unsigned 16-bit values.
-Valid if this control is of type <constant>V4L2_CTRL_TYPE_U16</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32 *</entry>
-           <entry><structfield>p_u32</structfield></entry>
-           <entry>A pointer to a matrix control of unsigned 32-bit values.
-Valid if this control is of type <constant>V4L2_CTRL_TYPE_U32</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>void *</entry>
-           <entry><structfield>ptr</structfield></entry>
-           <entry>A pointer to a compound type which can be an N-dimensional array and/or a
-compound type (the control's type is >= <constant>V4L2_CTRL_COMPOUND_TYPES</constant>).
-Valid if <constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set for this control.
-</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-ext-controls">
-      <title>struct <structname>v4l2_ext_controls</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-        <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>ctrl_class</structfield></entry>
-           <entry>The control class to which all controls belong, see
-<xref linkend="ctrl-class" />. Drivers that use a kernel framework for handling
-controls will also accept a value of 0 here, meaning that the controls can
-belong to any control class. Whether drivers support this can be tested by setting
-<structfield>ctrl_class</structfield> to 0 and calling <constant>VIDIOC_TRY_EXT_CTRLS</constant>
-with a <structfield>count</structfield> of 0. If that succeeds, then the driver
-supports this feature.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry><para>Which value of the control to get/set/try. <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
-will return the current value of the control and <constant>V4L2_CTRL_WHICH_DEF_VAL</constant> will
-return the default value of the control. Please note that you can only get the default value of the
-control, you cannot set or try it.</para>
-<para>For backwards compatibility you can also use a control class here (see
-<xref linkend="ctrl-class" />). In that case all controls have to belong to that
-control class. This usage is deprecated, instead just use <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.
-There are some very old drivers that do not yet support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
-and that require a control class here. You can test for such drivers by setting ctrl_class to
-<constant>V4L2_CTRL_WHICH_CUR_VAL</constant> and calling VIDIOC_TRY_EXT_CTRLS with a count of 0.
-If that fails, then the driver does not support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.</para>
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>count</structfield></entry>
-           <entry>The number of controls in the controls array. May
-also be zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>error_idx</structfield></entry>
-           <entry><para>Set by the driver in case of an error. If the error is
-associated with a particular control, then <structfield>error_idx</structfield>
-is set to the index of that control. If the error is not related to a specific
-control, or the validation step failed (see below), then
-<structfield>error_idx</structfield> is set to <structfield>count</structfield>.
-The value is undefined if the ioctl returned 0 (success).</para>
-
-<para>Before controls are read from/written to hardware a validation step
-takes place: this checks if all controls in the list are valid controls,
-if no attempt is made to write to a read-only control or read from a write-only
-control, and any other up-front checks that can be done without accessing the
-hardware. The exact validations done during this step are driver dependent
-since some checks might require hardware access for some devices, thus making
-it impossible to do those checks up-front. However, drivers should make a
-best-effort to do as many up-front checks as possible.</para>
-
-<para>This check is done to avoid leaving the hardware in an inconsistent state due
-to easy-to-avoid problems. But it leads to another problem: the application needs to
-know whether an error came from the validation step (meaning that the hardware
-was not touched) or from an error during the actual reading from/writing to hardware.</para>
-
-<para>The, in hindsight quite poor, solution for that is to set <structfield>error_idx</structfield>
-to <structfield>count</structfield> if the validation failed. This has the
-unfortunate side-effect that it is not possible to see which control failed the
-validation. If the validation was successful and the error happened while
-accessing the hardware, then <structfield>error_idx</structfield> is less than
-<structfield>count</structfield> and only the controls up to
-<structfield>error_idx-1</structfield> were read or written correctly, and the
-state of the remaining controls is undefined.</para>
-
-<para>Since <constant>VIDIOC_TRY_EXT_CTRLS</constant> does not access hardware
-there is also no need to handle the validation step in this special way,
-so <structfield>error_idx</structfield> will just be set to the control that
-failed the validation step instead of to <structfield>count</structfield>.
-This means that if <constant>VIDIOC_S_EXT_CTRLS</constant> fails with
-<structfield>error_idx</structfield> set to <structfield>count</structfield>,
-then you can call <constant>VIDIOC_TRY_EXT_CTRLS</constant> to try to discover
-the actual control that failed the validation step. Unfortunately, there
-is no <constant>TRY</constant> equivalent for <constant>VIDIOC_G_EXT_CTRLS</constant>.
-</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-ext-control; *</entry>
-           <entry><structfield>controls</structfield></entry>
-           <entry>Pointer to an array of
-<structfield>count</structfield> v4l2_ext_control structures. Ignored
-if <structfield>count</structfield> equals zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="ctrl-class">
-      <title>Control classes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_USER</constant></entry>
-           <entry>0x980000</entry>
-           <entry>The class containing user controls. These controls
-are described in <xref linkend="control" />. All controls that can be set
-using the &VIDIOC-S-CTRL; and &VIDIOC-G-CTRL; ioctl belong to this
-class.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_MPEG</constant></entry>
-           <entry>0x990000</entry>
-           <entry>The class containing MPEG compression controls.
-These controls are described in <xref
-               linkend="mpeg-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_CAMERA</constant></entry>
-           <entry>0x9a0000</entry>
-           <entry>The class containing camera controls.
-These controls are described in <xref
-               linkend="camera-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_FM_TX</constant></entry>
-           <entry>0x9b0000</entry>
-           <entry>The class containing FM Transmitter (FM TX) controls.
-These controls are described in <xref
-               linkend="fm-tx-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_FLASH</constant></entry>
-           <entry>0x9c0000</entry>
-           <entry>The class containing flash device controls.
-These controls are described in <xref
-               linkend="flash-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
-           <entry>0x9d0000</entry>
-           <entry>The class containing JPEG compression controls.
-These controls are described in <xref
-               linkend="jpeg-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
-           <entry>0x9e0000</entry> <entry>The class containing image
-           source controls. These controls are described in <xref
-           linkend="image-source-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_IMAGE_PROC</constant></entry>
-           <entry>0x9f0000</entry> <entry>The class containing image
-           processing controls. These controls are described in <xref
-           linkend="image-process-controls" />.</entry>
-         </row>
-
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_FM_RX</constant></entry>
-           <entry>0xa10000</entry>
-           <entry>The class containing FM Receiver (FM RX) controls.
-These controls are described in <xref
-               linkend="fm-rx-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_RF_TUNER</constant></entry>
-           <entry>0xa20000</entry>
-           <entry>The class containing RF tuner controls.
-These controls are described in <xref linkend="rf-tuner-controls" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-ext-control; <structfield>id</structfield>
-is invalid, the &v4l2-ext-controls;
-<structfield>which</structfield> is invalid, or the &v4l2-ext-control;
-<structfield>value</structfield> was inappropriate (e.g. the given menu
-index is not supported by the driver). This error code is
-also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
-<constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctls if two or more
-control values are in conflict.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The &v4l2-ext-control; <structfield>value</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The control is temporarily not changeable, possibly
-because another applications took over control of the device function
-this control belongs to.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOSPC</errorcode></term>
-       <listitem>
-         <para>The space reserved for the control's payload is insufficient.
-The field <structfield>size</structfield> is set to a value that is enough
-to store the payload and this error code is returned.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>Attempt to try or set a read-only control or to get a
-         write-only control.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
deleted file mode 100644 (file)
index 77607cc..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-<refentry id="vidioc-g-fbuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FBUF</refname>
-    <refname>VIDIOC_S_FBUF</refname>
-    <refpurpose>Get or set frame buffer overlay parameters</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_framebuffer *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_framebuffer *<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_G_FBUF, VIDIOC_S_FBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications can use the <constant>VIDIOC_G_FBUF</constant> and
-<constant>VIDIOC_S_FBUF</constant> ioctl to get and set the
-framebuffer parameters for a <link linkend="overlay">Video
-Overlay</link> or <link linkend="osd">Video Output Overlay</link>
-(OSD). The type of overlay is implied by the device type (capture or
-output device) and can be determined with the &VIDIOC-QUERYCAP; ioctl.
-One <filename>/dev/videoN</filename> device must not support both
-kinds of overlay.</para>
-
-    <para>The V4L2 API distinguishes destructive and non-destructive
-overlays. A destructive overlay copies captured video images into the
-video memory of a graphics card. A non-destructive overlay blends
-video images into a VGA signal or graphics into a video signal.
-<wordasword>Video Output Overlays</wordasword> are always
-non-destructive.</para>
-
-    <para>To get the current parameters applications call the
-<constant>VIDIOC_G_FBUF</constant> ioctl with a pointer to a
-<structname>v4l2_framebuffer</structname> structure. The driver fills
-all fields of the structure or returns an &EINVAL; when overlays are
-not supported.</para>
-
-    <para>To set the parameters for a <wordasword>Video Output
-Overlay</wordasword>, applications must initialize the
-<structfield>flags</structfield> field of a struct
-<structname>v4l2_framebuffer</structname>. Since the framebuffer is
-implemented on the TV card all other parameters are determined by the
-driver. When an application calls <constant>VIDIOC_S_FBUF</constant>
-with a pointer to this structure, the driver prepares for the overlay
-and returns the framebuffer parameters as
-<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
-code.</para>
-
-    <para>To set the parameters for a <wordasword>non-destructive
-Video Overlay</wordasword>, applications must initialize the
-<structfield>flags</structfield> field, the
-<structfield>fmt</structfield> substructure, and call
-<constant>VIDIOC_S_FBUF</constant>. Again the driver prepares for the
-overlay and returns the framebuffer parameters as
-<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
-code.</para>
-
-    <para>For a <wordasword>destructive Video Overlay</wordasword>
-applications must additionally provide a
-<structfield>base</structfield> address. Setting up a DMA to a
-random memory location can jeopardize the system security, its
-stability or even damage the hardware, therefore only the superuser
-can set the parameters for a destructive video overlay.</para>
-
-    <!-- NB v4l2_pix_format is also specified in pixfmt.sgml.-->
-
-    <table pgwide="1" frame="none" id="v4l2-framebuffer">
-      <title>struct <structname>v4l2_framebuffer</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry></entry>
-           <entry>Overlay capability flags set by the driver, see
-<xref linkend="framebuffer-cap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>Overlay control flags set by application and
-driver, see <xref linkend="framebuffer-flags" /></entry>
-         </row>
-         <row>
-           <entry>void *</entry>
-           <entry><structfield>base</structfield></entry>
-           <entry></entry>
-           <entry>Physical base address of the framebuffer,
-that is the address of the pixel in the top left corner of the
-framebuffer.<footnote><para>A physical base address may not suit all
-platforms. GK notes in theory we should pass something like PCI device
-+ memory region + offset instead. If you encounter problems please
-discuss on the linux-media mailing list: &v4l-ml;.</para></footnote></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>This field is irrelevant to
-<wordasword>non-destructive Video Overlays</wordasword>. For
-<wordasword>destructive Video Overlays</wordasword> applications must
-provide a base address. The driver may accept only base addresses
-which are a multiple of two, four or eight bytes. For
-<wordasword>Video Output Overlays</wordasword> the driver must return
-a valid base address, so applications can find the corresponding Linux
-framebuffer device (see <xref linkend="osd" />).</entry>
-         </row>
-         <row>
-           <entry>struct</entry>
-           <entry><structfield>fmt</structfield></entry>
-           <entry></entry>
-           <entry>Layout of the frame buffer.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the frame buffer in pixels.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the frame buffer in pixels.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>pixelformat</structfield></entry>
-           <entry>The pixel format of the
-framebuffer.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>For <wordasword>non-destructive Video
-Overlays</wordasword> this field only defines a format for the
-&v4l2-window; <structfield>chromakey</structfield> field.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>For <wordasword>destructive Video
-Overlays</wordasword> applications must initialize this field. For
-<wordasword>Video Output Overlays</wordasword> the driver must return
-a valid format.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Usually this is an RGB format (for example
-<link linkend="V4L2-PIX-FMT-RGB565"><constant>V4L2_PIX_FMT_RGB565</constant></link>)
-but YUV formats (only packed YUV formats when chroma keying is used,
-not including <constant>V4L2_PIX_FMT_YUYV</constant> and
-<constant>V4L2_PIX_FMT_UYVY</constant>) and the
-<constant>V4L2_PIX_FMT_PAL8</constant> format are also permitted. The
-behavior of the driver when an application requests a compressed
-format is undefined. See <xref linkend="pixfmt" /> for information on
-pixel formats.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-field;</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>Drivers and applications shall ignore this field.
-If applicable, the field order is selected with the &VIDIOC-S-FMT;
-ioctl, using the <structfield>field</structfield> field of
-&v4l2-window;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>bytesperline</structfield></entry>
-           <entry>Distance in bytes between the leftmost pixels in
-two adjacent lines.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>This field is irrelevant to
-<wordasword>non-destructive Video
-Overlays</wordasword>.</para><para>For <wordasword>destructive Video
-Overlays</wordasword> both applications and drivers can set this field
-to request padding bytes at the end of each line. Drivers however may
-ignore the requested value, returning <structfield>width</structfield>
-times bytes-per-pixel or a larger value required by the hardware. That
-implies applications can just set this field to zero to get a
-reasonable default.</para><para>For <wordasword>Video Output
-Overlays</wordasword> the driver must return a valid
-value.</para><para>Video hardware may access padding bytes, therefore
-they must reside in accessible memory. Consider for example the case
-where padding bytes after the last line of an image cross a system
-page boundary. Capture devices may write padding bytes, the value is
-undefined. Output devices ignore the contents of padding
-bytes.</para><para>When the image format is planar the
-<structfield>bytesperline</structfield> value applies to the first
-plane and is divided by the same factor as the
-<structfield>width</structfield> field for the other planes. For
-example the Cb and Cr planes of a YUV 4:2:0 image have half as many
-padding bytes following each line as the Y plane. To avoid ambiguities
-drivers must return a <structfield>bytesperline</structfield> value
-rounded up to a multiple of the scale factor.</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>sizeimage</structfield></entry>
-           <entry><para>This field is irrelevant to
-<wordasword>non-destructive Video Overlays</wordasword>. For
-<wordasword>destructive Video Overlays</wordasword> applications must
-initialize this field. For <wordasword>Video Output
-Overlays</wordasword> the driver must return a valid
-format.</para><para>Together with <structfield>base</structfield> it
-defines the framebuffer memory accessible by the
-driver.</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-colorspace;</entry>
-           <entry><structfield>colorspace</structfield></entry>
-           <entry>This information supplements the
-<structfield>pixelformat</structfield> and must be set by the driver,
-see <xref linkend="colorspaces" />.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>priv</structfield></entry>
-           <entry>Reserved. Drivers and applications must set this field to
-zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="framebuffer-cap">
-      <title>Frame Buffer Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The device is capable of non-destructive overlays.
-When the driver clears this flag, only destructive overlays are
-supported. There are no drivers yet which support both destructive and
-non-destructive overlays. Video Output Overlays are in practice always
-non-destructive.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
-           <entry>0x0002</entry>
-           <entry>The device supports clipping by chroma-keying the
-images. That is, image pixels replace pixels in the VGA or video
-signal only where the latter assume a certain color. Chroma-keying
-makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The device supports clipping using a list of clip
-rectangles.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant></entry>
-           <entry>0x0008</entry>
-           <entry>The device supports clipping using a bit mask.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LOCAL_ALPHA</constant></entry>
-           <entry>0x0010</entry>
-           <entry>The device supports clipping/blending using the
-alpha channel of the framebuffer or VGA signal. Alpha blending makes
-no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_GLOBAL_ALPHA</constant></entry>
-           <entry>0x0020</entry>
-           <entry>The device supports alpha blending using a global
-alpha value. Alpha blending makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LOCAL_INV_ALPHA</constant></entry>
-           <entry>0x0040</entry>
-           <entry>The device supports clipping/blending using the
-inverted alpha channel of the framebuffer or VGA signal. Alpha
-blending makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_SRC_CHROMAKEY</constant></entry>
-           <entry>0x0080</entry>
-           <entry>The device supports Source Chroma-keying. Video pixels
-with the chroma-key colors are replaced by framebuffer pixels, which is exactly opposite of
-<constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="framebuffer-flags">
-      <title>Frame Buffer Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_PRIMARY</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The framebuffer is the primary graphics surface.
-In other words, the overlay is destructive. This flag is typically set by any
-driver that doesn't have the <constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant>
-capability and it is cleared otherwise.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_OVERLAY</constant></entry>
-           <entry>0x0002</entry>
-           <entry>If this flag is set for a video capture device, then the
-driver will set the initial overlay size to cover the full framebuffer size,
-otherwise the existing overlay size (as set by &VIDIOC-S-FMT;) will be used.
-
-Only one video capture driver (bttv) supports this flag. The use of this flag
-for capture devices is deprecated. There is no way to detect which drivers
-support this flag, so the only reliable method of setting the overlay size is
-through &VIDIOC-S-FMT;.
-
-If this flag is set for a video output device, then the video output overlay
-window is relative to the top-left corner of the framebuffer and restricted
-to the size of the framebuffer. If it is cleared, then the video output
-overlay window is relative to the video output display.
-            </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_CHROMAKEY</constant></entry>
-           <entry>0x0004</entry>
-           <entry>Use chroma-keying. The chroma-key color is
-determined by the <structfield>chromakey</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" />
-and
-           <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">There are no flags to enable
-clipping using a list of clip rectangles or a bitmap. These methods
-are negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" /> and <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant></entry>
-           <entry>0x0008</entry>
-           <entry>Use the alpha channel of the framebuffer to clip or
-blend framebuffer pixels with video images. The blend
-function is: output = framebuffer pixel * alpha + video pixel * (1 -
-alpha). The actual alpha depth depends on the framebuffer pixel
-format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant></entry>
-           <entry>0x0010</entry>
-           <entry>Use a global alpha value to blend the framebuffer
-with video images. The blend function is: output = (framebuffer pixel
-* alpha + video pixel * (255 - alpha)) / 255. The alpha value is
-determined by the <structfield>global_alpha</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" />
-and <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_LOCAL_INV_ALPHA</constant></entry>
-           <entry>0x0020</entry>
-           <entry>Like
-<constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant>, use the alpha channel
-of the framebuffer to clip or blend framebuffer pixels with video
-images, but with an inverted alpha value. The blend function is:
-output = framebuffer pixel * (1 - alpha) + video pixel * alpha. The
-actual alpha depth depends on the framebuffer pixel format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_SRC_CHROMAKEY</constant></entry>
-           <entry>0x0040</entry>
-           <entry>Use source chroma-keying. The source chroma-key color is
-determined by the <structfield>chromakey</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-linkend="overlay" /> and <xref linkend="osd" />.
-Both chroma-keying are mutual exclusive to each other, so same
-<structfield>chromakey</structfield> field of &v4l2-window; is being used.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para><constant>VIDIOC_S_FBUF</constant> can only be called
-by a privileged user to negotiate the parameters for a destructive
-overlay.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <constant>VIDIOC_S_FBUF</constant> parameters are unsuitable.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
deleted file mode 100644 (file)
index ffcb448..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-<refentry id="vidioc-g-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FMT, VIDIOC_S_FMT,
-VIDIOC_TRY_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FMT</refname>
-    <refname>VIDIOC_S_FMT</refname>
-    <refname>VIDIOC_TRY_FMT</refname>
-    <refpurpose>Get or set the data format, try a format</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_format
-*<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_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls are used to negotiate the format of data
-(typically image format) exchanged between driver and
-application.</para>
-
-    <para>To query the current parameters applications set the
-<structfield>type</structfield> field of a struct
-<structname>v4l2_format</structname> to the respective buffer (stream)
-type. For example video capture devices use
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>. When the application
-calls the <constant>VIDIOC_G_FMT</constant> ioctl with a pointer to
-this structure the driver fills the respective member of the
-<structfield>fmt</structfield> union. In case of video capture devices
-that is either the &v4l2-pix-format; <structfield>pix</structfield> or
-the &v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member.
-When the requested buffer type is not supported drivers return an
-&EINVAL;.</para>
-
-    <para>To change the current format parameters applications
-initialize the <structfield>type</structfield> field and all
-fields of the respective <structfield>fmt</structfield>
-union member. For details see the documentation of the various devices
-types in <xref linkend="devices" />. Good practice is to query the
-current parameters first, and to
-modify only those parameters not suitable for the application. When
-the application calls the <constant>VIDIOC_S_FMT</constant> ioctl
-with a pointer to a <structname>v4l2_format</structname> structure
-the driver checks
-and adjusts the parameters against hardware abilities. Drivers
-should not return an error code unless the <structfield>type</structfield> field is invalid, this is
-a mechanism to fathom device capabilities and to approach parameters
-acceptable for both the application and driver. On success the driver
-may program the hardware, allocate resources and generally prepare for
-data exchange.
-Finally the <constant>VIDIOC_S_FMT</constant> ioctl returns the
-current format parameters as <constant>VIDIOC_G_FMT</constant> does.
-Very simple, inflexible devices may even ignore all input and always
-return the default parameters. However all V4L2 devices exchanging
-data with the application must implement the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl. When the requested buffer
-type is not supported drivers return an &EINVAL; on a
-<constant>VIDIOC_S_FMT</constant> attempt. When I/O is already in
-progress or the resource is not available for other reasons drivers
-return the &EBUSY;.</para>
-
-    <para>The <constant>VIDIOC_TRY_FMT</constant> ioctl is equivalent
-to <constant>VIDIOC_S_FMT</constant> with one exception: it does not
-change driver state. It can also be called at any time, never
-returning <errorcode>EBUSY</errorcode>. This function is provided to
-negotiate parameters, to learn about hardware limitations, without
-disabling I/O or possibly time consuming hardware preparations.
-Although strongly recommended drivers are not required to implement
-this ioctl.</para>
-
-    <para>The format as returned by <constant>VIDIOC_TRY_FMT</constant>
-must be identical to what <constant>VIDIOC_S_FMT</constant> returns for
-the same input or output.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-format">
-      <title>struct <structname>v4l2_format</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of the data stream, see <xref
-               linkend="v4l2-buf-type" />.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>fmt</structfield></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-pix-format;</entry>
-           <entry><structfield>pix</structfield></entry>
-           <entry>Definition of an image format, see <xref
-               linkend="pixfmt" />, used by video capture and output
-devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-pix-format-mplane;</entry>
-           <entry><structfield>pix_mp</structfield></entry>
-           <entry>Definition of an image format, see <xref
-               linkend="pixfmt" />, used by video capture and output
-devices that support the <link linkend="planar-apis">multi-planar
-version of the API</link>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-window;</entry>
-           <entry><structfield>win</structfield></entry>
-           <entry>Definition of an overlaid image, see <xref
-           linkend="overlay" />, used by video overlay devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-vbi-format;</entry>
-           <entry><structfield>vbi</structfield></entry>
-           <entry>Raw VBI capture or output parameters. This is
-discussed in more detail in <xref linkend="raw-vbi" />. Used by raw VBI
-capture and output devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-sliced-vbi-format;</entry>
-           <entry><structfield>sliced</structfield></entry>
-           <entry>Sliced VBI capture or output parameters. See
-<xref linkend="sliced" /> for details. Used by sliced VBI
-capture and output devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-sdr-format;</entry>
-           <entry><structfield>sdr</structfield></entry>
-           <entry>Definition of a data format, see
-<xref linkend="pixfmt" />, used by SDR capture and output devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw_data</structfield>[200]</entry>
-           <entry>Place holder for future extensions.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-format; <structfield>type</structfield>
-field is invalid or the requested buffer type not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
deleted file mode 100644 (file)
index d1034fb..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-<refentry id="vidioc-g-frequency">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FREQUENCY</refname>
-    <refname>VIDIOC_S_FREQUENCY</refname>
-    <refpurpose>Get or set tuner or modulator radio
-frequency</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_frequency
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_frequency
-*<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_G_FREQUENCY, VIDIOC_S_FREQUENCY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To get the current tuner or modulator radio frequency
-applications set the <structfield>tuner</structfield> field of a
-&v4l2-frequency; to the respective tuner or modulator number (only
-input devices have tuners, only output devices have modulators), zero
-out the <structfield>reserved</structfield> array and
-call the <constant>VIDIOC_G_FREQUENCY</constant> ioctl with a pointer
-to this structure. The driver stores the current frequency in the
-<structfield>frequency</structfield> field.</para>
-
-    <para>To change the current tuner or modulator radio frequency
-applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield> and
-<structfield>frequency</structfield> fields, and the
-<structfield>reserved</structfield> array of a &v4l2-frequency; and
-call the <constant>VIDIOC_S_FREQUENCY</constant> ioctl with a pointer
-to this structure. When the requested frequency is not possible the
-driver assumes the closest possible value. However
-<constant>VIDIOC_S_FREQUENCY</constant> is a write-only ioctl, it does
-not return the actual new frequency.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frequency">
-      <title>struct <structname>v4l2_frequency</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>The tuner or modulator index number. This is the
-same value as in the &v4l2-input; <structfield>tuner</structfield>
-field and the &v4l2-tuner; <structfield>index</structfield> field, or
-the &v4l2-output; <structfield>modulator</structfield> field and the
-&v4l2-modulator; <structfield>index</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The type must be set
-to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename>
-device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant>
-for all others. Set this field to <constant>V4L2_TUNER_RADIO</constant> for
-modulators (currently only radio modulators are supported).
-See <xref linkend="v4l2-tuner-type" /></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>frequency</structfield></entry>
-           <entry>Tuning frequency in units of 62.5 kHz, or if the
-&v4l2-tuner; or &v4l2-modulator; <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz. A 1 Hz unit is used when the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Drivers and
-           applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>tuner</structfield> index is out of
-bounds or the value in the <structfield>type</structfield> field is
-wrong.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>A hardware seek is in progress.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-input.xml b/Documentation/DocBook/media/v4l/vidioc-g-input.xml
deleted file mode 100644 (file)
index 1d43065..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<refentry id="vidioc-g-input">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_INPUT</refname>
-    <refname>VIDIOC_S_INPUT</refname>
-    <refpurpose>Query or select the current video input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>int *<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_G_INPUT, VIDIOC_S_INPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current video input applications call the
-<constant>VIDIOC_G_INPUT</constant> ioctl with a pointer to an integer
-where the driver stores the number of the input, as in the
-&v4l2-input; <structfield>index</structfield> field. This ioctl will
-fail only when there are no video inputs, returning
-<errorcode>EINVAL</errorcode>.</para>
-
-    <para>To select a video input applications store the number of the
-desired input in an integer and call the
-<constant>VIDIOC_S_INPUT</constant> ioctl with a pointer to this
-integer. Side effects are possible. For example inputs may support
-different video standards, so the driver may implicitly switch the
-current standard. Because of these possible side effects applications
-must select an input before querying or negotiating any other parameters.</para>
-
-    <para>Information about video inputs is available using the
-&VIDIOC-ENUMINPUT; ioctl.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the video input is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
deleted file mode 100644 (file)
index 098ff48..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<refentry id="vidioc-g-jpegcomp">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_JPEGCOMP</refname>
-    <refname>VIDIOC_S_JPEGCOMP</refname>
-    <refpurpose></refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_jpegcompression *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const v4l2_jpegcompression *<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_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
-    New drivers and applications should use <link linkend="jpeg-controls">
-    JPEG class controls</link> for image quality and JPEG markers control.
-    </para>
-
-    <para>[to do]</para>
-
-    <para>Ronald Bultje elaborates:</para>
-
-    <!-- See video4linux-list@redhat.com on 16 Oct 2002, subject
-"Re: [V4L] Re: v4l2 api / Zoran v4l2_jpegcompression" -->
-
-    <para>APP is some application-specific information. The
-application can set it itself, and it'll be stored in the JPEG-encoded
-fields (eg; interlacing information for in an AVI or so). COM is the
-same, but it's comments, like 'encoded by me' or so.</para>
-
-    <para>jpeg_markers describes whether the huffman tables,
-quantization tables and the restart interval information (all
-JPEG-specific stuff) should be stored in the JPEG-encoded fields.
-These define how the JPEG field is encoded. If you omit them,
-applications assume you've used standard encoding. You usually do want
-to add them.</para>
-
-    <!-- NB VIDIOC_S_JPEGCOMP is w/o. -->
-
-    <table pgwide="1" frame="none" id="v4l2-jpegcompression">
-      <title>struct <structname>v4l2_jpegcompression</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>int</entry>
-           <entry><structfield>quality</structfield></entry>
-           <entry>Deprecated. If <link linkend="jpeg-quality-control"><constant>
-           V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></link> control is exposed
-           by a driver applications should use it instead and ignore this field.
-           </entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>APPn</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>APP_len</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>APP_data</structfield>[60]</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>COM_len</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>COM_data</structfield>[60]</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>jpeg_markers</structfield></entry>
-           <entry>See <xref linkend="jpeg-markers"/>. Deprecated.
-           If <link linkend="jpeg-active-marker-control"><constant>
-           V4L2_CID_JPEG_ACTIVE_MARKER</constant></link> control
-           is exposed by a driver applications should use it instead
-           and ignore this field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="jpeg-markers">
-      <title>JPEG Markers Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DHT</constant></entry>
-           <entry>(1&lt;&lt;3)</entry>
-           <entry>Define Huffman Tables</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DQT</constant></entry>
-           <entry>(1&lt;&lt;4)</entry>
-           <entry>Define Quantization Tables</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DRI</constant></entry>
-           <entry>(1&lt;&lt;5)</entry>
-           <entry>Define Restart Interval</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_COM</constant></entry>
-           <entry>(1&lt;&lt;6)</entry>
-           <entry>Comment segment</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_APP</constant></entry>
-           <entry>(1&lt;&lt;7)</entry>
-           <entry>App segment, driver will always use APP0</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
deleted file mode 100644 (file)
index 96e17b3..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-<refentry id="vidioc-g-modulator">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_MODULATOR</refname>
-    <refname>VIDIOC_S_MODULATOR</refname>
-    <refpurpose>Get or set modulator attributes</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_modulator
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_modulator
-*<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_G_MODULATOR, VIDIOC_S_MODULATOR</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a modulator applications initialize
-the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-modulator; and
-call the <constant>VIDIOC_G_MODULATOR</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all modulators
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Modulators have two writable properties, an audio
-modulation set and the radio frequency. To change the modulated audio
-subprograms, applications initialize the <structfield>index
-</structfield> and <structfield>txsubchans</structfield> fields and the
-<structfield>reserved</structfield> array and call the
-<constant>VIDIOC_S_MODULATOR</constant> ioctl. Drivers may choose a
-different audio modulation if the request cannot be satisfied. However
-this is a write-only ioctl, it does not return the actual audio
-modulation selected.</para>
-
-    <para><link linkend="sdr">SDR</link> specific modulator types are
-<constant>V4L2_TUNER_SDR</constant> and <constant>V4L2_TUNER_RF</constant>.
-For SDR devices <structfield>txsubchans</structfield> field must be
-initialized to zero.
-The term 'modulator' means SDR transmitter in this context.</para>
-
-    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
-is available.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-modulator">
-      <title>struct <structname>v4l2_modulator</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the modulator, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the modulator, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Modulator capability flags. No flags are defined
-for this field, the tuner flags in &v4l2-tuner;
-are used accordingly. The audio flags indicate the ability
-to encode audio subprograms. They will <emphasis>not</emphasis>
-change for example with the current video standard.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry>The lowest tunable frequency in units of 62.5
-KHz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry>The highest tunable frequency in units of 62.5
-KHz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>txsubchans</structfield></entry>
-           <entry>With this field applications can determine how
-audio sub-carriers shall be modulated. It contains a set of flags as
-defined in <xref linkend="modulator-txsubchans" />. Note the tuner
-<structfield>rxsubchans</structfield> flags are reused, but the
-semantics are different. Video output devices are assumed to have an
-analog or PCM audio input with 1-3 channels. The
-<structfield>txsubchans</structfield> flags select one or more
-channels for modulation, together with some audio subprogram
-indicator, for example a stereo pilot tone.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry spanname="hspan">Type of the modulator, see <xref
-               linkend="v4l2-tuner-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="modulator-txsubchans">
-      <title>Modulator Audio Transmission Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>0x0001</entry>
-           <entry>Modulate channel 1 as mono audio, when the input
-has more channels, a down-mix of channel 1 and 2. This flag does not
-combine with <constant>V4L2_TUNER_SUB_STEREO</constant> or
-<constant>V4L2_TUNER_SUB_LANG1</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
-           <entry>0x0002</entry>
-           <entry>Modulate channel 1 and 2 as left and right
-channel of a stereo audio signal. When the input has only one channel
-or two channels and <constant>V4L2_TUNER_SUB_SAP</constant> is also
-set, channel 1 is encoded as left and right channel. This flag does
-not combine with <constant>V4L2_TUNER_SUB_MONO</constant> or
-<constant>V4L2_TUNER_SUB_LANG1</constant>. When the driver does not
-support stereo audio it shall fall back to mono.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
-           <entry>0x0008</entry>
-           <entry>Modulate channel 1 and 2 as primary and secondary
-language of a bilingual audio signal. When the input has only one
-channel it is used for both languages. It is not possible to encode
-the primary or secondary language only. This flag does not combine
-with <constant>V4L2_TUNER_SUB_MONO</constant>,
-<constant>V4L2_TUNER_SUB_STEREO</constant> or
-<constant>V4L2_TUNER_SUB_SAP</constant>. If the hardware does not
-support the respective audio matrix, or the current video standard
-does not permit bilingual audio the
-<constant>VIDIOC_S_MODULATOR</constant> ioctl shall return an &EINVAL;
-and the driver shall fall back to mono or stereo mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
-           <entry>0x0004</entry>
-           <entry>Same effect as
-<constant>V4L2_TUNER_SUB_SAP</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
-           <entry>0x0004</entry>
-           <entry>When combined with <constant>V4L2_TUNER_SUB_MONO
-</constant> the first channel is encoded as mono audio, the last
-channel as Second Audio Program. When the input has only one channel
-it is used for both audio tracks. When the input has three channels
-the mono track is a down-mix of channel 1 and 2. When combined with
-<constant>V4L2_TUNER_SUB_STEREO</constant> channel 1 and 2 are
-encoded as left and right stereo audio, channel 3 as Second Audio
-Program. When the input has only two channels, the first is encoded as
-left and right channel and the second as SAP. When the input has only
-one channel it is used for all audio tracks. It is not possible to
-encode a Second Audio Program only. This flag must combine with
-<constant>V4L2_TUNER_SUB_MONO</constant> or
-<constant>V4L2_TUNER_SUB_STEREO</constant>. If the hardware does not
-support the respective audio matrix, or the current video standard
-does not permit SAP the <constant>VIDIOC_S_MODULATOR</constant> ioctl
-shall return an &EINVAL; and driver shall fall back to mono or stereo
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
-           <entry>0x0010</entry>
-           <entry>Enable the RDS encoder for a radio FM transmitter.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-modulator;
-<structfield>index</structfield> is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-output.xml b/Documentation/DocBook/media/v4l/vidioc-g-output.xml
deleted file mode 100644 (file)
index 4533068..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<refentry id="vidioc-g-output">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_OUTPUT</refname>
-    <refname>VIDIOC_S_OUTPUT</refname>
-    <refpurpose>Query or select the current video output</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>int *<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_G_OUTPUT, VIDIOC_S_OUTPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current video output applications call the
-<constant>VIDIOC_G_OUTPUT</constant> ioctl with a pointer to an integer
-where the driver stores the number of the output, as in the
-&v4l2-output; <structfield>index</structfield> field. This ioctl
-will fail only when there are no video outputs, returning the
-&EINVAL;.</para>
-
-    <para>To select a video output applications store the number of the
-desired output in an integer and call the
-<constant>VIDIOC_S_OUTPUT</constant> ioctl with a pointer to this integer.
-Side effects are possible. For example outputs may support different
-video standards, so the driver may implicitly switch the current
-standard.
-standard. Because of these possible side effects applications
-must select an output before querying or negotiating any other parameters.</para>
-
-    <para>Information about video outputs is available using the
-&VIDIOC-ENUMOUTPUT; ioctl.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the video output is out of bounds, or
-there are no video outputs at all.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
deleted file mode 100644 (file)
index 7217287..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-<refentry id="vidioc-g-parm">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_PARM, VIDIOC_S_PARM</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_PARM</refname>
-    <refname>VIDIOC_S_PARM</refname>
-    <refpurpose>Get or set streaming parameters</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_streamparm *<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_G_PARM, VIDIOC_S_PARM</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The current video standard determines a nominal number of
-frames per second. If less than this number of frames is to be
-captured or output, applications can request frame skipping or
-duplicating on the driver side. This is especially useful when using
-the <function>read()</function> or <function>write()</function>, which
-are not augmented by timestamps or sequence counters, and to avoid
-unnecessary data copying.</para>
-
-    <para>Further these ioctls can be used to determine the number of
-buffers used internally by a driver in read/write mode. For
-implications see the section discussing the &func-read;
-function.</para>
-
-    <para>To get and set the streaming parameters applications call
-the <constant>VIDIOC_G_PARM</constant> and
-<constant>VIDIOC_S_PARM</constant> ioctl, respectively. They take a
-pointer to a struct <structname>v4l2_streamparm</structname> which
-contains a union holding separate parameters for input and output
-devices.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-streamparm">
-      <title>struct <structname>v4l2_streamparm</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>The buffer (stream) type, same as &v4l2-format;
-<structfield>type</structfield>, set by the application. See <xref
-           linkend="v4l2-buf-type" /></entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>parm</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-captureparm;</entry>
-           <entry><structfield>capture</structfield></entry>
-           <entry>Parameters for capture devices, used when
-<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-outputparm;</entry>
-           <entry><structfield>output</structfield></entry>
-           <entry>Parameters for output devices, used when
-<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw_data</structfield>[200]</entry>
-           <entry>A place holder for future extensions.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-captureparm">
-      <title>struct <structname>v4l2_captureparm</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>See <xref linkend="parm-caps" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capturemode</structfield></entry>
-           <entry>Set by drivers and applications, see <xref linkend="parm-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>timeperframe</structfield></entry>
-           <entry><para>This is the desired period between
-successive frames captured by the driver, in seconds. The
-field is intended to skip frames on the driver side, saving I/O
-bandwidth.</para><para>Applications store here the desired frame
-period, drivers return the actual frame period, which must be greater
-or equal to the nominal frame period determined by the current video
-standard (&v4l2-standard; <structfield>frameperiod</structfield>
-field). Changing the video standard (also implicitly by switching the
-video input) may reset this parameter to the nominal frame period. To
-reset manually applications can just set this field to
-zero.</para><para>Drivers support this function only when they set the
-<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
-<structfield>capability</structfield> field.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>extendedmode</structfield></entry>
-           <entry>Custom (driver specific) streaming parameters. When
-unused, applications and drivers must set this field to zero.
-Applications using this field should check the driver name and
-version, see <xref linkend="querycap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>readbuffers</structfield></entry>
-           <entry>Applications set this field to the desired number
-of buffers used internally by the driver in &func-read; mode. Drivers
-return the actual number of buffers. When an application requests zero
-buffers, drivers should just return the current setting rather than
-the minimum or an error code. For details see <xref
-               linkend="rw" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-outputparm">
-      <title>struct <structname>v4l2_outputparm</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>See <xref linkend="parm-caps" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>outputmode</structfield></entry>
-           <entry>Set by drivers and applications, see <xref
-           linkend="parm-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>timeperframe</structfield></entry>
-           <entry>This is the desired period between
-successive frames output by the driver, in seconds.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>The field is intended to
-repeat frames on the driver side in &func-write; mode (in streaming
-mode timestamps can be used to throttle the output), saving I/O
-bandwidth.</para><para>Applications store here the desired frame
-period, drivers return the actual frame period, which must be greater
-or equal to the nominal frame period determined by the current video
-standard (&v4l2-standard; <structfield>frameperiod</structfield>
-field). Changing the video standard (also implicitly by switching the
-video output) may reset this parameter to the nominal frame period. To
-reset manually applications can just set this field to
-zero.</para><para>Drivers support this function only when they set the
-<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
-<structfield>capability</structfield> field.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>extendedmode</structfield></entry>
-           <entry>Custom (driver specific) streaming parameters. When
-unused, applications and drivers must set this field to zero.
-Applications using this field should check the driver name and
-version, see <xref linkend="querycap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>writebuffers</structfield></entry>
-           <entry>Applications set this field to the desired number
-of buffers used internally by the driver in
-<function>write()</function> mode. Drivers return the actual number of
-buffers. When an application requests zero buffers, drivers should
-just return the current setting rather than the minimum or an error
-code. For details see <xref linkend="rw" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="parm-caps">
-      <title>Streaming Parameters Capabilites</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CAP_TIMEPERFRAME</constant></entry>
-           <entry>0x1000</entry>
-           <entry>The frame skipping/repeating controlled by the
-<structfield>timeperframe</structfield> field is supported.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="parm-flags">
-      <title>Capture Parameters Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MODE_HIGHQUALITY</constant></entry>
-           <entry>0x0001</entry>
-           <entry><para>High quality imaging mode. High quality mode
-is intended for still imaging applications. The idea is to get the
-best possible image quality that the hardware can deliver. It is not
-defined how the driver writer may achieve that; it will depend on the
-hardware and the ingenuity of the driver writer. High quality mode is
-a different mode from the regular motion video capture modes. In
-high quality mode:<itemizedlist>
-                 <listitem>
-                   <para>The driver may be able to capture higher
-resolutions than for motion capture.</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may support fewer pixel formats
-than motion capture (eg; true color).</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may capture and arithmetically
-combine multiple successive fields or frames to remove color edge
-artifacts and reduce the noise in the video data.
-</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may capture images in slices like
-a scanner in order to handle larger format images than would otherwise
-be possible. </para>
-                 </listitem>
-                 <listitem>
-                   <para>An image capture operation may be
-significantly slower than motion capture. </para>
-                 </listitem>
-                 <listitem>
-                   <para>Moving objects in the image might have
-excessive motion blur. </para>
-                 </listitem>
-                 <listitem>
-                   <para>Capture might only work through the
-<function>read()</function> call.</para>
-                 </listitem>
-               </itemizedlist></para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-priority.xml b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml
deleted file mode 100644 (file)
index 6a81b4f..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<refentry id="vidioc-g-priority">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_PRIORITY</refname>
-    <refname>VIDIOC_S_PRIORITY</refname>
-    <refpurpose>Query or request the access priority associated with a
-file descriptor</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>enum v4l2_priority *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const enum v4l2_priority *<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_G_PRIORITY, VIDIOC_S_PRIORITY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to an enum v4l2_priority type.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current access priority
-applications call the <constant>VIDIOC_G_PRIORITY</constant> ioctl
-with a pointer to an enum v4l2_priority variable where the driver stores
-the current priority.</para>
-
-    <para>To request an access priority applications store the
-desired priority in an enum v4l2_priority variable and call
-<constant>VIDIOC_S_PRIORITY</constant> ioctl with a pointer to this
-variable.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-priority">
-      <title>enum v4l2_priority</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_PRIORITY_UNSET</constant></entry>
-           <entry>0</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_BACKGROUND</constant></entry>
-           <entry>1</entry>
-           <entry>Lowest priority, usually applications running in
-background, for example monitoring VBI transmissions. A proxy
-application running in user space will be necessary if multiple
-applications want to read from a device at this priority.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_INTERACTIVE</constant></entry>
-           <entry>2</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_DEFAULT</constant></entry>
-           <entry>2</entry>
-           <entry>Medium priority, usually applications started and
-interactively controlled by the user. For example TV viewers, Teletext
-browsers, or just "panel" applications to change the channel or video
-controls. This is the default priority unless an application requests
-another.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_RECORD</constant></entry>
-           <entry>3</entry>
-           <entry>Highest priority. Only one file descriptor can have
-this priority, it blocks any other fd from changing device properties.
-Usually applications which must not be interrupted, like video
-recording.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The requested priority value is invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>Another application already requested higher
-priority.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
deleted file mode 100644 (file)
index 997f4e9..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-<refentry id="vidioc-g-selection">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_SELECTION, VIDIOC_S_SELECTION</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_SELECTION</refname>
-    <refname>VIDIOC_S_SELECTION</refname>
-    <refpurpose>Get or set one of the selection rectangles</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_selection *<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_G_SELECTION, VIDIOC_S_SELECTION</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The ioctls are used to query and configure selection rectangles.</para>
-
-<para>To query the cropping (composing) rectangle set &v4l2-selection;
-<structfield> type </structfield> field to the respective buffer type.
-Do not use the multiplanar buffer types.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
-instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and use
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.  The next step is
-setting the value of &v4l2-selection; <structfield>target</structfield> field
-to <constant>V4L2_SEL_TGT_CROP</constant> (<constant>V4L2_SEL_TGT_COMPOSE</constant>).
-Please refer to table <xref linkend="v4l2-selections-common" /> or <xref linkend="selection-api" />
-for additional targets.  The <structfield>flags</structfield> and <structfield>reserved
-</structfield> fields of &v4l2-selection; are ignored and they must be filled
-with zeros.  The driver fills the rest of the structure or
-returns &EINVAL; if incorrect buffer type or target was used. If cropping
-(composing) is not supported then the active rectangle is not mutable and it is
-always equal to the bounds rectangle.  Finally, the &v4l2-rect;
-<structfield>r</structfield> rectangle is filled with the current cropping
-(composing) coordinates. The coordinates are expressed in driver-dependent
-units. The only exception are rectangles for images in raw formats, whose
-coordinates are always expressed in pixels.</para>
-
-<para>To change the cropping (composing) rectangle set the &v4l2-selection;
-<structfield>type</structfield> field to the respective buffer type.  Do not
-use multiplanar buffers.  Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>
-instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>.  Use
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.  The next step is
-setting the value of &v4l2-selection; <structfield>target</structfield> to
-<constant>V4L2_SEL_TGT_CROP</constant> (<constant>V4L2_SEL_TGT_COMPOSE</constant>).
-Please refer to table <xref linkend="v4l2-selections-common" /> or <xref linkend="selection-api" />
-for additional targets.  The &v4l2-rect; <structfield>r</structfield> rectangle need to be
-set to the desired active area. Field &v4l2-selection; <structfield> reserved
-</structfield> is ignored and must be filled with zeros.  The driver may adjust
-coordinates of the requested rectangle. An application may
-introduce constraints to control rounding behaviour. The &v4l2-selection;
-<structfield>flags</structfield> field must be set to one of the following:
-
-<itemizedlist>
-  <listitem>
-<para><constant>0</constant> - The driver can adjust the rectangle size freely
-and shall choose a crop/compose rectangle as close as possible to the requested
-one.</para>
-  </listitem>
-  <listitem>
-<para><constant>V4L2_SEL_FLAG_GE</constant> - The driver is not allowed to
-shrink the rectangle.  The original rectangle must lay inside the adjusted
-one.</para>
-  </listitem>
-  <listitem>
-<para><constant>V4L2_SEL_FLAG_LE</constant> - The driver is not allowed to
-enlarge the rectangle.  The adjusted rectangle must lay inside the original
-one.</para>
-  </listitem>
-  <listitem>
-<para><constant>V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE</constant> - The driver
-must choose the size exactly the same as in the requested rectangle.</para>
-  </listitem>
-</itemizedlist>
-
-Please refer to <xref linkend="sel-const-adjust" />.
-
-</para>
-
-<para> The driver may have to adjusts the requested dimensions against hardware
-limits and other parts as the pipeline, i.e. the bounds given by the
-capture/output window or TV display. The closest possible values of horizontal
-and vertical offset and sizes are chosen according to following priority:
-
-<orderedlist>
-  <listitem>
-    <para>Satisfy constraints from &v4l2-selection; <structfield>flags</structfield>.</para>
-  </listitem>
-  <listitem>
-    <para>Adjust width, height, left, and top to hardware limits and alignments.</para>
-  </listitem>
-  <listitem>
-    <para>Keep center of adjusted rectangle as close as possible to the original one.</para>
-  </listitem>
-  <listitem>
-    <para>Keep width and height as close as possible to original ones.</para>
-  </listitem>
-  <listitem>
-    <para>Keep horizontal and vertical offset as close as possible to original ones.</para>
-  </listitem>
-</orderedlist>
-
-On success the &v4l2-rect; <structfield>r</structfield> field contains
-the adjusted rectangle. When the parameters are unsuitable the application may
-modify the cropping (composing) or image parameters and repeat the cycle until
-satisfactory parameters have been negotiated. If constraints flags have to be
-violated at then ERANGE is returned. The error indicates that <emphasis>there
-exist no rectangle</emphasis> that satisfies the constraints.</para>
-
-  <para>Selection targets and flags are documented in <xref
-  linkend="v4l2-selections-common"/>.</para>
-
-    <para>
-      <figure id="sel-const-adjust">
-       <title>Size adjustments with constraint flags.</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="constraints.png" format="PNG" />
-         </imageobject>
-         <textobject>
-           <phrase>Behaviour of rectangle adjustment for different constraint
-            flags.</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-    </para>
-
-  <para>
-    <table pgwide="1" frame="none" id="v4l2-selection">
-      <title>struct <structname>v4l2_selection</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the buffer (from &v4l2-buf-type;).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>target</structfield></entry>
-            <entry>Used to select between <link linkend="v4l2-selections-common"> cropping
-           and composing rectangles</link>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-            <entry>Flags controlling the selection rectangle adjustments, refer to
-           <link linkend="v4l2-selection-flags">selection flags</link>.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>r</structfield></entry>
-           <entry>The selection rectangle.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[9]</structfield></entry>
-           <entry>Reserved fields for future use. Drivers and applications must zero this array.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>Given buffer type <structfield>type</structfield> or
-the selection target <structfield>target</structfield> is not supported,
-or the <structfield>flags</structfield> argument is not valid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>It is not possible to adjust &v4l2-rect; <structfield>
-r</structfield> rectangle to satisfy all constraints given in the
-<structfield>flags</structfield> argument.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>It is not possible to apply change of the selection rectangle
-at the moment. Usually because streaming is in progress.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
deleted file mode 100644 (file)
index d05623c..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-<refentry id="vidioc-g-sliced-vbi-cap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_SLICED_VBI_CAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_SLICED_VBI_CAP</refname>
-    <refpurpose>Query sliced VBI capabilities</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_sliced_vbi_cap *<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_G_SLICED_VBI_CAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To find out which data services are supported by a sliced
-VBI capture or output device, applications initialize the
-<structfield>type</structfield> field of a &v4l2-sliced-vbi-cap;,
-clear the <structfield>reserved</structfield> array and
-call the <constant>VIDIOC_G_SLICED_VBI_CAP</constant> ioctl. The
-driver fills in the remaining fields or returns an &EINVAL; if the
-sliced VBI API is unsupported or <structfield>type</structfield>
-is invalid.</para>
-
-    <para>Note the <structfield>type</structfield> field was added,
-and the ioctl changed from read-only to write-read, in Linux 2.6.19.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-sliced-vbi-cap">
-      <title>struct <structname>v4l2_sliced_vbi_cap</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="3*" />
-       <colspec colname="c2" colwidth="3*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec spanname="hspan" namest="c3" nameend="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_set</structfield></entry>
-           <entry spanname="hspan">A set of all data services
-supported by the driver. Equal to the union of all elements of the
-<structfield>service_lines </structfield> array.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_lines</structfield>[2][24]</entry>
-           <entry spanname="hspan">Each element of this array
-contains a set of data services the hardware can look for or insert
-into a particular scan line. Data services are defined in <xref
-               linkend="vbi-services" />. Array indices map to ITU-R
-line numbers (see also <xref
-               linkend="vbi-525" /> and <xref
-linkend="vbi-625" />) as follows:</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Element</entry>
-           <entry>525 line systems</entry>
-           <entry>625 line systems</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][1]</entry>
-           <entry align="center">1</entry>
-           <entry align="center">1</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][23]</entry>
-           <entry align="center">23</entry>
-           <entry align="center">23</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][1]</entry>
-           <entry align="center">264</entry>
-           <entry align="center">314</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][23]</entry>
-           <entry align="center">286</entry>
-           <entry align="center">336</entry>
-         </row>
-         <row>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">The number of VBI lines the
-hardware can capture or output per frame, or the number of services it
-can identify on a given line may be limited. For example on PAL line
-16 the hardware may be able to look for a VPS or Teletext signal, but
-not both at the same time. Applications can learn about these limits
-using the &VIDIOC-S-FMT; ioctl as described in <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">Drivers must set
-<structfield>service_lines</structfield>[0][0] and
-<structfield>service_lines</structfield>[1][0] to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, see <xref
-                 linkend="v4l2-buf-type" />. Should be
-<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry spanname="hspan">This array is reserved for future
-extensions. Applications and drivers must set it to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- See also dev-sliced-vbi.sgml -->
-    <table pgwide="1" frame="none" id="vbi-services">
-      <title>Sliced VBI services</title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="2*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec spanname='rlp' namest='c3' nameend='c5' />
-       <thead>
-         <row>
-           <entry>Symbol</entry>
-           <entry>Value</entry>
-           <entry>Reference</entry>
-           <entry>Lines, usually</entry>
-           <entry>Payload</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SLICED_TELETEXT_B</constant> (Teletext
-System B)</entry>
-           <entry>0x0001</entry>
-           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
-           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
-           <entry>Last 42 of the 45 byte Teletext packet, that is
-without clock run-in and framing code, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VPS</constant></entry>
-           <entry>0x0400</entry>
-           <entry><xref linkend="ets300231" /></entry>
-           <entry>PAL line 16</entry>
-           <entry>Byte number 3 to 15 according to Figure 9 of
-ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry><xref linkend="cea608" /></entry>
-           <entry>NTSC line 21, 284 (second field 21)</entry>
-           <entry>Two bytes in transmission order, including parity
-bit, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
-           <entry>0x4000</entry>
-           <entry><xref linkend="en300294" />, <xref linkend="itu1119" /></entry>
-           <entry>PAL/SECAM line 23</entry>
-           <entry><screen>
-Byte        0                 1
-     msb         lsb  msb           lsb
-Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
-</screen></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry spanname="rlp">Set of services applicable to 525
-line systems.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
-           <entry>0x4401</entry>
-           <entry spanname="rlp">Set of services applicable to 625
-line systems.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The value in the <structfield>type</structfield> field is
-wrong.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-std.xml b/Documentation/DocBook/media/v4l/vidioc-g-std.xml
deleted file mode 100644 (file)
index 4a89841..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<refentry id="vidioc-g-std">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_STD, VIDIOC_S_STD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_STD</refname>
-    <refname>VIDIOC_S_STD</refname>
-    <refpurpose>Query or select the video standard of the current input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_std_id
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const v4l2_std_id
-*<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_G_STD, VIDIOC_S_STD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query and select the current video standard applications
-use the <constant>VIDIOC_G_STD</constant> and <constant>VIDIOC_S_STD</constant> ioctls which take a pointer to a
-&v4l2-std-id; type as argument. <constant>VIDIOC_G_STD</constant> can
-return a single flag or a set of flags as in &v4l2-standard; field
-<structfield>id</structfield>. The flags must be unambiguous such
-that they appear in only one enumerated <structname>v4l2_standard</structname> structure.</para>
-
-    <para><constant>VIDIOC_S_STD</constant> accepts one or more
-flags, being a write-only ioctl it does not return the actual new standard as
-<constant>VIDIOC_G_STD</constant> does. When no flags are given or
-the current input does not support the requested standard the driver
-returns an &EINVAL;. When the standard set is ambiguous drivers may
-return <errorcode>EINVAL</errorcode> or choose any of the requested
-standards. If the current input or output does not support standard video timings (e.g. if
-&VIDIOC-ENUMINPUT; does not set the <constant>V4L2_IN_CAP_STD</constant> flag), then
-&ENODATA; is returned.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Standard video timings are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
deleted file mode 100644 (file)
index 459b7e5..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-<refentry id="vidioc-g-tuner">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_TUNER</refname>
-    <refname>VIDIOC_S_TUNER</refname>
-    <refpurpose>Get or set tuner attributes</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_tuner
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_tuner
-*<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_G_TUNER, VIDIOC_S_TUNER</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a tuner applications initialize the
-<structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-tuner; and call the
-<constant>VIDIOC_G_TUNER</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all tuners
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Tuners have two writable properties, the audio mode and
-the radio frequency. To change the audio mode, applications initialize
-the <structfield>index</structfield>,
-<structfield>audmode</structfield> and
-<structfield>reserved</structfield> fields and call the
-<constant>VIDIOC_S_TUNER</constant> ioctl. This will
-<emphasis>not</emphasis> change the current tuner, which is determined
-by the current video input. Drivers may choose a different audio mode
-if the requested mode is invalid or unsupported. Since this is a
-<!-- FIXME -->write-only ioctl, it does not return the actually
-selected audio mode.</para>
-
-    <para><link linkend="sdr">SDR</link> specific tuner types are
-<constant>V4L2_TUNER_SDR</constant> and <constant>V4L2_TUNER_RF</constant>.
-For SDR devices <structfield>audmode</structfield> field must be
-initialized to zero.
-The term 'tuner' means SDR receiver in this context.</para>
-
-    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
-is available.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-tuner">
-      <title>struct <structname>v4l2_tuner</structname></title>
-      <tgroup cols="3">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="1*" />
-       <spanspec spanname="hspan" namest="c3" nameend="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry spanname="hspan">Identifies the tuner, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry spanname="hspan"><para>Name of the tuner, a
-NUL-terminated ASCII string. This information is intended for the
-user.<!-- FIXME Video inputs already have a name, the purpose of this
-field is not quite clear.--></para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry spanname="hspan">Type of the tuner, see <xref
-               linkend="v4l2-tuner-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry spanname="hspan"><para>Tuner capability flags, see
-<xref linkend="tuner-capability" />. Audio flags indicate the ability
-to decode audio subprograms. They will <emphasis>not</emphasis>
-change, for example with the current video standard.</para><para>When
-the structure refers to a radio tuner the
-<constant>V4L2_TUNER_CAP_LANG1</constant>,
-<constant>V4L2_TUNER_CAP_LANG2</constant> and
-<constant>V4L2_TUNER_CAP_NORM</constant> flags can't be used.</para>
-<para>If multiple frequency bands are supported, then
-<structfield>capability</structfield> is the union of all
-<structfield>capability</structfield> fields of each &v4l2-frequency-band;.
-</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry spanname="hspan">The lowest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.
-If multiple frequency bands are supported, then
-<structfield>rangelow</structfield> is the lowest frequency
-of all the frequency bands.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry spanname="hspan">The highest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_1HZ</constant> is set, in units of 1 Hz.
-If multiple frequency bands are supported, then
-<structfield>rangehigh</structfield> is the highest frequency
-of all the frequency bands.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rxsubchans</structfield></entry>
-           <entry spanname="hspan"><para>Some tuners or audio
-decoders can determine the received audio subprograms by analyzing
-audio carriers, pilot tones or other indicators. To pass this
-information drivers set flags defined in <xref
-                 linkend="tuner-rxsubchans" /> in this field. For
-example:</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>receiving mono audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>STEREO | SAP</constant></entry>
-           <entry>receiving stereo audio and a secondary audio
-program</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>MONO | STEREO</constant></entry>
-           <entry>receiving mono or stereo audio, the hardware cannot
-distinguish</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>LANG1 | LANG2</constant></entry>
-           <entry>receiving bilingual audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>MONO | STEREO | LANG1 | LANG2</constant></entry>
-           <entry>receiving mono, stereo or bilingual
-audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan"><para>When the
-<constant>V4L2_TUNER_CAP_STEREO</constant>,
-<constant>_LANG1</constant>, <constant>_LANG2</constant> or
-<constant>_SAP</constant> flag is cleared in the
-<structfield>capability</structfield> field, the corresponding
-<constant>V4L2_TUNER_SUB_</constant> flag must not be set
-here.</para><para>This field is valid only if this is the tuner of the
-current video input, or when the structure refers to a radio
-tuner.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audmode</structfield></entry>
-           <entry spanname="hspan"><para>The selected audio mode, see
-<xref linkend="tuner-audmode" /> for valid values. The audio mode does
-not affect audio subprogram detection, and like a <link
-linkend="control">control</link> it does not automatically change
-unless the requested mode is invalid or unsupported. See <xref
-                 linkend="tuner-matrix" /> for possible results when
-the selected and received audio programs do not
-match.</para><para>Currently this is the only field of struct
-<structname>v4l2_tuner</structname> applications can
-change.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>signal</structfield></entry>
-           <entry spanname="hspan">The signal strength if known, ranging
-from 0 to 65535. Higher values indicate a better signal.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>afc</structfield></entry>
-           <entry spanname="hspan">Automatic frequency control: When the
-<structfield>afc</structfield> value is negative, the frequency is too
-low, when positive too high.<!-- FIXME need example what to do when it never
-settles at zero, &ie; range is what? --></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry spanname="hspan">Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-tuner-type">
-      <title>enum v4l2_tuner_type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_RADIO</constant></entry>
-           <entry>1</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_ANALOG_TV</constant></entry>
-           <entry>2</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SDR</constant></entry>
-           <entry>4</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_RF</constant></entry>
-           <entry>5</entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-capability">
-      <title>Tuner and Modulator Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LOW</constant></entry>
-           <entry>0x0001</entry>
-           <entry>When set, tuning frequencies are expressed in units of
-62.5 Hz instead of 62.5 kHz.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_NORM</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This is a multi-standard tuner; the video standard
-can or must be switched. (B/G PAL tuners for example are typically not
-      considered multi-standard because the video standard is automatically
-      determined from the frequency band.) The set of supported video
-      standards is available from the &v4l2-input; pointing to this tuner,
-      see the description of ioctl &VIDIOC-ENUMINPUT; for details. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_HWSEEK_BOUNDED</constant></entry>
-           <entry>0x0004</entry>
-           <entry>If set, then this tuner supports the hardware seek functionality
-           where the seek stops when it reaches the end of the frequency range.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_HWSEEK_WRAP</constant></entry>
-           <entry>0x0008</entry>
-           <entry>If set, then this tuner supports the hardware seek functionality
-           where the seek wraps around when it reaches the end of the frequency range.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
-       <entry>0x0010</entry>
-       <entry>Stereo audio reception is supported.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LANG1</constant></entry>
-           <entry>0x0040</entry>
-           <entry>Reception of the primary language of a bilingual
-audio program is supported. Bilingual audio is a feature of
-two-channel systems, transmitting the primary language monaural on the
-main audio carrier and a secondary language monaural on a second
-carrier. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LANG2</constant></entry>
-           <entry>0x0020</entry>
-           <entry>Reception of the secondary language of a bilingual
-audio program is supported. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_SAP</constant></entry>
-           <entry>0x0020</entry>
-           <entry><para>Reception of a secondary audio program is
-supported. This is a feature of the BTSC system which accompanies the
-NTSC video standard. Two audio carriers are available for mono or
-stereo transmissions of a primary language, and an independent third
-carrier for a monaural secondary language. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</para><para>Note the
-<constant>V4L2_TUNER_CAP_LANG2</constant> and
-<constant>V4L2_TUNER_CAP_SAP</constant> flags are synonyms.
-<constant>V4L2_TUNER_CAP_SAP</constant> applies when the tuner
-supports the <constant>V4L2_STD_NTSC_M</constant> video
-standard.</para><!-- FIXME what if PAL+NTSC and Bi but not SAP? --></entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_RDS</constant></entry>
-       <entry>0x0080</entry>
-       <entry>RDS capture is supported. This capability is only valid for
-radio tuners.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant></entry>
-       <entry>0x0100</entry>
-       <entry>The RDS data is passed as unparsed RDS blocks.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant></entry>
-       <entry>0x0200</entry>
-       <entry>The RDS data is parsed by the hardware and set via controls.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_FREQ_BANDS</constant></entry>
-       <entry>0x0400</entry>
-       <entry>The &VIDIOC-ENUM-FREQ-BANDS; ioctl can be used to enumerate
-       the available frequency bands.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_HWSEEK_PROG_LIM</constant></entry>
-       <entry>0x0800</entry>
-       <entry>The range to search when using the hardware seek functionality
-       is programmable, see &VIDIOC-S-HW-FREQ-SEEK; for details.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_1HZ</constant></entry>
-       <entry>0x1000</entry>
-       <entry>When set, tuning frequencies are expressed in units of 1 Hz instead of 62.5 kHz.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-rxsubchans">
-      <title>Tuner Audio Reception Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The tuner receives a mono audio signal.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
-           <entry>0x0002</entry>
-           <entry>The tuner receives a stereo audio signal.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
-           <entry>0x0008</entry>
-           <entry>The tuner receives the primary language of a
-bilingual audio signal. Drivers must clear this flag when the current
-video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The tuner receives the secondary language of a
-bilingual audio signal (or a second audio program).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The tuner receives a Second Audio Program. Note the
-<constant>V4L2_TUNER_SUB_LANG2</constant> and
-<constant>V4L2_TUNER_SUB_SAP</constant> flags are synonyms. The
-<constant>V4L2_TUNER_SUB_SAP</constant> flag applies when the
-current video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
-           <entry>0x0010</entry>
-           <entry>The tuner receives an RDS channel.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-audmode">
-      <title>Tuner Audio Modes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_MONO</constant></entry>
-           <entry>0</entry>
-           <entry>Play mono audio. When the tuner receives a stereo
-signal this a down-mix of the left and right channel. When the tuner
-receives a bilingual or SAP signal this mode selects the primary
-language.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_STEREO</constant></entry>
-           <entry>1</entry>
-           <entry><para>Play stereo audio. When the tuner receives
-bilingual audio it may play different languages on the left and right
-channel or the primary language is played on both channels.</para><para>Playing
-different languages in this mode is
-deprecated. New drivers should do this only in
-<constant>MODE_LANG1_LANG2</constant>.</para><para>When the tuner
-receives no stereo signal or does not support stereo reception the
-driver shall fall back to <constant>MODE_MONO</constant>.</para></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG1</constant></entry>
-           <entry>3</entry>
-           <entry>Play the primary language, mono or stereo. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG2</constant></entry>
-           <entry>2</entry>
-           <entry>Play the secondary language, mono. When the tuner
-receives no bilingual audio or SAP, or their reception is not
-supported the driver shall fall back to mono or stereo mode. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_SAP</constant></entry>
-           <entry>2</entry>
-           <entry>Play the Second Audio Program. When the tuner
-receives no bilingual audio or SAP, or their reception is not
-supported the driver shall fall back to mono or stereo mode. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this mode.
-Note the <constant>V4L2_TUNER_MODE_LANG2</constant> and
-<constant>V4L2_TUNER_MODE_SAP</constant> are synonyms.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG1_LANG2</constant></entry>
-           <entry>4</entry>
-           <entry>Play the primary language on the left channel, the
-secondary language on the right channel. When the tuner receives no
-bilingual audio or SAP, it shall fall back to
-<constant>MODE_LANG1</constant> or <constant>MODE_MONO</constant>.
-Only <constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="all" id="tuner-matrix">
-      <title>Tuner Audio Matrix</title>
-      <tgroup cols="6" align="center">
-       <colspec align="left" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colwidth="1*" />
-       <colspec colwidth="1*" />
-       <colspec colnum="6" colname="c6" colwidth="1*" />
-       <spanspec namest="c2" nameend="c6" spanname="hspan" align="center" />
-       <thead>
-         <row>
-           <entry></entry>
-           <entry spanname="hspan">Selected
-<constant>V4L2_TUNER_MODE_</constant></entry>
-         </row>
-         <row>
-           <entry>Received <constant>V4L2_TUNER_SUB_</constant></entry>
-           <entry><constant>MONO</constant></entry>
-           <entry><constant>STEREO</constant></entry>
-           <entry><constant>LANG1</constant></entry>
-           <entry><constant>LANG2 = SAP</constant></entry>
-           <entry><constant>LANG1_LANG2</constant><footnote><para>This
-mode has been added in Linux 2.6.17 and may not be supported by older
-drivers.</para></footnote></entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MONO</constant></entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-           <entry>Mono</entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-         </row>
-         <row>
-           <entry><constant>MONO | SAP</constant></entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-           <entry>Mono</entry>
-           <entry>SAP</entry>
-           <entry>Mono/SAP (preferred) or Mono/Mono</entry>
-         </row>
-         <row>
-           <entry><constant>STEREO</constant></entry>
-           <entry>L+R</entry>
-           <entry>L/R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>L/R (preferred) or L+R/L+R</entry>
-         </row>
-         <row>
-           <entry><constant>STEREO | SAP</constant></entry>
-           <entry>L+R</entry>
-           <entry>L/R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>SAP</entry>
-           <entry>L+R/SAP (preferred) or L/R or L+R/L+R</entry>
-         </row>
-         <row>
-           <entry><constant>LANG1 | LANG2</constant></entry>
-           <entry>Language&nbsp;1</entry>
-           <entry>Lang1/Lang2 (deprecated<footnote><para>Playback of
-both languages in <constant>MODE_STEREO</constant> is deprecated. In
-the future drivers should produce only the primary language in this
-mode. Applications should request
-<constant>MODE_LANG1_LANG2</constant> to record both languages or a
-stereo signal.</para></footnote>) or
-Lang1/Lang1</entry>
-           <entry>Language&nbsp;1</entry>
-           <entry>Language&nbsp;2</entry>
-           <entry>Lang1/Lang2 (preferred) or Lang1/Lang1</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-tuner; <structfield>index</structfield> is
-out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-log-status.xml b/Documentation/DocBook/media/v4l/vidioc-log-status.xml
deleted file mode 100644 (file)
index 5ded7d3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<refentry id="vidioc-log-status">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_LOG_STATUS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_LOG_STATUS</refname>
-    <refpurpose>Log driver status information</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>As the video/audio devices become more complicated it
-becomes harder to debug problems. When this ioctl is called the driver
-will output the current device status to the kernel log. This is
-particular useful when dealing with problems like no sound, no video
-and incorrectly tuned channels. Also many modern devices autodetect
-video and audio standards and this ioctl will report what the device
-thinks what the standard is. Mismatches may give an indication where
-the problem is.</para>
-
-    <para>This ioctl is optional and not all drivers support it. It
-was introduced in Linux 2.6.15.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-overlay.xml b/Documentation/DocBook/media/v4l/vidioc-overlay.xml
deleted file mode 100644 (file)
index 250a7de..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<refentry id="vidioc-overlay">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_OVERLAY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_OVERLAY</refname>
-    <refpurpose>Start or stop video overlay</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const int *<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_OVERLAY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is part of the <link linkend="overlay">video
-    overlay</link> I/O method. Applications call
-    <constant>VIDIOC_OVERLAY</constant> to start or stop the
-    overlay. It takes a pointer to an integer which must be set to
-    zero by the application to stop overlay, to one to start.</para>
-
-    <para>Drivers do not support &VIDIOC-STREAMON; or
-&VIDIOC-STREAMOFF; with <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The overlay parameters have not been set up. See <xref
-linkend="overlay" /> for the necessary steps.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
deleted file mode 100644 (file)
index 7bde698..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-<refentry id="vidioc-prepare-buf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_PREPARE_BUF</refname>
-    <refpurpose>Prepare a buffer for I/O</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_buffer *<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_PREPARE_BUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications can optionally call the
-<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
-to the driver before actually enqueuing it, using the
-<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
-Such preparations may include cache invalidation or cleaning. Performing them
-in advance saves time during the actual I/O. In case such cache operations are
-not required, the application can use one of
-<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
-<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
-step.</para>
-
-    <para>The <structname>v4l2_buffer</structname> structure is
-specified in <xref linkend="buffer" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>File I/O is in progress.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not
-supported, or the <structfield>index</structfield> is out of bounds,
-or no buffers have been allocated yet, or the
-<structfield>userptr</structfield> or
-<structfield>length</structfield> are invalid.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
deleted file mode 100644 (file)
index 8b98a0e..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-<refentry id="vidioc-qbuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QBUF, VIDIOC_DQBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QBUF</refname>
-    <refname>VIDIOC_DQBUF</refname>
-    <refpurpose>Exchange a buffer with the driver</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_buffer *<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_QBUF, VIDIOC_DQBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications call the <constant>VIDIOC_QBUF</constant> ioctl
-to enqueue an empty (capturing) or filled (output) buffer in the
-driver's incoming queue. The semantics depend on the selected I/O
-method.</para>
-
-    <para>To enqueue a buffer applications set the <structfield>type</structfield>
-field of a &v4l2-buffer; to the same buffer type as was previously used
-with &v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
-<structfield>type</structfield>. Applications must also set the
-<structfield>index</structfield> field. Valid index numbers range from
-zero to the number of buffers allocated with &VIDIOC-REQBUFS;
-(&v4l2-requestbuffers; <structfield>count</structfield>) minus one. The
-contents of the struct <structname>v4l2_buffer</structname> returned
-by a &VIDIOC-QUERYBUF; ioctl will do as well. When the buffer is
-intended for output (<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>, or
-<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>) applications must also
-initialize the <structfield>bytesused</structfield>,
-<structfield>field</structfield> and
-<structfield>timestamp</structfield> fields, see <xref
-linkend="buffer" /> for details.
-Applications must also set <structfield>flags</structfield> to 0.
-The <structfield>reserved2</structfield> and
-<structfield>reserved</structfield> fields must be set to 0. When using
-the <link linkend="planar-apis">multi-planar API</link>, the
-<structfield>m.planes</structfield> field must contain a userspace pointer
-to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
-field must be set to the number of elements in that array.
-</para>
-
-    <para>To enqueue a <link linkend="mmap">memory mapped</link>
-buffer applications set the <structfield>memory</structfield>
-field to <constant>V4L2_MEMORY_MMAP</constant>. When
-<constant>VIDIOC_QBUF</constant> is called with a pointer to this
-structure the driver sets the
-<constant>V4L2_BUF_FLAG_MAPPED</constant> and
-<constant>V4L2_BUF_FLAG_QUEUED</constant> flags and clears the
-<constant>V4L2_BUF_FLAG_DONE</constant> flag in the
-<structfield>flags</structfield> field, or it returns an
-&EINVAL;.</para>
-
-    <para>To enqueue a <link linkend="userp">user pointer</link>
-buffer applications set the <structfield>memory</structfield>
-field to <constant>V4L2_MEMORY_USERPTR</constant>, the
-<structfield>m.userptr</structfield> field to the address of the
-buffer and <structfield>length</structfield> to its size. When the multi-planar
-API is used, <structfield>m.userptr</structfield> and
-<structfield>length</structfield> members of the passed array of &v4l2-plane;
-have to be used instead. When <constant>VIDIOC_QBUF</constant> is called with
-a pointer to this structure the driver sets the
-<constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the
-<constant>V4L2_BUF_FLAG_MAPPED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flags in the
-<structfield>flags</structfield> field, or it returns an error code.
-This ioctl locks the memory pages of the buffer in physical memory,
-they cannot be swapped out to disk. Buffers remain locked until
-dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is
-called, or until the device is closed.</para>
-
-    <para>To enqueue a <link linkend="dmabuf">DMABUF</link> buffer applications
-set the <structfield>memory</structfield> field to
-<constant>V4L2_MEMORY_DMABUF</constant> and the <structfield>m.fd</structfield>
-field to a file descriptor associated with a DMABUF buffer. When the
-multi-planar API is used the <structfield>m.fd</structfield> fields of the
-passed array of &v4l2-plane; have to be used instead. When
-<constant>VIDIOC_QBUF</constant> is called with a pointer to this structure the
-driver sets the <constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the
-<constant>V4L2_BUF_FLAG_MAPPED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flags in the
-<structfield>flags</structfield> field, or it returns an error code.  This
-ioctl locks the buffer. Locking a buffer means passing it to a driver for a
-hardware access (usually DMA).  If an application accesses (reads/writes) a
-locked buffer then the result is undefined.  Buffers remain locked until
-dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is called, or
-until the device is closed.</para>
-
-    <para>Applications call the <constant>VIDIOC_DQBUF</constant>
-ioctl to dequeue a filled (capturing) or displayed (output) buffer
-from the driver's outgoing queue. They just set the
-<structfield>type</structfield>, <structfield>memory</structfield>
-and <structfield>reserved</structfield>
-fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
-is called with a pointer to this structure the driver fills the
-remaining fields or returns an error code. The driver may also set
-<constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
-field. It indicates a non-critical (recoverable) streaming error. In such case
-the application may continue as normal, but should be aware that data in the
-dequeued buffer might be corrupted. When using the multi-planar API, the
-planes array must be passed in as well.</para>
-
-    <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
-buffer is in the outgoing queue. When the
-<constant>O_NONBLOCK</constant> flag was given to the &func-open;
-function, <constant>VIDIOC_DQBUF</constant> returns immediately
-with an &EAGAIN; when no buffer is available.</para>
-
-    <para>The <structname>v4l2_buffer</structname> structure is
-specified in <xref linkend="buffer" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using
-<constant>O_NONBLOCK</constant> and no buffer was in the outgoing
-queue.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not
-supported, or the <structfield>index</structfield> is out of bounds,
-or no buffers have been allocated yet, or the
-<structfield>userptr</structfield> or
-<structfield>length</structfield> are invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para><constant>VIDIOC_DQBUF</constant> failed due to an
-internal error. Can also indicate temporary problems like signal
-loss. Note the driver might dequeue an (empty) buffer despite
-returning an error, or even stop capturing. Reusing such buffer may be unsafe
-though and its details (e.g. <structfield>index</structfield>) may not be
-returned either. It is recommended that drivers indicate recoverable errors
-by setting the <constant>V4L2_BUF_FLAG_ERROR</constant> and returning 0 instead.
-In that case the application should be able to safely reuse the buffer and
-continue streaming.
-       </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPIPE</errorcode></term>
-       <listitem>
-         <para><constant>VIDIOC_DQBUF</constant> returns this on an empty
-capture queue for mem2mem codecs if a buffer with the
-<constant>V4L2_BUF_FLAG_LAST</constant> was already dequeued and no new buffers
-are expected to become available.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
deleted file mode 100644 (file)
index d41bf47..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<refentry id="vidioc-query-dv-timings">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERY_DV_TIMINGS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERY_DV_TIMINGS</refname>
-    <refname>VIDIOC_SUBDEV_QUERY_DV_TIMINGS</refname>
-    <refpurpose>Sense the DV preset received by the current
-input</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_dv_timings *<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_QUERY_DV_TIMINGS, VIDIOC_SUBDEV_QUERY_DV_TIMINGS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The hardware may be able to detect the current DV timings
-automatically, similar to sensing the video standard. To do so, applications
-call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
-&v4l2-dv-timings;. Once the hardware detects the timings, it will fill in the
-timings structure.</para>
-
-<para>Please note that drivers shall <emphasis>not</emphasis> switch timings automatically
-if new timings are detected. Instead, drivers should send the
-<constant>V4L2_EVENT_SOURCE_CHANGE</constant> event (if they support this) and expect
-that userspace will take action by calling <constant>VIDIOC_QUERY_DV_TIMINGS</constant>.
-The reason is that new timings usually mean different buffer sizes as well, and you
-cannot change buffer sizes on the fly. In general, applications that receive the
-Source Change event will have to call <constant>VIDIOC_QUERY_DV_TIMINGS</constant>,
-and if the detected timings are valid they will have to stop streaming, set the new
-timings, allocate new buffers and start streaming again.</para>
-
-<para>If the timings could not be detected because there was no signal, then
-<errorcode>ENOLINK</errorcode> is returned. If a signal was detected, but
-it was unstable and the receiver could not lock to the signal, then
-<errorcode>ENOLCK</errorcode> is returned. If the receiver could lock to the signal,
-but the format is unsupported (e.g. because the pixelclock is out of range
-of the hardware capabilities), then the driver fills in whatever timings it
-could find and returns <errorcode>ERANGE</errorcode>. In that case the application
-can call &VIDIOC-DV-TIMINGS-CAP; to compare the found timings with the hardware's
-capabilities in order to give more precise feedback to the user.
-</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Digital video timings are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOLINK</errorcode></term>
-       <listitem>
-         <para>No timings could be detected because no signal was found.
-</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOLCK</errorcode></term>
-       <listitem>
-         <para>The signal was unstable and the hardware could not lock on to it.
-</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>Timings were found, but they are out of range of the hardware
-capabilities.
-</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml
deleted file mode 100644 (file)
index 50bfcb5..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<refentry id="vidioc-querybuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYBUF</refname>
-    <refpurpose>Query the status of a buffer</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_buffer *<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_QUERYBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is part of the <link linkend="mmap">streaming
-</link> I/O method. It can be used to query the status of a
-buffer at any time after buffers have been allocated with the
-&VIDIOC-REQBUFS; ioctl.</para>
-
-    <para>Applications set the <structfield>type</structfield> field
-    of a &v4l2-buffer; to the same buffer type as was previously used with
-&v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
-<structfield>type</structfield>, and the <structfield>index</structfield>
-    field. Valid index numbers range from zero
-to the number of buffers allocated with &VIDIOC-REQBUFS;
-    (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
-The <structfield>reserved</structfield> and <structfield>reserved2 </structfield>
-fields must be set to 0.
-When using the <link linkend="planar-apis">multi-planar API</link>, the
-<structfield>m.planes</structfield> field must contain a userspace pointer to an
-array of &v4l2-plane; and the <structfield>length</structfield> field has
-to be set to the number of elements in that array.
-After calling <constant>VIDIOC_QUERYBUF</constant> with a pointer to
-    this structure drivers return an error code or fill the rest of
-the structure.</para>
-
-    <para>In the <structfield>flags</structfield> field the
-<constant>V4L2_BUF_FLAG_MAPPED</constant>,
-<constant>V4L2_BUF_FLAG_PREPARED</constant>,
-<constant>V4L2_BUF_FLAG_QUEUED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The
-<structfield>memory</structfield> field will be set to the current
-I/O method. For the single-planar API, the <structfield>m.offset</structfield>
-contains the offset of the buffer from the start of the device memory,
-the <structfield>length</structfield> field its size. For the multi-planar API,
-fields <structfield>m.mem_offset</structfield> and
-<structfield>length</structfield> in the <structfield>m.planes</structfield>
-array elements will be used instead and the <structfield>length</structfield>
-field of &v4l2-buffer; is set to the number of filled-in array elements.
-The driver may or may not set the remaining fields and flags, they are
-meaningless in this context.</para>
-
-    <para>The <structname>v4l2_buffer</structname> structure is
-    specified in <xref linkend="buffer" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not
-supported, or the <structfield>index</structfield> is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
deleted file mode 100644 (file)
index cd82148..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-<refentry id="vidioc-querycap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYCAP</refname>
-    <refpurpose>Query device capabilities</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_capability *<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_QUERYCAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All V4L2 devices support the
-<constant>VIDIOC_QUERYCAP</constant> ioctl. It is used to identify
-kernel devices compatible with this specification and to obtain
-information about driver and hardware capabilities. The ioctl takes a
-pointer to a &v4l2-capability; which is filled by the driver. When the
-driver is not compatible with this specification the ioctl returns an
-&EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-capability">
-      <title>struct <structname>v4l2_capability</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>driver</structfield>[16]</entry>
-           <entry><para>Name of the driver, a unique NUL-terminated
-ASCII string. For example: "bttv". Driver specific applications can
-use this information to verify the driver identity. It is also useful
-to work around known bugs, or to identify drivers in error reports.</para>
-<para>Storing strings in fixed sized arrays is bad
-practice but unavoidable here. Drivers and applications should take
-precautions to never read or write beyond the end of the array and to
-make sure the strings are properly NUL-terminated.</para></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>card</structfield>[32]</entry>
-           <entry>Name of the device, a NUL-terminated UTF-8 string.
-For example: "Yoyodyne TV/FM". One driver may support different brands
-or models of video hardware. This information is intended for users,
-for example in a menu of available devices. Since multiple TV cards of
-the same brand may be installed which are supported by the same
-driver, this name should be combined with the character device file
-name (&eg; <filename>/dev/video2</filename>) or the
-<structfield>bus_info</structfield> string to avoid
-ambiguities.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>bus_info</structfield>[32]</entry>
-           <entry>Location of the device in the system, a
-NUL-terminated ASCII string. For example: "PCI:0000:05:06.0". This
-information is intended for users, to distinguish multiple
-identical devices. If no such information is available the field must
-simply count the devices controlled by the driver ("platform:vivi-000").
-The bus_info must start with "PCI:" for PCI boards, "PCIe:" for PCI Express boards,
-"usb-" for USB devices, "I2C:" for i2c devices, "ISA:" for ISA devices,
-"parport" for parallel port devices and "platform:" for platform devices.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>version</structfield></entry>
-           <entry><para>Version number of the driver.</para>
-<para>Starting with kernel 3.1, the version reported is provided by the
-V4L2 subsystem following the kernel numbering scheme. However, it
-may not always return the same version as the kernel if, for example,
-a stable or distribution-modified kernel uses the V4L2 stack from a
-newer kernel.</para>
-<para>The version number is formatted using the
-<constant>KERNEL_VERSION()</constant> macro:</para></entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>
-<programlisting>
-#define KERNEL_VERSION(a,b,c) (((a) &lt;&lt; 16) + ((b) &lt;&lt; 8) + (c))
-
-__u32 version = KERNEL_VERSION(0, 8, 1);
-
-printf ("Version: %u.%u.%u\n",
-       (version &gt;&gt; 16) &amp; 0xFF,
-       (version &gt;&gt; 8) &amp; 0xFF,
-        version &amp; 0xFF);
-</programlisting></para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>Available capabilities of the physical device as a whole, see <xref
-               linkend="device-capabilities" />. The same physical device can export
-               multiple devices in /dev (e.g. /dev/videoX, /dev/vbiY and /dev/radioZ).
-               The <structfield>capabilities</structfield> field should contain a union
-               of all capabilities available around the several V4L2 devices exported
-               to userspace.
-               For all those devices the <structfield>capabilities</structfield> field
-               returns the same set of capabilities. This allows applications to open
-               just one of the devices (typically the video device) and discover whether
-               video, vbi and/or radio are also supported.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>device_caps</structfield></entry>
-           <entry>Device capabilities of the opened device, see <xref
-               linkend="device-capabilities" />. Should contain the available capabilities
-               of that specific device node. So, for example, <structfield>device_caps</structfield>
-               of a radio device will only contain radio related capabilities and
-               no video or vbi capabilities. This field is only set if the <structfield>capabilities</structfield>
-               field contains the <constant>V4L2_CAP_DEVICE_CAPS</constant> capability.
-               Only the <structfield>capabilities</structfield> field can have the
-               <constant>V4L2_CAP_DEVICE_CAPS</constant> capability, <structfield>device_caps</structfield>
-               will never set <constant>V4L2_CAP_DEVICE_CAPS</constant>.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="device-capabilities">
-      <title>Device Capabilities Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>The device supports the single-planar API through the <link
-linkend="capture">Video Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant></entry>
-           <entry>0x00001000</entry>
-           <entry>The device supports the
-           <link linkend="planar-apis">multi-planar API</link> through the
-           <link linkend="capture">Video Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>The device supports the single-planar API through the <link
-linkend="output">Video Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant></entry>
-           <entry>0x00002000</entry>
-           <entry>The device supports the
-           <link linkend="planar-apis">multi-planar API</link> through the
-           <link linkend="output">Video Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_M2M</constant></entry>
-           <entry>0x00004000</entry>
-           <entry>The device supports the single-planar API through the
-           Video Memory-To-Memory interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_M2M_MPLANE</constant></entry>
-           <entry>0x00008000</entry>
-           <entry>The device supports the
-           <link linkend="planar-apis">multi-planar API</link> through the
-           Video Memory-To-Memory  interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>The device supports the <link
-linkend="overlay">Video Overlay</link> interface. A video overlay device
-typically stores captured images directly in the video memory of a
-graphics card, with hardware clipping and scaling.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>The device supports the <link linkend="raw-vbi">Raw
-VBI Capture</link> interface, providing Teletext and Closed Caption
-data.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VBI_OUTPUT</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>The device supports the <link linkend="raw-vbi">Raw VBI Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant></entry>
-           <entry>0x00000040</entry>
-           <entry>The device supports the <link linkend="sliced">Sliced VBI Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant></entry>
-           <entry>0x00000080</entry>
-           <entry>The device supports the <link linkend="sliced">Sliced VBI Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RDS_CAPTURE</constant></entry>
-           <entry>0x00000100</entry>
-           <entry>The device supports the <link linkend="rds">RDS</link> capture interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant></entry>
-           <entry>0x00000200</entry>
-           <entry>The device supports the <link linkend="osd">Video
-Output Overlay</link> (OSD) interface. Unlike the <wordasword>Video
-Overlay</wordasword> interface, this is a secondary function of video
-output devices and overlays an image onto an outgoing video signal.
-When the driver sets this flag, it must clear the
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag and vice
-versa.<footnote><para>The &v4l2-framebuffer; lacks an
-&v4l2-buf-type; field, therefore the type of overlay is implied by the
-driver capabilities.</para></footnote></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_HW_FREQ_SEEK</constant></entry>
-           <entry>0x00000400</entry>
-           <entry>The device supports the &VIDIOC-S-HW-FREQ-SEEK; ioctl for
-hardware frequency seeking.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RDS_OUTPUT</constant></entry>
-           <entry>0x00000800</entry>
-           <entry>The device supports the <link linkend="rds">RDS</link> output interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_TUNER</constant></entry>
-           <entry>0x00010000</entry>
-           <entry>The device has some sort of tuner to
-receive RF-modulated video signals. For more information about
-tuner programming see
-<xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_AUDIO</constant></entry>
-           <entry>0x00020000</entry>
-           <entry>The device has audio inputs or outputs. It may or
-may not support audio recording or playback, in PCM or compressed
-formats. PCM audio support must be implemented as ALSA or OSS
-interface. For more information on audio inputs and outputs see <xref
-               linkend="audio" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RADIO</constant></entry>
-           <entry>0x00040000</entry>
-           <entry>This is a radio receiver.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_MODULATOR</constant></entry>
-           <entry>0x00080000</entry>
-           <entry>The device has some sort of modulator to
-emit RF-modulated video/audio signals. For more information about
-modulator programming see
-<xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SDR_CAPTURE</constant></entry>
-           <entry>0x00100000</entry>
-           <entry>The device supports the
-<link linkend="sdr">SDR Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_EXT_PIX_FORMAT</constant></entry>
-           <entry>0x00200000</entry>
-           <entry>The device supports the &v4l2-pix-format; extended
-fields.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SDR_OUTPUT</constant></entry>
-           <entry>0x00400000</entry>
-           <entry>The device supports the
-<link linkend="sdr">SDR Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_READWRITE</constant></entry>
-           <entry>0x01000000</entry>
-           <entry>The device supports the <link
-linkend="rw">read()</link> and/or <link linkend="rw">write()</link>
-I/O methods.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_ASYNCIO</constant></entry>
-           <entry>0x02000000</entry>
-           <entry>The device supports the <link
-linkend="async">asynchronous</link> I/O methods.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_STREAMING</constant></entry>
-           <entry>0x04000000</entry>
-           <entry>The device supports the <link
-linkend="mmap">streaming</link> I/O method.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_DEVICE_CAPS</constant></entry>
-           <entry>0x80000000</entry>
-           <entry>The driver fills the <structfield>device_caps</structfield>
-           field. This capability can only appear in the <structfield>capabilities</structfield>
-           field and never in the <structfield>device_caps</structfield> field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
deleted file mode 100644 (file)
index 55b7582..0000000
+++ /dev/null
@@ -1,661 +0,0 @@
-<refentry id="vidioc-queryctrl">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYCTRL</refname>
-    <refname>VIDIOC_QUERY_EXT_CTRL</refname>
-    <refname>VIDIOC_QUERYMENU</refname>
-    <refpurpose>Enumerate controls and menu control items</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_queryctrl *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_query_ext_ctrl *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_querymenu *<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_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a control applications set the
-<structfield>id</structfield> field of a &v4l2-queryctrl; and call the
-<constant>VIDIOC_QUERYCTRL</constant> ioctl with a pointer to this
-structure. The driver fills the rest of the structure or returns an
-&EINVAL; when the <structfield>id</structfield> is invalid.</para>
-
-    <para>It is possible to enumerate controls by calling
-<constant>VIDIOC_QUERYCTRL</constant> with successive
-<structfield>id</structfield> values starting from
-<constant>V4L2_CID_BASE</constant> up to and exclusive
-<constant>V4L2_CID_LASTP1</constant>. Drivers may return
-<errorcode>EINVAL</errorcode> if a control in this range is not
-supported. Further applications can enumerate private controls, which
-are not defined in this specification, by starting at
-<constant>V4L2_CID_PRIVATE_BASE</constant> and incrementing
-<structfield>id</structfield> until the driver returns
-<errorcode>EINVAL</errorcode>.</para>
-
-    <para>In both cases, when the driver sets the
-<constant>V4L2_CTRL_FLAG_DISABLED</constant> flag in the
-<structfield>flags</structfield> field this control is permanently
-disabled and should be ignored by the application.<footnote>
-       <para><constant>V4L2_CTRL_FLAG_DISABLED</constant> was
-intended for two purposes: Drivers can skip predefined controls not
-supported by the hardware (although returning EINVAL would do as
-well), or disable predefined and private controls after hardware
-detection without the trouble of reordering control arrays and indices
-(EINVAL cannot be used to skip private controls because it would
-prematurely end the enumeration).</para></footnote></para>
-
-    <para>When the application ORs <structfield>id</structfield> with
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver returns the
-next supported non-compound control, or <errorcode>EINVAL</errorcode>
-if there is none. In addition, the <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant>
-flag can be specified to enumerate all compound controls (i.e. controls
-with type &ge; <constant>V4L2_CTRL_COMPOUND_TYPES</constant> and/or array
-control, in other words controls that contain more than one value).
-Specify both <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> and
-<constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> in order to enumerate
-all controls, compound or not. Drivers which do not support these flags yet
-always return <errorcode>EINVAL</errorcode>.</para>
-
-    <para>The <constant>VIDIOC_QUERY_EXT_CTRL</constant> ioctl was
-introduced in order to better support controls that can use compound
-types, and to expose additional control information that cannot be
-returned in &v4l2-queryctrl; since that structure is full.</para>
-
-    <para><constant>VIDIOC_QUERY_EXT_CTRL</constant> is used in the
-same way as <constant>VIDIOC_QUERYCTRL</constant>, except that the
-<structfield>reserved</structfield> array must be zeroed as well.</para>
-
-    <para>Additional information is required for menu controls: the
-names of the menu items. To query them applications set the
-<structfield>id</structfield> and <structfield>index</structfield>
-fields of &v4l2-querymenu; and call the
-<constant>VIDIOC_QUERYMENU</constant> ioctl with a pointer to this
-structure. The driver fills the rest of the structure or returns an
-&EINVAL; when the <structfield>id</structfield> or
-<structfield>index</structfield> is invalid. Menu items are enumerated
-by calling <constant>VIDIOC_QUERYMENU</constant> with successive
-<structfield>index</structfield> values from &v4l2-queryctrl;
-<structfield>minimum</structfield> to
-<structfield>maximum</structfield>, inclusive. Note that it is possible
-for <constant>VIDIOC_QUERYMENU</constant> to return an &EINVAL; for some
-indices between <structfield>minimum</structfield> and <structfield>maximum</structfield>.
-In that case that particular menu item is not supported by this driver. Also note that
-the <structfield>minimum</structfield> value is not necessarily 0.</para>
-
-    <para>See also the examples in <xref linkend="control" />.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-queryctrl">
-      <title>struct <structname>v4l2_queryctrl</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the application. See
-<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
-with V4L2_CTRL_FLAG_NEXT_CTRL the driver clears the flag and returns
-the first control with a higher ID. Drivers which do not support this
-flag yet always return an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of control, see <xref
-               linkend="v4l2-ctrl-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the control, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry>Minimum value, inclusive. This field gives a lower
-bound for the control. See &v4l2-ctrl-type; how the minimum value is to
-be used for each possible control type. Note that this a signed 32-bit value.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry>Maximum value, inclusive. This field gives an upper
-bound for the control. See &v4l2-ctrl-type; how the maximum value is to
-be used for each possible control type. Note that this a signed 32-bit value.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry><para>This field gives a step size for the control.
-See &v4l2-ctrl-type; how the step value is to be used for each possible
-control type. Note that this an unsigned 32-bit value.
-</para><para>Generally drivers should not scale hardware
-control values. It may be necessary for example when the
-<structfield>name</structfield> or <structfield>id</structfield> imply
-a particular unit and the hardware actually accepts only multiples of
-said unit. If so, drivers must take care values are properly rounded
-when scaling, such that errors will not accumulate on repeated
-read-write cycles.</para><para>This field gives the smallest change of
-an integer control actually affecting hardware. Often the information
-is needed when the user can change controls by keyboard or GUI
-buttons, rather than a slider. When for example a hardware register
-accepts values 0-511 and the driver reports 0-65535, step should be
-128.</para><para>Note that although signed, the step value is supposed to
-be always positive.</para></entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>default_value</structfield></entry>
-           <entry>The default value of a
-<constant>V4L2_CTRL_TYPE_INTEGER</constant>,
-<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
-<constant>_MENU</constant> or <constant>_INTEGER_MENU</constant> control.
-Not valid for other types of controls.
-Note that drivers reset controls to their default value only when the
-driver is first loaded, never afterwards.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Control flags, see <xref
-               linkend="control-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-query-ext-ctrl">
-      <title>struct <structname>v4l2_query_ext_ctrl</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the application. See
-<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
-with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver clears the
-flag and returns the first non-compound control with a higher ID. When the
-ID is ORed with <constant>V4L2_CTRL_FLAG_NEXT_COMPOUND</constant> the driver
-clears the flag and returns the first compound control with a higher ID.
-Set both to get the first control (compound or not) with a higher ID.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of control, see <xref
-               linkend="v4l2-ctrl-type" />.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the control, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__s64</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry>Minimum value, inclusive. This field gives a lower
-bound for the control. See &v4l2-ctrl-type; how the minimum value is to
-be used for each possible control type. Note that this a signed 64-bit value.</entry>
-         </row>
-         <row>
-           <entry>__s64</entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry>Maximum value, inclusive. This field gives an upper
-bound for the control. See &v4l2-ctrl-type; how the maximum value is to
-be used for each possible control type. Note that this a signed 64-bit value.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry><para>This field gives a step size for the control.
-See &v4l2-ctrl-type; how the step value is to be used for each possible
-control type. Note that this an unsigned 64-bit value.
-</para><para>Generally drivers should not scale hardware
-control values. It may be necessary for example when the
-<structfield>name</structfield> or <structfield>id</structfield> imply
-a particular unit and the hardware actually accepts only multiples of
-said unit. If so, drivers must take care values are properly rounded
-when scaling, such that errors will not accumulate on repeated
-read-write cycles.</para><para>This field gives the smallest change of
-an integer control actually affecting hardware. Often the information
-is needed when the user can change controls by keyboard or GUI
-buttons, rather than a slider. When for example a hardware register
-accepts values 0-511 and the driver reports 0-65535, step should be
-128.</para></entry>
-         </row>
-         <row>
-           <entry>__s64</entry>
-           <entry><structfield>default_value</structfield></entry>
-           <entry>The default value of a
-<constant>V4L2_CTRL_TYPE_INTEGER</constant>, <constant>_INTEGER64</constant>,
-<constant>_BOOLEAN</constant>, <constant>_BITMASK</constant>,
-<constant>_MENU</constant>, <constant>_INTEGER_MENU</constant>,
-<constant>_U8</constant> or <constant>_U16</constant> control.
-Not valid for other types of controls.
-Note that drivers reset controls to their default value only when the
-driver is first loaded, never afterwards.
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Control flags, see <xref
-               linkend="control-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>elem_size</structfield></entry>
-           <entry>The size in bytes of a single element of the array.
-Given a char pointer <constant>p</constant> to a 3-dimensional array you can find the
-position of cell <constant>(z, y, x)</constant> as follows:
-<constant>p + ((z * dims[1] + y) * dims[0] + x) * elem_size</constant>. <structfield>elem_size</structfield>
-is always valid, also when the control isn't an array. For string controls
-<structfield>elem_size</structfield> is equal to <structfield>maximum + 1</structfield>.
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>elems</structfield></entry>
-           <entry>The number of elements in the N-dimensional array. If this control
-is not an array, then <structfield>elems</structfield> is 1. The <structfield>elems</structfield>
-field can never be 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>nr_of_dims</structfield></entry>
-           <entry>The number of dimension in the N-dimensional array. If this control
-is not an array, then this field is 0.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>dims[V4L2_CTRL_MAX_DIMS]</structfield></entry>
-           <entry>The size of each dimension. The first <structfield>nr_of_dims</structfield>
-elements of this array must be non-zero, all remaining elements must be zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[32]</entry>
-           <entry>Reserved for future extensions. Applications and drivers
-must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-querymenu">
-      <title>struct <structname>v4l2_querymenu</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry></entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the application
-from the respective &v4l2-queryctrl;
-<structfield>id</structfield>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry></entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Index of the menu item, starting at zero, set by
-           the application.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the menu item, a NUL-terminated ASCII
-string. This information is intended for the user. This field is valid
-for <constant>V4L2_CTRL_FLAG_MENU</constant> type controls.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s64</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>
-              Value of the integer menu item. This field is valid for
-              <constant>V4L2_CTRL_FLAG_INTEGER_MENU</constant> type
-              controls.
-            </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry></entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-ctrl-type">
-      <title>enum v4l2_ctrl_type</title>
-      <tgroup cols="5" align="left">
-       <colspec colwidth="30*" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="55*" />
-       <thead>
-         <row>
-           <entry>Type</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry><structfield>step</structfield></entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry>Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_INTEGER</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>An integer-valued control ranging from minimum to
-maximum inclusive. The step value indicates the increment between
-values.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_BOOLEAN</constant></entry>
-           <entry>0</entry>
-           <entry>1</entry>
-           <entry>1</entry>
-           <entry>A boolean-valued control. Zero corresponds to
-"disabled", and one means "enabled".</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_MENU</constant></entry>
-           <entry>&ge; 0</entry>
-           <entry>1</entry>
-           <entry>N-1</entry>
-           <entry>The control has a menu of N choices. The names of
-the menu items can be enumerated with the
-<constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_INTEGER_MENU</constant></entry>
-           <entry>&ge; 0</entry>
-           <entry>1</entry>
-           <entry>N-1</entry>
-           <entry>
-              The control has a menu of N choices. The values of the
-              menu items can be enumerated with the
-              <constant>VIDIOC_QUERYMENU</constant> ioctl. This is
-              similar to <constant>V4L2_CTRL_TYPE_MENU</constant>
-              except that instead of strings, the menu items are
-              signed 64-bit integers.
-            </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
-           <entry>0</entry>
-           <entry>n/a</entry>
-           <entry>any</entry>
-           <entry>A bitmask field. The maximum value is the set of bits that can
-be used, all other bits are to be 0. The maximum value is interpreted as a __u32,
-allowing the use of bit 31 in the bitmask.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_BUTTON</constant></entry>
-           <entry>0</entry>
-           <entry>0</entry>
-           <entry>0</entry>
-           <entry>A control which performs an action when set.
-Drivers must ignore the value passed with
-<constant>VIDIOC_S_CTRL</constant> and return an &EINVAL; on a
-<constant>VIDIOC_G_CTRL</constant> attempt.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_INTEGER64</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>A 64-bit integer valued control. Minimum, maximum
-and step size cannot be queried using <constant>VIDIOC_QUERYCTRL</constant>.
-Only <constant>VIDIOC_QUERY_EXT_CTRL</constant> can retrieve the 64-bit
-min/max/step values, they should be interpreted as n/a when using
-<constant>VIDIOC_QUERYCTRL</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_STRING</constant></entry>
-           <entry>&ge; 0</entry>
-           <entry>&ge; 1</entry>
-           <entry>&ge; 0</entry>
-           <entry>The minimum and maximum string lengths. The step size
-means that the string must be (minimum + N * step) characters long for
-N &ge; 0. These lengths do not include the terminating zero, so in order to
-pass a string of length 8 to &VIDIOC-S-EXT-CTRLS; you need to set the
-<structfield>size</structfield> field of &v4l2-ext-control; to 9. For &VIDIOC-G-EXT-CTRLS; you can
-set the <structfield>size</structfield> field to <structfield>maximum</structfield> + 1.
-Which character encoding is used will depend on the string control itself and
-should be part of the control documentation.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant></entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>This is not a control. When
-<constant>VIDIOC_QUERYCTRL</constant> is called with a control ID
-equal to a control class code (see <xref linkend="ctrl-class" />) + 1, the
-ioctl returns the name of the control class and this control type.
-Older drivers which do not support this feature return an
-&EINVAL;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_U8</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>An unsigned 8-bit valued control ranging from minimum to
-maximum inclusive. The step value indicates the increment between
-values.
-</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_U16</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>An unsigned 16-bit valued control ranging from minimum to
-maximum inclusive. The step value indicates the increment between
-values.
-</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_U32</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>An unsigned 32-bit valued control ranging from minimum to
-maximum inclusive. The step value indicates the increment between
-values.
-</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="control-flags">
-      <title>Control Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_DISABLED</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This control is permanently disabled and should be
-ignored by the application. Any attempt to change the control will
-result in an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_GRABBED</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This control is temporarily unchangeable, for
-example because another application took over control of the
-respective resource. Such controls may be displayed specially in a
-user interface. Attempts to change the control may result in an
-&EBUSY;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_READ_ONLY</constant></entry>
-           <entry>0x0004</entry>
-           <entry>This control is permanently readable only. Any
-attempt to change the control will result in an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_UPDATE</constant></entry>
-           <entry>0x0008</entry>
-           <entry>A hint that changing this control may affect the
-value of other controls within the same control class. Applications
-should update their user interface accordingly.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_INACTIVE</constant></entry>
-           <entry>0x0010</entry>
-           <entry>This control is not applicable to the current
-configuration and should be displayed accordingly in a user interface.
-For example the flag may be set on a MPEG audio level 2 bitrate
-control when MPEG audio encoding level 1 was selected with another
-control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_SLIDER</constant></entry>
-           <entry>0x0020</entry>
-           <entry>A hint that this control is best represented as a
-slider-like element in a user interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant></entry>
-           <entry>0x0040</entry>
-           <entry>This control is permanently writable only. Any
-attempt to read the control will result in an &EACCES; error code. This
-flag is typically present for relative controls or action controls where
-writing a value will cause the device to carry out a given action
-(&eg; motor control) but no meaningful value can be returned.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_VOLATILE</constant></entry>
-           <entry>0x0080</entry>
-           <entry>This control is volatile, which means that the value of the control
-changes continuously. A typical example would be the current gain value if the device
-is in auto-gain mode. In such a case the hardware calculates the gain value based on
-the lighting conditions which can change over time. Note that setting a new value for
-a volatile control will have no effect and no <constant>V4L2_EVENT_CTRL_CH_VALUE</constant>
-will be sent, unless the <constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant> flag
-(see below) is also set. Otherwise the new value will just be ignored.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant></entry>
-           <entry>0x0100</entry>
-           <entry>This control has a pointer type, so its value has to be accessed
-using one of the pointer fields of &v4l2-ext-control;. This flag is set for controls
-that are an array, string, or have a compound type. In all cases you have to set a
-pointer to memory containing the payload of the control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant></entry>
-           <entry>0x0200</entry>
-           <entry>The value provided to the control will be propagated to the driver
-even if it remains constant. This is required when the control represents an action
-on the hardware. For example: clearing an error flag or triggering the flash. All the
-controls of the type <constant>V4L2_CTRL_TYPE_BUTTON</constant> have this flag set.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-queryctrl; <structfield>id</structfield>
-is invalid. The &v4l2-querymenu; <structfield>id</structfield> is
-invalid or <structfield>index</structfield> is out of range (less than
-<structfield>minimum</structfield> or greater than <structfield>maximum</structfield>)
-or this particular menu item is not supported by the driver.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>An attempt was made to read a write-only control.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querystd.xml b/Documentation/DocBook/media/v4l/vidioc-querystd.xml
deleted file mode 100644 (file)
index 3ceae35..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<refentry id="vidioc-querystd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYSTD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYSTD</refname>
-    <refpurpose>Sense the video standard received by the current
-input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_std_id *<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_QUERYSTD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The hardware may be able to detect the current video
-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. 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>
-
-<para>Please note that drivers shall <emphasis>not</emphasis> switch the video standard
-automatically if a new video standard is detected. Instead, drivers should send the
-<constant>V4L2_EVENT_SOURCE_CHANGE</constant> event (if they support this) and expect
-that userspace will take action by calling <constant>VIDIOC_QUERYSTD</constant>.
-The reason is that a new video standard can mean different buffer sizes as well, and you
-cannot change buffer sizes on the fly. In general, applications that receive the
-Source Change event will have to call <constant>VIDIOC_QUERYSTD</constant>,
-and if the detected video standard is valid they will have to stop streaming, set the new
-standard, allocate new buffers and start streaming again.</para>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>Standard video timings are not supported for this input or output.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
deleted file mode 100644 (file)
index 6f529e1..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<refentry id="vidioc-reqbufs">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_REQBUFS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_REQBUFS</refname>
-    <refpurpose>Initiate Memory Mapping, User Pointer or DMA Buffer I/O</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_requestbuffers *<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_REQBUFS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-<para>This ioctl is used to initiate <link linkend="mmap">memory mapped</link>,
-<link linkend="userp">user pointer</link> or <link
-linkend="dmabuf">DMABUF</link> based I/O.  Memory mapped buffers are located in
-device memory and must be allocated with this ioctl before they can be mapped
-into the application's address space. User buffers are allocated by
-applications themselves, and this ioctl is merely used to switch the driver
-into user pointer I/O mode and to setup some internal structures.
-Similarly, DMABUF buffers are allocated by applications through a device
-driver, and this ioctl only configures the driver into DMABUF I/O mode without
-performing any direct allocation.</para>
-
-    <para>To allocate device buffers applications initialize all fields of the
-<structname>v4l2_requestbuffers</structname> structure.  They set the
-<structfield>type</structfield> field to the respective stream or buffer type,
-the <structfield>count</structfield> field to the desired number of buffers,
-<structfield>memory</structfield> must be set to the requested I/O method and
-the <structfield>reserved</structfield> array must be zeroed. When the ioctl is
-called with a pointer to this structure the driver will attempt to allocate the
-requested number of buffers and it stores the actual number allocated in the
-<structfield>count</structfield> field. It can be smaller than the number
-requested, even zero, when the driver runs out of free memory. A larger number
-is also possible when the driver requires more buffers to function correctly.
-For example video output requires at least two buffers, one displayed and one
-filled by the application.</para>
-    <para>When the I/O method is not supported the ioctl
-returns an &EINVAL;.</para>
-
-    <para>Applications can call <constant>VIDIOC_REQBUFS</constant>
-again to change the number of buffers, however this cannot succeed
-when any buffers are still mapped. A <structfield>count</structfield>
-value of zero frees all buffers, after aborting or finishing any DMA
-in progress, an implicit &VIDIOC-STREAMOFF;. <!-- mhs: I see no
-reason why munmap()ping one or even all buffers must imply
-streamoff.--></para>
-
-    <table pgwide="1" frame="none" id="v4l2-requestbuffers">
-      <title>struct <structname>v4l2_requestbuffers</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>count</structfield></entry>
-           <entry>The number of buffers requested or granted.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the stream or buffers, this is the same
-as the &v4l2-format; <structfield>type</structfield> field. See <xref
-               linkend="v4l2-buf-type" /> for valid values.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>memory</structfield></entry>
-           <entry>Applications set this field to
-<constant>V4L2_MEMORY_MMAP</constant>,
-<constant>V4L2_MEMORY_DMABUF</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
-/>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>A place holder for future extensions. Drivers and applications
-must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer type (<structfield>type</structfield> field) or the
-requested I/O method (<structfield>memory</structfield>) is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
deleted file mode 100644 (file)
index a5fc4c4..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-<refentry id="vidioc-s-hw-freq-seek">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_S_HW_FREQ_SEEK</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_S_HW_FREQ_SEEK</refname>
-    <refpurpose>Perform a hardware frequency seek</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_hw_freq_seek
-*<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_S_HW_FREQ_SEEK</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Start a hardware frequency seek from the current frequency.
-To do this applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield>, <structfield>seek_upward</structfield>,
-<structfield>wrap_around</structfield>, <structfield>spacing</structfield>,
-<structfield>rangelow</structfield> and <structfield>rangehigh</structfield>
-fields, and zero out the <structfield>reserved</structfield> array of a
-&v4l2-hw-freq-seek; and call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant>
-ioctl with a pointer to this structure.</para>
-
-    <para>The <structfield>rangelow</structfield> and
-<structfield>rangehigh</structfield> fields can be set to a non-zero value to
-tell the driver to search a specific band. If the &v4l2-tuner;
-<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_HWSEEK_PROG_LIM</constant> flag set, these values
-must fall within one of the bands returned by &VIDIOC-ENUM-FREQ-BANDS;. If
-the <constant>V4L2_TUNER_CAP_HWSEEK_PROG_LIM</constant> flag is not set,
-then these values must exactly match those of one of the bands returned by
-&VIDIOC-ENUM-FREQ-BANDS;. If the current frequency of the tuner does not fall
-within the selected band it will be clamped to fit in the band before the
-seek is started.</para>
-
-    <para>If an error is returned, then the original frequency will
-    be restored.</para>
-
-    <para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
-
-    <para>If this ioctl is called from a non-blocking filehandle, then &EAGAIN; is
-    returned and no seek takes place.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
-      <title>struct <structname>v4l2_hw_freq_seek</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>The tuner index number. This is the
-same value as in the &v4l2-input; <structfield>tuner</structfield>
-field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. See <xref
-           linkend="v4l2-tuner-type" /></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>seek_upward</structfield></entry>
-           <entry>If non-zero, seek upward from the current frequency, else seek downward.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>wrap_around</structfield></entry>
-           <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.
-           The &v4l2-tuner; <structfield>capability</structfield> field will tell you what the
-           hardware supports.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>spacing</structfield></entry>
-           <entry>If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry>If non-zero, the lowest tunable frequency of the band to
-search in units of 62.5 kHz, or if the &v4l2-tuner;
-<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz or if the &v4l2-tuner;
-<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_1HZ</constant> flag set, in units of 1 Hz.
-If <structfield>rangelow</structfield> is zero a reasonable default value
-is used.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry>If non-zero, the highest tunable frequency of the band to
-search in units of 62.5 kHz, or if the &v4l2-tuner;
-<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_LOW</constant> flag set, in units of 62.5 Hz or if the &v4l2-tuner;
-<structfield>capability</structfield> field has the
-<constant>V4L2_TUNER_CAP_1HZ</constant> flag set, in units of 1 Hz.
-If <structfield>rangehigh</structfield> is zero a reasonable default value
-is used.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[5]</entry>
-           <entry>Reserved for future extensions. Applications
-           must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>tuner</structfield> index is out of
-bounds, the <structfield>wrap_around</structfield> value is not supported or
-one of the values in the <structfield>type</structfield>,
-<structfield>rangelow</structfield> or <structfield>rangehigh</structfield>
-fields is wrong.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Attempted to call <constant>VIDIOC_S_HW_FREQ_SEEK</constant>
-         with the filehandle in non-blocking mode.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENODATA</errorcode></term>
-       <listitem>
-         <para>The hardware seek found no channels.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>Another hardware seek is already in progress.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml
deleted file mode 100644 (file)
index 89fd7ce..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<refentry id="vidioc-streamon">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_STREAMON</refname>
-    <refname>VIDIOC_STREAMOFF</refname>
-    <refpurpose>Start or stop streaming I/O</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const int *<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_STREAMON, VIDIOC_STREAMOFF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl start and stop the capture
-or output process during streaming (<link linkend="mmap">memory
-mapping</link>, <link linkend="userp">user pointer</link> or
-<link linkend="dmabuf">DMABUF</link>) I/O.</para>
-
-    <para>Capture hardware is disabled and no input
-buffers are filled (if there are any empty buffers in the incoming
-queue) until <constant>VIDIOC_STREAMON</constant> has been called.
-Output hardware is disabled and no video signal is
-produced until <constant>VIDIOC_STREAMON</constant> has been called.
-The ioctl will succeed when at least one output buffer is in the
-incoming queue.</para>
-
-    <para>Memory-to-memory devices will not start until
-<constant>VIDIOC_STREAMON</constant> has been called for both the capture
-and output stream types.</para>
-
-    <para>If <constant>VIDIOC_STREAMON</constant> fails then any already
-queued buffers will remain queued.</para>
-
-    <para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of
-aborting or finishing any DMA in progress, unlocks any user pointer
-buffers locked in physical memory, and it removes all buffers from the
-incoming and outgoing queues. That means all images captured but not
-dequeued yet will be lost, likewise all images enqueued for output but
-not transmitted yet. I/O returns to the same state as after calling
-&VIDIOC-REQBUFS; and can be restarted accordingly.</para>
-
-    <para>If buffers have been queued with &VIDIOC-QBUF; and
-<constant>VIDIOC_STREAMOFF</constant> is called without ever having
-called <constant>VIDIOC_STREAMON</constant>, then those queued buffers
-will also be removed from the incoming queue and all are returned to the
-same state as after calling &VIDIOC-REQBUFS; and can be restarted
-accordingly.</para>
-
-    <para>Both ioctls take a pointer to an integer, the desired buffer or
-stream type. This is the same as &v4l2-requestbuffers;
-<structfield>type</structfield>.</para>
-
-    <para>If <constant>VIDIOC_STREAMON</constant> is called when streaming
-is already in progress, or if <constant>VIDIOC_STREAMOFF</constant> is called
-when streaming is already stopped, then 0 is returned. Nothing happens in the
-case of <constant>VIDIOC_STREAMON</constant>, but <constant>VIDIOC_STREAMOFF</constant>
-will return queued buffers to their starting state as mentioned above.</para>
-
-    <para>Note that applications can be preempted for unknown periods right
-before or after the <constant>VIDIOC_STREAMON</constant> or
-<constant>VIDIOC_STREAMOFF</constant> calls, there is no notion of
-starting or stopping "now". Buffer timestamps can be used to
-synchronize with other events.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not supported,
-         or no buffers have been allocated (memory mapping) or enqueued
-         (output) yet.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPIPE</errorcode></term>
-       <listitem>
-         <para>The driver implements <link
-         linkend="pad-level-formats">pad-level format configuration</link> and
-         the pipeline configuration is invalid.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOLINK</errorcode></term>
-       <listitem>
-         <para>The driver implements Media Controller interface and
-         the pipeline link configuration is invalid.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml
deleted file mode 100644 (file)
index 9d0251a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<refentry id="vidioc-subdev-enum-frame-interval">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
-    <refpurpose>Enumerate frame intervals</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_subdev_frame_interval_enum *
-       <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_SUBDEV_ENUM_FRAME_INTERVAL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl lets applications enumerate available frame intervals on a
-    given sub-device pad. Frame intervals only makes sense for sub-devices that
-    can control the frame period on their own. This includes, for instance,
-    image sensors and TV tuners.</para>
-
-    <para>For the common use case of image sensors, the frame intervals
-    available on the sub-device output pad depend on the frame format and size
-    on the same pad. Applications must thus specify the desired format and size
-    when enumerating frame intervals.</para>
-
-    <para>To enumerate frame intervals applications initialize the
-    <structfield>index</structfield>, <structfield>pad</structfield>,
-    <structfield>which</structfield>, <structfield>code</structfield>,
-    <structfield>width</structfield> and <structfield>height</structfield>
-    fields of &v4l2-subdev-frame-interval-enum; and call the
-    <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
-    to this structure. Drivers fill the rest of the structure or return
-    an &EINVAL; if one of the input fields is invalid. All frame intervals are
-    enumerable by beginning at index zero and incrementing by one until
-    <errorcode>EINVAL</errorcode> is returned.</para>
-
-    <para>Available frame intervals may depend on the current 'try' formats
-    at other pads of the sub-device, as well as on the current active links. See
-    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
-
-    <para>Sub-devices that support the frame interval enumeration ioctl should
-    implemented it on a single pad only. Its behaviour when supported on
-    multiple pads of the same sub-device is not defined.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
-      <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>interval</structfield></entry>
-           <entry>Period, in seconds, between consecutive video frames.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Frame intervals to be enumerated, from &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-interval-enum;
-         <structfield>pad</structfield> references a non-existing pad, one of
-         the <structfield>code</structfield>, <structfield>width</structfield>
-         or <structfield>height</structfield> fields are invalid for the given
-         pad or the <structfield>index</structfield> field is out of bounds.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml
deleted file mode 100644 (file)
index 9b91b83..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-<refentry id="vidioc-subdev-enum-frame-size">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
-    <refpurpose>Enumerate media bus frame sizes</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_subdev_frame_size_enum *
-       <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_SUBDEV_ENUM_FRAME_SIZE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl allows applications to enumerate all frame sizes
-    supported by a sub-device on the given pad for the given media bus format.
-    Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
-    ioctl.</para>
-
-    <para>To enumerate frame sizes applications initialize the
-    <structfield>pad</structfield>, <structfield>which</structfield> ,
-    <structfield>code</structfield> and <structfield>index</structfield>
-    fields of the &v4l2-subdev-mbus-code-enum; and call the
-    <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
-    the structure. Drivers fill the minimum and maximum frame sizes or return
-    an &EINVAL; if one of the input parameters is invalid.</para>
-
-    <para>Sub-devices that only support discrete frame sizes (such as most
-    sensors) will return one or more frame sizes with identical minimum and
-    maximum values.</para>
-
-    <para>Not all possible sizes in given [minimum, maximum] ranges need to be
-    supported. For instance, a scaler that uses a fixed-point scaling ratio
-    might not be able to produce every frame size between the minimum and
-    maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
-    try the sub-device for an exact supported frame size.</para>
-
-    <para>Available frame sizes may depend on the current 'try' formats at other
-    pads of the sub-device, as well as on the current active links and the
-    current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
-    information about try formats.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
-      <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_width</structfield></entry>
-           <entry>Minimum frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_width</structfield></entry>
-           <entry>Maximum frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_height</structfield></entry>
-           <entry>Minimum frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_height</structfield></entry>
-           <entry>Maximum frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Frame sizes to be enumerated, from &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
-         references a non-existing pad, the <structfield>code</structfield> is
-         invalid for the given pad or the <structfield>index</structfield>
-         field is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml
deleted file mode 100644 (file)
index c67256a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-<refentry id="vidioc-subdev-enum-mbus-code">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
-    <refpurpose>Enumerate media bus formats</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_subdev_mbus_code_enum *
-       <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_SUBDEV_ENUM_MBUS_CODE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To enumerate media bus formats available at a given sub-device pad
-    applications initialize the <structfield>pad</structfield>, <structfield>which</structfield>
-    and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
-    call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
-    pointer to this structure. Drivers fill the rest of the structure or return
-    an &EINVAL; if either the <structfield>pad</structfield> or
-    <structfield>index</structfield> are invalid. All media bus formats are
-    enumerable by beginning at index zero and incrementing by one until
-    <errorcode>EINVAL</errorcode> is returned.</para>
-
-    <para>Available media bus formats may depend on the current 'try' formats
-    at other pads of the sub-device, as well as on the current active links. See
-    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
-      <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Media bus format codes to be enumerated, from &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
-         references a non-existing pad, or the <structfield>index</structfield>
-         field is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
deleted file mode 100644 (file)
index 4cddd78..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-<refentry id="vidioc-subdev-g-crop">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_CROP</refname>
-    <refname>VIDIOC_SUBDEV_S_CROP</refname>
-    <refpurpose>Get or set the crop rectangle on a subdev pad</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_subdev_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_subdev_crop *<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_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Obsolete</title>
-
-      <para>This is an <link linkend="obsolete">obsolete</link>
-      interface and may be removed in the future. It is superseded by
-      <link linkend="vidioc-subdev-g-selection">the selection
-      API</link>.</para>
-    </note>
-
-    <para>To retrieve the current crop rectangle applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
-    desired pad number as reported by the media API and the
-    <structfield>which</structfield> field to
-    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
-    <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
-    structure. The driver fills the members of the <structfield>rect</structfield>
-    field or returns &EINVAL; if the input arguments are invalid, or if cropping
-    is not supported on the given pad.</para>
-
-    <para>To change the current crop rectangle applications set both the
-    <structfield>pad</structfield> and <structfield>which</structfield> fields
-    and all members of the <structfield>rect</structfield> field. They then call
-    the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
-    structure. The driver verifies the requested crop rectangle, adjusts it
-    based on the hardware capabilities and configures the device. Upon return
-    the &v4l2-subdev-crop; contains the current format as would be returned
-    by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
-
-    <para>Applications can query the device capabilities by setting the
-    <structfield>which</structfield> to
-    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
-    rectangles are not applied to the device by the driver, but are mangled
-    exactly as active crop rectangles and stored in the sub-device file handle.
-    Two applications querying the same sub-device would thus not interact with
-    each other.</para>
-
-    <para>Drivers must not return an error solely because the requested crop
-    rectangle doesn't match the device capabilities. They must instead modify
-    the rectangle to match what the hardware can provide. The modified format
-    should be as close as possible to the original request.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-crop">
-      <title>struct <structname>v4l2_subdev_crop</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media framework.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Crop rectangle to get or set, from
-           &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>rect</structfield></entry>
-           <entry>Crop rectangle boundaries, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The crop rectangle can't be changed because the pad is currently
-         busy. This can be caused, for instance, by an active video stream on
-         the pad. The ioctl must not be retried without performing another
-         action to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
-         references a non-existing pad, the <structfield>which</structfield>
-         field references a non-existing format, or cropping is not supported
-         on the given subdev pad.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
deleted file mode 100644 (file)
index 781089c..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-<refentry id="vidioc-subdev-g-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_FMT</refname>
-    <refname>VIDIOC_SUBDEV_S_FMT</refname>
-    <refpurpose>Get or set the data format on a subdev pad</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_subdev_format *<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_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls are used to negotiate the frame format at specific
-    subdev pads in the image pipeline.</para>
-
-    <para>To retrieve the current format applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
-    desired pad number as reported by the media API and the
-    <structfield>which</structfield> field to
-    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
-    structure the driver fills the members of the <structfield>format</structfield>
-    field.</para>
-
-    <para>To change the current format applications set both the
-    <structfield>pad</structfield> and <structfield>which</structfield> fields
-    and all members of the <structfield>format</structfield> field. When they
-    call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
-    structure the driver verifies the requested format, adjusts it based on the
-    hardware capabilities and configures the device. Upon return the
-    &v4l2-subdev-format; contains the current format as would be returned by a
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
-
-    <para>Applications can query the device capabilities by setting the
-    <structfield>which</structfield> to
-    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
-    applied to the device by the driver, but are changed exactly as active
-    formats and stored in the sub-device file handle. Two applications querying
-    the same sub-device would thus not interact with each other.</para>
-
-    <para>For instance, to try a format at the output pad of a sub-device,
-    applications would first set the try format at the sub-device input with the
-    <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
-    retrieve the default format at the output pad with the
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
-    pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
-    the returned value.</para>
-
-    <para>Try formats do not depend on active formats, but can depend on the
-    current links configuration or sub-device controls value. For instance, a
-    low-pass noise filter might crop pixels at the frame boundaries, modifying
-    its output frame size.</para>
-
-    <para>Drivers must not return an error solely because the requested format
-    doesn't match the device capabilities. They must instead modify the format
-    to match what the hardware can provide. The modified format should be as
-    close as possible to the original request.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-format">
-      <title>struct <structname>v4l2_subdev_format</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-mbus-framefmt;</entry>
-           <entry><structfield>format</structfield></entry>
-           <entry>Definition of an image format, see <xref
-           linkend="v4l2-mbus-framefmt" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
-      <title>enum <structname>v4l2_subdev_format_whence</structname></title>
-      <tgroup cols="3">
-        &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
-           <entry>0</entry>
-           <entry>Try formats, used for querying device capabilities.</entry>
-         </row>
-         <row>
-           <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
-           <entry>1</entry>
-           <entry>Active formats, applied to the hardware.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The format can't be changed because the pad is currently busy.
-         This can be caused, for instance, by an active video stream on the
-         pad. The ioctl must not be retried without performing another action
-         to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-format; <structfield>pad</structfield>
-         references a non-existing pad, or the <structfield>which</structfield>
-         field references a non-existing format.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml
deleted file mode 100644 (file)
index 848ec78..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<refentry id="vidioc-subdev-g-frame-interval">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
-    <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
-    <refpurpose>Get or set the frame interval on a subdev pad</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_subdev_frame_interval *<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_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls are used to get and set the frame interval at specific
-    subdev pads in the image pipeline. The frame interval only makes sense for
-    sub-devices that can control the frame period on their own. This includes,
-    for instance, image sensors and TV tuners. Sub-devices that don't support
-    frame intervals must not implement these ioctls.</para>
-
-    <para>To retrieve the current frame interval applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
-    the desired pad number as reported by the media controller API. When they
-    call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
-    pointer to this structure the driver fills the members of the
-    <structfield>interval</structfield> field.</para>
-
-    <para>To change the current frame interval applications set both the
-    <structfield>pad</structfield> field and all members of the
-    <structfield>interval</structfield> field. When they call the
-    <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
-    this structure the driver verifies the requested interval, adjusts it based
-    on the hardware capabilities and configures the device. Upon return the
-    &v4l2-subdev-frame-interval; contains the current frame interval as would be
-    returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
-    </para>
-
-    <para>Drivers must not return an error solely because the requested interval
-    doesn't match the device capabilities. They must instead modify the interval
-    to match what the hardware can provide. The modified interval should be as
-    close as possible to the original request.</para>
-
-    <para>Sub-devices that support the frame interval ioctls should implement
-    them on a single pad only. Their behaviour when supported on multiple pads
-    of the same sub-device is not defined.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
-      <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>interval</structfield></entry>
-           <entry>Period, in seconds, between consecutive video frames.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The frame interval can't be changed because the pad is currently
-         busy. This can be caused, for instance, by an active video stream on
-         the pad. The ioctl must not be retried without performing another
-         action to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
-         references a non-existing pad, or the pad doesn't support frame
-         intervals.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
deleted file mode 100644 (file)
index 8346b2e..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<refentry id="vidioc-subdev-g-selection">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_SELECTION</refname>
-    <refname>VIDIOC_SUBDEV_S_SELECTION</refname>
-    <refpurpose>Get or set selection rectangles on a subdev pad</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_subdev_selection *<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_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The selections are used to configure various image
-    processing functionality performed by the subdevs which affect the
-    image size. This currently includes cropping, scaling and
-    composition.</para>
-
-    <para>The selection API replaces <link
-    linkend="vidioc-subdev-g-crop">the old subdev crop API</link>. All
-    the function of the crop API, and more, are supported by the
-    selections API.</para>
-
-    <para>See <xref linkend="subdev"></xref> for
-    more information on how each selection target affects the image
-    processing pipeline inside the subdevice.</para>
-
-    <refsect2>
-      <title>Types of selection targets</title>
-
-      <para>There are two types of selection targets: actual and bounds. The
-      actual targets are the targets which configure the hardware. The BOUNDS
-      target will return a rectangle that contain all possible actual
-      rectangles.</para>
-    </refsect2>
-
-    <refsect2>
-      <title>Discovering supported features</title>
-
-      <para>To discover which targets are supported, the user can
-      perform <constant>VIDIOC_SUBDEV_G_SELECTION</constant> on them.
-      Any unsupported target will return
-      <constant>EINVAL</constant>.</para>
-
-    <para>Selection targets and flags are documented in <xref
-    linkend="v4l2-selections-common"/>.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-selection">
-      <title>struct <structname>v4l2_subdev_selection</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Active or try selection, from
-           &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media framework.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>target</structfield></entry>
-           <entry>Target selection rectangle. See
-           <xref linkend="v4l2-selections-common" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags. See
-           <xref linkend="v4l2-selection-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>r</structfield></entry>
-           <entry>Selection rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    </refsect2>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The selection rectangle can't be changed because the
-         pad is currently busy. This can be caused, for instance, by
-         an active video stream on the pad. The ioctl must not be
-         retried without performing another action to fix the problem
-         first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-selection;
-         <structfield>pad</structfield> references a non-existing
-         pad, the <structfield>which</structfield> field references a
-         non-existing format, or the selection target is not
-         supported on the given subdev pad.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
deleted file mode 100644 (file)
index 5fd0ee7..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<refentry id="vidioc-subscribe-event">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-      <refname>VIDIOC_SUBSCRIBE_EVENT</refname>
-      <refname>VIDIOC_UNSUBSCRIBE_EVENT</refname>
-    <refpurpose>Subscribe or unsubscribe event</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_event_subscription
-*<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_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
-    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-event-subscription">
-      <title>struct <structname>v4l2_event_subscription</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the event, see <xref linkend="event-type" />. Note that
-<constant>V4L2_EVENT_ALL</constant> can be used with VIDIOC_UNSUBSCRIBE_EVENT
-for unsubscribing all events at once.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>ID of the event source. If there is no ID associated with
-               the event source, then set this to 0. Whether or not an event
-               needs an ID depends on the event type.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Event flags, see <xref linkend="event-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[5]</entry>
-           <entry>Reserved for future extensions. Drivers and applications
-           must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="event-flags">
-      <title>Event Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_SUB_FL_SEND_INITIAL</constant></entry>
-           <entry>0x0001</entry>
-           <entry>When this event is subscribed an initial event will be sent
-               containing the current status. This only makes sense for events
-               that are triggered by a status change such as <constant>V4L2_EVENT_CTRL</constant>.
-               Other events will ignore this flag.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant></entry>
-           <entry>0x0002</entry>
-           <entry><para>If set, then events directly caused by an ioctl will also be sent to
-               the filehandle that called that ioctl. For example, changing a control using
-               &VIDIOC-S-CTRL; will cause a V4L2_EVENT_CTRL to be sent back to that same
-               filehandle. Normally such events are suppressed to prevent feedback loops
-               where an application changes a control to a one value and then another, and
-               then receives an event telling it that that control has changed to the first
-               value.</para>
-
-               <para>Since it can't tell whether that event was caused by another application
-               or by the &VIDIOC-S-CTRL; call it is hard to decide whether to set the
-               control to the value in the event, or ignore it.</para>
-
-               <para>Think carefully when you set this flag so you won't get into situations
-               like that.</para>
-           </entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-  <refsect1>
-    &return-value;
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/vbi_525.gif.b64 b/Documentation/DocBook/media/vbi_525.gif.b64
deleted file mode 100644 (file)
index d5dcf06..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
-SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrMSrRMidhA1/uNbB9j2CZ8
-Kc+qHDXDTT2jK3BuPau13vFpdmc/p6Uh5SeYoXMHyFNomEeYiNEVKCFFx8Wz2Eh56YWp2bfnGXk1
-OEhaKnem2rYa6vp3KIqaBhULmsk4Ufc1KTbq4rfbhxkcOQx22limZ4P8STYH3PsGu8pqe439aw36
-eji9qT1rGCpraf5MkQynyJeuG0c73imvLYzuUAwF/P6WTK8vHDdj2Qia8hYL4bF2o/CpmydOXa6I
-uqQNPFepny/+d+cM0qsH8qNGCI8M3gvG7KG8iSJJVoNIp1w5h/C+gSPjgWE9hR0Lqmzp0RFPjLV+
-hoRki2XNPJyCVmy2U6KnHm6WnboRcOPFkS59xqQpEKZRpkDHfi1rdqlXgTMVKVVL7h/cnmi1rtxq
-t27Yn1n5xrySUi81iYAlvR2MN23Fm/nkyHzp9G9iSof3Ps1pE3PmyV2dhaSL1Jiee3/ZjI5Mkhlj
-xDPXGnkClgns1pxV0K6d4rbYF7pRv44CW7Dtojt6f/YxO7hxrrmVJ3/eZDnd4tCjVw+OPbv27dy7
-e/8OPrz48eTLmz+PPr369ezbu38PP778+fTr27+PP7/+/fz++/v/D2CAAg5IYIEGHohgggouSNFv
-1l2HHIRCACehgw9eOIR0001I4YVq8MJIVZItUpJiG564GG75VJaXb5aVthtljwnV1mauyXijVqtB
-FVRoK7Foxi0kNphaYdhYNRUxQMZDWZKd9IXTQTmmFluUDQln5TcqBrnlYEOhaGJXNZrUpR24sLPN
-kC6uaBGWMywERpWISeUZacIE5iZH8OApJ3FrtvhnY5AdR1iZVOw4p1BTZhljlGNG1aijfgIKl4+f
-kNZjoIL2ySOacX4kYlyyfDgooWBSWmikOH15mU5ksfqiqUVqNsySXN7FqZ5jWdoTr7sSqaOtTH6Y
-EajMNZX+kbC53qopDDMuymhprgLbGaTUbgrtm8smCqOqQRYbZrV58vijtzZgNW2TTHZEag7rHFuU
-Pp4aSq6sc9EJa7jinpVuq/Ruy+xSj9KibL0YyRXrXr7WlC+242qrDMJsEYYSVvAiUzGJwg7c7BqI
-GjyiuQ5f7PG/7j57VqkpqryyyJ0WDDBxC29ymr3+YFEzyRpLE5qG91qYYYVAR4hh0B0WTbTRR1Mn
-NBKTDs0h0lErTTXTSyddNdZabw311ET7nLDTTct2tddmn82bc2V3zbbYazMId9xyz0133XbfjXfe
-eu/Nd99+/w144IIPTnjhhh+OeOKKczcR2CYvDnnkkgf+XoTF2eUCs9uTb85554MrVUjmJGDuuMue
-n4566gKyxM+T2L37cNqqz0577QG2/ikpVxEie7LflW578MIPL1vroVdifOy3outkscD/THz00k+v
-ne46ApQT70o2ZWz1RT5Pffji2w4YWcqLkrzvMhNT/Wjuvy/6+PLPL/w/854vr+t58gP+vufySb8A
-CnB8phEBmo7nhDHwz3vQGKADH0jAT4UgVGZQILjeBsEManB6GqKgP+h0vtFtcIQk5KAJpqAa/znL
-Xc4CXv9KCMP2fMyA8fvDDCdYwzbg7IQbwZ0IqeHCGArRbj4UwgvxgDJSHXEfIUQVEpuIqiLycIhU
-jJv+FNO2RCeJQ4kPuuIHUMi+Kb4piFUso4K8yIQsYm8cIlKj9VrQQyiqUH9mrOPm0DgcN8YsXoLQ
-Ix1HAMY/ArKCdiyk5PDYHD+6qo1dlOPItIXIG0XSkJT02yR5qEg2EqyRHYyjzyrnyEqK8oyhTEgj
-7bFJo13SI2EwzCdDhDP4yXKWtKxYLWWJsVu+L5e6rFkv4bezX9pSmDd0XzdgZkwa7SJnFDMNMX35
-TFdGM5jE5GU1o4kn1WDzmXbg2TaFaSZrgvNks+ymOL9Jy3DesGUiSd5wmEhGt5SiHUipp+naCZL7
-6ZOV+WyixMJhT1MKlJ+CFCP2nmexf9plCZZbJWT+3Cm7MJIxSfGcp0WTglGC9CtL+9RERz3aT3pm
-FFeiuShBHcqNN75ToqjkaBhXqr8XJnSPIC0oHP2JU5FqdKQ2g5jyLNerfgo1qDolKTlMmsqTlrJa
-Km1OAmOGCKa+1KkstRBEUdDQpUpqoEk1KlF2ei2fftQoYyVrSFERUK9aQp4tRakmbXrTqtbUpXD9
-oVw1d9UTZLWiXO0jWnn61Y7xca5mJWxhifpXsKr1IWxV6kQPitc1GnZOTcVqFhRq0Lxmdqp6palb
-L5vYxQL0nkA9rGnVgql9FvWoiu2qX9uqVWxVtrNP/em6lsdZ2t6VbE9ap1B9y9qS9jWwwS2uzvD+
-OdmFDjWoIF0tcZ+7VqTWFLjMpS5Ri6krsaoJpt6M2hFLK7bGuha6DAPsqSi7XNSmV73NDa1xVSLe
-1xLUqlaLbViWCF7vJu27ns2pe8k72rCSq6z3XW+B22ve8rZWvuM9LW/xm13LPo2q9mUufScU3+gm
-OMCiDRtukytVEIcYsRuO44I1LNz5RrTCytXvfo/G3wnTNsOM/S98S+zED1vYwS0WsWxxGkLMbjXF
-DWbvhV185CS/GMm9ky6KOywmHM/xxz7WMY97bFbn3vjENR7ulSVM05QumcljXnGMabwnGysYylO2
-spG/TOUqo1fLa35vl4ksZ7uyeMRmrq8akav+5OI5+c5sFlRaezpgA/P5zXDGLZ05bOc0e5nRD/Zz
-mfscHWYiQdNKAK6n4wfAxSTi09wk5zipqctunvqct1T1L8P5i1GLLtTsdMRBrBvrHNoE18fEL6dH
-CexgC3vYxC62sY+N7GQre9nMbraznw3taEt72tSutrWvje1sa3vb3O62t78N7nCLe9zkLre5z43u
-dKt73exut7vfDe94y3ve9K63ve9t7SBkNdH47re/9Qq6CAP63wQvuGZ2mYneFoPWBm+4w8VUWiMB
-5IIPr7jFX2a/YCZ8zxfvuLnf1VB5QcnjJDd4YTKucN3xuuQsb7nLXw7zmMt85jSvuc1vjvP+nOt8
-5zzvuc9/DvSgC33oRC+60Y+O9KQrfelMb7rTnw71qEt96lSvutWvjvWsa33rXO+6178O9rCLfexk
-L7vZz472scG0vllD24rZzrW28bbtcl873N2uObUfqkQzJFaJPAO9Fm53W34/mcbO+7/t9j1ksfzY
-MiUO+DaXDPCLT9VpKr8yZnpQDM50JcmkyTOdNT5Enx8mxhAPaxApq/CULxjFV9S8kT9yhWts0zL4
-JVnX44uigl1481Cf8KsI3Kf+Er6biMXS18/+gy2JJfBzFw/Mc35U0NcXJxAh+4A1ENC69xdoER38
-34Mf+sZvF/5OP3yQ+QKAt8+14Z9/2dH+H3dnh4d/Als5f1MzMcdsCoj5SfwwqXVb/Mca6qd9WBaA
-R/J+1qddDHeAUZZy85c+mOcp/ndc5QMqGyMawrd5ACVx/8dYKrcsFQg7DAhEu6NAG7g9q3cU3RN4
-zBJV9jdwsXM/GQiCRuZWNWh7Msh3QmaAhoYSIyhja1ALbQJ/obM+L0iExvJry8d8LpiAuPdSN7h9
-3VOD3kdHW1AVsOOAxEclTySEIIQOHViF7XSFZQgUVFiGj8CCYpiGR+g8Axgt24c8Q9gpvTJbHjZg
-IjguFJQVZChbH2h/2rODJjgqxieDGTiFevgyFKWGAYOBj8gtVPF564IpLRKJgziAgAj+ieFniNxX
-fUo4LPcXhn2YEqMnif+TMYNHgKoWeTTYTGoifZzXeAsoivpXJ2f4PaHHik7oMZ1ni4yIi8fDib+I
-gen3g6pohE34gMa4cbO4ixJkh8m4d0HYi5Lniq1XjMqojcqgd2AmNXVnd3g3juRIYXT3dnGXjuZ4
-jl/zjboVjuvIjvB4d/NoUOiYd+qYj/Z4j+6IQXNXj/IojuAYkAK5j/yoZwV5kAa5kA2Zdg8JkREp
-kRNJkRVpkT73ZxwnjASpjwCJkIP0jv3Yke34kSAZjww5kPQ4kiSZkipZkhOkNifpkOWIkjQ5kzZJ
-NqyXi9uYeIrXho8TZtTlCjnEMfn+Z07jN3n3hIuC1ZNKeY2JiD6Zs0gC5iWzliav+Inv51vKx3wo
-WIrTV3uh2IqC9zjZN5ZL2DBgSZW+iI2GBpTT2IwmtpajqJSGIY232JRbuQ1myZZoKZZZmTt8ySV3
-ggapWEHRAJjU2JaL6YVMKYepMpe/GJlH6ZTI2Jdu6ZRcuZGQBJePqTCTmYRG2XyO6Q52Ui5QuJn7
-sA4amC2XOYeJCWukWVugeX2y+ZeiGZSO0ZrncpdGWYKwOZq2mV94SXwzEyymCULIo4u0h5rt95ZD
-uZuuyS2xSJuNeZZ3WJlhBmRQBAhCGVrLmRfGCXF1yTyg2ThkQlZ5eJ3lWYipOZ3+UKmd/uSDrwmf
-ciSY76kuacmY+Hk9lWmEwumJ8BmDSBl9/zKgpEmI6CkjGcOM/MmN3QicnRmX0OBpuvmW3GlD4jkr
-QEmUFuqfHXokUjkPGtoYDSqd+meiE+qMehmf0ZmQComTHtmScSWTMWqjHPmSMPmPMhpRGemjMYmP
-N4mjM0qjMHqjLkmkL5qjIPCjLXqhLqqkSWqSQXqkSFqTLHmlVpqlIrmkF+mlXwqmYSqmY7puiEim
-Zzogj4GEaMqmAIIQmtmmcTofbyqhcqp0GSlD1gCndvpvuqYldSU3dOqkfJpun/VFt1md5sFQjOKn
-hFpu+dObKVMXUnSMx5AfDBX+agfqqH0qQQtkCrMZf81gqBvnmemBTZtacuCyp98yFbyAD/NJSLiD
-p4dKoSuHqu62qJHqlpTYJ5AgcvKBqbfqclroUOUZBynoFP/pHrMqrI8KL2CErB1YQPHBrM06bjwJ
-lxsDJCkkqgD3WNZ6Ro16lT5gq0JCnBPGrfs5SerJcaOKm+BaH+4KC5kkZoR2nTTBrixToKCESTwK
-r2mqkatySi1lr/uJr7nFpJ6kooMWpf8KsHpErwQraed6sIAKLez6SQHrsHAjr6wQsSpGMzzIqp0U
-ZfwKR9W6sfzRsarwsXnWrYDJryurohjbWSibsvohs5MmaBI7se45qQhLq5L+YrIiZLM3ix85i2e/
-oRMHJLJesmfoArVPyWqldnivNrW1hGqvhk5Xi7VcW05ei0u9JrbKNLbS8nioyE1bC7bAtLYIt7Xo
-BLfmBLdWW7Vz20vq9E2mFrZ1u2qihrcdRHq19Vj5CoaFVqIMC2kAdq/U57KWqGh0hWBJu2WG67Q6
-y11AO6WEq6O71WjIhbRSBaubG1OVZrH7R7lAhLhyGWmLO4MHtmOUhoDqhWaJO7mru34YorlBC1mV
-Frr8RmWf61K9q7uaRaO5K1m26xKzq7qKa7CM+7qu27nadVaWC4GnCxXKS2HG+1CYm7nHG717FVnC
-Syuje7mlq0XIK7DUO2T+6Luwvhu97gu7iya7qVu97Fu5khtZ5ju+2ru94uu8v6ux1Oe/BUG8ema8
-A+y9T8Zg9suZCGqZjtu4pfm4wUu/68u8FqzAFwa8H7bBjgZVyAi+vDuo8xvAIVy/F5y++Eu7dZaI
-wym/sQvDL6xc2IvBLFy7C6zBJfxECPV9BIZe+ru/CZy96DfEWHm/DDxGFYyZ1luqcfa+EPy8MQy6
-SsyqXLbCPeti5fq74gq62JWtSMTFwavFUgyPFShlKVxkV7y8ienCkPvEEhzBEkzDS4zEBaq+ZXxp
-+RtopEs1MQYwCIzAQJzEZ1zFBPq/8evGiOzEWUbFR4zChZzG5bvHkoz+aWRmyZRsw5mMxRl8w51M
-sYcMvYrsZqFMwiq8xpp8yptcyavMynw8yXrcyqksy7d7x5D8yA46ymScyzKcyKUcySfsyWpMy5Z2
-yZjsyrGMzOBoxlYcsrXsyMHMum28yKSsyz8cub9cw8Kczc1MzK+szHl8zMX8zXVcuNh8uIT8zJ/c
-utUsvVHMyxTszA3MxOWMw8mMx+BcxOIczsY8y9s8zOZsy9DcvOv8zrvcy+zcgI0sz+RsugBdvPic
-z/Z8zxmSoqNT0aq4a1JiI92Q0bm2aqeqt3cb0qk20q1W0iYttbR4ax3N0RsNBBdNQ114QjCNQzLd
-AjRttDmt0zvN0z1u7dM/DdRBLdRDTdRFbdRHjdRJrdRLzdRN7dRPDdVRLdVTTdVVbdVXjdVfVBkx
-+APSnNU5bZaaCsVfPdQnR8TkJwlnTdZAnSwXJIidutZBHbhrqpqnuKpx/a9c3RdvndZ43dO+pCSY
-E9gqF8bNWgAAOw==
diff --git a/Documentation/DocBook/media/vbi_625.gif.b64 b/Documentation/DocBook/media/vbi_625.gif.b64
deleted file mode 100644 (file)
index 831f49a..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
-SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrOCqVMidhAVdqVbLmx73Wc
-FXfNabGFzfbG3Rz0bDO/2G1hzJ7o8ceT56dB+Gb4JciD16fnh3VI97bmOCE4tyhVUSbHKOlg1xnp
-6aWFKDfaecrqQlrK2vqK2bjImPFaiLuKuxvY+2HLq1tniHcLzFmWy6mnitxMeWs5iaZo0xZhTahj
-rdzXHa3m6Eod+h1+LW7MXpx83P7962y+ju4O//5oGr8PHUvs36VjoCBsujTsxp5t0MIB1MZLYb07
-CBt+QlWRHz/+Zto62NLYD+Ouj7Q+ZlMj0J80kCr1iaSHT6WmeAXPAXOVzNs0hw8fHAwzkeLATz9E
-xVo2qCa2o7AA9Wz5cmXIgFAhKu2Yb2q1rFSrDmUZFeUgrQaLdhWriFZKGKt6LNTSlopXthevrIUB
-d9rSp6FGcbnLwCRYe2ELo+VK+CxEwF9XkoypeCtZn05dTiqlNupMxnyWxXkL17OVtHz7loMTdO+4
-pGsMsz0dKbVcyK7LXsWbyKSweTA95qatDHho4T7TqqsdWN1toaFbExNMHMkTzimgR2cSZfpgI9qt
-T8aePbz4IQebeLcsZDz56ecjv2g/9z37+fTNd6+vPb/+/fz++/v/D2CAAg5IYIEGHohgggouyGCD
-Dj4IYYQSTkhhhRZeiGGGGm7IYYcefghiiCKOSGKJJp6IYooqrsjidyrAh9yL+K2nng/31WgjjtzN
-mKOO8lFHxhlJxRjkkEY2tloWy51k2mxAVoaQQkImRiRuIyEmD5ZIomeVYMLIZhMkS6rWm4vJecZl
-cWBsRomUz+Vlymg4bWflYnGWo5FOGZ02FphPYmbkmHQmRxRSgzJXpntl/UlmcIca5ItvilJJx2OS
-TkrZo5k6CgemfBDFKJPF7ZRTIZsMgxUip4qKKFN5UropSKD54xasW9p6a65VBiYmb/dc2qZuwMaH
-laXvZEb+FbKPCKpkm68KutBoTshZWpN6MRqtm6H+8ZmTulabqplhXikuNtBhgqqnM6SLa7jE2nZd
-rGzK5CeUqMxJq6l2YavvTn6yGVG7zGn77aZgvOvuruvGexnCndXLq5YCC2Vsmg2LUzGcTSm8r7fg
-0pUKxMgwdOdY/O4JaMkFf/pqyiv/Jau9CY/asqatOlwnzuM6JvHMOsPsZaQZ/3zzV0NfdnS4HL3c
-KsBZpnIk01NCHbXP1o4MsSjgyAzp0xsddzHRHqOz2289d83wmb46e/aibauZNhXGMWuz3KjNG6Vz
-+fooHY/p8Q0ejYDL6PeO9hX+4+DVsRr4DjByPMLjE5v+ILnUJ1Qe9t+Cb855j4d/jrnVfSuOQuii
-N+5555qrbjjrrTt+Y4uyz0577bbfjnvuuu/Oe+++/w588MIPT3zxxh+PfPLKL8+87rWGYLqI0TdP
-ffWwM249oXKDgC/y02cPfvgkkPJ97t137075HKovfvvuQ1KXh9zKJ6V37A7P/vv6739Oa0BFnoRK
-QG9+2PlJMLDnu/zxb4EMxJPJ/DLA/sXvF0EogsgG5hQDkupeCOydAhkIwvcdAYJeqYdfymOMCvLK
-Swe7yKqgkLU4dZB3AaRbCG8YwhrOEGazUaHJNuKboqjQaRBMSDrqBkOu4W9uTAQbDp8IRSV2jFtm
-2Y7+thwIDyzi64VIBKIMvQip+/Gwit5Tkw2jiMbsGcVRPfyhBTdGq7gY6ovoG1UL6ximJSwtVLjT
-YRr/mMZZFctJRZSgLswiR73gMWcsqw0Jx0a8DwJyksAj4CCjRr7T2aSCiQTiIiMGsvg8UorBkyQl
-T7k7S3aNXQJEm2lWxcl9bRGFnWFM2TAIyuOZEpUpOqNHLhgMX9ahXqq02xZTQrCdRQyWdpolq+Yk
-uTdqMoG8BOEnZSSsHYLRRmukFAnFGKOA2ayVsBjhNkUgTVcab5fVNNE1F5fNk33wnY2y2iOBWbQ2
-8rFj9axLNBmZy3W2c4H0vFwXcTmUeXaxmBmUlf3+LkmSdJprn5kb50AvWruCUu6g3gKNQrtZmns+
-dJUU/WE/6bjRgAIUoyx1J0e599I0eNQ+INXVPaEH0ZTeAZzE2QI7WwrU7Hw0KzNdT00rOkqckjSm
-9jynUvMJyaBKVX5MDSJN9jHUj+UzqTCdGtWcOECJyAmf8CqSbWDTxLSiVa1MZA1b5+bWt5ImZHI1
-Dj2YZddgiSyvel1rXc3w17bSNbCiIWxhDUsGwyoWbNdYrGITO1jCJjatRXIsYs/gV7betbJkhZtM
-ndqChkaPJ6fYTdk2g9pyQUmVrJVJQDS6Qnak9pBX1RxXxyfa2o4LmoG7LW6nVdJjgfa3imzc/Ez+
-K9ubKNdiuWytSJz7XKbCliKzxapuE+fJ3k5wHVOoX3AB4tvIAYKnxEUp4Yp7Xj5Od6LLtS5tmYtQ
-8Lo2uq5Fbns5+N7Xei68T82ufl3J2/Tyt78Bxm6BS5fb9HJ0vXI57X2jcUv50pe7842uffOLX/f+
-t3UDPmAS59Xd8X63MR32sD9tO1zxfti4y0phcjEMYdV+dsISpnB9XfzgVuS4xgberk79S+Pdphid
-CRbwkEML3KpKmMH6OC6OYaxjKGtVNdDlMYn1e2ENZ3jLQdbuFxe34grL68hdRa+RyaviQo02g51F
-kpN74WApV0rGFumy0sQs3yxzOcpatjOY/eX+Zbols06wCXSbrwzWPyt5w9hdsHQfHVM0L5POMfPz
-mC09Zj3HWM6XZPToFo3nT7Nv0F7e3KhJ+WNHa5rPe04opUkN4FDf+cZwfnGfWY3pH59am2UGda51
-PZ5dj7glb+4Xp5d66yl3VNax/nVzHx3nZM9ZuCiutrV7vN9gZ3t1xW7xjqct7YoK2dlUZnasV+3q
-Y2cqwsL2tY2vLerrDfu68ea2t40dbmS32nIzfreVkYblJ+d73d8GOLxLzeFtHzzhC1e0qgW+705H
-fJrlJveyLb5sdIN74gSnNsM/DvJ6N1zk2H5dt1Vla45v8tWofjbG+01hjUt80wO/dMgRXvL+nOsc
-CHM1Qs/fw9fhkEtMmrBhovMW2Mn+Vel1Zbpcnf50r7KN6CMpOj6DjoSfZ/3o1dG6Erz+da5Pdexk
-L7vZz472tKt97Wxvu9vfDve4y33udK+73e+O97zrfe9877vf/w74wAt+8IQvvOEPj/jEK37xjG+8
-4x8P+chLfvKUr7zlL4/5zGt+85zvvOfx7sNrXfzzpC89gyQB6zqbfvWsL9Bh7xgyNbd+9rT3zxwr
-3aly1n73vAcdMw7rxt4Lf/iE4+LX2rJH4it/+bLNvSI7JXbmS3/61K++9a+P/exrf/vc7773vw/+
-8It//OQvv/nPj/70q3/97G+/+98P//j+y3/+9K+//e+P//zrf//877///w+AASiAA0iABWiAB4iA
-CaiAC8iADeiADwiBtoc4n+Y6FChvFYg6qaOBG/g6HNiBq3OBE7gua1I1FCd1JKhsXkVa4jaCPRRD
-XoOCKUg1MMeCtVQZ0RdVZQVD/+I1dzImWsMT0AKDUmeCR3I3HHOELXdSahMoP/g0n/GCUdKETvgn
-5MMnJ3MYX4VFRQgoUChIboMmybdSIHOFYqhSfQFoJlWDQGOEYjMLs2A5b7iC6kQzaCJ6ayhLX6VN
-JONAgHVUdSiHu2KFPoaHD5QykrZDsYEq3VQSUzQ5qzUyMniDOTiGNoeFGPE8/DZjQjj+XzhIiXfm
-ibymegeFLBqkiZFYM4XoMXqjiqNHiskSikqIKIX2iDA3K9mSJ9QiiZmAiq3YhrIIjCoYjOrFilQo
-dGamibzoMlxoViozBrhIg8yojDOYjM6hi9XoXZcohf/whVaBWYi4LZXQh7WYhNsiil9Gi6eIe4lY
-KsP4Um6yV+04jKVIV7U4ilVIVKkYKzXGUAZHS3QoGbEniRv0j/tYWpmojqT1h+5yTANZaY5Whc8g
-Q8QEJ/AIjlrTi+aIMkn0M7lgKAupPQTTjWiIexfpDBZhhp+4PQ/Zj2TYUNpYh81CkRsJezKYSUt4
-hi6piDBJkuOYkji5ks5nSUA4JZz+uI1KMpPHyBIjeTVqBpKvcYNRmCTRCJBNmYtPaZV22Ip5cHv8
-xpVEWJVQiZRMKZakYZRS+HNkyYRaqJYtaIRS6Y0zGI/zRmlEJoIKFoIeaIF6mYEg6Jcf+JeNlpd/
-Y0qFGTsY2JeCGZiKCZiNuZeO+ZiMCZnnZZikg2CWaVCYiWSaWV6I6XB8mZiRKZmiGYGlaZqniZqp
-qZqryZqt2WuDOZl4uZikKZux+ZmzGZq5WZu2mZmc2ZueeZm+aZfC2V+wyZupZpy0eZu4uZzHuZlE
-OYUK85UlaJA6uJTSuTXU6IvTeJbwpUw9CDluKTZAWZ3N8TZiWZdulZ7UaY9s6Z3+NqidDjmNmFiR
-ntAtKRiI9qknh+GFgoh842iTqvCR7QmWDmmI79mT6hJKCgpVBkpm5RmewQWODRqSP5mTMWmhFLow
-XyOPzdBCC/VfBVmJBqOS5BlfIPomJeqOGvqd40mX71gL53km8RQscdOi6siRCHqiOMqNDGouwCSi
-TUKCSXmUYLSfRzmHYYmeD3mK98meI+qLKgqhUbqWBEqIDpqhUOqS63mOXfqkPJp6SgpgF+RgTnNv
-6Uil8MiOKcpr9AhHzNgsUjpiSZMRXGqidzqCV7c2ERqkVLqicroXdEozb5qQZNSeikimiSiROEGk
-YMhm+FifPTo5v7dPGNkyWTr+pzJ6oQ6ahy76p16KqSy6oYLqp6DqpTB6qqU4oeeIkBjzhDv5iNMZ
-n1NapUlKq/DplOT4P1+6qTwqXbEoqp7lqakao5qKqz66klwqTFQkWJAzV0Z3V31KosT5msmpm7up
-nMH5OcCprdaKrdn6m9yqU5W5reK6meUKms05mteqruwart7aru46rncZr99qr/farelar/mqr+/K
-nPvqr//qmgNLsAVrsAeLsAl7O8ansNP3U9ZjKaHasID0sNxTsc3Dbi86sfxzaPzRsZOUse62sR9y
-Ho8BI+RUp1KhhlMVshc7sgMSG8N0pUGZi8HET2KRYUxGSS37sh60jMuCZgD+Sqgn6U+xtLLTJqIS
-5bInEkD7+LE9qyASQShBCBX3g0j66KHFZbRDS3CkhkfQtLQu9UqGKrJQmyD+s1O1MpciRrYn9opm
-xkrPMkO0VEVqe7QNdFlm2yIFpoxusap1ezO8lTWdFJVu25U3qjKpeDBhWyI1BKx6CyJJJWltyahW
-dCrRgowf9kKH26s3qXrSAkV+BLm086EvKaYNirIZpyqlK2Lsxbmiij5xG7qjKzwh9oxA8k8eCmtf
-m10+pTFXyrgkEry0GyDd5Q2ykbtmtE1DtFN2YUGY2ranyjzDq3ePi05PO3U+IEzF6rsV8byg25mT
-BpJS+0aryqnTe33mC1P+WUVv+iYE6otUMzss4utNpuu6yGlN6auxWWtUMbFGWZW8S6Gza1hiXHJg
-w4lD1Jt38EtBNOW/NMdN+ysqBYwwFDwXB1ycxCsgDGxV/du+7ssdHAyhFtwuJFy/Ioy4GuyxEjwQ
-7OtpMxfCLEwnJvwyNGxTD6qjKkwjLvy++QjBPVy2UmTD0zTETYXCWqrD9MHDMexxuMbEAdxGAZwJ
-sNoCQOGH2MtZjhVZSWdZr7d0W9x00cqseAV2Z7VXz2pZYNx0XRxXSafGXRzGUwjHbwVZcxzHscfG
-39hEWWzHalXH2/saYsWrxYqSMnxxA6xyhoRviTxpyMqkV/Zy9+iPEMf+v+q2cqaGw8BSxEsGaZyR
-jWsWZmdmyM92xLOGyD9cyfdWc7iBN5Dsb678b6ZMyaWVcqjcY6XcbKfMySAGiqO8iUFMaJncaxh8
-rpucboucyoxMXTksybP2ygZnYzIXRrXsxLfsy3Wmy5A8wGH6Wbh8admMaNesusCMS+AMw7RcawUH
-wgm5otzscs8sy+mMzNW8cSjmzeNmzrkcaUr4yYFGzhh0z738z4c80PaLcvK8yo08nu68o84cy/qM
-0Adtyay8rcRcXsY8yW56buKsptPTzwkX0C6Xzx03zy1MzcccngxdcfDcbNE8yyatziSdbSFdzgX9
-yxqdaRxdZIpm0b/+iaY+PcgeJs2UEW3KjKeQGMmPDM2cHNHJbMv1DNKAbMpYLNKJ2kH1I9W5TNWk
-nNWwTHJ9M9SKnNDL7Mgq7YpevdTa/NJuUNRPjXNvbWQKt3NwPdc8nSNhjRdtTc9wqtQOjdZ+PclN
-jc4TrdBy/dV0bdcjp62SZNYEdtdr3RF6jdKH2s6VLYqN/cuCDdOETdYX2G6f7dmGfdg3F9c7gtex
-FdOXvNCWrV6sDZF3KNGqbNT6FNqKDWyiXdqkXdeL/diazdYnDdXsfNmuXWVq7duRDdznPNqJrdvM
-vdu8XdG4DWan3bypTdFlTdzmNm4ufdzTbN2FbdvFLN3OvdzkHd7RF93bJf3b393ZKZ3dSY3Z2AzZ
-3s3ZAhzd551mNv3Ozw3U5lHGpfPfl3NGA351Rmfgj6XHd7xYUKdZCR51rGE2vVJ1E04eAU45Fl7F
-1htMGv5LHN7hXZ3EIS7iI07iJW7iJ47iKa7iK87iLe7iLw7jMS7jM07jNW7jN47jOa7jO87jPe7j
-Pw7kQV68E+EQhqrAQs6aZmirzYzkQC4aAmmIygHlTS7kP0G3gRJ8VB7kAGCRbQB8uqflTu6Ci4jl
-ehjmPs7laf58XB7Fau6DR56aBQAAOw==
diff --git a/Documentation/DocBook/media/vbi_hsync.gif.b64 b/Documentation/DocBook/media/vbi_hsync.gif.b64
deleted file mode 100644 (file)
index cdafabe..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-R0lGODlhBwHJAOcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
-Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
-ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0
-NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH
-R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa
-WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t
-bW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA
-gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOT
-k5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaam
-pqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5
-ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zM
-zM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f
-3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy
-8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///ywAAAAABwHJAAAI/gD/CRxI
-sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN
-mzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtarVqyQBYN1aVSvXr1C9gh2rVOxCsV4B
-mE2b0GxDt2TjtnWo9l9du2rrar2bl+BavQL3ApZLeC5du3j77g2MF/FAtIv1AoZb+Gfey5gza97M
-ua/ByJ4XI8b8+PHl0ZkrE6XsuCDr1xD5ip7d2m9pv6IZqxYK+zPC3g/T0mabGLdk4YEH7wYK3PZB
-yqyXSw/++3l139OzS4R+Hbtr7eCp/nv/bp18+PMKuZcfj7792fXm47ufz/52fd308zu/X3u/fv3N
-+Sfgf/MFaJ98BLpnIH4IJojegv0d6GB7EEI4oXYVdnfhgxoOyOCG4WXIH4jTidggiSV2KOGHKGa3
-oIUtqvaiijEuNyN8NUp344g5EqYef9H1KNePJwYpJFlEehjhkT7iuCKLTMZl4olRgjWlklV+deWT
-WWpJ45JgdrnVllCKOeaXMJrZFZpfqmkVmWG6SRWcRsoZFZl12hkWmzxemCdXeAr555lOgjnof4de
-tSOVG0KWaFl3GVponH52ZumlmGaq6aaY0pjmhJppmRqQbTaKm6gewgnio2uSOumq/jpO+qmDrE5F
-p6AtSZZeSrf2WOtEoZEmm2C/Astnn6CapKtjbClWZki95lhsbLcRtxmlHkVb47TBWcuYcGvxeiyj
-fp7kGbOJEZscStrGyK1T7bb4blPxojgvU4Hiulu+vto4Lpck3rvUoljCuq+npZp6cKGz0uovwwmX
-u3CRESc7sZINJyhwWbJW7PDFXGZM4MZI1WsvyCF7rDHKZYqMKMuSvmqwS5yOypHJAcP0K8k4z5xr
-RTz/C7DPLO2crdDPEr2S0R31rDDNQB/dMbISQ01R0FOT+/TPV0vtqtZVc21s0wjLLONFJG8XNdkQ
-y5z2UNy+TW3XbN8Ho9xBxa3z/to3lz0i3nljBPhbfG+UZMoqG5db2+KJ9O7gDDHd99dUstpscsgR
-x6CzqC0O0uN70z05xVlHdNpwgvUHGWrFef5RppGHPjawNddue3nB5nYufsKmu/vrhL/3kuRqq1Tr
-6pd/G+6HymGLdvC7Dl+46cYD7aywoSleXGOtj5RnnZALP3vx7Bb2J/iyk6++subTZanz2ZJ2te2R
-st8+9NaFHx/x1Jff5GFz0Z9/+Dc3c9EnSK4ryfLG1z89GaY6AjwQARvnQLfBr24XpFrizGSk+tlv
-aOJbXwULxj3/gTB6DBwhCD2oQLBtkIR66mAEVTe9AqqQhCzMigvNhsIbrnCG/m6ZIAB9+MPqwfCB
-IryhDI14QiQ2kIiUyqH3dqhBHtoJfSZs4gu16CYsGpCKYDyinLz4QS5W8YwcjF0WkxbCJxKRjC0M
-oxnlmCU46tA19BPiCO04xZjM8IBq/GL63hjIMloNitiS4uv+aMUxRk5/ihQXIhMJSUaiUUzgq6RM
-LEmhR5qLk2LsoieVBco5YnKUCiwlG2OIyqyoMoNpPIsm/TjJRMKya698JYZiB7kELq2W6OvlLT8H
-TF62MJfM+R3+lnnIAB5zk8zBHOZks7/BqEuXwXwmLS1DzestDnmNud5MsqlDZPKGWMkzT+9CBc33
-5PGd8IynPOfJwkilLp37/gniN8dZyDgOcienCadudnc6anavnT30p/SKokvH9fOO/+RmqxIK0YUi
-EosBNVz2tnnRR9KzUxyFYjAzqpHehZSQbdxYEBEqUhcVM0WTbGhNZBor+7xNj8SMaT7TJc1Tgcug
-Bf2LNZnlKODp1KYCbR64ujcZ0OBxe5FR3jAfqsSdNiujucMnPnl3uaxiraNI3ep3hro8161uNLbB
-G00fNk3abG+aAiXqcKqlGG8Oy6hgLang+HnUjERyiBFV4VpZitKa5rWEgKJjldgpKs5d9KOQjeym
-XkrSMdnzpYatpWY3y1l6NXGB3RlsZ9eDzp7ydKmnW1dAlTnaQ94zruEkS2tUnfra1iIUdRvlHueu
-iS7N2daic1VncEEz3N/6MbVyNU1TV0tUdL3VuF6aKnQhJdrpWve62M2udrfL3e5697vgDa94x0ve
-8lIkIAA7
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
deleted file mode 100644 (file)
index a2765d8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-       "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-<!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
-<!ENTITY media-indices SYSTEM "./media-indices.tmpl">
-
-<!ENTITY eg                     "e.&nbsp;g.">
-<!ENTITY ie                     "i.&nbsp;e.">
-<!ENTITY fd                     "File descriptor returned by <link linkend='func-open'><function>open()</function></link>.">
-<!ENTITY fe_fd                  "File descriptor returned by <link linkend='frontend_f_open'><function>open()</function></link>.">
-<!ENTITY i2c                    "I<superscript>2</superscript>C">
-<!ENTITY return-value          "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
-<!ENTITY return-value-dvb      "<para>RETURN VALUE</para><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
-<!ENTITY manvol                 "<manvolnum>2</manvolnum>">
-
-<!-- Table templates: structs, structs w/union, defines. -->
-<!ENTITY cs-str                 "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
-<!ENTITY cs-ustr                "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='1*' /><colspec colname='c4' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c4' />">
-<!ENTITY cs-def                 "<colspec colname='c1' colwidth='3*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='4*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
-
-<!-- Video for Linux mailing list address. -->
-<!ENTITY v4l-ml                 "<ulink url='https://linuxtv.org/lists.php'>https://linuxtv.org/lists.php</ulink>">
-
-<!-- LinuxTV v4l-dvb repository. -->
-<!ENTITY v4l-dvb               "<ulink url='https://linuxtv.org/repo/'>https://linuxtv.org/repo/</ulink>">
-<!ENTITY dash-ent-8             "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-10            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-12            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-14            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-16            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-20            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-22            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-<!ENTITY dash-ent-24            "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
-]>
-
-<book id="media_api" lang="en">
-<bookinfo>
-       <title>LINUX MEDIA INFRASTRUCTURE API</title>
-
-       <copyright>
-               <year>2009-2015</year>
-               <holder>LinuxTV Developers</holder>
-       </copyright>
-
-       <legalnotice>
-               <para>Permission is granted to copy, distribute and/or modify
-               this document under the terms of the GNU Free Documentation License,
-               Version 1.1 or any later version published by the Free Software
-               Foundation. A copy of the license is included in the chapter entitled
-               "GNU Free Documentation License"</para>
-       </legalnotice>
-</bookinfo>
-
-<toc></toc> <!-- autogenerated -->
-
-<preface>
-       <title>Introduction</title>
-
-       <para>This document covers the Linux Kernel to Userspace API's used by
-               video and radio streaming devices, including video cameras,
-               analog and digital TV receiver cards, AM/FM receiver cards,
-               streaming capture and output devices, codec devices and remote
-               controllers.</para>
-       <para>A typical media device hardware is shown at
-       <xref linkend="typical_media_device" />.</para>
-       <figure id="typical_media_device">
-           <title>Typical Media Device</title>
-           <mediaobject>
-               <imageobject>
-                   <imagedata fileref="typical_media_device.svg" format="SVG" />
-               </imageobject>
-               <textobject>
-                   <phrase>Typical Media Device Block Diagram</phrase>
-               </textobject>
-           </mediaobject>
-       </figure>
-       <para>The media infrastructure API was designed to control such
-           devices. It is divided into five parts.</para>
-       <para>The first part covers radio, video capture and output,
-               cameras, analog TV devices and codecs.</para>
-       <para>The second part covers the
-               API used for digital TV and Internet reception via one of the
-               several digital tv standards. While it is called as DVB API,
-               in fact it covers several different video standards including
-               DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S,etc. The complete
-               list of supported standards can be found at
-               <xref linkend="fe-delivery-system-t" />.</para>
-       <para>The third part covers the Remote Controller API.</para>
-       <para>The fourth part covers the Media Controller API.</para>
-       <para>The fifth part covers the CEC (Consumer Electronics Control) API.</para>
-       <para>It should also be noted that a media device may also have audio
-             components, like mixers, PCM capture, PCM playback, etc, which
-             are controlled via ALSA API.</para>
-       <para>For additional information and for the latest development code,
-               see: <ulink url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
-       <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
-</preface>
-
-<part id="v4l2spec">
-&sub-v4l2;
-</part>
-<part id="dvbapi">
-&sub-dvbapi;
-</part>
-<part id="remotes">
-&sub-remote_controllers;
-</part>
-<part id="media_common">
-&sub-media-controller;
-</part>
-<part id="cec">
-&sub-cec-api;
-</part>
-
-<chapter id="gen_errors">
-&sub-gen-errors;
-</chapter>
-
-&sub-fdl-appendix;
-
-</book>
index fd565e1..857f1e2 100644 (file)
@@ -63,11 +63,12 @@ sgmldocs:
 psdocs:
 mandocs:
 installmandocs:
-cleanmediadocs:
 
 cleandocs:
        $(Q)rm -rf $(BUILDDIR)
 
+endif # HAVE_SPHINX
+
 dochelp:
        @echo  ' Linux kernel internal documentation in different formats (Sphinx):'
        @echo  '  htmldocs        - HTML'
@@ -75,5 +76,3 @@ dochelp:
        @echo  '  epubdocs        - EPUB'
        @echo  '  xmldocs         - XML'
        @echo  '  cleandocs       - clean all generated files'
-
-endif # HAVE_SPHINX
index 1179850..c55df29 100644 (file)
@@ -78,422 +78,111 @@ CONFIG_PCI_MSI option.
 
 4.2 Using MSI
 
-Most of the hard work is done for the driver in the PCI layer.  It simply
-has to request that the PCI layer set up the MSI capability for this
+Most of the hard work is done for the driver in the PCI layer.  The driver
+simply has to request that the PCI layer set up the MSI capability for this
 device.
 
-4.2.1 pci_enable_msi
+To automatically use MSI or MSI-X interrupt vectors, use the following
+function:
 
-int pci_enable_msi(struct pci_dev *dev)
+  int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+               unsigned int max_vecs, unsigned int flags);
 
-A successful call allocates ONE interrupt to the device, regardless
-of how many MSIs the device supports.  The device is switched from
-pin-based interrupt mode to MSI mode.  The dev->irq number is changed
-to a new number which represents the message signaled interrupt;
-consequently, this function should be called before the driver calls
-request_irq(), because an MSI is delivered via a vector that is
-different from the vector of a pin-based interrupt.
+which allocates up to max_vecs interrupt vectors for a PCI device.  It
+returns the number of vectors allocated or a negative error.  If the device
+has a requirements for a minimum number of vectors the driver can pass a
+min_vecs argument set to this limit, and the PCI core will return -ENOSPC
+if it can't meet the minimum number of vectors.
 
-4.2.2 pci_enable_msi_range
+The flags argument should normally be set to 0, but can be used to pass the
+PCI_IRQ_NOMSI and PCI_IRQ_NOMSIX flag in case a device claims to support
+MSI or MSI-X, but the support is broken, or to pass PCI_IRQ_NOLEGACY in
+case the device does not support legacy interrupt lines.
 
-int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
+By default this function will spread the interrupts around the available
+CPUs, but this feature can be disabled by passing the PCI_IRQ_NOAFFINITY
+flag.
 
-This function allows a device driver to request any number of MSI
-interrupts within specified range from 'minvec' to 'maxvec'.
+To get the Linux IRQ numbers passed to request_irq() and free_irq() and the
+vectors, use the following function:
 
-If this function returns a positive number it indicates the number of
-MSI interrupts that have been successfully allocated.  In this case
-the device is switched from pin-based interrupt mode to MSI mode and
-updates dev->irq to be the lowest of the new interrupts assigned to it.
-The other interrupts assigned to the device are in the range dev->irq
-to dev->irq + returned value - 1.  Device driver can use the returned
-number of successfully allocated MSI interrupts to further allocate
-and initialize device resources.
+  int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
 
-If this function returns a negative number, it indicates an error and
-the driver should not attempt to request any more MSI interrupts for
-this device.
+Any allocated resources should be freed before removing the device using
+the following function:
 
-This function should be called before the driver calls request_irq(),
-because MSI interrupts are delivered via vectors that are different
-from the vector of a pin-based interrupt.
+  void pci_free_irq_vectors(struct pci_dev *dev);
 
-It is ideal if drivers can cope with a variable number of MSI interrupts;
-there are many reasons why the platform may not be able to provide the
-exact number that a driver asks for.
+If a device supports both MSI-X and MSI capabilities, this API will use the
+MSI-X facilities in preference to the MSI facilities.  MSI-X supports any
+number of interrupts between 1 and 2048.  In contrast, MSI is restricted to
+a maximum of 32 interrupts (and must be a power of two).  In addition, the
+MSI interrupt vectors must be allocated consecutively, so the system might
+not be able to allocate as many vectors for MSI as it could for MSI-X.  On
+some platforms, MSI interrupts must all be targeted at the same set of CPUs
+whereas MSI-X interrupts can all be targeted at different CPUs.
 
-There could be devices that can not operate with just any number of MSI
-interrupts within a range.  See chapter 4.3.1.3 to get the idea how to
-handle such devices for MSI-X - the same logic applies to MSI.
+If a device supports neither MSI-X or MSI it will fall back to a single
+legacy IRQ vector.
 
-4.2.1.1 Maximum possible number of MSI interrupts
+The typical usage of MSI or MSI-X interrupts is to allocate as many vectors
+as possible, likely up to the limit supported by the device.  If nvec is
+larger than the number supported by the device it will automatically be
+capped to the supported limit, so there is no need to query the number of
+vectors supported beforehand:
 
-The typical usage of MSI interrupts is to allocate as many vectors as
-possible, likely up to the limit returned by pci_msi_vec_count() function:
-
-static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
-{
-       return pci_enable_msi_range(pdev, 1, nvec);
-}
-
-Note the value of 'minvec' parameter is 1.  As 'minvec' is inclusive,
-the value of 0 would be meaningless and could result in error.
-
-Some devices have a minimal limit on number of MSI interrupts.
-In this case the function could look like this:
-
-static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
-{
-       return pci_enable_msi_range(pdev, FOO_DRIVER_MINIMUM_NVEC, nvec);
-}
-
-4.2.1.2 Exact number of MSI interrupts
+       nvec = pci_alloc_irq_vectors(pdev, 1, nvec, 0);
+       if (nvec < 0)
+               goto out_err;
 
 If a driver is unable or unwilling to deal with a variable number of MSI
-interrupts it could request a particular number of interrupts by passing
-that number to pci_enable_msi_range() function as both 'minvec' and 'maxvec'
-parameters:
-
-static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
-{
-       return pci_enable_msi_range(pdev, nvec, nvec);
-}
-
-Note, unlike pci_enable_msi_exact() function, which could be also used to
-enable a particular number of MSI-X interrupts, pci_enable_msi_range()
-returns either a negative errno or 'nvec' (not negative errno or 0 - as
-pci_enable_msi_exact() does).
-
-4.2.1.3 Single MSI mode
-
-The most notorious example of the request type described above is
-enabling the single MSI mode for a device.  It could be done by passing
-two 1s as 'minvec' and 'maxvec':
-
-static int foo_driver_enable_single_msi(struct pci_dev *pdev)
-{
-       return pci_enable_msi_range(pdev, 1, 1);
-}
-
-Note, unlike pci_enable_msi() function, which could be also used to
-enable the single MSI mode, pci_enable_msi_range() returns either a
-negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
-does).
-
-4.2.3 pci_enable_msi_exact
-
-int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
-
-This variation on pci_enable_msi_range() call allows a device driver to
-request exactly 'nvec' MSIs.
-
-If this function returns a negative number, it indicates an error and
-the driver should not attempt to request any more MSI interrupts for
-this device.
-
-By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
-returns zero in case of success, which indicates MSI interrupts have been
-successfully allocated.
-
-4.2.4 pci_disable_msi
-
-void pci_disable_msi(struct pci_dev *dev)
-
-This function should be used to undo the effect of pci_enable_msi_range().
-Calling it restores dev->irq to the pin-based interrupt number and frees
-the previously allocated MSIs.  The interrupts may subsequently be assigned
-to another device, so drivers should not cache the value of dev->irq.
-
-Before calling this function, a device driver must always call free_irq()
-on any interrupt for which it previously called request_irq().
-Failure to do so results in a BUG_ON(), leaving the device with
-MSI enabled and thus leaking its vector.
-
-4.2.4 pci_msi_vec_count
-
-int pci_msi_vec_count(struct pci_dev *dev)
-
-This function could be used to retrieve the number of MSI vectors the
-device requested (via the Multiple Message Capable register). The MSI
-specification only allows the returned value to be a power of two,
-up to a maximum of 2^5 (32).
-
-If this function returns a negative number, it indicates the device is
-not capable of sending MSIs.
-
-If this function returns a positive number, it indicates the maximum
-number of MSI interrupt vectors that could be allocated.
-
-4.3 Using MSI-X
-
-The MSI-X capability is much more flexible than the MSI capability.
-It supports up to 2048 interrupts, each of which can be controlled
-independently.  To support this flexibility, drivers must use an array of
-`struct msix_entry':
-
-struct msix_entry {
-       u16     vector; /* kernel uses to write alloc vector */
-       u16     entry; /* driver uses to specify entry */
-};
-
-This allows for the device to use these interrupts in a sparse fashion;
-for example, it could use interrupts 3 and 1027 and yet allocate only a
-two-element array.  The driver is expected to fill in the 'entry' value
-in each element of the array to indicate for which entries the kernel
-should assign interrupts; it is invalid to fill in two entries with the
-same number.
-
-4.3.1 pci_enable_msix_range
-
-int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
-                         int minvec, int maxvec)
-
-Calling this function asks the PCI subsystem to allocate any number of
-MSI-X interrupts within specified range from 'minvec' to 'maxvec'.
-The 'entries' argument is a pointer to an array of msix_entry structs
-which should be at least 'maxvec' entries in size.
-
-On success, the device is switched into MSI-X mode and the function
-returns the number of MSI-X interrupts that have been successfully
-allocated.  In this case the 'vector' member in entries numbered from
-0 to the returned value - 1 is populated with the interrupt number;
-the driver should then call request_irq() for each 'vector' that it
-decides to use.  The device driver is responsible for keeping track of the
-interrupts assigned to the MSI-X vectors so it can free them again later.
-Device driver can use the returned number of successfully allocated MSI-X
-interrupts to further allocate and initialize device resources.
-
-If this function returns a negative number, it indicates an error and
-the driver should not attempt to allocate any more MSI-X interrupts for
-this device.
-
-This function, in contrast with pci_enable_msi_range(), does not adjust
-dev->irq.  The device will not generate interrupts for this interrupt
-number once MSI-X is enabled.
-
-Device drivers should normally call this function once per device
-during the initialization phase.
-
-It is ideal if drivers can cope with a variable number of MSI-X interrupts;
-there are many reasons why the platform may not be able to provide the
-exact number that a driver asks for.
-
-There could be devices that can not operate with just any number of MSI-X
-interrupts within a range.  E.g., an network adapter might need let's say
-four vectors per each queue it provides.  Therefore, a number of MSI-X
-interrupts allocated should be a multiple of four.  In this case interface
-pci_enable_msix_range() can not be used alone to request MSI-X interrupts
-(since it can allocate any number within the range, without any notion of
-the multiple of four) and the device driver should master a custom logic
-to request the required number of MSI-X interrupts.
-
-4.3.1.1 Maximum possible number of MSI-X interrupts
-
-The typical usage of MSI-X interrupts is to allocate as many vectors as
-possible, likely up to the limit returned by pci_msix_vec_count() function:
-
-static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
-{
-       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
-                                    1, nvec);
-}
-
-Note the value of 'minvec' parameter is 1.  As 'minvec' is inclusive,
-the value of 0 would be meaningless and could result in error.
-
-Some devices have a minimal limit on number of MSI-X interrupts.
-In this case the function could look like this:
-
-static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
-{
-       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
-                                    FOO_DRIVER_MINIMUM_NVEC, nvec);
-}
-
-4.3.1.2 Exact number of MSI-X interrupts
-
-If a driver is unable or unwilling to deal with a variable number of MSI-X
-interrupts it could request a particular number of interrupts by passing
-that number to pci_enable_msix_range() function as both 'minvec' and 'maxvec'
-parameters:
-
-static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
-{
-       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
-                                    nvec, nvec);
-}
-
-Note, unlike pci_enable_msix_exact() function, which could be also used to
-enable a particular number of MSI-X interrupts, pci_enable_msix_range()
-returns either a negative errno or 'nvec' (not negative errno or 0 - as
-pci_enable_msix_exact() does).
-
-4.3.1.3 Specific requirements to the number of MSI-X interrupts
-
-As noted above, there could be devices that can not operate with just any
-number of MSI-X interrupts within a range.  E.g., let's assume a device that
-is only capable sending the number of MSI-X interrupts which is a power of
-two.  A routine that enables MSI-X mode for such device might look like this:
-
-/*
- * Assume 'minvec' and 'maxvec' are non-zero
- */
-static int foo_driver_enable_msix(struct foo_adapter *adapter,
-                                 int minvec, int maxvec)
-{
-       int rc;
-
-       minvec = roundup_pow_of_two(minvec);
-       maxvec = rounddown_pow_of_two(maxvec);
-
-       if (minvec > maxvec)
-               return -ERANGE;
-
-retry:
-       rc = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
-                                  maxvec, maxvec);
-       /*
-        * -ENOSPC is the only error code allowed to be analyzed
-        */
-       if (rc == -ENOSPC) {
-               if (maxvec == 1)
-                       return -ENOSPC;
-
-               maxvec /= 2;
-
-               if (minvec > maxvec)
-                       return -ENOSPC;
-
-               goto retry;
-       }
-
-       return rc;
-}
-
-Note how pci_enable_msix_range() return value is analyzed for a fallback -
-any error code other than -ENOSPC indicates a fatal error and should not
-be retried.
-
-4.3.2 pci_enable_msix_exact
-
-int pci_enable_msix_exact(struct pci_dev *dev,
-                         struct msix_entry *entries, int nvec)
-
-This variation on pci_enable_msix_range() call allows a device driver to
-request exactly 'nvec' MSI-Xs.
-
-If this function returns a negative number, it indicates an error and
-the driver should not attempt to allocate any more MSI-X interrupts for
-this device.
-
-By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
-returns zero in case of success, which indicates MSI-X interrupts have been
-successfully allocated.
-
-Another version of a routine that enables MSI-X mode for a device with
-specific requirements described in chapter 4.3.1.3 might look like this:
-
-/*
- * Assume 'minvec' and 'maxvec' are non-zero
- */
-static int foo_driver_enable_msix(struct foo_adapter *adapter,
-                                 int minvec, int maxvec)
-{
-       int rc;
-
-       minvec = roundup_pow_of_two(minvec);
-       maxvec = rounddown_pow_of_two(maxvec);
-
-       if (minvec > maxvec)
-               return -ERANGE;
-
-retry:
-       rc = pci_enable_msix_exact(adapter->pdev,
-                                  adapter->msix_entries, maxvec);
-
-       /*
-        * -ENOSPC is the only error code allowed to be analyzed
-        */
-       if (rc == -ENOSPC) {
-               if (maxvec == 1)
-                       return -ENOSPC;
-
-               maxvec /= 2;
-
-               if (minvec > maxvec)
-                       return -ENOSPC;
-
-               goto retry;
-       } else if (rc < 0) {
-               return rc;
-       }
-
-       return maxvec;
-}
-
-4.3.3 pci_disable_msix
-
-void pci_disable_msix(struct pci_dev *dev)
-
-This function should be used to undo the effect of pci_enable_msix_range().
-It frees the previously allocated MSI-X interrupts. The interrupts may
-subsequently be assigned to another device, so drivers should not cache
-the value of the 'vector' elements over a call to pci_disable_msix().
-
-Before calling this function, a device driver must always call free_irq()
-on any interrupt for which it previously called request_irq().
-Failure to do so results in a BUG_ON(), leaving the device with
-MSI-X enabled and thus leaking its vector.
-
-4.3.3 The MSI-X Table
-
-The MSI-X capability specifies a BAR and offset within that BAR for the
-MSI-X Table.  This address is mapped by the PCI subsystem, and should not
-be accessed directly by the device driver.  If the driver wishes to
-mask or unmask an interrupt, it should call disable_irq() / enable_irq().
+interrupts it can request a particular number of interrupts by passing that
+number to pci_alloc_irq_vectors() function as both 'min_vecs' and
+'max_vecs' parameters:
 
-4.3.4 pci_msix_vec_count
+       ret = pci_alloc_irq_vectors(pdev, nvec, nvec, 0);
+       if (ret < 0)
+               goto out_err;
 
-int pci_msix_vec_count(struct pci_dev *dev)
+The most notorious example of the request type described above is enabling
+the single MSI mode for a device.  It could be done by passing two 1s as
+'min_vecs' and 'max_vecs':
 
-This function could be used to retrieve number of entries in the device
-MSI-X table.
+       ret = pci_alloc_irq_vectors(pdev, 1, 1, 0);
+       if (ret < 0)
+               goto out_err;
 
-If this function returns a negative number, it indicates the device is
-not capable of sending MSI-Xs.
+Some devices might not support using legacy line interrupts, in which case
+the PCI_IRQ_NOLEGACY flag can be used to fail the request if the platform
+can't provide MSI or MSI-X interrupts:
 
-If this function returns a positive number, it indicates the maximum
-number of MSI-X interrupt vectors that could be allocated.
+       nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_NOLEGACY);
+       if (nvec < 0)
+               goto out_err;
 
-4.4 Handling devices implementing both MSI and MSI-X capabilities
+4.3 Legacy APIs
 
-If a device implements both MSI and MSI-X capabilities, it can
-run in either MSI mode or MSI-X mode, but not both simultaneously.
-This is a requirement of the PCI spec, and it is enforced by the
-PCI layer.  Calling pci_enable_msi_range() when MSI-X is already
-enabled or pci_enable_msix_range() when MSI is already enabled
-results in an error.  If a device driver wishes to switch between MSI
-and MSI-X at runtime, it must first quiesce the device, then switch
-it back to pin-interrupt mode, before calling pci_enable_msi_range()
-or pci_enable_msix_range() and resuming operation.  This is not expected
-to be a common operation but may be useful for debugging or testing
-during development.
+The following old APIs to enable and disable MSI or MSI-X interrupts should
+not be used in new code:
 
-4.5 Considerations when using MSIs
+  pci_enable_msi()             /* deprecated */
+  pci_enable_msi_range()       /* deprecated */
+  pci_enable_msi_exact()       /* deprecated */
+  pci_disable_msi()            /* deprecated */
+  pci_enable_msix_range()      /* deprecated */
+  pci_enable_msix_exact()      /* deprecated */
+  pci_disable_msix()           /* deprecated */
 
-4.5.1 Choosing between MSI-X and MSI
+Additionally there are APIs to provide the number of supported MSI or MSI-X
+vectors: pci_msi_vec_count() and pci_msix_vec_count().  In general these
+should be avoided in favor of letting pci_alloc_irq_vectors() cap the
+number of vectors.  If you have a legitimate special use case for the count
+of vectors we might have to revisit that decision and add a
+pci_nr_irq_vectors() helper that handles MSI and MSI-X transparently.
 
-If your device supports both MSI-X and MSI capabilities, you should use
-the MSI-X facilities in preference to the MSI facilities.  As mentioned
-above, MSI-X supports any number of interrupts between 1 and 2048.
-In contrast, MSI is restricted to a maximum of 32 interrupts (and
-must be a power of two).  In addition, the MSI interrupt vectors must
-be allocated consecutively, so the system might not be able to allocate
-as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
-interrupts must all be targeted at the same set of CPUs whereas MSI-X
-interrupts can all be targeted at different CPUs.
+4.4 Considerations when using MSIs
 
-4.5.2 Spinlocks
+4.4.1 Spinlocks
 
 Most device drivers have a per-device spinlock which is taken in the
 interrupt handler.  With pin-based interrupts or a single MSI, it is not
@@ -505,7 +194,7 @@ acquire the spinlock.  Such deadlocks can be avoided by using
 spin_lock_irqsave() or spin_lock_irq() which disable local interrupts
 and acquire the lock (see Documentation/DocBook/kernel-locking).
 
-4.6 How to tell whether MSI/MSI-X is enabled on a device
+4.5 How to tell whether MSI/MSI-X is enabled on a device
 
 Using 'lspci -v' (as root) may show some devices with "MSI", "Message
 Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
index 6b1de70..ec83bbc 100644 (file)
@@ -66,6 +66,13 @@ Here is what the fields mean:
             This feature should be used with care as the interpreter
             will run with root permissions when a setuid binary owned by root
             is run with binfmt_misc.
+      'F' - fix binary.  The usual behaviour of binfmt_misc is to spawn the
+           binary lazily when the misc format file is invoked.  However,
+           this doesn't work very well in the face of mount namespaces and
+           changeroots, so the F mode opens the binary as soon as the
+           emulation is installed and uses the opened image to spawn the
+           emulator, meaning it is always available once installed,
+           regardless of how the environment changes.
 
 
 There are some restrictions:
index 026d133..bcdb2b4 100644 (file)
@@ -269,7 +269,7 @@ Arjan's proposed request priority scheme allows higher levels some broad
   requests which haven't aged too much on the queue. Potentially this priority
   could even be exposed to applications in some manner, providing higher level
   tunability. Time based aging avoids starvation of lower priority
-  requests. Some bits in the bi_rw flags field in the bio structure are
+  requests. Some bits in the bi_opf flags field in the bio structure are
   intended to be used for this priority information.
 
 
@@ -432,7 +432,7 @@ struct bio {
        struct bio          *bi_next;    /* request queue link */
        struct block_device *bi_bdev;   /* target device */
        unsigned long       bi_flags;    /* status, command, etc */
-       unsigned long       bi_rw;       /* low bits: r/w, high: priority */
+       unsigned long       bi_opf;       /* low bits: r/w, high: priority */
 
        unsigned int    bi_vcnt;     /* how may bio_vec's */
        struct bvec_iter        bi_iter;        /* current index into bio_vec array */
index 947e6fe..308e5ff 100644 (file)
@@ -2,7 +2,7 @@
                                -------
 
 Written by Paul Menage <menage@google.com> based on
-Documentation/cgroups/cpusets.txt
+Documentation/cgroup-v1/cpusets.txt
 
 Original copyright statements from cpusets.txt:
 Portions Copyright (C) 2004 BULL SA.
@@ -72,7 +72,7 @@ On their own, the only use for cgroups is for simple job
 tracking. The intention is that other subsystems hook into the generic
 cgroup support to provide new attributes for cgroups, such as
 accounting/limiting the resources which processes in a cgroup can
-access. For example, cpusets (see Documentation/cgroups/cpusets.txt) allow
+access. For example, cpusets (see Documentation/cgroup-v1/cpusets.txt) allow
 you to associate a set of CPUs and a set of memory nodes with the
 tasks in each cgroup.
 
index e5cdcd4..e5ac5da 100644 (file)
@@ -48,7 +48,7 @@ hooks, beyond what is already present, required to manage dynamic
 job placement on large systems.
 
 Cpusets use the generic cgroup subsystem described in
-Documentation/cgroups/cgroups.txt.
+Documentation/cgroup-v1/cgroups.txt.
 
 Requests by a task, using the sched_setaffinity(2) system call to
 include CPUs in its CPU affinity mask, and using the mbind(2) and
index 78a8c29..5c7f310 100644 (file)
@@ -6,7 +6,7 @@ Because VM is getting complex (one of reasons is memcg...), memcg's behavior
 is complex. This is a document for memcg's internal behavior.
 Please note that implementation details can be changed.
 
-(*) Topics on API should be in Documentation/cgroups/memory.txt)
+(*) Topics on API should be in Documentation/cgroup-v1/memory.txt)
 
 0. How to record usage ?
    2 objects are used.
@@ -256,7 +256,7 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y.
 
        You can see charges have been moved by reading *.usage_in_bytes or
        memory.stat of both A and B.
-       See 8.2 of Documentation/cgroups/memory.txt to see what value should be
+       See 8.2 of Documentation/cgroup-v1/memory.txt to see what value should be
        written to move_charge_at_immigrate.
 
  9.10 Memory thresholds
index 7f773d5..01fb1da 100644 (file)
@@ -38,6 +38,15 @@ as a regular user, and install it with
 
         sudo make install
 
+ Supplemental documentation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For supplemental documentation refer to the wiki:
+
+https://bottest.wiki.kernel.org/coccicheck
+
+The wiki documentation always refers to the linux-next version of the script.
+
  Using Coccinelle on the Linux kernel
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -94,11 +103,26 @@ To enable verbose messages set the V= variable, for example:
 
    make coccicheck MODE=report V=1
 
+ Coccinelle parallelization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 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
 
+As of Coccinelle 1.0.2 Coccinelle uses Ocaml parmap for parallelization,
+if support for this is detected you will benefit from parmap parallelization.
+
+When parmap is enabled coccicheck will enable dynamic load balancing by using
+'--chunksize 1' argument, this ensures we keep feeding threads with work
+one by one, so that we avoid the situation where most work gets done by only
+a few threads. With dynamic load balancing, if a thread finishes early we keep
+feeding it more work.
+
+When parmap is enabled, if an error occurs in Coccinelle, this error
+value is propagated back, the return value of the 'make coccicheck'
+captures this return value.
 
  Using Coccinelle with a single semantic patch
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -142,15 +166,118 @@ semantic patch as shown in the previous section.
 The "report" mode is the default. You can select another one with the
 MODE variable explained above.
 
+ Debugging Coccinelle SmPL patches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using coccicheck is best as it provides in the spatch command line
+include options matching the options used when we compile the kernel.
+You can learn what these options are by using V=1, you could then
+manually run Coccinelle with debug options added.
+
+Alternatively you can debug running Coccinelle against SmPL patches
+by asking for stderr to be redirected to stderr, by default stderr
+is redirected to /dev/null, if you'd like to capture stderr you
+can specify the DEBUG_FILE="file.txt" option to coccicheck. For
+instance:
+
+    rm -f cocci.err
+    make coccicheck COCCI=scripts/coccinelle/free/kfree.cocci MODE=report DEBUG_FILE=cocci.err
+    cat cocci.err
+
+You can use SPFLAGS to add debugging flags, for instance you may want to
+add both --profile --show-trying to SPFLAGS when debugging. For instance
+you may want to use:
+
+    rm -f err.log
+    export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
+    make coccicheck DEBUG_FILE="err.log" MODE=report SPFLAGS="--profile --show-trying" M=./drivers/mfd/arizona-irq.c
+
+err.log will now have the profiling information, while stdout will
+provide some progress information as Coccinelle moves forward with
+work.
+
+DEBUG_FILE support is only supported when using coccinelle >= 1.2.
+
+ .cocciconfig support
+~~~~~~~~~~~~~~~~~~~~~~
+
+Coccinelle supports reading .cocciconfig for default Coccinelle options that
+should be used every time spatch is spawned, the order of precedence for
+variables for .cocciconfig is as follows:
+
+  o Your current user's home directory is processed first
+  o Your directory from which spatch is called is processed next
+  o The directory provided with the --dir option is processed last, if used
+
+Since coccicheck runs through make, it naturally runs from the kernel
+proper dir, as such the second rule above would be implied for picking up a
+.cocciconfig when using 'make coccicheck'.
+
+'make coccicheck' also supports using M= targets.If you do not supply
+any M= target, it is assumed you want to target the entire kernel.
+The kernel coccicheck script has:
+
+    if [ "$KBUILD_EXTMOD" = "" ] ; then
+        OPTIONS="--dir $srctree $COCCIINCLUDE"
+    else
+        OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
+    fi
+
+KBUILD_EXTMOD is set when an explicit target with M= is used. For both cases
+the spatch --dir argument is used, as such third rule applies when whether M=
+is used or not, and when M= is used the target directory can have its own
+.cocciconfig file. When M= is not passed as an argument to coccicheck the
+target directory is the same as the directory from where spatch was called.
+
+If not using the kernel's coccicheck target, keep the above precedence
+order logic of .cocciconfig reading. If using the kernel's coccicheck target,
+override any of the kernel's .coccicheck's settings using SPFLAGS.
+
+We help Coccinelle when used against Linux with a set of sensible defaults
+options for Linux with our own Linux .cocciconfig. This hints to coccinelle
+git can be used for 'git grep' queries over coccigrep. A timeout of 200
+seconds should suffice for now.
+
+The options picked up by coccinelle when reading a .cocciconfig do not appear
+as arguments to spatch processes running on your system, to confirm what
+options will be used by Coccinelle run:
+
+      spatch --print-options-only
+
+You can override with your own preferred index option by using SPFLAGS. Take
+note that when there are conflicting options Coccinelle takes precedence for
+the last options passed. Using .cocciconfig is possible to use idutils, however
+given the order of precedence followed by Coccinelle, since the kernel now
+carries its own .cocciconfig, you will need to use SPFLAGS to use idutils if
+desired. See below section "Additional flags" for more details on how to use
+idutils.
+
  Additional flags
 ~~~~~~~~~~~~~~~~~~
 
 Additional flags can be passed to spatch through the SPFLAGS
-variable.
+variable. This works as Coccinelle respects the last flags
+given to it when options are in conflict.
 
     make SPFLAGS=--use-glimpse coccicheck
+
+Coccinelle supports idutils as well but requires coccinelle >= 1.0.6.
+When no ID file is specified coccinelle assumes your ID database file
+is in the file .id-utils.index on the top level of the kernel, coccinelle
+carries a script scripts/idutils_index.sh which creates the database with
+
+    mkid -i C --output .id-utils.index
+
+If you have another database filename you can also just symlink with this
+name.
+
     make SPFLAGS=--use-idutils coccicheck
 
+Alternatively you can specify the database filename explicitly, for
+instance:
+
+    make SPFLAGS="--use-idutils /full-path/to/ID" coccicheck
+
 See spatch --help to learn more about spatch options.
 
 Note that the '--use-glimpse' and '--use-idutils' options
@@ -159,6 +286,25 @@ 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.
 
+ SmPL patch specific options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SmPL patches can have their own requirements for options passed
+to Coccinelle. SmPL patch specific options can be provided by
+providing them at the top of the SmPL patch, for instance:
+
+// Options: --no-includes --include-headers
+
+ SmPL patch Coccinelle requirements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As Coccinelle features get added some more advanced SmPL patches
+may require newer versions of Coccinelle. If an SmPL patch requires
+at least a version of Coccinelle, this can be specified as follows,
+as an example if requiring at least Coccinelle >= 1.0.5:
+
+// Requires: 1.0.5
+
  Proposing new semantic patches
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index 6ff5c23..c430307 100644 (file)
@@ -42,7 +42,7 @@ Optional feature parameters:
     <direction>: Either 'r' to corrupt reads or 'w' to corrupt writes.
                 'w' is incompatible with drop_writes.
     <value>: The value (from 0-255) to write.
-    <flags>: Perform the replacement only if bio->bi_rw has all the
+    <flags>: Perform the replacement only if bio->bi_opf has all the
             selected flags set.
 
 Examples:
index 6c9f0c8..e85ce3d 100644 (file)
@@ -20,6 +20,8 @@ Optional properties:
   2: Half-period mode
   4: Quarter-period mode
 - wakeup-source: Boolean, rotary encoder can wake up the system.
+- rotary-encoder,encoding: String, the method used to encode steps.
+  Supported are "gray" (the default and more common) and "binary".
 
 Deprecated properties:
 - rotary-encoder,half-period: Makes the driver work on half-period mode.
@@ -34,6 +36,7 @@ Example:
                        compatible = "rotary-encoder";
                        gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */
                        linux,axis = <0>; /* REL_X */
+                       rotary-encoder,encoding = "gray";
                        rotary-encoder,relative-axis;
                };
 
@@ -42,5 +45,6 @@ Example:
                        gpios = <&gpio 21 0>, <&gpio 22 0>;
                        linux,axis = <1>; /* ABS_Y */
                        rotary-encoder,steps = <24>;
+                       rotary-encoder,encoding = "binary";
                        rotary-encoder,rollover;
                };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
new file mode 100644 (file)
index 0000000..1112e0d
--- /dev/null
@@ -0,0 +1,36 @@
+* GSL 1680 touchscreen controller
+
+Required properties:
+- compatible             : "silead,gsl1680"
+- reg                    : I2C slave address of the chip (0x40)
+- interrupt-parent       : a phandle pointing to the interrupt controller
+                           serving the interrupt for this chip
+- interrupts             : interrupt specification for the gsl1680 interrupt
+- power-gpios            : Specification for the pin connected to the gsl1680's
+                           shutdown input. This needs to be driven high to take the
+                           gsl1680 out of its low power state
+- touchscreen-size-x     : See touchscreen.txt
+- touchscreen-size-y     : See touchscreen.txt
+
+Optional properties:
+- touchscreen-inverted-x  : See touchscreen.txt
+- touchscreen-inverted-y  : See touchscreen.txt
+- touchscreen-swapped-x-y : See touchscreen.txt
+- silead,max-fingers     : maximum number of fingers the touchscreen can detect
+
+Example:
+
+i2c@00000000 {
+       gsl1680: touchscreen@40 {
+               compatible = "silead,gsl1680";
+               reg = <0x40>;
+               interrupt-parent = <&pio>;
+               interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>;
+               power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>;
+               touchscreen-size-x = <480>;
+               touchscreen-size-y = <800>;
+               touchscreen-inverted-x;
+               touchscreen-swapped-x-y;
+               silead,max-fingers = <5>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt
new file mode 100644 (file)
index 0000000..d87ad14
--- /dev/null
@@ -0,0 +1,33 @@
+* SiS I2C Multiple Touch Controller
+
+Required properties:
+- compatible: must be "sis,9200-ts"
+- reg: i2c slave address
+- interrupt-parent: the phandle for the interrupt controller
+  (see interrupt binding [0])
+- interrupts: touch controller interrupt (see interrupt
+  binding [0])
+
+Optional properties:
+- pinctrl-names: should be "default" (see pinctrl binding [1]).
+- pinctrl-0: a phandle pointing to the pin settings for the
+  device (see pinctrl binding [1]).
+- attn-gpios: the gpio pin used as attention line
+- reset-gpios: the gpio pin used to reset the controller
+- wakeup-source: touchscreen can be used as a wakeup source
+
+[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example:
+
+       sis9255@5c  {
+               compatible = "sis,9200-ts";
+               reg = <0x5c>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_sis>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+               irq-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&gpio2 30 GPIO_ACTIVE_LOW>;
+       };
index 21055e2..c1359f4 100644 (file)
@@ -46,6 +46,10 @@ Required properties:
                        0 maps to GPMC_WAIT0 pin.
  - gpio-cells:         Must be set to 2
 
+Required properties when using NAND prefetch dma:
+ - dmas                        GPMC NAND prefetch dma channel
+ - dma-names           Must be set to "rxtx"
+
 Timing properties for child nodes. All are optional and default to 0.
 
  - gpmc,sync-clk-ps:   Minimum clock period for synchronous mode, in picoseconds
@@ -137,7 +141,8 @@ Example for an AM33xx board:
                ti,hwmods = "gpmc";
                reg = <0x50000000 0x2000>;
                interrupts = <100>;
-
+               dmas = <&edma 52 0>;
+               dma-names = "rxtx";
                gpmc,num-cs = <8>;
                gpmc,num-waitpins = <2>;
                #address-cells = <2>;
diff --git a/Documentation/devicetree/bindings/misc/ramoops.txt b/Documentation/devicetree/bindings/misc/ramoops.txt
deleted file mode 100644 (file)
index cd02cec..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Ramoops oops/panic logger
-=========================
-
-ramoops provides persistent RAM storage for oops and panics, so they can be
-recovered after a reboot. It is a backend to pstore, so this node is named
-"ramoops" after the backend, rather than "pstore" which is the subsystem.
-
-Parts of this storage may be set aside for other persistent log buffers, such
-as kernel log messages, or for optional ECC error-correction data.  The total
-size of these optional buffers must fit in the reserved region.
-
-Any remaining space will be used for a circular buffer of oops and panic
-records.  These records have a configurable size, with a size of 0 indicating
-that they should be disabled.
-
-At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size"
-must be set non-zero, but are otherwise optional as listed below.
-
-
-Required properties:
-
-- compatible: must be "ramoops"
-
-- memory-region: phandle to a region of memory that is preserved between
-  reboots
-
-
-Optional properties:
-
-- ecc-size: enables ECC support and specifies ECC buffer size in bytes
-  (defaults to 0: no ECC)
-
-- record-size: maximum size in bytes of each dump done on oops/panic
-  (defaults to 0: disabled)
-
-- console-size: size in bytes of log buffer reserved for kernel messages
-  (defaults to 0: disabled)
-
-- ftrace-size: size in bytes of log buffer reserved for function tracing and
-  profiling (defaults to 0: disabled)
-
-- pmsg-size: size in bytes of log buffer reserved for userspace messages
-  (defaults to 0: disabled)
-
-- unbuffered: if present, use unbuffered mappings to map the reserved region
-  (defaults to buffered mappings)
-
-- no-dump-oops: if present, only dump panics (defaults to panics and oops)
diff --git a/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt b/Documentation/devicetree/bindings/mtd/atmel-quadspi.txt
new file mode 100644 (file)
index 0000000..4898070
--- /dev/null
@@ -0,0 +1,32 @@
+* Atmel Quad Serial Peripheral Interface (QSPI)
+
+Required properties:
+- compatible:     Should be "atmel,sama5d2-qspi".
+- reg:            Should contain the locations and lengths of the base registers
+                  and the mapped memory.
+- reg-names:      Should contain the resource reg names:
+                  - qspi_base: configuration register address space
+                  - qspi_mmap: memory mapped address space
+- interrupts:     Should contain the interrupt for the device.
+- clocks:         The phandle of the clock needed by the QSPI controller.
+- #address-cells: Should be <1>.
+- #size-cells:    Should be <0>.
+
+Example:
+
+spi@f0020000 {
+       compatible = "atmel,sama5d2-qspi";
+       reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>;
+       reg-names = "qspi_base", "qspi_mmap";
+       interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>;
+       clocks = <&spi0_clk>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_spi0_default>;
+       status = "okay";
+
+       m25p80@0 {
+               ...
+       };
+};
index 7066597..b40f3a4 100644 (file)
@@ -27,6 +27,7 @@ Required properties:
                          brcm,brcmnand-v6.2
                          brcm,brcmnand-v7.0
                          brcm,brcmnand-v7.1
+                         brcm,brcmnand-v7.2
                          brcm,brcmnand
 - reg              : the register start and length for NAND register region.
                      (optional) Flash DMA register range (if present)
diff --git a/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt b/Documentation/devicetree/bindings/mtd/cadence-quadspi.txt
new file mode 100644 (file)
index 0000000..f248056
--- /dev/null
@@ -0,0 +1,56 @@
+* Cadence Quad SPI controller
+
+Required properties:
+- compatible : Should be "cdns,qspi-nor".
+- reg : Contains two entries, each of which is a tuple consisting of a
+       physical address and length. The first entry is the address and
+       length of the controller register set. The second entry is the
+       address and length of the QSPI Controller data area.
+- interrupts : Unit interrupt specifier for the controller interrupt.
+- clocks : phandle to the Quad SPI clock.
+- cdns,fifo-depth : Size of the data FIFO in words.
+- cdns,fifo-width : Bus width of the data FIFO in bytes.
+- cdns,trigger-address : 32-bit indirect AHB trigger address.
+
+Optional properties:
+- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not.
+
+Optional subnodes:
+Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional
+custom properties:
+- cdns,read-delay : Delay for read capture logic, in clock cycles
+- cdns,tshsl-ns : Delay in nanoseconds for the length that the master
+                  mode chip select outputs are de-asserted between
+                 transactions.
+- cdns,tsd2d-ns : Delay in nanoseconds between one chip select being
+                  de-activated and the activation of another.
+- cdns,tchsh-ns : Delay in nanoseconds between last bit of current
+                  transaction and deasserting the device chip select
+                 (qspi_n_ss_out).
+- cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low
+                  and first bit transfer.
+
+Example:
+
+       qspi: spi@ff705000 {
+               compatible = "cdns,qspi-nor";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <0xff705000 0x1000>,
+                     <0xffa00000 0x1000>;
+               interrupts = <0 151 4>;
+               clocks = <&qspi_clk>;
+               cdns,is-decoded-cs;
+               cdns,fifo-depth = <128>;
+               cdns,fifo-width = <4>;
+               cdns,trigger-address = <0x00000000>;
+
+               flash0: n25q00@0 {
+                       ...
+                       cdns,read-delay = <4>;
+                       cdns,tshsl-ns = <50>;
+                       cdns,tsd2d-ns = <50>;
+                       cdns,tchsh-ns = <4>;
+                       cdns,tslch-ns = <4>;
+               };
+       };
index 3ee7e20..174f68c 100644 (file)
@@ -39,7 +39,7 @@ Optional properties:
 
                "prefetch-polled"       Prefetch polled mode (default)
                "polled"                Polled mode, without prefetch
-               "prefetch-dma"          Prefetch enabled sDMA mode
+               "prefetch-dma"          Prefetch enabled DMA mode
                "prefetch-irq"          Prefetch enabled irq mode
 
  - elm_id:     <deprecated> use "ti,elm-id" instead
diff --git a/Documentation/devicetree/bindings/mtd/hisilicon,fmc-spi-nor.txt b/Documentation/devicetree/bindings/mtd/hisilicon,fmc-spi-nor.txt
new file mode 100644 (file)
index 0000000..7498152
--- /dev/null
@@ -0,0 +1,24 @@
+HiSilicon SPI-NOR Flash Controller
+
+Required properties:
+- compatible : Should be "hisilicon,fmc-spi-nor" and one of the following strings:
+               "hisilicon,hi3519-spi-nor"
+- address-cells : Should be 1.
+- size-cells : Should be 0.
+- reg : Offset and length of the register set for the controller device.
+- reg-names : Must include the following two entries: "control", "memory".
+- clocks : handle to spi-nor flash controller clock.
+
+Example:
+spi-nor-controller@10000000 {
+       compatible = "hisilicon,hi3519-spi-nor", "hisilicon,fmc-spi-nor";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0x10000000 0x1000>, <0x14000000 0x1000000>;
+       reg-names = "control", "memory";
+       clocks = <&clock HI3519_FMC_CLK>;
+       spi-nor@0 {
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/mtk-nand.txt b/Documentation/devicetree/bindings/mtd/mtk-nand.txt
new file mode 100644 (file)
index 0000000..069c192
--- /dev/null
@@ -0,0 +1,160 @@
+MTK SoCs NAND FLASH controller (NFC) DT binding
+
+This file documents the device tree bindings for MTK SoCs NAND controllers.
+The functional split of the controller requires two drivers to operate:
+the nand controller interface driver and the ECC engine driver.
+
+The hardware description for both devices must be captured as device
+tree nodes.
+
+1) NFC NAND Controller Interface (NFI):
+=======================================
+
+The first part of NFC is NAND Controller Interface (NFI) HW.
+Required NFI properties:
+- compatible:                  Should be "mediatek,mtxxxx-nfc".
+- reg:                         Base physical address and size of NFI.
+- interrupts:                  Interrupts of NFI.
+- clocks:                      NFI required clocks.
+- clock-names:                 NFI clocks internal name.
+- status:                      Disabled default. Then set "okay" by platform.
+- ecc-engine:                  Required ECC Engine node.
+- #address-cells:              NAND chip index, should be 1.
+- #size-cells:                 Should be 0.
+
+Example:
+
+       nandc: nfi@1100d000 {
+               compatible = "mediatek,mt2701-nfc";
+               reg = <0 0x1100d000 0 0x1000>;
+               interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
+               clocks = <&pericfg CLK_PERI_NFI>,
+                        <&pericfg CLK_PERI_NFI_PAD>;
+               clock-names = "nfi_clk", "pad_clk";
+               status = "disabled";
+               ecc-engine = <&bch>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+        };
+
+Platform related properties, should be set in {platform_name}.dts:
+- children nodes:      NAND chips.
+
+Children nodes properties:
+- reg:                 Chip Select Signal, default 0.
+                       Set as reg = <0>, <1> when need 2 CS.
+Optional:
+- nand-on-flash-bbt:   Store BBT on NAND Flash.
+- nand-ecc-mode:       the NAND ecc mode (check driver for supported modes)
+- nand-ecc-step-size:  Number of data bytes covered by a single ECC step.
+                       valid values: 512 and 1024.
+                       1024 is recommended for large page NANDs.
+- nand-ecc-strength:   Number of bits to correct per ECC step.
+                       The valid values that the controller supports are: 4, 6,
+                       8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44,
+                       48, 52, 56, 60.
+                       The strength should be calculated as follows:
+                       E = (S - F) * 8 / 14
+                       S = O / (P / Q)
+                               E :     nand-ecc-strength.
+                               S :     spare size per sector.
+                               F :     FDM size, should be in the range [1,8].
+                                       It is used to store free oob data.
+                               O :     oob size.
+                               P :     page size.
+                               Q :     nand-ecc-step-size.
+                       If the result does not match any one of the listed
+                       choices above, please select the smaller valid value from
+                       the list.
+                       (otherwise the driver will do the adjustment at runtime)
+- pinctrl-names:       Default NAND pin GPIO setting name.
+- pinctrl-0:           GPIO setting node.
+
+Example:
+       &pio {
+               nand_pins_default: nanddefault {
+                       pins_dat {
+                               pinmux = <MT2701_PIN_111_MSDC0_DAT7__FUNC_NLD7>,
+                                        <MT2701_PIN_112_MSDC0_DAT6__FUNC_NLD6>,
+                                        <MT2701_PIN_114_MSDC0_DAT4__FUNC_NLD4>,
+                                        <MT2701_PIN_118_MSDC0_DAT3__FUNC_NLD3>,
+                                        <MT2701_PIN_121_MSDC0_DAT0__FUNC_NLD0>,
+                                        <MT2701_PIN_120_MSDC0_DAT1__FUNC_NLD1>,
+                                        <MT2701_PIN_113_MSDC0_DAT5__FUNC_NLD5>,
+                                        <MT2701_PIN_115_MSDC0_RSTB__FUNC_NLD8>,
+                                        <MT2701_PIN_119_MSDC0_DAT2__FUNC_NLD2>;
+                               input-enable;
+                               drive-strength = <MTK_DRIVE_8mA>;
+                               bias-pull-up;
+                       };
+
+                       pins_we {
+                               pinmux = <MT2701_PIN_117_MSDC0_CLK__FUNC_NWEB>;
+                               drive-strength = <MTK_DRIVE_8mA>;
+                               bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+                       };
+
+                       pins_ale {
+                               pinmux = <MT2701_PIN_116_MSDC0_CMD__FUNC_NALE>;
+                               drive-strength = <MTK_DRIVE_8mA>;
+                               bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+                       };
+               };
+       };
+
+       &nandc {
+               status = "okay";
+               pinctrl-names = "default";
+               pinctrl-0 = <&nand_pins_default>;
+               nand@0 {
+                       reg = <0>;
+                       nand-on-flash-bbt;
+                       nand-ecc-mode = "hw";
+                       nand-ecc-strength = <24>;
+                       nand-ecc-step-size = <1024>;
+               };
+       };
+
+NAND chip optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+       nand@0 {
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       preloader@0 {
+                               label = "pl";
+                               read-only;
+                               reg = <0x00000000 0x00400000>;
+                       };
+                       android@0x00400000 {
+                               label = "android";
+                               reg = <0x00400000 0x12c00000>;
+                       };
+               };
+       };
+
+2) ECC Engine:
+==============
+
+Required BCH properties:
+- compatible:  Should be "mediatek,mtxxxx-ecc".
+- reg:         Base physical address and size of ECC.
+- interrupts:  Interrupts of ECC.
+- clocks:      ECC required clocks.
+- clock-names: ECC clocks internal name.
+- status:      Disabled default. Then set "okay" by platform.
+
+Example:
+
+       bch: ecc@1100e000 {
+               compatible = "mediatek,mt2701-ecc";
+               reg = <0 0x1100e000 0 0x1000>;
+               interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
+               clocks = <&pericfg CLK_PERI_NFI_ECC>;
+               clock-names = "nfiecc_clk";
+               status = "disabled";
+       };
index 086d6f4..f322f56 100644 (file)
@@ -11,10 +11,16 @@ Required properties:
     * "ahb" : AHB gating clock
     * "mod" : nand controller clock
 
+Optional properties:
+- dmas : shall reference DMA channel associated to the NAND controller.
+- dma-names : shall be "rxtx".
+
 Optional children nodes:
 Children nodes represent the available nand chips.
 
 Optional properties:
+- reset : phandle + reset specifier pair
+- reset-names : must contain "ahb"
 - allwinner,rb : shall contain the native Ready/Busy ids.
  or
 - rb-gpios : shall contain the gpios used as R/B pins.
diff --git a/Documentation/devicetree/bindings/pci/aardvark-pci.txt b/Documentation/devicetree/bindings/pci/aardvark-pci.txt
new file mode 100644 (file)
index 0000000..bbcd9f4
--- /dev/null
@@ -0,0 +1,56 @@
+Aardvark PCIe controller
+
+This PCIe controller is used on the Marvell Armada 3700 ARM64 SoC.
+
+The Device Tree node describing an Aardvark PCIe controller must
+contain the following properties:
+
+ - compatible: Should be "marvell,armada-3700-pcie"
+ - reg: range of registers for the PCIe controller
+ - interrupts: the interrupt line of the PCIe controller
+ - #address-cells: set to <3>
+ - #size-cells: set to <2>
+ - device_type: set to "pci"
+ - ranges: ranges for the PCI memory and I/O regions
+ - #interrupt-cells: set to <1>
+ - msi-controller: indicates that the PCIe controller can itself
+   handle MSI interrupts
+ - msi-parent: pointer to the MSI controller to be used
+ - interrupt-map-mask and interrupt-map: standard PCI properties to
+   define the mapping of the PCIe interface to interrupt numbers.
+ - bus-range: PCI bus numbers covered
+
+In addition, the Device Tree describing an Aardvark PCIe controller
+must include a sub-node that describes the legacy interrupt controller
+built into the PCIe controller. This sub-node must have the following
+properties:
+
+ - interrupt-controller
+ - #interrupt-cells: set to <1>
+
+Example:
+
+       pcie0: pcie@d0070000 {
+               compatible = "marvell,armada-3700-pcie";
+               device_type = "pci";
+               status = "disabled";
+               reg = <0 0xd0070000 0 0x20000>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               bus-range = <0x00 0xff>;
+               interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+               #interrupt-cells = <1>;
+               msi-controller;
+               msi-parent = <&pcie0>;
+               ranges = <0x82000000 0 0xe8000000   0 0xe8000000 0 0x1000000 /* Port 0 MEM */
+                         0x81000000 0 0xe9000000   0 0xe9000000 0 0x10000>; /* Port 0 IO*/
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc 0>,
+                               <0 0 0 2 &pcie_intc 1>,
+                               <0 0 0 3 &pcie_intc 2>,
+                               <0 0 0 4 &pcie_intc 3>;
+               pcie_intc: interrupt-controller {
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt b/Documentation/devicetree/bindings/pci/axis,artpec6-pcie.txt
new file mode 100644 (file)
index 0000000..330a45b
--- /dev/null
@@ -0,0 +1,46 @@
+* Axis ARTPEC-6 PCIe interface
+
+This PCIe host controller is based on the Synopsys DesignWare PCIe IP
+and thus inherits all the common properties defined in designware-pcie.txt.
+
+Required properties:
+- compatible: "axis,artpec6-pcie", "snps,dw-pcie"
+- reg: base addresses and lengths of the PCIe controller (DBI),
+       the phy controller, and configuration address space.
+- reg-names: Must include the following entries:
+       - "dbi"
+       - "phy"
+       - "config"
+- interrupts: A list of interrupt outputs of the controller. Must contain an
+  entry for each entry in the interrupt-names property.
+- interrupt-names: Must include the following entries:
+       - "msi": The interrupt that is asserted when an MSI is received
+- axis,syscon-pcie: A phandle pointing to the ARTPEC-6 system controller,
+       used to enable and control the Synopsys IP.
+
+Example:
+
+       pcie@f8050000 {
+               compatible = "axis,artpec6-pcie", "snps,dw-pcie";
+               reg = <0xf8050000 0x2000
+                      0xf8040000 0x1000
+                      0xc0000000 0x1000>;
+               reg-names = "dbi", "phy", "config";
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+                         /* downstream I/O */
+               ranges = <0x81000000 0 0x00010000 0xc0010000 0 0x00010000
+                         /* non-prefetchable memory */
+                         0x82000000 0 0xc0020000 0xc0020000 0 0x1ffe0000>;
+               num-lanes = <2>;
+               interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "msi";
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 0 0x7>;
+               interrupt-map = <0 0 0 1 &intc GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 0 2 &intc GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 0 3 &intc GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 0 4 &intc GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+               axis,syscon-pcie = <&syscon>;
+       };
diff --git a/Documentation/devicetree/bindings/pwm/brcm,iproc-pwm.txt b/Documentation/devicetree/bindings/pwm/brcm,iproc-pwm.txt
new file mode 100644 (file)
index 0000000..21f75bb
--- /dev/null
@@ -0,0 +1,21 @@
+Broadcom iProc PWM controller device tree bindings
+
+This controller has 4 channels.
+
+Required Properties :
+- compatible: must be "brcm,iproc-pwm"
+- reg: physical base address and length of the controller's registers
+- clocks: phandle + clock specifier pair for the external clock
+- #pwm-cells: Should be 3. See pwm.txt in this directory for a
+  description of the cells format.
+
+Refer to clocks/clock-bindings.txt for generic clock consumer properties.
+
+Example:
+
+pwm: pwm@18031000 {
+       compatible = "brcm,iproc-pwm";
+       reg = <0x18031000 0x28>;
+       clocks = <&osc>;
+       #pwm-cells = <3>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt b/Documentation/devicetree/bindings/pwm/google,cros-ec-pwm.txt
new file mode 100644 (file)
index 0000000..472bd46
--- /dev/null
@@ -0,0 +1,23 @@
+* PWM controlled by ChromeOS EC
+
+Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller
+(EC) and controlled via a host-command interface.
+
+An EC PWM node should be only found as a sub-node of the EC node (see
+Documentation/devicetree/bindings/mfd/cros-ec.txt).
+
+Required properties:
+- compatible: Must contain "google,cros-ec-pwm"
+- #pwm-cells: Should be 1. The cell specifies the PWM index.
+
+Example:
+       cros-ec@0 {
+               compatible = "google,cros-ec-spi";
+
+               ...
+
+               cros_ec_pwm: ec-pwm {
+                       compatible = "google,cros-ec-pwm";
+                       #pwm-cells = <1>;
+               };
+       };
index c52f03b..b4e7377 100644 (file)
@@ -1,10 +1,14 @@
 Tegra SoC PWFM controller
 
 Required properties:
-- compatible: For Tegra20, must contain "nvidia,tegra20-pwm".  For Tegra30,
-  must contain "nvidia,tegra30-pwm".  Otherwise, must contain
-  "nvidia,<chip>-pwm", plus one of the above, where <chip> is tegra114,
-  tegra124, tegra132, or tegra210.
+- compatible: Must be:
+  - "nvidia,tegra20-pwm": for Tegra20
+  - "nvidia,tegra30-pwm", "nvidia,tegra20-pwm": for Tegra30
+  - "nvidia,tegra114-pwm", "nvidia,tegra20-pwm": for Tegra114
+  - "nvidia,tegra124-pwm", "nvidia,tegra20-pwm": for Tegra124
+  - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132
+  - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210
+  - "nvidia,tegra186-pwm": for Tegra186
 - reg: physical base address and length of the controller's registers
 - #pwm-cells: should be 2. See pwm.txt in this directory for a description of
   the cells format.
index 0822a08..d6de643 100644 (file)
@@ -7,6 +7,7 @@ Required Properties:
  - "renesas,pwm-r8a7790": for R-Car H2
  - "renesas,pwm-r8a7791": for R-Car M2-W
  - "renesas,pwm-r8a7794": for R-Car E2
+ - "renesas,pwm-r8a7795": for R-Car H3
 - reg: base address and length of the registers block for the PWM.
 - #pwm-cells: should be 2. See pwm.txt in this directory for a description of
   the cells format.
diff --git a/Documentation/devicetree/bindings/pwm/st,stmpe-pwm.txt b/Documentation/devicetree/bindings/pwm/st,stmpe-pwm.txt
new file mode 100644 (file)
index 0000000..cb20964
--- /dev/null
@@ -0,0 +1,18 @@
+== ST STMPE PWM controller ==
+
+This is a PWM block embedded in the ST Microelectronics STMPE
+(ST Multi-Purpose Expander) chips. The PWM is registered as a
+subdevices of the STMPE MFD device.
+
+Required properties:
+- compatible: should be:
+  - "st,stmpe-pwm"
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
+
+Example:
+
+pwm0: pwm {
+       compatible = "st,stmpe-pwm";
+       #pwm-cells = <2>;
+};
index dd6f59c..3aeba9f 100644 (file)
@@ -34,6 +34,18 @@ Only required for Voltage Table Mode:
                            First cell is voltage in microvolts (uV)
                            Second cell is duty-cycle in percent (%)
 
+Optional properties for Continuous mode:
+- pwm-dutycycle-unit:  Integer value encoding the duty cycle unit. If not
+                       defined, <100> is assumed, meaning that
+                       pwm-dutycycle-range contains values expressed in
+                       percent.
+
+- pwm-dutycycle-range: Should contain 2 entries. The first entry is encoding
+                       the dutycycle for regulator-min-microvolt and the
+                       second one the dutycycle for regulator-max-microvolt.
+                       Duty cycle values are expressed in pwm-dutycycle-unit.
+                       If not defined, <0 100> is assumed.
+
 NB: To be clear, if voltage-table is provided, then the device will be used
 in Voltage Table Mode.  If no voltage-table is provided, then the device will
 be used in Continuous Voltage Mode.
@@ -53,6 +65,13 @@ Continuous Voltage With Enable GPIO Example:
                regulator-min-microvolt = <1016000>;
                regulator-max-microvolt = <1114000>;
                regulator-name = "vdd_logic";
+               /* unit == per-mille */
+               pwm-dutycycle-unit = <1000>;
+               /*
+                * Inverted PWM logic, and the duty cycle range is limited
+                * to 30%-70%.
+                */
+               pwm-dutycycle-range <700 300>; /* */
        };
 
 Voltage Table Example:
diff --git a/Documentation/devicetree/bindings/reserved-memory/ramoops.txt b/Documentation/devicetree/bindings/reserved-memory/ramoops.txt
new file mode 100644 (file)
index 0000000..e81f821
--- /dev/null
@@ -0,0 +1,48 @@
+Ramoops oops/panic logger
+=========================
+
+ramoops provides persistent RAM storage for oops and panics, so they can be
+recovered after a reboot. This is a child-node of "/reserved-memory", and
+is named "ramoops" after the backend, rather than "pstore" which is the
+subsystem.
+
+Parts of this storage may be set aside for other persistent log buffers, such
+as kernel log messages, or for optional ECC error-correction data.  The total
+size of these optional buffers must fit in the reserved region.
+
+Any remaining space will be used for a circular buffer of oops and panic
+records.  These records have a configurable size, with a size of 0 indicating
+that they should be disabled.
+
+At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size"
+must be set non-zero, but are otherwise optional as listed below.
+
+
+Required properties:
+
+- compatible: must be "ramoops"
+
+- reg: region of memory that is preserved between reboots
+
+
+Optional properties:
+
+- ecc-size: enables ECC support and specifies ECC buffer size in bytes
+  (defaults to 0: no ECC)
+
+- record-size: maximum size in bytes of each dump done on oops/panic
+  (defaults to 0: disabled)
+
+- console-size: size in bytes of log buffer reserved for kernel messages
+  (defaults to 0: disabled)
+
+- ftrace-size: size in bytes of log buffer reserved for function tracing and
+  profiling (defaults to 0: disabled)
+
+- pmsg-size: size in bytes of log buffer reserved for userspace messages
+  (defaults to 0: disabled)
+
+- unbuffered: if present, use unbuffered mappings to map the reserved region
+  (defaults to buffered mappings)
+
+- no-dump-oops: if present, only dump panics (defaults to panics and oops)
index 68391a4..1992aa9 100644 (file)
@@ -238,6 +238,7 @@ simtek
 sii    Seiko Instruments, Inc.
 silergy        Silergy Corp.
 sirf   SiRF Technology, Inc.
+sis    Silicon Integrated Systems Corp.
 sitronix       Sitronix Technology Corporation
 skyworks       Skyworks Solutions, Inc.
 smsc   Standard Microsystems Corporation
index 8ea834f..5385cba 100644 (file)
@@ -3,6 +3,7 @@
 *.bc
 *.bin
 *.bz2
+*.c.[012]*.*
 *.cis
 *.cpio
 *.csp
index 1b3c39a..d30fb2c 100644 (file)
@@ -12,7 +12,7 @@ prototypes:
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct dentry *,
+       int (*d_compare)(const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(struct dentry *);
        int (*d_init)(struct dentry *);
index 5b21ef7..c0727dc 100644 (file)
@@ -267,7 +267,8 @@ among NILFS2 files can be depicted as follows:
                                   `-- file (ino=yy)
                                     ( regular file, directory, or symlink )
 
-For detail on the format of each file, please see include/linux/nilfs2_fs.h.
+For detail on the format of each file, please see nilfs2_ondisk.h
+located at include/uapi/linux directory.
 
 There are no patents or other intellectual property that we protect
 with regard to the design of NILFS2.  It is allowed to replicate the
index e1a0056..1dfdec7 100644 (file)
@@ -281,7 +281,7 @@ on the wait queue and one attempt is made to recycle them. Obviously,
 if the client-core stays dead too long, the arbitrary userspace processes
 trying to use Orangefs will be negatively affected. Waiting ops
 that can't be serviced will be removed from the request list and
-have their states set to "given up". In-progress ops that can't 
+have their states set to "given up". In-progress ops that can't
 be serviced will be removed from the in_progress hash table and
 have their states set to "given up".
 
@@ -338,7 +338,7 @@ particular response.
   PVFS2_VFS_OP_STATFS
     fill a pvfs2_statfs_response_t with useless info <g>. It is hard for
     us to know, in a timely fashion, these statistics about our
-    distributed network filesystem. 
+    distributed network filesystem.
 
   PVFS2_VFS_OP_FS_MOUNT
     fill a pvfs2_fs_mount_response_t which is just like a PVFS_object_kref
@@ -386,7 +386,7 @@ responses:
 
   io_array[1].iov_base = address of global variable "pdev_magic" (int32_t)
   io_array[1].iov_len = sizeof(int32_t)
-  
+
   io_array[2].iov_base = address of parameter "tag" (PVFS_id_gen_t)
   io_array[2].iov_len = sizeof(int64_t)
 
@@ -402,5 +402,47 @@ Readdir responses initialize the fifth element io_array like this:
   io_array[4].iov_len = contents of member trailer_size (PVFS_size)
                         from out_downcall member of global variable
                         vfs_request
-  
+
+Orangefs exploits the dcache in order to avoid sending redundant
+requests to userspace. We keep object inode attributes up-to-date with
+orangefs_inode_getattr. Orangefs_inode_getattr uses two arguments to
+help it decide whether or not to update an inode: "new" and "bypass".
+Orangefs keeps private data in an object's inode that includes a short
+timeout value, getattr_time, which allows any iteration of
+orangefs_inode_getattr to know how long it has been since the inode was
+updated. When the object is not new (new == 0) and the bypass flag is not
+set (bypass == 0) orangefs_inode_getattr returns without updating the inode
+if getattr_time has not timed out. Getattr_time is updated each time the
+inode is updated.
+
+Creation of a new object (file, dir, sym-link) includes the evaluation of
+its pathname, resulting in a negative directory entry for the object.
+A new inode is allocated and associated with the dentry, turning it from
+a negative dentry into a "productive full member of society". Orangefs
+obtains the new inode from Linux with new_inode() and associates
+the inode with the dentry by sending the pair back to Linux with
+d_instantiate().
+
+The evaluation of a pathname for an object resolves to its corresponding
+dentry. If there is no corresponding dentry, one is created for it in
+the dcache. Whenever a dentry is modified or verified Orangefs stores a
+short timeout value in the dentry's d_time, and the dentry will be trusted
+for that amount of time. Orangefs is a network filesystem, and objects
+can potentially change out-of-band with any particular Orangefs kernel module
+instance, so trusting a dentry is risky. The alternative to trusting
+dentries is to always obtain the needed information from userspace - at
+least a trip to the client-core, maybe to the servers. Obtaining information
+from a dentry is cheap, obtaining it from userspace is relatively expensive,
+hence the motivation to use the dentry when possible.
+
+The timeout values d_time and getattr_time are jiffy based, and the
+code is designed to avoid the jiffy-wrap problem:
+
+"In general, if the clock may have wrapped around more than once, there
+is no way to tell how much time has elapsed. However, if the times t1
+and t2 are known to be fairly close, we can reliably compute the
+difference in a way that takes into account the possibility that the
+clock may have wrapped between times."
+
+                      from course notes by instructor Andy Wang
 
index a5fb89c..b1bd05e 100644 (file)
@@ -585,3 +585,10 @@ in your dentry operations instead.
        in the instances.  Rationale: !@#!@# security_d_instantiate() needs to be
        called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
        ->d_instantiate() uses not just ->getxattr() but ->setxattr() as well.
+--
+[mandatory]
+       ->d_compare() doesn't get parent as a separate argument anymore.  If you
+       used it for finding the struct super_block involved, dentry->d_sb will
+       work just as well; if it's something more complicated, use dentry->d_parent.
+       Just be careful not to assume that fetching it more than once will yield
+       the same value - in RCU mode it could change under you.
index d9c11d2..a85355c 100644 (file)
@@ -98,7 +98,7 @@ A memory policy with a valid NodeList will be saved, as specified, for
 use at file creation time.  When a task allocates a file in the file
 system, the mount option memory policy will be applied with a NodeList,
 if any, modified by the calling task's cpuset constraints
-[See Documentation/cgroups/cpusets.txt] and any optional flags, listed
+[See Documentation/cgroup-v1/cpusets.txt] and any optional flags, listed
 below.  If the resulting NodeLists is the empty set, the effective memory
 policy for the file will revert to "default" policy.
 
index 8a19685..9ace359 100644 (file)
@@ -931,7 +931,7 @@ struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct dentry *,
+       int (*d_compare)(const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        int (*d_init)(struct dentry *);
diff --git a/Documentation/gcc-plugins.txt b/Documentation/gcc-plugins.txt
new file mode 100644 (file)
index 0000000..891c694
--- /dev/null
@@ -0,0 +1,87 @@
+GCC plugin infrastructure
+=========================
+
+
+1. Introduction
+===============
+
+GCC plugins are loadable modules that provide extra features to the
+compiler [1]. They are useful for runtime instrumentation and static analysis.
+We can analyse, change and add further code during compilation via
+callbacks [2], GIMPLE [3], IPA [4] and RTL passes [5].
+
+The GCC plugin infrastructure of the kernel supports all gcc versions from
+4.5 to 6.0, building out-of-tree modules, cross-compilation and building in a
+separate directory.
+Plugin source files have to be compilable by both a C and a C++ compiler as well
+because gcc versions 4.5 and 4.6 are compiled by a C compiler,
+gcc-4.7 can be compiled by a C or a C++ compiler,
+and versions 4.8+ can only be compiled by a C++ compiler.
+
+Currently the GCC plugin infrastructure supports only the x86, arm and arm64
+architectures.
+
+This infrastructure was ported from grsecurity [6] and PaX [7].
+
+--
+[1] https://gcc.gnu.org/onlinedocs/gccint/Plugins.html
+[2] https://gcc.gnu.org/onlinedocs/gccint/Plugin-API.html#Plugin-API
+[3] https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
+[4] https://gcc.gnu.org/onlinedocs/gccint/IPA.html
+[5] https://gcc.gnu.org/onlinedocs/gccint/RTL.html
+[6] https://grsecurity.net/
+[7] https://pax.grsecurity.net/
+
+
+2. Files
+========
+
+$(src)/scripts/gcc-plugins
+       This is the directory of the GCC plugins.
+
+$(src)/scripts/gcc-plugins/gcc-common.h
+       This is a compatibility header for GCC plugins.
+       It should be always included instead of individual gcc headers.
+
+$(src)/scripts/gcc-plugin.sh
+       This script checks the availability of the included headers in
+       gcc-common.h and chooses the proper host compiler to build the plugins
+       (gcc-4.7 can be built by either gcc or g++).
+
+$(src)/scripts/gcc-plugins/gcc-generate-gimple-pass.h
+$(src)/scripts/gcc-plugins/gcc-generate-ipa-pass.h
+$(src)/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
+$(src)/scripts/gcc-plugins/gcc-generate-rtl-pass.h
+       These headers automatically generate the registration structures for
+       GIMPLE, SIMPLE_IPA, IPA and RTL passes. They support all gcc versions
+       from 4.5 to 6.0.
+       They should be preferred to creating the structures by hand.
+
+
+3. Usage
+========
+
+You must install the gcc plugin headers for your gcc version,
+e.g., on Ubuntu for gcc-4.9:
+
+       apt-get install gcc-4.9-plugin-dev
+
+Enable a GCC plugin based feature in the kernel config:
+
+       CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
+
+To compile only the plugin(s):
+
+       make gcc-plugins
+
+or just run the kernel make and compile the whole kernel with
+the cyclomatic complexity GCC plugin.
+
+
+4. How to add a new GCC plugin
+==============================
+
+The GCC plugins are in $(src)/scripts/gcc-plugins/. You can use a file or a directory
+here. It must be added to $(src)/scripts/gcc-plugins/Makefile,
+$(src)/scripts/Makefile.gcc-plugins and $(src)/arch/Kconfig.
+See the cyc_complexity_plugin.c (CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) GCC plugin.
index b6fcaf6..4c5ce3e 100644 (file)
@@ -17,6 +17,7 @@ DRM,Generic,“rotation”,BITMASK,"{ 0, ""rotate-0"" }, { 1, ""rotate-90"" }, {
 ,,“CRTC_H”,RANGE,"Min=0, Max=UINT_MAX",Plane,Scanout CRTC (destination) height (atomic)
 ,,“FB_ID”,OBJECT,DRM_MODE_OBJECT_FB,Plane,Scanout framebuffer (atomic)
 ,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Plane,CRTC that plane is attached to (atomic)
+,,“zpos”,RANGE,"Min=0, Max=UINT_MAX","Plane,Z-order of the plane.Planes with higher Z-order values are displayed on top, planes with identical Z-order values are display in an undefined order"
 ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD
 ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD
index 56af5e4..81c7f2b 100644 (file)
@@ -248,7 +248,7 @@ Code  Seq#(hex)     Include File            Comments
 'm'    00      drivers/scsi/megaraid/megaraid_ioctl.h  conflict!
 'm'    00-1F   net/irda/irmod.h        conflict!
 'n'    00-7F   linux/ncp_fs.h and fs/ncpfs/ioctl.c
-'n'    80-8F   linux/nilfs2_fs.h       NILFS2
+'n'    80-8F   uapi/linux/nilfs2_api.h NILFS2
 'n'    E0-FF   linux/matroxfb.h        matroxfb
 'o'    00-1F   fs/ocfs2/ocfs2_fs.h     OCFS2
 'o'     00-03   mtd/ubi-user.h         conflict! (OCFS2 and UBI overlaps)
index e24aa11..46c030a 100644 (file)
@@ -2320,6 +2320,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Note that if CONFIG_MODULE_SIG_FORCE is set, that
                        is always true, so this option does nothing.
 
+       module_blacklist=  [KNL] Do not load a comma-separated list of
+                       modules.  Useful for debugging problem modules.
+
        mousedev.tap_time=
                        [MOUSE] Maximum time between finger touching and
                        leaving touchpad surface for touch to be considered
@@ -3021,6 +3024,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                resource_alignment=
                                Format:
                                [<order of align>@][<domain>:]<bus>:<slot>.<func>[; ...]
+                               [<order of align>@]pci:<vendor>:<device>\
+                                               [:<subvendor>:<subdevice>][; ...]
                                Specifies alignment and device to reassign
                                aligned memory resources.
                                If <order of align> is not specified,
@@ -3039,6 +3044,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                hpmemsize=nn[KMG]       The fixed amount of bus space which is
                                reserved for hotplug bridge's memory window.
                                Default size is 2 megabytes.
+               hpbussize=nn    The minimum amount of additional bus numbers
+                               reserved for buses below a hotplug bridge.
+                               Default is 1.
                realloc=        Enable/disable reallocating PCI bridge resources
                                if allocations done by BIOS are too small to
                                accommodate resources required by all child
@@ -3070,6 +3078,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                compat  Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe
                        ports driver.
 
+       pcie_port_pm=   [PCIE] PCIe port power management handling:
+               off     Disable power management of all PCIe ports
+               force   Forcibly enable power management of all PCIe ports
+
        pcie_pme=       [PCIE,PM] Native PCIe PME signaling options:
                nomsi   Do not use MSI for native PCIe PME signaling (this makes
                        all PCIe root ports use INTx for all services).
@@ -3173,6 +3185,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
                        default: disabled
 
+       printk.devkmsg={on,off,ratelimit}
+                       Control writing to /dev/kmsg.
+                       on - unlimited logging to /dev/kmsg from userspace
+                       off - logging to /dev/kmsg disabled
+                       ratelimit - ratelimit the logging
+                       Default: ratelimit
+
        printk.time=    Show timing data prefixed to each printk message line
                        Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 
@@ -3570,7 +3589,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        relax_domain_level=
                        [KNL, SMP] Set scheduler's default relax_domain_level.
-                       See Documentation/cgroups/cpusets.txt.
+                       See Documentation/cgroup-v1/cpusets.txt.
 
        relative_sleep_states=
                        [SUSPEND] Use sleep state labeling where the deepest
@@ -3858,6 +3877,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        using these two parameters to set the minimum and
                        maximum port values.
 
+       sunrpc.svc_rpc_per_connection_limit=
+                       [NFS,SUNRPC]
+                       Limit the number of requests that the server will
+                       process in parallel from a single connection.
+                       The default value is 0 (no limit).
+
        sunrpc.pool_mode=
                        [NFS]
                        Control how the NFS server code allocates CPUs to
@@ -3893,7 +3918,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        swapaccount=[0|1]
                        [KNL] Enable accounting of swap in memory resource
                        controller if no parameter or 1 is given or disable
-                       it if 0 is given (See Documentation/cgroups/memory.txt)
+                       it if 0 is given (See Documentation/cgroup-v1/memory.txt)
 
        swiotlb=        [ARM,IA-64,PPC,MIPS,X86]
                        Format: { <int> | force }
index edec3a3..bbc3a8b 100644 (file)
@@ -10,7 +10,7 @@ REFERENCES
 
 o      Documentation/IRQ-affinity.txt:  Binding interrupts to sets of CPUs.
 
-o      Documentation/cgroups:  Using cgroups to bind tasks to sets of CPUs.
+o      Documentation/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.
 
 o      man taskset:  Using the taskset command to bind tasks to sets
        of CPUs.
index 696d5ca..f0e3361 100644 (file)
@@ -271,3 +271,9 @@ Since the private key is used to sign modules, viruses and malware could use
 the private key to sign modules and compromise the operating system.  The
 private key must be either destroyed or moved to a secure location and not kept
 in the root node of the kernel source tree.
+
+If you use the same private key to sign modules for multiple kernel
+configurations, you must ensure that the module version information is
+sufficient to prevent loading a module into a different kernel.  Either
+set CONFIG_MODVERSIONS=y or ensure that each configuration has a different
+kernel release string by changing EXTRAVERSION or CONFIG_LOCALVERSION.
index 9264bca..26b9f31 100644 (file)
@@ -45,18 +45,34 @@ corrupt, but usually it is restorable.
 
 2. Setting the parameters
 
-Setting the ramoops parameters can be done in 3 different manners:
- 1. Use the module parameters (which have the names of the variables described
- as before).
- For quick debugging, you can also reserve parts of memory during boot
- and then use the reserved memory for ramoops. For example, assuming a machine
- with > 128 MB of memory, the following kernel command line will tell the
- kernel to use only the first 128 MB of memory, and place ECC-protected ramoops
- region at 128 MB boundary:
+Setting the ramoops parameters can be done in several different manners:
+
+ A. Use the module parameters (which have the names of the variables described
+ as before). For quick debugging, you can also reserve parts of memory during
+ boot and then use the reserved memory for ramoops. For example, assuming a
+ machine with > 128 MB of memory, the following kernel command line will tell
+ the kernel to use only the first 128 MB of memory, and place ECC-protected
+ ramoops region at 128 MB boundary:
  "mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1"
- 2. Use Device Tree bindings, as described in
- Documentation/device-tree/bindings/misc/ramoops.txt.
- 3. Use a platform device and set the platform data. The parameters can then
+
+ B. Use Device Tree bindings, as described in
+ Documentation/device-tree/bindings/reserved-memory/ramoops.txt.
+ For example:
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               ramoops@8f000000 {
+                       compatible = "ramoops";
+                       reg = <0 0x8f000000 0 0x100000>;
+                       record-size = <0x4000>;
+                       console-size = <0x4000>;
+               };
+       };
+
+ C. Use a platform device and set the platform data. The parameters can then
  be set through that platform data. An example of doing that is:
 
 #include <linux/pstore_ram.h>
index 20c120d..6e491a6 100644 (file)
@@ -82,8 +82,7 @@ III. Module parameters
 
 - 'dbg_level' - This parameter allows to control amount of debug information
         generated by this device driver. This parameter is formed by set of
-        This parameter can be changed bit masks that correspond to the specific
-        functional block.
+        bit masks that correspond to the specific functional blocks.
         For mask definitions see 'drivers/rapidio/devices/rio_mport_cdev.c'
         This parameter can be changed dynamically.
         Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
diff --git a/Documentation/rapidio/rio_cm.txt b/Documentation/rapidio/rio_cm.txt
new file mode 100644 (file)
index 0000000..27aa401
--- /dev/null
@@ -0,0 +1,119 @@
+RapidIO subsystem Channelized Messaging character device driver (rio_cm.c)
+==========================================================================
+
+Version History:
+----------------
+  1.0.0 - Initial driver release.
+
+==========================================================================
+
+I. Overview
+
+This device driver is the result of collaboration within the RapidIO.org
+Software Task Group (STG) between Texas Instruments, Prodrive Technologies,
+Nokia Networks, BAE and IDT.  Additional input was received from other members
+of RapidIO.org.
+
+The objective was to create a character mode driver interface which exposes
+messaging capabilities of RapidIO endpoint devices (mports) directly
+to applications, in a manner that allows the numerous and varied RapidIO
+implementations to interoperate.
+
+This driver (RIO_CM) provides to user-space applications shared access to
+RapidIO mailbox messaging resources.
+
+RapidIO specification (Part 2) defines that endpoint devices may have up to four
+messaging mailboxes in case of multi-packet message (up to 4KB) and
+up to 64 mailboxes if single-packet messages (up to 256 B) are used. In addition
+to protocol definition limitations, a particular hardware implementation can
+have reduced number of messaging mailboxes.  RapidIO aware applications must
+therefore share the messaging resources of a RapidIO endpoint.
+
+Main purpose of this device driver is to provide RapidIO mailbox messaging
+capability to large number of user-space processes by introducing socket-like
+operations using a single messaging mailbox.  This allows applications to
+use the limited RapidIO messaging hardware resources efficiently.
+
+Most of device driver's operations are supported through 'ioctl' system calls.
+
+When loaded this device driver creates a single file system node named rio_cm
+in /dev directory common for all registered RapidIO mport devices.
+
+Following ioctl commands are available to user-space applications:
+
+- RIO_CM_MPORT_GET_LIST : Returns to caller list of local mport devices that
+    support messaging operations (number of entries up to RIO_MAX_MPORTS).
+    Each list entry is combination of mport's index in the system and RapidIO
+    destination ID assigned to the port.
+- RIO_CM_EP_GET_LIST_SIZE : Returns number of messaging capable remote endpoints
+    in a RapidIO network associated with the specified mport device.
+- RIO_CM_EP_GET_LIST : Returns list of RapidIO destination IDs for messaging
+    capable remote endpoints (peers) available in a RapidIO network associated
+    with the specified mport device.
+- RIO_CM_CHAN_CREATE : Creates RapidIO message exchange channel data structure
+    with channel ID assigned automatically or as requested by a caller.
+- RIO_CM_CHAN_BIND : Binds the specified channel data structure to the specified
+    mport device.
+- RIO_CM_CHAN_LISTEN : Enables listening for connection requests on the specified
+    channel.
+- RIO_CM_CHAN_ACCEPT : Accepts a connection request from peer on the specified
+    channel. If wait timeout for this request is specified by a caller it is
+    a blocking call. If timeout set to 0 this is non-blocking call - ioctl
+    handler checks for a pending connection request and if one is not available
+    exits with -EGAIN error status immediately.
+- RIO_CM_CHAN_CONNECT : Sends a connection request to a remote peer/channel.
+- RIO_CM_CHAN_SEND : Sends a data message through the specified channel.
+    The handler for this request assumes that message buffer specified by
+    a caller includes the reserved space for a packet header required by
+    this driver.
+- RIO_CM_CHAN_RECEIVE : Receives a data message through a connected channel.
+    If the channel does not have an incoming message ready to return this ioctl
+    handler will wait for new message until timeout specified by a caller
+    expires. If timeout value is set to 0, ioctl handler uses a default value
+    defined by MAX_SCHEDULE_TIMEOUT.
+- RIO_CM_CHAN_CLOSE : Closes a specified channel and frees associated buffers.
+    If the specified channel is in the CONNECTED state, sends close notification
+    to the remote peer.
+
+The ioctl command codes and corresponding data structures intended for use by
+user-space applications are defined in 'include/uapi/linux/rio_cm_cdev.h'.
+
+II. Hardware Compatibility
+
+This device driver uses standard interfaces defined by kernel RapidIO subsystem
+and therefore it can be used with any mport device driver registered by RapidIO
+subsystem with limitations set by available mport HW implementation of messaging
+mailboxes.
+
+III. Module parameters
+
+- 'dbg_level' - This parameter allows to control amount of debug information
+        generated by this device driver. This parameter is formed by set of
+        bit masks that correspond to the specific functional block.
+        For mask definitions see 'drivers/rapidio/devices/rio_cm.c'
+        This parameter can be changed dynamically.
+        Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
+
+- 'cmbox' - Number of RapidIO mailbox to use (default value is 1).
+        This parameter allows to set messaging mailbox number that will be used
+        within entire RapidIO network. It can be used when default mailbox is
+        used by other device drivers or is not supported by some nodes in the
+        RapidIO network.
+
+- 'chstart' - Start channel number for dynamic assignment. Default value - 256.
+        Allows to exclude channel numbers below this parameter from dynamic
+        allocation to avoid conflicts with software components that use
+        reserved predefined channel numbers.
+
+IV. Known problems
+
+  None.
+
+V. User-space Applications and API Library
+
+Messaging API library and applications that use this device driver are available
+from RapidIO.org.
+
+VI. TODO List
+
+- Add support for system notification messages (reserved channel 0).
index 7c1c7bf..cd2a293 100644 (file)
@@ -25,6 +25,32 @@ fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
         This parameter can be changed dynamically.
         Use CONFIG_RAPIDIO_DEBUG=y to enable debug output at the top level.
 
+- 'dma_desc_per_channel' - This parameter defines number of hardware buffer
+        descriptors allocated for each registered Tsi721 DMA channel.
+        Its default value is 128.
+
+- 'dma_txqueue_sz' - DMA transactions queue size. Defines number of pending
+        transaction requests that can be accepted by each DMA channel.
+        Default value is 16.
+
+- 'dma_sel' - DMA channel selection mask. Bitmask that defines which hardware
+        DMA channels (0 ... 6) will be registered with DmaEngine core.
+        If bit is set to 1, the corresponding DMA channel will be registered.
+        DMA channels not selected by this mask will not be used by this device
+        driver. Default value is 0x7f (use all channels).
+
+- 'pcie_mrrs' - override value for PCIe Maximum Read Request Size (MRRS).
+        This parameter gives an ability to override MRRS value set during PCIe
+        configuration process. Tsi721 supports read request sizes up to 4096B.
+        Value for this parameter must be set as defined by PCIe specification:
+        0 = 128B, 1 = 256B, 2 = 512B, 3 = 1024B, 4 = 2048B and 5 = 4096B.
+        Default value is '-1' (= keep platform setting).
+
+- 'mbox_sel' - RIO messaging MBOX selection mask. This is a bitmask that defines
+        messaging MBOXes are managed by this device driver. Mask bits 0 - 3
+        correspond to MBOX0 - MBOX3. MBOX is under driver's control if the
+        corresponding bit is set to '1'. Default value is 0x0f (= all).
+
 II. Known problems
 
   None.
index e114513..53a2fe1 100644 (file)
@@ -431,7 +431,7 @@ CONTENTS
 
  -deadline tasks cannot have an affinity mask smaller that the entire
  root_domain they are created on. However, affinities can be specified
- through the cpuset facility (Documentation/cgroups/cpusets.txt).
+ through the cpuset facility (Documentation/cgroup-v1/cpusets.txt).
 
 5.1 SCHED_DEADLINE and cpusets HOWTO
 ------------------------------------
index f14f493..edd861c 100644 (file)
@@ -215,7 +215,7 @@ SCHED_BATCH) tasks.
 
    These options need CONFIG_CGROUPS to be defined, and let the administrator
    create arbitrary groups of tasks, using the "cgroup" pseudo filesystem.  See
-   Documentation/cgroups/cgroups.txt for more information about this filesystem.
+   Documentation/cgroup-v1/cgroups.txt for more information about this filesystem.
 
 When CONFIG_FAIR_GROUP_SCHED is defined, a "cpu.shares" file is created for each
 group created using the pseudo filesystem.  See example steps below to create
index 71b54d5..a03f0d9 100644 (file)
@@ -133,7 +133,7 @@ This uses the cgroup virtual file system and "<cgroup>/cpu.rt_runtime_us"
 to control the CPU time reserved for each control group.
 
 For more information on working with control groups, you should read
-Documentation/cgroups/cgroups.txt as well.
+Documentation/cgroup-v1/cgroups.txt as well.
 
 Group settings are checked against the following limits in order to keep the
 configuration schedulable:
index 3320460..ffab8b5 100644 (file)
@@ -764,6 +764,20 @@ send before ratelimiting kicks in.
 
 ==============================================================
 
+printk_devkmsg:
+
+Control the logging to /dev/kmsg from userspace:
+
+ratelimit: default, ratelimited
+on: unlimited logging to /dev/kmsg from userspace
+off: logging to /dev/kmsg disabled
+
+The kernel command line parameter printk.devkmsg= overrides this and is
+a one-time setting until next reboot: once set, it cannot be changed by
+this sysctl interface anymore.
+
+==============================================================
+
 randomize_va_space:
 
 This option can be used to select the type of process address
index a4482cc..739db9a 100644 (file)
@@ -1433,13 +1433,16 @@ KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
 4.52 KVM_SET_GSI_ROUTING
 
 Capability: KVM_CAP_IRQ_ROUTING
-Architectures: x86 s390
+Architectures: x86 s390 arm arm64
 Type: vm ioctl
 Parameters: struct kvm_irq_routing (in)
 Returns: 0 on success, -1 on error
 
 Sets the GSI routing table entries, overwriting any previously set entries.
 
+On arm/arm64, GSI routing has the following limitation:
+- GSI routing does not apply to KVM_IRQ_LINE but only to KVM_IRQFD.
+
 struct kvm_irq_routing {
        __u32 nr;
        __u32 flags;
@@ -1468,7 +1471,13 @@ struct kvm_irq_routing_entry {
 #define KVM_IRQ_ROUTING_S390_ADAPTER 3
 #define KVM_IRQ_ROUTING_HV_SINT 4
 
-No flags are specified so far, the corresponding field must be set to zero.
+flags:
+- KVM_MSI_VALID_DEVID: used along with KVM_IRQ_ROUTING_MSI routing entry
+  type, specifies that the devid field contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace should
+  never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
+- zero otherwise
 
 struct kvm_irq_routing_irqchip {
        __u32 irqchip;
@@ -1479,9 +1488,21 @@ struct kvm_irq_routing_msi {
        __u32 address_lo;
        __u32 address_hi;
        __u32 data;
-       __u32 pad;
+       union {
+               __u32 pad;
+               __u32 devid;
+       };
 };
 
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
+
+On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
+feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
+address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
+address_hi must be zero.
+
 struct kvm_irq_routing_s390_adapter {
        __u64 ind_addr;
        __u64 summary_addr;
@@ -1583,6 +1604,17 @@ struct kvm_lapic_state {
 Reads the Local APIC registers and copies them into the input argument.  The
 data format and layout are the same as documented in the architecture manual.
 
+If KVM_X2APIC_API_USE_32BIT_IDS feature of KVM_CAP_X2APIC_API is
+enabled, then the format of APIC_ID register depends on the APIC mode
+(reported by MSR_IA32_APICBASE) of its VCPU.  x2APIC stores APIC ID in
+the APIC_ID register (bytes 32-35).  xAPIC only allows an 8-bit APIC ID
+which is stored in bits 31-24 of the APIC register, or equivalently in
+byte 35 of struct kvm_lapic_state's regs field.  KVM_GET_LAPIC must then
+be called after MSR_IA32_APICBASE has been set with KVM_SET_MSR.
+
+If KVM_X2APIC_API_USE_32BIT_IDS feature is disabled, struct kvm_lapic_state
+always uses xAPIC format.
+
 
 4.58 KVM_SET_LAPIC
 
@@ -1600,6 +1632,10 @@ struct kvm_lapic_state {
 Copies the input argument into the Local APIC registers.  The data format
 and layout are the same as documented in the architecture manual.
 
+The format of the APIC ID register (bytes 32-35 of struct kvm_lapic_state's
+regs field) depends on the state of the KVM_CAP_X2APIC_API capability.
+See the note in KVM_GET_LAPIC.
+
 
 4.59 KVM_IOEVENTFD
 
@@ -2032,6 +2068,12 @@ registers, find a list below:
   MIPS  | KVM_REG_MIPS_CP0_CONFIG5      | 32
   MIPS  | KVM_REG_MIPS_CP0_CONFIG7      | 32
   MIPS  | KVM_REG_MIPS_CP0_ERROREPC     | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH1    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH2    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH3    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH4    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH5    | 64
+  MIPS  | KVM_REG_MIPS_CP0_KSCRATCH6    | 64
   MIPS  | KVM_REG_MIPS_COUNT_CTL        | 64
   MIPS  | KVM_REG_MIPS_COUNT_RESUME     | 64
   MIPS  | KVM_REG_MIPS_COUNT_HZ         | 64
@@ -2156,7 +2198,7 @@ after pausing the vcpu, but before it is resumed.
 4.71 KVM_SIGNAL_MSI
 
 Capability: KVM_CAP_SIGNAL_MSI
-Architectures: x86
+Architectures: x86 arm64
 Type: vm ioctl
 Parameters: struct kvm_msi (in)
 Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
@@ -2169,10 +2211,23 @@ struct kvm_msi {
        __u32 address_hi;
        __u32 data;
        __u32 flags;
-       __u8  pad[16];
+       __u32 devid;
+       __u8  pad[12];
 };
 
-No flags are defined so far. The corresponding field must be 0.
+flags: KVM_MSI_VALID_DEVID: devid contains a valid value.  The per-VM
+  KVM_CAP_MSI_DEVID capability advertises the requirement to provide
+  the device ID.  If this capability is not available, userspace
+  should never set the KVM_MSI_VALID_DEVID flag as the ioctl might fail.
+
+If KVM_MSI_VALID_DEVID is set, devid contains a unique device identifier
+for the device that wrote the MSI message.  For PCI, this is usually a
+BFD identifier in the lower 16 bits.
+
+On x86, address_hi is ignored unless the KVM_X2APIC_API_USE_32BIT_IDS
+feature of KVM_CAP_X2APIC_API capability is enabled.  If it is enabled,
+address_hi bits 31-8 provide bits 31-8 of the destination id.  Bits 7-0 of
+address_hi must be zero.
 
 
 4.71 KVM_CREATE_PIT2
@@ -2345,9 +2400,13 @@ Note that closing the resamplefd is not sufficient to disable the
 irqfd.  The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
 and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
 
-On ARM/ARM64, the gsi field in the kvm_irqfd struct specifies the Shared
-Peripheral Interrupt (SPI) index, such that the GIC interrupt ID is
-given by gsi + 32.
+On arm/arm64, gsi routing being supported, the following can happen:
+- in case no routing entry is associated to this gsi, injection fails
+- in case the gsi is associated to an irqchip routing entry,
+  irqchip.pin + 32 corresponds to the injected SPI ID.
+- in case the gsi is associated to an MSI routing entry, the MSI
+  message and device ID are translated into an LPI (support restricted
+  to GICv3 ITS in-kernel emulation).
 
 4.76 KVM_PPC_ALLOCATE_HTAB
 
@@ -2520,6 +2579,7 @@ Parameters: struct kvm_device_attr
 Returns: 0 on success, -1 on error
 Errors:
   ENXIO:  The group or attribute is unknown/unsupported for this device
+          or hardware support is missing.
   EPERM:  The attribute cannot (currently) be accessed this way
           (e.g. read-only attribute, or attribute that only makes
           sense when the device is in a different state)
@@ -2547,6 +2607,7 @@ Parameters: struct kvm_device_attr
 Returns: 0 on success, -1 on error
 Errors:
   ENXIO:  The group or attribute is unknown/unsupported for this device
+          or hardware support is missing.
 
 Tests whether a device supports a particular attribute.  A successful
 return indicates the attribute is implemented.  It does not necessarily
@@ -3803,6 +3864,42 @@ Allows use of runtime-instrumentation introduced with zEC12 processor.
 Will return -EINVAL if the machine does not support runtime-instrumentation.
 Will return -EBUSY if a VCPU has already been created.
 
+7.7 KVM_CAP_X2APIC_API
+
+Architectures: x86
+Parameters: args[0] - features that should be enabled
+Returns: 0 on success, -EINVAL when args[0] contains invalid features
+
+Valid feature flags in args[0] are
+
+#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+
+Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
+KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
+allowing the use of 32-bit APIC IDs.  See KVM_CAP_X2APIC_API in their
+respective sections.
+
+KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK must be enabled for x2APIC to work
+in logical mode or with more than 255 VCPUs.  Otherwise, KVM treats 0xff
+as a broadcast even in x2APIC mode in order to support physical x2APIC
+without interrupt remapping.  This is undesirable in logical mode,
+where 0xff represents CPUs 0-7 in cluster 0.
+
+7.8 KVM_CAP_S390_USER_INSTR0
+
+Architectures: s390
+Parameters: none
+
+With this capability enabled, all illegal instructions 0x0000 (2 bytes) will
+be intercepted and forwarded to user space. User space can use this
+mechanism e.g. to realize 2-byte software breakpoints. The kernel will
+not inject an operating exception for these instructions, user space has
+to take care of that.
+
+This capability can be enabled dynamically even if VCPUs were already
+created and are running.
+
 8. Other capabilities.
 ----------------------
 
index 59541d4..89182f8 100644 (file)
@@ -4,16 +4,22 @@ ARM Virtual Generic Interrupt Controller (VGIC)
 Device types supported:
   KVM_DEV_TYPE_ARM_VGIC_V2     ARM Generic Interrupt Controller v2.0
   KVM_DEV_TYPE_ARM_VGIC_V3     ARM Generic Interrupt Controller v3.0
+  KVM_DEV_TYPE_ARM_VGIC_ITS    ARM Interrupt Translation Service Controller
 
-Only one VGIC instance may be instantiated through either this API or the
-legacy KVM_CREATE_IRQCHIP api.  The created VGIC will act as the VM interrupt
-controller, requiring emulated user-space devices to inject interrupts to the
-VGIC instead of directly to CPUs.
+Only one VGIC instance of the V2/V3 types above may be instantiated through
+either this API or the legacy KVM_CREATE_IRQCHIP api.  The created VGIC will
+act as the VM interrupt controller, requiring emulated user-space devices to
+inject interrupts to the VGIC instead of directly to CPUs.
 
 Creating a guest GICv3 device requires a host GICv3 as well.
 GICv3 implementations with hardware compatibility support allow a guest GICv2
 as well.
 
+Creating a virtual ITS controller requires a host GICv3 (but does not depend
+on having physical ITS controllers).
+There can be multiple ITS controllers per guest, each of them has to have
+a separate, non-overlapping MMIO region.
+
 Groups:
   KVM_DEV_ARM_VGIC_GRP_ADDR
   Attributes:
@@ -39,6 +45,13 @@ Groups:
       Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
       This address needs to be 64K aligned.
 
+    KVM_VGIC_V3_ADDR_TYPE_ITS (rw, 64-bit)
+      Base address in the guest physical address space of the GICv3 ITS
+      control register frame. The ITS allows MSI(-X) interrupts to be
+      injected into guests. This extension is optional. If the kernel
+      does not support the ITS, the call returns -ENODEV.
+      Only valid for KVM_DEV_TYPE_ARM_VGIC_ITS.
+      This address needs to be 64K aligned and the region covers 128K.
 
   KVM_DEV_ARM_VGIC_GRP_DIST_REGS
   Attributes:
@@ -109,8 +122,8 @@ Groups:
   KVM_DEV_ARM_VGIC_GRP_CTRL
   Attributes:
     KVM_DEV_ARM_VGIC_CTRL_INIT
-      request the initialization of the VGIC, no additional parameter in
-      kvm_device_attr.addr.
+      request the initialization of the VGIC or ITS, no additional parameter
+      in kvm_device_attr.addr.
   Errors:
     -ENXIO: VGIC not properly configured as required prior to calling
      this attribute
index a9ea877..b6cda49 100644 (file)
@@ -20,7 +20,8 @@ Enables Collaborative Memory Management Assist (CMMA) for the virtual machine.
 
 1.2. ATTRIBUTE: KVM_S390_VM_MEM_CLR_CMMA
 Parameters: none
-Returns: 0
+Returns: -EINVAL if CMMA was not enabled
+         0 otherwise
 
 Clear the CMMA status for all guest pages, so any pages the guest marked
 as unused are again used any may not be reclaimed by the host.
@@ -85,6 +86,90 @@ Returns:    -EBUSY in case 1 or more vcpus are already activated (only in write
            -ENOMEM if not enough memory is available to process the ioctl
            0 in case of success
 
+2.3. ATTRIBUTE: KVM_S390_VM_CPU_MACHINE_FEAT (r/o)
+
+Allows user space to retrieve available cpu features. A feature is available if
+provided by the hardware and supported by kvm. In theory, cpu features could
+even be completely emulated by kvm.
+
+struct kvm_s390_vm_cpu_feat {
+        __u64 feat[16]; # Bitmap (1 = feature available), MSB 0 bit numbering
+};
+
+Parameters: address of a buffer to load the feature list from.
+Returns:    -EFAULT if the given address is not accessible from kernel space.
+           0 in case of success.
+
+2.4. ATTRIBUTE: KVM_S390_VM_CPU_PROCESSOR_FEAT (r/w)
+
+Allows user space to retrieve or change enabled cpu features for all VCPUs of a
+VM. Features that are not available cannot be enabled.
+
+See 2.3. for a description of the parameter struct.
+
+Parameters: address of a buffer to store/load the feature list from.
+Returns:    -EFAULT if the given address is not accessible from kernel space.
+           -EINVAL if a cpu feature that is not available is to be enabled.
+           -EBUSY if at least one VCPU has already been defined.
+           0 in case of success.
+
+2.5. ATTRIBUTE: KVM_S390_VM_CPU_MACHINE_SUBFUNC (r/o)
+
+Allows user space to retrieve available cpu subfunctions without any filtering
+done by a set IBC. These subfunctions are indicated to the guest VCPU via
+query or "test bit" subfunctions and used e.g. by cpacf functions, plo and ptff.
+
+A subfunction block is only valid if KVM_S390_VM_CPU_MACHINE contains the
+STFL(E) bit introducing the affected instruction. If the affected instruction
+indicates subfunctions via a "query subfunction", the response block is
+contained in the returned struct. If the affected instruction
+indicates subfunctions via a "test bit" mechanism, the subfunction codes are
+contained in the returned struct in MSB 0 bit numbering.
+
+struct kvm_s390_vm_cpu_subfunc {
+       u8 plo[32];           # always valid (ESA/390 feature)
+       u8 ptff[16];          # valid with TOD-clock steering
+       u8 kmac[16];          # valid with Message-Security-Assist
+       u8 kmc[16];           # valid with Message-Security-Assist
+       u8 km[16];            # valid with Message-Security-Assist
+       u8 kimd[16];          # valid with Message-Security-Assist
+       u8 klmd[16];          # valid with Message-Security-Assist
+       u8 pckmo[16];         # valid with Message-Security-Assist-Extension 3
+       u8 kmctr[16];         # valid with Message-Security-Assist-Extension 4
+       u8 kmf[16];           # valid with Message-Security-Assist-Extension 4
+       u8 kmo[16];           # valid with Message-Security-Assist-Extension 4
+       u8 pcc[16];           # valid with Message-Security-Assist-Extension 4
+       u8 ppno[16];          # valid with Message-Security-Assist-Extension 5
+       u8 reserved[1824];    # reserved for future instructions
+};
+
+Parameters: address of a buffer to load the subfunction blocks from.
+Returns:    -EFAULT if the given address is not accessible from kernel space.
+           0 in case of success.
+
+2.6. ATTRIBUTE: KVM_S390_VM_CPU_PROCESSOR_SUBFUNC (r/w)
+
+Allows user space to retrieve or change cpu subfunctions to be indicated for
+all VCPUs of a VM. This attribute will only be available if kernel and
+hardware support are in place.
+
+The kernel uses the configured subfunction blocks for indication to
+the guest. A subfunction block will only be used if the associated STFL(E) bit
+has not been disabled by user space (so the instruction to be queried is
+actually available for the guest).
+
+As long as no data has been written, a read will fail. The IBC will be used
+to determine available subfunctions in this case, this will guarantee backward
+compatibility.
+
+See 2.5. for a description of the parameter struct.
+
+Parameters: address of a buffer to store/load the subfunction blocks from.
+Returns:    -EFAULT if the given address is not accessible from kernel space.
+           -EINVAL when reading, if there was no write yet.
+           -EBUSY if at least one VCPU has already been defined.
+           0 in case of success.
+
 3. GROUP: KVM_S390_VM_TOD
 Architectures: s390
 
index 19f94a6..f2491a8 100644 (file)
@@ -89,7 +89,7 @@ In mmu_spte_clear_track_bits():
    old_spte = *spte;
 
    /* 'if' condition is satisfied. */
-   if (old_spte.Accssed == 1 &&
+   if (old_spte.Accessed == 1 &&
         old_spte.W == 0)
       spte = 0ull;
                                          on fast page fault path:
@@ -102,7 +102,7 @@ In mmu_spte_clear_track_bits():
       old_spte = xchg(spte, 0ull)
 
 
-   if (old_spte.Accssed == 1)
+   if (old_spte.Accessed == 1)
       kvm_set_pfn_accessed(spte.pfn);
    if (old_spte.Dirty == 1)
       kvm_set_pfn_dirty(spte.pfn);
index ade0127..e0b58c0 100644 (file)
@@ -63,7 +63,7 @@ nodes.  Each emulated node will manage a fraction of the underlying cells'
 physical memory.  NUMA emluation is useful for testing NUMA kernel and
 application features on non-NUMA platforms, and as a sort of memory resource
 management mechanism when used together with cpusets.
-[see Documentation/cgroups/cpusets.txt]
+[see Documentation/cgroup-v1/cpusets.txt]
 
 For each node with memory, Linux constructs an independent memory management
 subsystem, complete with its own free page lists, in-use page lists, usage
@@ -113,7 +113,7 @@ allocation behavior using Linux NUMA memory policy.
 
 System administrators can restrict the CPUs and nodes' memories that a non-
 privileged user can specify in the scheduling or NUMA commands and functions
-using control groups and CPUsets.  [see Documentation/cgroups/cpusets.txt]
+using control groups and CPUsets.  [see Documentation/cgroup-v1/cpusets.txt]
 
 On architectures that do not hide memoryless nodes, Linux will include only
 zones [nodes] with memory in the zonelists.  This means that for a memoryless
index badb050..622b927 100644 (file)
@@ -9,7 +9,7 @@ document attempts to describe the concepts and APIs of the 2.6 memory policy
 support.
 
 Memory policies should not be confused with cpusets
-(Documentation/cgroups/cpusets.txt)
+(Documentation/cgroup-v1/cpusets.txt)
 which is an administrative mechanism for restricting the nodes from which
 memory may be allocated by a set of processes. Memory policies are a
 programming interface that a NUMA-aware application can take advantage of.  When
index 94bd9c1..0478ae2 100644 (file)
@@ -38,7 +38,7 @@ locations.
 Larger installations usually partition the system using cpusets into
 sections of nodes. Paul Jackson has equipped cpusets with the ability to
 move pages when a task is moved to another cpuset (See
-Documentation/cgroups/cpusets.txt).
+Documentation/cgroup-v1/cpusets.txt).
 Cpusets allows the automation of process locality. If a task is moved to
 a new cpuset then also all its pages are moved with it so that the
 performance of the process does not sink dramatically. Also the pages
index 0026a8d..e147185 100644 (file)
@@ -122,7 +122,7 @@ MEMORY CONTROL GROUP INTERACTION
 --------------------------------
 
 The unevictable LRU facility interacts with the memory control group [aka
-memory controller; see Documentation/cgroups/memory.txt] by extending the
+memory controller; see Documentation/cgroup-v1/memory.txt] by extending the
 lru_list enum.
 
 The memory controller data structure automatically gets a per-zone unevictable
index 0f11d9b..4b09f18 100644 (file)
@@ -8,7 +8,7 @@ assign them to cpusets and their attached tasks.  This is a way of limiting the
 amount of system memory that are available to a certain class of tasks.
 
 For more information on the features of cpusets, see
-Documentation/cgroups/cpusets.txt.
+Documentation/cgroup-v1/cpusets.txt.
 There are a number of different configurations you can use for your needs.  For
 more information on the numa=fake command line option and its various ways of
 configuring fake nodes, see Documentation/x86/x86_64/boot-options.txt.
@@ -33,7 +33,7 @@ A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
        On node 3 totalpages: 131072
 
 Now following the instructions for mounting the cpusets filesystem from
-Documentation/cgroups/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
+Documentation/cgroup-v1/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
 address spaces) to individual cpusets:
 
        [root@xroads /]# mkdir exampleset
index b5c04df..a306795 100644 (file)
@@ -778,6 +778,11 @@ W: http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/dma/dma-axi-dmac.c
 
+ANDROID CONFIG FRAGMENTS
+M:     Rob Herring <robh@kernel.org>
+S:     Supported
+F:     kernel/configs/android*
+
 ANDROID DRIVERS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Arve Hjønnevåg <arve@android.com>
@@ -1644,7 +1649,8 @@ F:        arch/arm/mach-s5pv210/
 
 ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Kamil Debski <k.debski@samsung.com>
+M:     Kamil Debski <kamil@wypas.org>
+M:     Andrzej Hajda <a.hajda@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
@@ -1652,8 +1658,9 @@ F:        drivers/media/platform/s5p-g2d/
 
 ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
-M:     Kamil Debski <k.debski@samsung.com>
+M:     Kamil Debski <kamil@wypas.org>
 M:     Jeongtae Park <jtp.park@samsung.com>
+M:     Andrzej Hajda <a.hajda@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
@@ -2347,7 +2354,10 @@ S:       Supported
 F:     drivers/media/platform/sti/bdisp
 
 BEFS FILE SYSTEM
-S:     Orphan
+M:     Luis de Bethencourt <luisbg@osg.samsung.com>
+M:     Salah Triki <salah.triki@gmail.com>
+S:     Maintained
+T:     git git://github.com/luisbg/linux-befs.git
 F:     Documentation/filesystems/befs.txt
 F:     fs/befs/
 
@@ -3210,7 +3220,7 @@ M:        Johannes Weiner <hannes@cmpxchg.org>
 L:     cgroups@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
-F:     Documentation/cgroups/
+F:     Documentation/cgroup*
 F:     include/linux/cgroup*
 F:     kernel/cgroup*
 
@@ -3221,7 +3231,7 @@ W:        http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
-F:     Documentation/cgroups/cpusets.txt
+F:     Documentation/cgroup-v1/cpusets.txt
 F:     include/linux/cpuset.h
 F:     kernel/cpuset.c
 
@@ -3485,6 +3495,7 @@ F:        Documentation/ABI/testing/sysfs-class-cxl
 CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER
 M:     Manoj N. Kumar <manoj@linux.vnet.ibm.com>
 M:     Matthew R. Ochs <mrochs@linux.vnet.ibm.com>
+M:     Uma Krishnan <ukrishn@linux.vnet.ibm.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/cxlflash/
@@ -5095,6 +5106,15 @@ L:       linux-scsi@vger.kernel.org
 S:     Odd Fixes (e.g., new signatures)
 F:     drivers/scsi/fdomain.*
 
+GCC PLUGINS
+M:     Kees Cook <keescook@chromium.org>
+R:     Emese Revfy <re.emese@gmail.com>
+L:     kernel-hardening@lists.openwall.com
+S:     Maintained
+F:     scripts/gcc-plugins/
+F:     scripts/gcc-plugin.sh
+F:     Documentation/gcc-plugins.txt
+
 GCOV BASED KERNEL PROFILING
 M:     Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
 S:     Maintained
@@ -5813,7 +5833,15 @@ M:       Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/ibmvscsi/ibmvscsi*
-F:     drivers/scsi/ibmvscsi/viosrp.h
+F:     include/scsi/viosrp.h
+
+IBM Power Virtual SCSI Device Target Driver
+M:     Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+M:     Michael Cyr <mikecyr@linux.vnet.ibm.com>
+L:     linux-scsi@vger.kernel.org
+L:     target-devel@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/ibmvscsi_tgt/
 
 IBM Power Virtual FC Device Drivers
 M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
@@ -7621,6 +7649,15 @@ W:       http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlxsw/
 
+SOFT-ROCE DRIVER (rxe)
+M:     Moni Shoua <monis@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+S:     Supported
+W:     https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+F:     drivers/infiniband/hw/rxe/
+F:     include/uapi/rdma/rdma_user_rxe.h
+
 MEMBARRIER SUPPORT
 M:     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
@@ -8256,8 +8293,9 @@ T:        git git://github.com/konis/nilfs2.git
 S:     Supported
 F:     Documentation/filesystems/nilfs2.txt
 F:     fs/nilfs2/
-F:     include/linux/nilfs2_fs.h
 F:     include/trace/events/nilfs2.h
+F:     include/uapi/linux/nilfs2_api.h
+F:     include/uapi/linux/nilfs2_ondisk.h
 
 NINJA SCSI-3 / NINJA SCSI-32Bi (16bit/CardBus) PCMCIA SCSI HOST ADAPTER DRIVER
 M:     YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
@@ -8304,6 +8342,7 @@ F:        drivers/ntb/
 F:     drivers/net/ntb_netdev.c
 F:     include/linux/ntb.h
 F:     include/linux/ntb_transport.h
+F:     tools/testing/selftests/ntb/
 
 NTB INTEL DRIVER
 M:     Jon Mason <jdmason@kudzu.us>
@@ -8875,6 +8914,7 @@ L:        linux-pci@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-pci/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
 S:     Supported
+F:     Documentation/devicetree/bindings/pci/
 F:     Documentation/PCI/
 F:     drivers/pci/
 F:     include/linux/pci*
@@ -8938,6 +8978,13 @@ L:       linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/pci/host/*mvebu*
 
+PCI DRIVER FOR AARDVARK (Marvell Armada 3700)
+M:     Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+L:     linux-pci@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/pci/host/pci-aardvark.c
+
 PCI DRIVER FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@gmail.com>
 L:     linux-tegra@vger.kernel.org
@@ -9020,6 +9067,15 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/pci/xgene-pci-msi.txt
 F:     drivers/pci/host/pci-xgene-msi.c
 
+PCIE DRIVER FOR AXIS ARTPEC
+M:     Niklas Cassel <niklas.cassel@axis.com>
+M:     Jesper Nilsson <jesper.nilsson@axis.com>
+L:     linux-arm-kernel@axis.com
+L:     linux-pci@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/pci/axis,artpec*
+F:     drivers/pci/host/*artpec*
+
 PCIE DRIVER FOR HISILICON
 M:     Zhou Wang <wangzhou1@hisilicon.com>
 M:     Gabriele Paoloni <gabriele.paoloni@huawei.com>
@@ -9197,6 +9253,16 @@ W:       http://www.st.com/spear
 S:     Maintained
 F:     drivers/pinctrl/spear/
 
+PISTACHIO SOC SUPPORT
+M:      James Hartley <james.hartley@imgtec.com>
+M:      Ionela Voinescu <ionela.voinescu@imgtec.com>
+L:      linux-mips@linux-mips.org
+S:      Maintained
+F:      arch/mips/pistachio/
+F:      arch/mips/include/asm/mach-pistachio/
+F:      arch/mips/boot/dts/pistachio/
+F:      arch/mips/configs/pistachio*_defconfig
+
 PKTCDVD DRIVER
 M:     Jiri Kosina <jikos@kernel.org>
 S:     Maintained
@@ -9436,7 +9502,8 @@ S:        Odd Fixes
 F:     drivers/media/usb/pwc/*
 
 PWM FAN DRIVER
-M:     Kamil Debski <k.debski@samsung.com>
+M:     Kamil Debski <kamil@wypas.org>
+M:     Lukasz Majewski <l.majewski@samsung.com>
 L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/hwmon/pwm-fan.txt
@@ -9774,10 +9841,14 @@ L:      rtc-linux@googlegroups.com
 Q:     http://patchwork.ozlabs.org/project/rtc-linux/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
 S:     Maintained
+F:     Documentation/devicetree/bindings/rtc/
 F:     Documentation/rtc.txt
 F:     drivers/rtc/
 F:     include/linux/rtc.h
 F:     include/uapi/linux/rtc.h
+F:     include/linux/rtc/
+F:     include/linux/platform_data/rtc-*
+F:     tools/testing/selftests/timers/rtctest.c
 
 REALTEK AUDIO CODECS
 M:     Bard Liao <bardliao@realtek.com>
@@ -10184,7 +10255,8 @@ T:      git https://github.com/lmajewski/linux-samsung-thermal.git
 F:     drivers/thermal/samsung/
 
 SAMSUNG USB2 PHY DRIVER
-M:     Kamil Debski <k.debski@samsung.com>
+M:     Kamil Debski <kamil@wypas.org>
+M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -12348,6 +12420,19 @@ S:     Maintained
 F:     drivers/media/v4l2-core/videobuf2-*
 F:     include/media/videobuf2-*
 
+VIRTIO AND VHOST VSOCK DRIVER
+M:     Stefan Hajnoczi <stefanha@redhat.com>
+L:     kvm@vger.kernel.org
+L:     virtualization@lists.linux-foundation.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     include/linux/virtio_vsock.h
+F:     include/uapi/linux/virtio_vsock.h
+F:     net/vmw_vsock/virtio_transport_common.c
+F:     net/vmw_vsock/virtio_transport.c
+F:     drivers/vhost/vsock.c
+F:     drivers/vhost/vsock.h
+
 VIRTUAL SERIO DEVICE DRIVER
 M:     Stephen Chandler Paul <thatslyude@gmail.com>
 S:     Maintained
index 393b615..8c504f3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
-PATCHLEVEL = 7
+PATCHLEVEL = 8
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Psychotic Stoned Sheep
 
 # *DOCUMENTATION*
@@ -371,26 +371,27 @@ CFLAGS_KERNEL     =
 AFLAGS_KERNEL  =
 LDFLAGS_vmlinux =
 CFLAGS_GCOV    = -fprofile-arcs -ftest-coverage -fno-tree-loop-im
-CFLAGS_KCOV    = -fsanitize-coverage=trace-pc
+CFLAGS_KCOV    := $(call cc-option,-fsanitize-coverage=trace-pc,)
 
 
 # Use USERINCLUDE when you must reference the UAPI directories only.
 USERINCLUDE    := \
                -I$(srctree)/arch/$(hdr-arch)/include/uapi \
-               -Iarch/$(hdr-arch)/include/generated/uapi \
+               -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \
                -I$(srctree)/include/uapi \
-               -Iinclude/generated/uapi \
+               -I$(objtree)/include/generated/uapi \
                 -include $(srctree)/include/linux/kconfig.h
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := \
                -I$(srctree)/arch/$(hdr-arch)/include \
-               -Iarch/$(hdr-arch)/include/generated/uapi \
-               -Iarch/$(hdr-arch)/include/generated \
+               -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \
+               -I$(objtree)/arch/$(hdr-arch)/include/generated \
                $(if $(KBUILD_SRC), -I$(srctree)/include) \
-               -Iinclude \
-               $(USERINCLUDE)
+               -I$(objtree)/include
+
+LINUXINCLUDE   += $(filter-out $(LINUXINCLUDE),$(USERINCLUDE))
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
@@ -554,7 +555,7 @@ ifeq ($(KBUILD_EXTMOD),)
 # in parallel
 PHONY += scripts
 scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
-        asm-generic
+        asm-generic gcc-plugins
        $(Q)$(MAKE) $(build)=$(@)
 
 # Objects we will link into vmlinux / subdirs we need to visit
@@ -620,7 +621,6 @@ include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
 KBUILD_CFLAGS  += $(call cc-disable-warning,maybe-uninitialized,)
-KBUILD_CFLAGS  += $(call cc-disable-warning,frame-address,)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 KBUILD_CFLAGS  += -Os
@@ -635,6 +635,8 @@ endif
 # Tell gcc to never replace conditional load with a non-conditional one
 KBUILD_CFLAGS  += $(call cc-option,--param=allow-store-data-races=0)
 
+include scripts/Makefile.gcc-plugins
+
 ifdef CONFIG_READABLE_ASM
 # Disable optimizations that make assembler listings hard to read.
 # reorder blocks reorders the control in the function
@@ -666,21 +668,11 @@ endif
 endif
 # Find arch-specific stack protector compiler sanity-checking script.
 ifdef CONFIG_CC_STACKPROTECTOR
-  stackp-path := $(srctree)/scripts/gcc-$(ARCH)_$(BITS)-has-stack-protector.sh
-  ifneq ($(wildcard $(stackp-path)),)
-    stackp-check := $(stackp-path)
-  endif
+  stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh
+  stackp-check := $(wildcard $(stackp-path))
 endif
 KBUILD_CFLAGS += $(stackp-flag)
 
-ifdef CONFIG_KCOV
-  ifeq ($(call cc-option, $(CFLAGS_KCOV)),)
-    $(warning Cannot use CONFIG_KCOV: \
-             -fsanitize-coverage=trace-pc is not supported by compiler)
-    CFLAGS_KCOV =
-  endif
-endif
-
 ifeq ($(cc-name),clang)
 KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,)
 KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,)
@@ -1019,7 +1011,7 @@ prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
 
 archprepare: archheaders archscripts prepare1 scripts_basic
 
-prepare0: archprepare
+prepare0: archprepare gcc-plugins
        $(Q)$(MAKE) $(build)=.
 
 # All the preparing..
@@ -1433,7 +1425,7 @@ $(help-board-dirs): help-%:
 
 # Documentation targets
 # ---------------------------------------------------------------------------
-DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs cleanmediadocs
+DOC_TARGETS := xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs
 PHONY += $(DOC_TARGETS)
 $(DOC_TARGETS): scripts_basic FORCE
        $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype
@@ -1531,6 +1523,7 @@ clean: $(clean-dirs)
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
                -o -name modules.builtin -o -name '.tmp_*.o.*' \
+               -o -name '*.c.[012]*.*' \
                -o -name '*.gcno' \) -type f -print | xargs rm -f
 
 # Generate tags for editors
@@ -1641,7 +1634,7 @@ endif
        $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
        $(build)=$(build-dir)
 # Make sure the latest headers are built for Documentation
-Documentation/: headers_install
+Documentation/ samples/: headers_install
 %/: prepare scripts FORCE
        $(cmd_crmodverdir)
        $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
index 1599629..e9c9334 100644 (file)
@@ -357,6 +357,43 @@ config SECCOMP_FILTER
 
          See Documentation/prctl/seccomp_filter.txt for details.
 
+config HAVE_GCC_PLUGINS
+       bool
+       help
+         An arch should select this symbol if it supports building with
+         GCC plugins.
+
+menuconfig GCC_PLUGINS
+       bool "GCC plugins"
+       depends on HAVE_GCC_PLUGINS
+       depends on !COMPILE_TEST
+       help
+         GCC plugins are loadable modules that provide extra features to the
+         compiler. They are useful for runtime instrumentation and static analysis.
+
+         See Documentation/gcc-plugins.txt for details.
+
+config GCC_PLUGIN_CYC_COMPLEXITY
+       bool "Compute the cyclomatic complexity of a function"
+       depends on GCC_PLUGINS
+       help
+         The complexity M of a function's control flow graph is defined as:
+          M = E - N + 2P
+         where
+
+         E = the number of edges
+         N = the number of nodes
+         P = the number of connected components (exit nodes).
+
+config GCC_PLUGIN_SANCOV
+       bool
+       depends on GCC_PLUGINS
+       help
+         This plugin inserts a __sanitizer_cov_trace_pc() call at the start of
+         basic blocks. It supports all gcc versions with plugin support (from
+         gcc-4.5 on). It is based on the commit "Add fuzzing coverage support"
+         by Dmitry Vyukov <dvyukov@google.com>.
+
 config HAVE_CC_STACKPROTECTOR
        bool
        help
@@ -424,6 +461,15 @@ config CC_STACKPROTECTOR_STRONG
 
 endchoice
 
+config HAVE_ARCH_WITHIN_STACK_FRAMES
+       bool
+       help
+         An architecture should select this if it can walk the kernel stack
+         frames to determine if an object is part of either the arguments
+         or local variables (i.e. that it excludes saved return addresses,
+         and similar) by implementing an inline arch_within_stack_frames(),
+         which is used by CONFIG_HARDENED_USERCOPY.
+
 config HAVE_CONTEXT_TRACKING
        bool
        help
index 8399bd0..0cbe4c5 100644 (file)
@@ -15,7 +15,7 @@ targets               := vmlinux.gz vmlinux \
 OBJSTRIP       := $(obj)/tools/objstrip
 
 HOSTCFLAGS     := -Wall -I$(objtree)/usr/include
-BOOTCFLAGS     += -I$(obj) -I$(srctree)/$(obj)
+BOOTCFLAGS     += -I$(objtree)/$(obj) -I$(srctree)/$(obj)
 
 # SRM bootable image.  Copy to offset 512 of a partition.
 $(obj)/bootimage: $(addprefix $(obj)/tools/,mkbb lxboot bootlx) $(obj)/vmlinux.nh
index 3c3451f..c63b6ac 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ALPHA_DMA_MAPPING_H
 #define _ALPHA_DMA_MAPPING_H
 
-#include <linux/dma-attrs.h>
-
 extern struct dma_map_ops *dma_ops;
 
 static inline struct dma_map_ops *get_dma_ops(struct device *dev)
diff --git a/arch/alpha/include/asm/rtc.h b/arch/alpha/include/asm/rtc.h
deleted file mode 100644 (file)
index f71c3b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/rtc.h>
index 32e920a..e9e90bf 100644 (file)
@@ -86,33 +86,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define TS_UAC_NOPRINT         0x0001  /* ! Preserve the following three */
 #define TS_UAC_NOFIX           0x0002  /* ! flags as they match          */
 #define TS_UAC_SIGBUS          0x0004  /* ! userspace part of 'osf_sysinfo' */
-#define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
-#endif
 
 #define SET_UNALIGN_CTL(task,value)    ({                              \
        __u32 status = task_thread_info(task)->status & ~UAC_BITMASK;   \
index 53dd2f1..d5f0580 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/gct.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
-#include <asm/rtc.h>
 #include <asm/vga.h>
 
 #include "proto.h"
index f54bdf6..d3398f6 100644 (file)
 #define __initmv __initdata
 #define ALIAS_MV(x)
 #else
-#define __initmv __initdata_refok
+#define __initmv __refdata
 
 /* GCC actually has a syntax for defining aliases, but is under some
    delusion that you shouldn't be able to declare it extern somewhere
index 8e735b5..bb152e2 100644 (file)
@@ -109,7 +109,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
 
 static void *alpha_noop_alloc_coherent(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t gfp,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        void *ret;
 
index 8969bf2..451fc9c 100644 (file)
@@ -349,7 +349,7 @@ static struct pci_dev *alpha_gendev_to_pci(struct device *dev)
 static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction dir,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        int dac_allowed;
@@ -369,7 +369,7 @@ static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
 
 static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
                                 size_t size, enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        unsigned long flags;
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
@@ -433,7 +433,7 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
 
 static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
                                      dma_addr_t *dma_addrp, gfp_t gfp,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        void *cpu_addr;
@@ -478,7 +478,7 @@ try_again:
 
 static void alpha_pci_free_coherent(struct device *dev, size_t size,
                                    void *cpu_addr, dma_addr_t dma_addr,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
@@ -651,7 +651,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
 
 static int alpha_pci_map_sg(struct device *dev, struct scatterlist *sg,
                            int nents, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        struct scatterlist *start, *end, *out;
@@ -729,7 +729,7 @@ static int alpha_pci_map_sg(struct device *dev, struct scatterlist *sg,
 
 static void alpha_pci_unmap_sg(struct device *dev, struct scatterlist *sg,
                               int nents, enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        struct pci_dev *pdev = alpha_gendev_to_pci(dev);
        unsigned long flags;
index f535a3f..ceed68c 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 
-#include <asm/rtc.h>
-
 #include "proto.h"
 
 
@@ -81,7 +79,7 @@ init_rtc_epoch(void)
 static int
 alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       __get_rtc_time(tm);
+       mc146818_get_time(tm);
 
        /* Adjust for non-default epochs.  It's easier to depend on the
           generic __get_rtc_time and adjust the epoch here than create
@@ -112,7 +110,7 @@ alpha_rtc_set_time(struct device *dev, struct rtc_time *tm)
                tm = &xtm;
        }
 
-       return __set_rtc_time(tm);
+       return mc146818_set_time(tm);
 }
 
 static int
index ab74b5d..20afc65 100644 (file)
@@ -22,7 +22,7 @@
 
 
 static void *arc_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        unsigned long order = get_order(size);
        struct page *page;
@@ -46,7 +46,7 @@ static void *arc_dma_alloc(struct device *dev, size_t size,
         *   (vs. always going to memory - thus are faster)
         */
        if ((is_isa_arcv2() && ioc_exists) ||
-           dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs))
+           (attrs & DMA_ATTR_NON_CONSISTENT))
                need_coh = 0;
 
        /*
@@ -90,13 +90,13 @@ static void *arc_dma_alloc(struct device *dev, size_t size,
 }
 
 static void arc_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        phys_addr_t paddr = plat_dma_to_phys(dev, dma_handle);
        struct page *page = virt_to_page(paddr);
        int is_non_coh = 1;
 
-       is_non_coh = dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs) ||
+       is_non_coh = (attrs & DMA_ATTR_NON_CONSISTENT) ||
                        (is_isa_arcv2() && ioc_exists);
 
        if (PageHighMem(page) || !is_non_coh)
@@ -130,7 +130,7 @@ static void _dma_cache_sync(phys_addr_t paddr, size_t size,
 
 static dma_addr_t arc_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        phys_addr_t paddr = page_to_phys(page) + offset;
        _dma_cache_sync(paddr, size, dir);
@@ -138,7 +138,7 @@ static dma_addr_t arc_dma_map_page(struct device *dev, struct page *page,
 }
 
 static int arc_dma_map_sg(struct device *dev, struct scatterlist *sg,
-          int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+          int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
index 8be9303..399e2f2 100644 (file)
@@ -220,7 +220,7 @@ void __init mem_init(void)
 /*
  * free_initmem: Free all the __init memory.
  */
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
        free_initmem_default(-1);
 }
index 14b4cf7..a9c4e48 100644 (file)
@@ -35,6 +35,7 @@ config ARM
        select HARDIRQS_SW_RESEND
        select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
        select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
        select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
        select HAVE_ARCH_MMAP_RND_BITS if MMU
@@ -54,6 +55,7 @@ config ARM
        select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
        select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
+       select HAVE_GCC_PLUGINS
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
        select HAVE_IDE if PCI || ISA || PCMCIA
@@ -699,7 +701,7 @@ config ARCH_VIRT
        depends on ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_GIC
-       select ARM_GIC_V2M if PCI_MSI
+       select ARM_GIC_V2M if PCI
        select ARM_GIC_V3
        select ARM_PSCI
        select HAVE_ARM_ARCH_TIMER
index 1143c4d..3012816 100644 (file)
@@ -310,7 +310,7 @@ static inline void unmap_single(struct device *dev, struct safe_buffer *buf,
  */
 static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        dma_addr_t dma_addr;
        int ret;
@@ -344,7 +344,7 @@ static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
  * should be)
  */
 static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-               enum dma_data_direction dir, struct dma_attrs *attrs)
+               enum dma_data_direction dir, unsigned long attrs)
 {
        struct safe_buffer *buf;
 
index a83570f..d009f79 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/mm_types.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-debug.h>
 
 #include <asm/memory.h>
@@ -174,7 +173,7 @@ static inline void dma_mark_clean(void *addr, size_t size) { }
  * to be the device-viewed address.
  */
 extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-                          gfp_t gfp, struct dma_attrs *attrs);
+                          gfp_t gfp, unsigned long attrs);
 
 /**
  * arm_dma_free - free memory allocated by arm_dma_alloc
@@ -191,7 +190,7 @@ extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
  * during and after this call executing are illegal.
  */
 extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
-                        dma_addr_t handle, struct dma_attrs *attrs);
+                        dma_addr_t handle, unsigned long attrs);
 
 /**
  * arm_dma_mmap - map a coherent DMA allocation into user space
@@ -208,7 +207,7 @@ extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
  */
 extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                        void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                       struct dma_attrs *attrs);
+                       unsigned long attrs);
 
 /*
  * This can be called during early boot to increase the size of the atomic
@@ -262,16 +261,16 @@ extern void dmabounce_unregister_dev(struct device *);
  * The scatter list versions of the above methods.
  */
 extern int arm_dma_map_sg(struct device *, struct scatterlist *, int,
-               enum dma_data_direction, struct dma_attrs *attrs);
+               enum dma_data_direction, unsigned long attrs);
 extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int,
-               enum dma_data_direction, struct dma_attrs *attrs);
+               enum dma_data_direction, unsigned long attrs);
 extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
                enum dma_data_direction);
 extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
                enum dma_data_direction);
 extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
                void *cpu_addr, dma_addr_t dma_addr, size_t size,
-               struct dma_attrs *attrs);
+               unsigned long attrs);
 
 #endif /* __KERNEL__ */
 #endif
index c2b9b4b..1869af6 100644 (file)
@@ -53,6 +53,30 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
 /* Function pointer to optional machine-specific reinitialization */
 extern void (*kexec_reinit)(void);
 
+static inline unsigned long phys_to_boot_phys(phys_addr_t phys)
+{
+       return phys_to_idmap(phys);
+}
+#define phys_to_boot_phys phys_to_boot_phys
+
+static inline phys_addr_t boot_phys_to_phys(unsigned long entry)
+{
+       return idmap_to_phys(entry);
+}
+#define boot_phys_to_phys boot_phys_to_phys
+
+static inline unsigned long page_to_boot_pfn(struct page *page)
+{
+       return page_to_pfn(page) + (arch_phys_to_idmap_offset >> PAGE_SHIFT);
+}
+#define page_to_boot_pfn page_to_boot_pfn
+
+static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
+{
+       return pfn_to_page(boot_pfn - (arch_phys_to_idmap_offset >> PAGE_SHIFT));
+}
+#define boot_pfn_to_page boot_pfn_to_page
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_KEXEC */
index 3d5a5cd..58faff5 100644 (file)
@@ -66,6 +66,8 @@ extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
 extern void __init_stage2_translation(void);
+
+extern void __kvm_hyp_reset(unsigned long);
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
index 96387d4..de338d9 100644 (file)
@@ -241,8 +241,7 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
                int exception_index);
 
-static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
-                                      phys_addr_t pgd_ptr,
+static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
                                       unsigned long hyp_stack_ptr,
                                       unsigned long vector_ptr)
 {
@@ -251,18 +250,13 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
         * code. The init code doesn't need to preserve these
         * registers as r0-r3 are already callee saved according to
         * the AAPCS.
-        * Note that we slightly misuse the prototype by casing the
+        * Note that we slightly misuse the prototype by casting the
         * stack pointer to a void *.
-        *
-        * We don't have enough registers to perform the full init in
-        * one go.  Install the boot PGD first, and then install the
-        * runtime PGD, stack pointer and vectors. The PGDs are always
-        * passed as the third argument, in order to be passed into
-        * r2-r3 to the init code (yes, this is compliant with the
-        * PCS!).
-        */
 
-       kvm_call_hyp(NULL, 0, boot_pgd_ptr);
+        * The PGDs are always passed as the third argument, in order
+        * to be passed into r2-r3 to the init code (yes, this is
+        * compliant with the PCS!).
+        */
 
        kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
 }
@@ -272,16 +266,13 @@ static inline void __cpu_init_stage2(void)
        kvm_call_hyp(__init_stage2_translation);
 }
 
-static inline void __cpu_reset_hyp_mode(phys_addr_t boot_pgd_ptr,
+static inline void __cpu_reset_hyp_mode(unsigned long vector_ptr,
                                        phys_addr_t phys_idmap_start)
 {
-       /*
-        * TODO
-        * kvm_call_reset(boot_pgd_ptr, phys_idmap_start);
-        */
+       kvm_call_hyp((void *)virt_to_idmap(__kvm_hyp_reset), vector_ptr);
 }
 
-static inline int kvm_arch_dev_ioctl_check_extension(long ext)
+static inline int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 {
        return 0;
 }
index f0e8607..6eaff28 100644 (file)
@@ -25,9 +25,6 @@
 
 #define __hyp_text __section(.hyp.text) notrace
 
-#define kern_hyp_va(v) (v)
-#define hyp_kern_va(v) (v)
-
 #define __ACCESS_CP15(CRn, Op1, CRm, Op2)      \
        "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
 #define __ACCESS_CP15_64(Op1, CRm)             \
index f9a6506..3bb803d 100644 (file)
  * We directly use the kernel VA for the HYP, as we can directly share
  * the mapping (HTTBR "covers" TTBR1).
  */
-#define HYP_PAGE_OFFSET_MASK   UL(~0)
-#define HYP_PAGE_OFFSET                PAGE_OFFSET
-#define KERN_TO_HYP(kva)       (kva)
-
-/*
- * Our virtual mapping for the boot-time MMU-enable code. Must be
- * shared across all the page-tables. Conveniently, we use the vectors
- * page, where no kernel data will ever be shared with HYP.
- */
-#define TRAMPOLINE_VA          UL(CONFIG_VECTORS_BASE)
+#define kern_hyp_va(kva)       (kva)
 
 /*
  * KVM_MMU_CACHE_MIN_PAGES is the number of stage2 page table translation levels.
@@ -49,9 +40,8 @@
 #include <asm/pgalloc.h>
 #include <asm/stage2_pgtable.h>
 
-int create_hyp_mappings(void *from, void *to);
+int create_hyp_mappings(void *from, void *to, pgprot_t prot);
 int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
-void free_boot_hyp_pgd(void);
 void free_hyp_pgds(void);
 
 void stage2_unmap_vm(struct kvm *kvm);
@@ -65,7 +55,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
 void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
 
 phys_addr_t kvm_mmu_get_httbr(void);
-phys_addr_t kvm_mmu_get_boot_httbr(void);
 phys_addr_t kvm_get_idmap_vector(void);
 phys_addr_t kvm_get_idmap_start(void);
 int kvm_mmu_init(void);
index 0070e85..2d88af5 100644 (file)
@@ -22,6 +22,7 @@ struct hw_pci {
        struct msi_controller *msi_ctrl;
        struct pci_ops  *ops;
        int             nr_controllers;
+       unsigned int    io_optional:1;
        void            **private_data;
        int             (*setup)(int nr, struct pci_sys_data *);
        struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
index d622040..a8d656d 100644 (file)
@@ -97,7 +97,9 @@ extern pgprot_t               pgprot_s2_device;
 #define PAGE_READONLY_EXEC     _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
 #define PAGE_KERNEL            _MOD_PROT(pgprot_kernel, L_PTE_XN)
 #define PAGE_KERNEL_EXEC       pgprot_kernel
-#define PAGE_HYP               _MOD_PROT(pgprot_kernel, L_PTE_HYP)
+#define PAGE_HYP               _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_XN)
+#define PAGE_HYP_EXEC          _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY)
+#define PAGE_HYP_RO            _MOD_PROT(pgprot_kernel, L_PTE_HYP | L_PTE_RDONLY | L_PTE_XN)
 #define PAGE_HYP_DEVICE                _MOD_PROT(pgprot_hyp_device, L_PTE_HYP)
 #define PAGE_S2                        _MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY)
 #define PAGE_S2_DEVICE         _MOD_PROT(pgprot_s2_device, L_PTE_S2_RDONLY)
index 62a6f65..a93c0f9 100644 (file)
@@ -480,7 +480,10 @@ arm_copy_from_user(void *to, const void __user *from, unsigned long n);
 static inline unsigned long __must_check
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       unsigned int __ua_flags = uaccess_save_and_enable();
+       unsigned int __ua_flags;
+
+       check_object_size(to, n, false);
+       __ua_flags = uaccess_save_and_enable();
        n = arm_copy_from_user(to, from, n);
        uaccess_restore(__ua_flags);
        return n;
@@ -495,11 +498,15 @@ static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 #ifndef CONFIG_UACCESS_WITH_MEMCPY
-       unsigned int __ua_flags = uaccess_save_and_enable();
+       unsigned int __ua_flags;
+
+       check_object_size(from, n, true);
+       __ua_flags = uaccess_save_and_enable();
        n = arm_copy_to_user(to, from, n);
        uaccess_restore(__ua_flags);
        return n;
 #else
+       check_object_size(from, n, true);
        return arm_copy_to_user(to, from, n);
 #endif
 }
index d4ceaf5..a2e75b8 100644 (file)
@@ -80,6 +80,10 @@ static inline bool is_kernel_in_hyp_mode(void)
        return false;
 }
 
+/* The section containing the hypervisor idmap text */
+extern char __hyp_idmap_text_start[];
+extern char __hyp_idmap_text_end[];
+
 /* The section containing the hypervisor text */
 extern char __hyp_text_start[];
 extern char __hyp_text_end[];
index 9408a99..95ce6ac 100644 (file)
@@ -2,15 +2,14 @@
 #define _ASM_ARM_XEN_PAGE_COHERENT_H
 
 #include <asm/page.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-mapping.h>
 
 void __xen_dma_map_page(struct device *hwdev, struct page *page,
             dma_addr_t dev_addr, unsigned long offset, size_t size,
-            enum dma_data_direction dir, struct dma_attrs *attrs);
+            enum dma_data_direction dir, unsigned long attrs);
 void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs);
+               unsigned long attrs);
 void __xen_dma_sync_single_for_cpu(struct device *hwdev,
                dma_addr_t handle, size_t size, enum dma_data_direction dir);
 
@@ -18,22 +17,20 @@ void __xen_dma_sync_single_for_device(struct device *hwdev,
                dma_addr_t handle, size_t size, enum dma_data_direction dir);
 
 static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
-               dma_addr_t *dma_handle, gfp_t flags,
-               struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs)
 {
        return __generic_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs);
 }
 
 static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
-               void *cpu_addr, dma_addr_t dma_handle,
-               struct dma_attrs *attrs)
+               void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs)
 {
        __generic_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs);
 }
 
 static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
             dma_addr_t dev_addr, unsigned long offset, size_t size,
-            enum dma_data_direction dir, struct dma_attrs *attrs)
+            enum dma_data_direction dir, unsigned long attrs)
 {
        unsigned long page_pfn = page_to_xen_pfn(page);
        unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
@@ -58,8 +55,7 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
 }
 
 static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
-               size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        unsigned long pfn = PFN_DOWN(handle);
        /*
index 05e61a2..2f0e077 100644 (file)
@@ -410,7 +410,8 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
-static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+static int pcibios_init_resource(int busnr, struct pci_sys_data *sys,
+                                int io_optional)
 {
        int ret;
        struct resource_entry *window;
@@ -420,6 +421,14 @@ static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
                         &iomem_resource, sys->mem_offset);
        }
 
+       /*
+        * If a platform says I/O port support is optional, we don't add
+        * the default I/O space.  The platform is responsible for adding
+        * any I/O space it needs.
+        */
+       if (io_optional)
+               return 0;
+
        resource_list_for_each_entry(window, &sys->resources)
                if (resource_type(window->res) == IORESOURCE_IO)
                        return 0;
@@ -466,7 +475,7 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
                if (ret > 0) {
                        struct pci_host_bridge *host_bridge;
 
-                       ret = pcibios_init_resources(nr, sys);
+                       ret = pcibios_init_resource(nr, sys, hw->io_optional);
                        if (ret)  {
                                kfree(sys);
                                break;
@@ -515,25 +524,23 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
        list_for_each_entry(sys, &head, node) {
                struct pci_bus *bus = sys->bus;
 
-               if (!pci_has_flag(PCI_PROBE_ONLY)) {
+               /*
+                * We insert PCI resources into the iomem_resource and
+                * ioport_resource trees in either pci_bus_claim_resources()
+                * or pci_bus_assign_resources().
+                */
+               if (pci_has_flag(PCI_PROBE_ONLY)) {
+                       pci_bus_claim_resources(bus);
+               } else {
                        struct pci_bus *child;
 
-                       /*
-                        * Size the bridge windows.
-                        */
                        pci_bus_size_bridges(bus);
-
-                       /*
-                        * Assign resources.
-                        */
                        pci_bus_assign_resources(bus);
 
                        list_for_each_entry(child, &bus->children, node)
                                pcie_bus_configure_settings(child);
                }
-               /*
-                * Tell drivers about devices found.
-                */
+
                pci_bus_add_devices(bus);
        }
 }
@@ -590,18 +597,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-/**
- * pcibios_enable_device - Enable I/O and memory.
- * @dev: PCI device to be enabled
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       if (pci_has_flag(PCI_PROBE_ONLY))
-               return 0;
-
-       return pci_enable_resources(dev, mask);
-}
-
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
index 59fd0e2..b18c1ea 100644 (file)
@@ -57,7 +57,7 @@ int machine_kexec_prepare(struct kimage *image)
        for (i = 0; i < image->nr_segments; i++) {
                current_segment = &image->segment[i];
 
-               if (!memblock_is_region_memory(current_segment->mem,
+               if (!memblock_is_region_memory(idmap_to_phys(current_segment->mem),
                                               current_segment->memsz))
                        return -EINVAL;
 
index da2f6c3..df7f2a7 100644 (file)
@@ -848,10 +848,29 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
        kernel_data.end     = virt_to_phys(_end - 1);
 
        for_each_memblock(memory, region) {
+               phys_addr_t start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
+               phys_addr_t end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
+               unsigned long boot_alias_start;
+
+               /*
+                * Some systems have a special memory alias which is only
+                * used for booting.  We need to advertise this region to
+                * kexec-tools so they know where bootable RAM is located.
+                */
+               boot_alias_start = phys_to_idmap(start);
+               if (arm_has_idmap_alias() && boot_alias_start != IDMAP_INVALID_ADDR) {
+                       res = memblock_virt_alloc(sizeof(*res), 0);
+                       res->name = "System RAM (boot alias)";
+                       res->start = boot_alias_start;
+                       res->end = phys_to_idmap(end);
+                       res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+                       request_resource(&iomem_resource, res);
+               }
+
                res = memblock_virt_alloc(sizeof(*res), 0);
                res->name  = "System RAM";
-               res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
-               res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
+               res->start = start;
+               res->end = end;
                res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
 
                request_resource(&iomem_resource, res);
@@ -1000,9 +1019,25 @@ static void __init reserve_crashkernel(void)
                (unsigned long)(crash_base >> 20),
                (unsigned long)(total_mem >> 20));
 
+       /* The crashk resource must always be located in normal mem */
        crashk_res.start = crash_base;
        crashk_res.end = crash_base + crash_size - 1;
        insert_resource(&iomem_resource, &crashk_res);
+
+       if (arm_has_idmap_alias()) {
+               /*
+                * If we have a special RAM alias for use at boot, we
+                * need to advertise to kexec tools where the alias is.
+                */
+               static struct resource crashk_boot_res = {
+                       .name = "Crash kernel (boot alias)",
+                       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+               };
+
+               crashk_boot_res.start = phys_to_idmap(crash_base);
+               crashk_boot_res.end = crashk_boot_res.start + crash_size - 1;
+               insert_resource(&iomem_resource, &crashk_boot_res);
+       }
 }
 #else
 static inline void reserve_crashkernel(void) {}
index 087acb5..5f221ac 100644 (file)
@@ -279,8 +279,12 @@ asmlinkage long sys_oabi_epoll_wait(int epfd,
        mm_segment_t fs;
        long ret, err, i;
 
-       if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
+       if (maxevents <= 0 ||
+                       maxevents > (INT_MAX/sizeof(*kbuf)) ||
+                       maxevents > (INT_MAX/sizeof(*events)))
                return -EINVAL;
+       if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents))
+               return -EFAULT;
        kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
        if (!kbuf)
                return -ENOMEM;
@@ -317,6 +321,8 @@ asmlinkage long sys_oabi_semtimedop(int semid,
 
        if (nsops < 1 || nsops > SEMOPM)
                return -EINVAL;
+       if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops))
+               return -EFAULT;
        sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
        if (!sops)
                return -ENOMEM;
index 99420fc..d24e5dd 100644 (file)
@@ -44,7 +44,7 @@
 #endif
 
 #if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
-       defined(CONFIG_GENERIC_BUG)
+       defined(CONFIG_GENERIC_BUG) || defined(CONFIG_JUMP_LABEL)
 #define ARM_EXIT_KEEP(x)       x
 #define ARM_EXIT_DISCARD(x)
 #else
index 02abfff..3e1cd04 100644 (file)
@@ -32,6 +32,8 @@ config KVM
        select KVM_VFIO
        select HAVE_KVM_EVENTFD
        select HAVE_KVM_IRQFD
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQ_ROUTING
        depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
        ---help---
          Support hosting virtualized guest machines.
@@ -46,13 +48,6 @@ config KVM_ARM_HOST
        ---help---
          Provides host support for ARM processors.
 
-config KVM_NEW_VGIC
-       bool "New VGIC implementation"
-       depends on KVM
-       default y
-       ---help---
-         uses the new VGIC implementation
-
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
index a596b58..10d77a6 100644 (file)
@@ -22,7 +22,6 @@ obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
 
-ifeq ($(CONFIG_KVM_NEW_VGIC),y)
 obj-y += $(KVM)/arm/vgic/vgic.o
 obj-y += $(KVM)/arm/vgic/vgic-init.o
 obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
@@ -30,9 +29,5 @@ obj-y += $(KVM)/arm/vgic/vgic-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
-else
-obj-y += $(KVM)/arm/vgic.o
-obj-y += $(KVM)/arm/vgic-v2.o
-obj-y += $(KVM)/arm/vgic-v2-emul.o
-endif
+obj-y += $(KVM)/irqchip.o
 obj-y += $(KVM)/arm/arch_timer.o
index f1bde7c..d94bb90 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -122,7 +123,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        if (ret)
                goto out_fail_alloc;
 
-       ret = create_hyp_mappings(kvm, kvm + 1);
+       ret = create_hyp_mappings(kvm, kvm + 1, PAGE_HYP);
        if (ret)
                goto out_free_stage2_pgd;
 
@@ -201,7 +202,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = KVM_MAX_VCPUS;
                break;
        default:
-               r = kvm_arch_dev_ioctl_check_extension(ext);
+               r = kvm_arch_dev_ioctl_check_extension(kvm, ext);
                break;
        }
        return r;
@@ -239,7 +240,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
        if (err)
                goto free_vcpu;
 
-       err = create_hyp_mappings(vcpu, vcpu + 1);
+       err = create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP);
        if (err)
                goto vcpu_uninit;
 
@@ -377,7 +378,7 @@ void force_vm_exit(const cpumask_t *mask)
 
 /**
  * need_new_vmid_gen - check that the VMID is still valid
- * @kvm: The VM's VMID to checkt
+ * @kvm: The VM's VMID to check
  *
  * return true if there is a new generation of VMIDs being used
  *
@@ -616,7 +617,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                 * Enter the guest
                 */
                trace_kvm_entry(*vcpu_pc(vcpu));
-               __kvm_guest_enter();
+               guest_enter_irqoff();
                vcpu->mode = IN_GUEST_MODE;
 
                ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
@@ -642,14 +643,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                local_irq_enable();
 
                /*
-                * We do local_irq_enable() before calling kvm_guest_exit() so
+                * We do local_irq_enable() before calling guest_exit() so
                 * that if a timer interrupt hits while running the guest we
                 * account that tick as being spent in the guest.  We enable
-                * preemption after calling kvm_guest_exit() so that if we get
+                * preemption after calling guest_exit() so that if we get
                 * preempted we make sure ticks after that is not counted as
                 * guest time.
                 */
-               kvm_guest_exit();
+               guest_exit();
                trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
 
                /*
@@ -1039,7 +1040,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
 static void cpu_init_hyp_mode(void *dummy)
 {
-       phys_addr_t boot_pgd_ptr;
        phys_addr_t pgd_ptr;
        unsigned long hyp_stack_ptr;
        unsigned long stack_page;
@@ -1048,13 +1048,12 @@ static void cpu_init_hyp_mode(void *dummy)
        /* Switch from the HYP stub to our own HYP init vector */
        __hyp_set_vectors(kvm_get_idmap_vector());
 
-       boot_pgd_ptr = kvm_mmu_get_boot_httbr();
        pgd_ptr = kvm_mmu_get_httbr();
        stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
        hyp_stack_ptr = stack_page + PAGE_SIZE;
        vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
 
-       __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
+       __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
        __cpu_init_stage2();
 
        kvm_arm_init_debug();
@@ -1076,15 +1075,9 @@ static void cpu_hyp_reinit(void)
 
 static void cpu_hyp_reset(void)
 {
-       phys_addr_t boot_pgd_ptr;
-       phys_addr_t phys_idmap_start;
-
-       if (!is_kernel_in_hyp_mode()) {
-               boot_pgd_ptr = kvm_mmu_get_boot_httbr();
-               phys_idmap_start = kvm_get_idmap_start();
-
-               __cpu_reset_hyp_mode(boot_pgd_ptr, phys_idmap_start);
-       }
+       if (!is_kernel_in_hyp_mode())
+               __cpu_reset_hyp_mode(hyp_default_vectors,
+                                    kvm_get_idmap_start());
 }
 
 static void _kvm_arch_hardware_enable(void *discard)
@@ -1294,14 +1287,14 @@ static int init_hyp_mode(void)
         * Map the Hyp-code called directly from the host
         */
        err = create_hyp_mappings(kvm_ksym_ref(__hyp_text_start),
-                                 kvm_ksym_ref(__hyp_text_end));
+                                 kvm_ksym_ref(__hyp_text_end), PAGE_HYP_EXEC);
        if (err) {
                kvm_err("Cannot map world-switch code\n");
                goto out_err;
        }
 
        err = create_hyp_mappings(kvm_ksym_ref(__start_rodata),
-                                 kvm_ksym_ref(__end_rodata));
+                                 kvm_ksym_ref(__end_rodata), PAGE_HYP_RO);
        if (err) {
                kvm_err("Cannot map rodata section\n");
                goto out_err;
@@ -1312,7 +1305,8 @@ static int init_hyp_mode(void)
         */
        for_each_possible_cpu(cpu) {
                char *stack_page = (char *)per_cpu(kvm_arm_hyp_stack_page, cpu);
-               err = create_hyp_mappings(stack_page, stack_page + PAGE_SIZE);
+               err = create_hyp_mappings(stack_page, stack_page + PAGE_SIZE,
+                                         PAGE_HYP);
 
                if (err) {
                        kvm_err("Cannot map hyp stack\n");
@@ -1324,7 +1318,7 @@ static int init_hyp_mode(void)
                kvm_cpu_context_t *cpu_ctxt;
 
                cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu);
-               err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1);
+               err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP);
 
                if (err) {
                        kvm_err("Cannot map host CPU state: %d\n", err);
@@ -1332,10 +1326,6 @@ static int init_hyp_mode(void)
                }
        }
 
-#ifndef CONFIG_HOTPLUG_CPU
-       free_boot_hyp_pgd();
-#endif
-
        /* set size of VMID supported by CPU */
        kvm_vmid_bits = kvm_get_vmid_bits();
        kvm_info("%d-bit VMID\n", kvm_vmid_bits);
index a494def..af93e3f 100644 (file)
@@ -210,7 +210,7 @@ bool kvm_condition_valid(struct kvm_vcpu *vcpu)
  * @vcpu:      The VCPU pointer
  *
  * When exceptions occur while instructions are executed in Thumb IF-THEN
- * blocks, the ITSTATE field of the CPSR is not advanved (updated), so we have
+ * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
  * to do this little bit of work manually. The fields map like this:
  *
  * IT[7:0] -> CPSR[26:25],CPSR[15:10]
index 9093ed0..9aca920 100644 (file)
@@ -182,7 +182,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 /**
  * kvm_arm_copy_reg_indices - get indices of all registers.
  *
- * We do core registers right here, then we apppend coproc regs.
+ * We do core registers right here, then we append coproc regs.
  */
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
index 1f9ae17..bf89c91 100644 (file)
  *       r2,r3 = Hypervisor pgd pointer
  *
  * The init scenario is:
- * - We jump in HYP with four parameters: boot HYP pgd, runtime HYP pgd,
- *   runtime stack, runtime vectors
- * - Enable the MMU with the boot pgd
- * - Jump to a target into the trampoline page (remember, this is the same
- *   physical page!)
- * - Now switch to the runtime pgd (same VA, and still the same physical
- *   page!)
+ * - We jump in HYP with 3 parameters: runtime HYP pgd, runtime stack,
+ *   runtime vectors
  * - Invalidate TLBs
  * - Set stack and vectors
+ * - Setup the page tables
+ * - Enable the MMU
  * - Profit! (or eret, if you only care about the code).
- *
- * As we only have four registers available to pass parameters (and we
- * need six), we split the init in two phases:
- * - Phase 1: r0 = 0, r1 = 0, r2,r3 contain the boot PGD.
- *   Provides the basic HYP init, and enable the MMU.
- * - Phase 2: r0 = ToS, r1 = vectors, r2,r3 contain the runtime PGD.
- *   Switches to the runtime PGD, set stack and vectors.
  */
 
        .text
@@ -68,8 +58,11 @@ __kvm_hyp_init:
        W(b)    .
 
 __do_hyp_init:
-       cmp     r0, #0                  @ We have a SP?
-       bne     phase2                  @ Yes, second stage init
+       @ Set stack pointer
+       mov     sp, r0
+
+       @ Set HVBAR to point to the HYP vectors
+       mcr     p15, 4, r1, c12, c0, 0  @ HVBAR
 
        @ Set the HTTBR to point to the hypervisor PGD pointer passed
        mcrr    p15, 4, rr_lo_hi(r2, r3), c2
@@ -114,34 +107,25 @@ __do_hyp_init:
  THUMB(        ldr     r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_TE)          )
        orr     r1, r1, r2
        orr     r0, r0, r1
-       isb
        mcr     p15, 4, r0, c1, c0, 0   @ HSCR
+       isb
 
-       @ End of init phase-1
        eret
 
-phase2:
-       @ Set stack pointer
-       mov     sp, r0
-
-       @ Set HVBAR to point to the HYP vectors
-       mcr     p15, 4, r1, c12, c0, 0  @ HVBAR
-
-       @ Jump to the trampoline page
-       ldr     r0, =TRAMPOLINE_VA
-       adr     r1, target
-       bfi     r0, r1, #0, #PAGE_SHIFT
-       ret     r0
+       @ r0 : stub vectors address
+ENTRY(__kvm_hyp_reset)
+       /* We're now in idmap, disable MMU */
+       mrc     p15, 4, r1, c1, c0, 0   @ HSCTLR
+       ldr     r2, =(HSCTLR_M | HSCTLR_A | HSCTLR_C | HSCTLR_I)
+       bic     r1, r1, r2
+       mcr     p15, 4, r1, c1, c0, 0   @ HSCTLR
 
-target:        @ We're now in the trampoline code, switch page tables
-       mcrr    p15, 4, rr_lo_hi(r2, r3), c2
+       /* Install stub vectors */
+       mcr     p15, 4, r0, c12, c0, 0  @ HVBAR
        isb
 
-       @ Invalidate the old TLBs
-       mcr     p15, 4, r0, c8, c7, 0   @ TLBIALLH
-       dsb     ish
-
        eret
+ENDPROC(__kvm_hyp_reset)
 
        .ltorg
 
diff --git a/arch/arm/kvm/irq.h b/arch/arm/kvm/irq.h
new file mode 100644 (file)
index 0000000..b74099b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * 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 header is included by irqchip.c. However, on ARM, interrupt
+ * controller declarations are located in include/kvm/arm_vgic.h since
+ * they are mostly shared between arm and arm64.
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include <kvm/arm_vgic.h>
+
+#endif
index 45c43ae..bda27b6 100644 (file)
@@ -32,8 +32,6 @@
 
 #include "trace.h"
 
-extern char  __hyp_idmap_text_start[], __hyp_idmap_text_end[];
-
 static pgd_t *boot_hyp_pgd;
 static pgd_t *hyp_pgd;
 static pgd_t *merged_hyp_pgd;
@@ -483,28 +481,6 @@ static void unmap_hyp_range(pgd_t *pgdp, phys_addr_t start, u64 size)
        } while (pgd++, addr = next, addr != end);
 }
 
-/**
- * free_boot_hyp_pgd - free HYP boot page tables
- *
- * Free the HYP boot page tables. The bounce page is also freed.
- */
-void free_boot_hyp_pgd(void)
-{
-       mutex_lock(&kvm_hyp_pgd_mutex);
-
-       if (boot_hyp_pgd) {
-               unmap_hyp_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
-               unmap_hyp_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
-               free_pages((unsigned long)boot_hyp_pgd, hyp_pgd_order);
-               boot_hyp_pgd = NULL;
-       }
-
-       if (hyp_pgd)
-               unmap_hyp_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
-
-       mutex_unlock(&kvm_hyp_pgd_mutex);
-}
-
 /**
  * free_hyp_pgds - free Hyp-mode page tables
  *
@@ -519,15 +495,20 @@ void free_hyp_pgds(void)
 {
        unsigned long addr;
 
-       free_boot_hyp_pgd();
-
        mutex_lock(&kvm_hyp_pgd_mutex);
 
+       if (boot_hyp_pgd) {
+               unmap_hyp_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
+               free_pages((unsigned long)boot_hyp_pgd, hyp_pgd_order);
+               boot_hyp_pgd = NULL;
+       }
+
        if (hyp_pgd) {
+               unmap_hyp_range(hyp_pgd, hyp_idmap_start, PAGE_SIZE);
                for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE)
-                       unmap_hyp_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
+                       unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE);
                for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
-                       unmap_hyp_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
+                       unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE);
 
                free_pages((unsigned long)hyp_pgd, hyp_pgd_order);
                hyp_pgd = NULL;
@@ -679,17 +660,18 @@ static phys_addr_t kvm_kaddr_to_phys(void *kaddr)
  * create_hyp_mappings - duplicate a kernel virtual address range in Hyp mode
  * @from:      The virtual kernel start address of the range
  * @to:                The virtual kernel end address of the range (exclusive)
+ * @prot:      The protection to be applied to this range
  *
  * The same virtual address as the kernel virtual address is also used
  * in Hyp-mode mapping (modulo HYP_PAGE_OFFSET) to the same underlying
  * physical pages.
  */
-int create_hyp_mappings(void *from, void *to)
+int create_hyp_mappings(void *from, void *to, pgprot_t prot)
 {
        phys_addr_t phys_addr;
        unsigned long virt_addr;
-       unsigned long start = KERN_TO_HYP((unsigned long)from);
-       unsigned long end = KERN_TO_HYP((unsigned long)to);
+       unsigned long start = kern_hyp_va((unsigned long)from);
+       unsigned long end = kern_hyp_va((unsigned long)to);
 
        if (is_kernel_in_hyp_mode())
                return 0;
@@ -704,7 +686,7 @@ int create_hyp_mappings(void *from, void *to)
                err = __create_hyp_mappings(hyp_pgd, virt_addr,
                                            virt_addr + PAGE_SIZE,
                                            __phys_to_pfn(phys_addr),
-                                           PAGE_HYP);
+                                           prot);
                if (err)
                        return err;
        }
@@ -723,8 +705,8 @@ int create_hyp_mappings(void *from, void *to)
  */
 int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
 {
-       unsigned long start = KERN_TO_HYP((unsigned long)from);
-       unsigned long end = KERN_TO_HYP((unsigned long)to);
+       unsigned long start = kern_hyp_va((unsigned long)from);
+       unsigned long end = kern_hyp_va((unsigned long)to);
 
        if (is_kernel_in_hyp_mode())
                return 0;
@@ -1687,14 +1669,6 @@ phys_addr_t kvm_mmu_get_httbr(void)
                return virt_to_phys(hyp_pgd);
 }
 
-phys_addr_t kvm_mmu_get_boot_httbr(void)
-{
-       if (__kvm_cpu_uses_extended_idmap())
-               return virt_to_phys(merged_hyp_pgd);
-       else
-               return virt_to_phys(boot_hyp_pgd);
-}
-
 phys_addr_t kvm_get_idmap_vector(void)
 {
        return hyp_idmap_vector;
@@ -1705,6 +1679,22 @@ phys_addr_t kvm_get_idmap_start(void)
        return hyp_idmap_start;
 }
 
+static int kvm_map_idmap_text(pgd_t *pgd)
+{
+       int err;
+
+       /* Create the idmap in the boot page tables */
+       err =   __create_hyp_mappings(pgd,
+                                     hyp_idmap_start, hyp_idmap_end,
+                                     __phys_to_pfn(hyp_idmap_start),
+                                     PAGE_HYP_EXEC);
+       if (err)
+               kvm_err("Failed to idmap %lx-%lx\n",
+                       hyp_idmap_start, hyp_idmap_end);
+
+       return err;
+}
+
 int kvm_mmu_init(void)
 {
        int err;
@@ -1719,28 +1709,41 @@ int kvm_mmu_init(void)
         */
        BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
 
-       hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, hyp_pgd_order);
-       boot_hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, hyp_pgd_order);
+       kvm_info("IDMAP page: %lx\n", hyp_idmap_start);
+       kvm_info("HYP VA range: %lx:%lx\n",
+                kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
 
-       if (!hyp_pgd || !boot_hyp_pgd) {
-               kvm_err("Hyp mode PGD not allocated\n");
-               err = -ENOMEM;
+       if (hyp_idmap_start >= kern_hyp_va(PAGE_OFFSET) &&
+           hyp_idmap_start <  kern_hyp_va(~0UL)) {
+               /*
+                * The idmap page is intersecting with the VA space,
+                * it is not safe to continue further.
+                */
+               kvm_err("IDMAP intersecting with HYP VA, unable to continue\n");
+               err = -EINVAL;
                goto out;
        }
 
-       /* Create the idmap in the boot page tables */
-       err =   __create_hyp_mappings(boot_hyp_pgd,
-                                     hyp_idmap_start, hyp_idmap_end,
-                                     __phys_to_pfn(hyp_idmap_start),
-                                     PAGE_HYP);
-
-       if (err) {
-               kvm_err("Failed to idmap %lx-%lx\n",
-                       hyp_idmap_start, hyp_idmap_end);
+       hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, hyp_pgd_order);
+       if (!hyp_pgd) {
+               kvm_err("Hyp mode PGD not allocated\n");
+               err = -ENOMEM;
                goto out;
        }
 
        if (__kvm_cpu_uses_extended_idmap()) {
+               boot_hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+                                                        hyp_pgd_order);
+               if (!boot_hyp_pgd) {
+                       kvm_err("Hyp boot PGD not allocated\n");
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               err = kvm_map_idmap_text(boot_hyp_pgd);
+               if (err)
+                       goto out;
+
                merged_hyp_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
                if (!merged_hyp_pgd) {
                        kvm_err("Failed to allocate extra HYP pgd\n");
@@ -1748,29 +1751,10 @@ int kvm_mmu_init(void)
                }
                __kvm_extend_hypmap(boot_hyp_pgd, hyp_pgd, merged_hyp_pgd,
                                    hyp_idmap_start);
-               return 0;
-       }
-
-       /* Map the very same page at the trampoline VA */
-       err =   __create_hyp_mappings(boot_hyp_pgd,
-                                     TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
-                                     __phys_to_pfn(hyp_idmap_start),
-                                     PAGE_HYP);
-       if (err) {
-               kvm_err("Failed to map trampoline @%lx into boot HYP pgd\n",
-                       TRAMPOLINE_VA);
-               goto out;
-       }
-
-       /* Map the same page again into the runtime page tables */
-       err =   __create_hyp_mappings(hyp_pgd,
-                                     TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
-                                     __phys_to_pfn(hyp_idmap_start),
-                                     PAGE_HYP);
-       if (err) {
-               kvm_err("Failed to map trampoline @%lx into runtime HYP pgd\n",
-                       TRAMPOLINE_VA);
-               goto out;
+       } else {
+               err = kvm_map_idmap_text(hyp_pgd);
+               if (err)
+                       goto out;
        }
 
        return 0;
index 0048b5a..4b5e802 100644 (file)
@@ -52,7 +52,7 @@ static const struct kvm_irq_level cortexa_vtimer_irq = {
  * @vcpu: The VCPU pointer
  *
  * This function finds the right table above and sets the registers on the
- * virtual CPU struct to their architectually defined reset values.
+ * virtual CPU struct to their architecturally defined reset values.
  */
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
index 45b81a2..3b39ea3 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/m48t86.h>
+#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
index 38b0da3..ed9a014 100644 (file)
@@ -320,11 +320,11 @@ static struct impd1_device impd1_devs[] = {
 #define IMPD1_VALID_IRQS 0x00000bffU
 
 /*
- * As this module is bool, it is OK to have this as __init_refok() - no
+ * As this module is bool, it is OK to have this as __ref() - no
  * probe calls will be done after the initial system bootup, as devices
  * are discovered as part of the machine startup.
  */
-static int __init_refok impd1_probe(struct lm_device *dev)
+static int __ref impd1_probe(struct lm_device *dev)
 {
        struct impd1_module *impd1;
        int irq_base;
index 45a0520..6af5430 100644 (file)
@@ -343,7 +343,7 @@ void __init mv78xx0_init_early(void)
                                DDR_WINDOW_CPU1_BASE, DDR_WINDOW_CPU_SZ);
 }
 
-void __init_refok mv78xx0_timer_init(void)
+void __ref mv78xx0_timer_init(void)
 {
        orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
                        IRQ_MV78XX0_TIMER_1, get_tclk());
index c2626f8..e920dd8 100644 (file)
@@ -209,7 +209,7 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
        int err;
 
        switch (event) {
-       case BUS_NOTIFY_DEL_DEVICE:
+       case BUS_NOTIFY_REMOVED_DEVICE:
                if (pdev->archdata.od)
                        omap_device_delete(pdev->archdata.od);
                break;
index 3a58a5d..8d59726 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
-#include <linux/m48t86.h>
+#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timeriomem-rng.h>
index fa5f51d..be4a661 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/delay.h>
 
-#include <linux/rtc-v3020.h>
+#include <linux/platform_data/rtc-v3020.h>
 #include <video/mbxfb.h>
 
 #include <linux/spi/spi.h>
index 5f5ac7c..868448d 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
 #include <linux/leds.h>
-#include <linux/rtc-v3020.h>
+#include <linux/platform_data/rtc-v3020.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 
index 6e0268d..03354c2 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/delay.h>
 
 #include <linux/dm9000.h>
-#include <linux/rtc-v3020.h>
+#include <linux/platform_data/rtc-v3020.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
index b7eed75..c6834c0 100644 (file)
@@ -128,16 +128,16 @@ static void __dma_page_dev_to_cpu(struct page *, unsigned long,
  */
 static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
             unsigned long offset, size_t size, enum dma_data_direction dir,
-            struct dma_attrs *attrs)
+            unsigned long attrs)
 {
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __dma_page_cpu_to_dev(page, offset, size, dir);
        return pfn_to_dma(dev, page_to_pfn(page)) + offset;
 }
 
 static dma_addr_t arm_coherent_dma_map_page(struct device *dev, struct page *page,
             unsigned long offset, size_t size, enum dma_data_direction dir,
-            struct dma_attrs *attrs)
+            unsigned long attrs)
 {
        return pfn_to_dma(dev, page_to_pfn(page)) + offset;
 }
@@ -157,10 +157,9 @@ static dma_addr_t arm_coherent_dma_map_page(struct device *dev, struct page *pag
  * whatever the device wrote there.
  */
 static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
-               size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
                                      handle & ~PAGE_MASK, size, dir);
 }
@@ -198,12 +197,12 @@ struct dma_map_ops arm_dma_ops = {
 EXPORT_SYMBOL(arm_dma_ops);
 
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
-       dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
+       dma_addr_t *handle, gfp_t gfp, unsigned long attrs);
 static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
-                                 dma_addr_t handle, struct dma_attrs *attrs);
+                                 dma_addr_t handle, unsigned long attrs);
 static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                 void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                struct dma_attrs *attrs);
+                unsigned long attrs);
 
 struct dma_map_ops arm_coherent_dma_ops = {
        .alloc                  = arm_coherent_dma_alloc,
@@ -639,11 +638,11 @@ static void __free_from_contiguous(struct device *dev, struct page *page,
        dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
 }
 
-static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
+static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot)
 {
-       prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
-                           pgprot_writecombine(prot) :
-                           pgprot_dmacoherent(prot);
+       prot = (attrs & DMA_ATTR_WRITE_COMBINE) ?
+                       pgprot_writecombine(prot) :
+                       pgprot_dmacoherent(prot);
        return prot;
 }
 
@@ -751,7 +750,7 @@ static struct arm_dma_allocator remap_allocator = {
 
 static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                         gfp_t gfp, pgprot_t prot, bool is_coherent,
-                        struct dma_attrs *attrs, const void *caller)
+                        unsigned long attrs, const void *caller)
 {
        u64 mask = get_coherent_dma_mask(dev);
        struct page *page = NULL;
@@ -764,7 +763,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                .gfp = gfp,
                .prot = prot,
                .caller = caller,
-               .want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs),
+               .want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),
                .coherent_flag = is_coherent ? COHERENT : NORMAL,
        };
 
@@ -834,7 +833,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
  * virtual and bus address for that space.
  */
 void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-                   gfp_t gfp, struct dma_attrs *attrs)
+                   gfp_t gfp, unsigned long attrs)
 {
        pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
 
@@ -843,7 +842,7 @@ void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 }
 
 static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
-       dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+       dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
 {
        return __dma_alloc(dev, size, handle, gfp, PAGE_KERNEL, true,
                           attrs, __builtin_return_address(0));
@@ -851,7 +850,7 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
 
 static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                 void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 {
        int ret = -ENXIO;
 #ifdef CONFIG_MMU
@@ -879,14 +878,14 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
  */
 static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                 void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 {
        return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
 }
 
 int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                 void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 {
 #ifdef CONFIG_MMU
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
@@ -898,7 +897,7 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
  * Free a buffer as defined by the above mapping.
  */
 static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
-                          dma_addr_t handle, struct dma_attrs *attrs,
+                          dma_addr_t handle, unsigned long attrs,
                           bool is_coherent)
 {
        struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
@@ -908,7 +907,7 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
                .size = PAGE_ALIGN(size),
                .cpu_addr = cpu_addr,
                .page = page,
-               .want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs),
+               .want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),
        };
 
        buf = arm_dma_buffer_find(cpu_addr);
@@ -920,20 +919,20 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
 }
 
 void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
-                 dma_addr_t handle, struct dma_attrs *attrs)
+                 dma_addr_t handle, unsigned long attrs)
 {
        __arm_dma_free(dev, size, cpu_addr, handle, attrs, false);
 }
 
 static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
-                                 dma_addr_t handle, struct dma_attrs *attrs)
+                                 dma_addr_t handle, unsigned long attrs)
 {
        __arm_dma_free(dev, size, cpu_addr, handle, attrs, true);
 }
 
 int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
                 void *cpu_addr, dma_addr_t handle, size_t size,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 {
        struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
        int ret;
@@ -1066,7 +1065,7 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
  * here.
  */
 int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-               enum dma_data_direction dir, struct dma_attrs *attrs)
+               enum dma_data_direction dir, unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        struct scatterlist *s;
@@ -1100,7 +1099,7 @@ int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
  * rules concerning calls here are the same as for dma_unmap_single().
  */
 void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-               enum dma_data_direction dir, struct dma_attrs *attrs)
+               enum dma_data_direction dir, unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        struct scatterlist *s;
@@ -1273,7 +1272,7 @@ static inline void __free_iova(struct dma_iommu_mapping *mapping,
 static const int iommu_order_array[] = { 9, 8, 4, 0 };
 
 static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
-                                         gfp_t gfp, struct dma_attrs *attrs,
+                                         gfp_t gfp, unsigned long attrs,
                                          int coherent_flag)
 {
        struct page **pages;
@@ -1289,7 +1288,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
        if (!pages)
                return NULL;
 
-       if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs))
+       if (attrs & DMA_ATTR_FORCE_CONTIGUOUS)
        {
                unsigned long order = get_order(size);
                struct page *page;
@@ -1307,7 +1306,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
        }
 
        /* Go straight to 4K chunks if caller says it's OK. */
-       if (dma_get_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, attrs))
+       if (attrs & DMA_ATTR_ALLOC_SINGLE_PAGES)
                order_idx = ARRAY_SIZE(iommu_order_array) - 1;
 
        /*
@@ -1363,12 +1362,12 @@ error:
 }
 
 static int __iommu_free_buffer(struct device *dev, struct page **pages,
-                              size_t size, struct dma_attrs *attrs)
+                              size_t size, unsigned long attrs)
 {
        int count = size >> PAGE_SHIFT;
        int i;
 
-       if (dma_get_attr(DMA_ATTR_FORCE_CONTIGUOUS, attrs)) {
+       if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
                dma_release_from_contiguous(dev, pages[0], count);
        } else {
                for (i = 0; i < count; i++)
@@ -1460,14 +1459,14 @@ static struct page **__atomic_get_pages(void *addr)
        return (struct page **)page;
 }
 
-static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
+static struct page **__iommu_get_pages(void *cpu_addr, unsigned long attrs)
 {
        struct vm_struct *area;
 
        if (__in_atomic_pool(cpu_addr, PAGE_SIZE))
                return __atomic_get_pages(cpu_addr);
 
-       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
                return cpu_addr;
 
        area = find_vm_area(cpu_addr);
@@ -1511,7 +1510,7 @@ static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
 }
 
 static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
-           dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs,
+           dma_addr_t *handle, gfp_t gfp, unsigned long attrs,
            int coherent_flag)
 {
        pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
@@ -1542,7 +1541,7 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
        if (*handle == DMA_ERROR_CODE)
                goto err_buffer;
 
-       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs))
+       if (attrs & DMA_ATTR_NO_KERNEL_MAPPING)
                return pages;
 
        addr = __iommu_alloc_remap(pages, size, gfp, prot,
@@ -1560,20 +1559,20 @@ err_buffer:
 }
 
 static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
-                   dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+           dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
 {
        return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, NORMAL);
 }
 
 static void *arm_coherent_iommu_alloc_attrs(struct device *dev, size_t size,
-                   dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+                   dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
 {
        return __arm_iommu_alloc_attrs(dev, size, handle, gfp, attrs, COHERENT);
 }
 
 static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                   struct dma_attrs *attrs)
+                   unsigned long attrs)
 {
        unsigned long uaddr = vma->vm_start;
        unsigned long usize = vma->vm_end - vma->vm_start;
@@ -1603,7 +1602,7 @@ static int __arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma
 }
 static int arm_iommu_mmap_attrs(struct device *dev,
                struct vm_area_struct *vma, void *cpu_addr,
-               dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+               dma_addr_t dma_addr, size_t size, unsigned long attrs)
 {
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
 
@@ -1612,7 +1611,7 @@ static int arm_iommu_mmap_attrs(struct device *dev,
 
 static int arm_coherent_iommu_mmap_attrs(struct device *dev,
                struct vm_area_struct *vma, void *cpu_addr,
-               dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+               dma_addr_t dma_addr, size_t size, unsigned long attrs)
 {
        return __arm_iommu_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
 }
@@ -1622,7 +1621,7 @@ static int arm_coherent_iommu_mmap_attrs(struct device *dev,
  * Must not be called with IRQs disabled.
  */
 void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
-       dma_addr_t handle, struct dma_attrs *attrs, int coherent_flag)
+       dma_addr_t handle, unsigned long attrs, int coherent_flag)
 {
        struct page **pages;
        size = PAGE_ALIGN(size);
@@ -1638,7 +1637,7 @@ void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                return;
        }
 
-       if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
+       if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0) {
                dma_common_free_remap(cpu_addr, size,
                        VM_ARM_DMA_CONSISTENT | VM_USERMAP);
        }
@@ -1648,20 +1647,20 @@ void __arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 }
 
 void arm_iommu_free_attrs(struct device *dev, size_t size,
-                   void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
+                   void *cpu_addr, dma_addr_t handle, unsigned long attrs)
 {
        __arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, NORMAL);
 }
 
 void arm_coherent_iommu_free_attrs(struct device *dev, size_t size,
-                   void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
+                   void *cpu_addr, dma_addr_t handle, unsigned long attrs)
 {
        __arm_iommu_free_attrs(dev, size, cpu_addr, handle, attrs, COHERENT);
 }
 
 static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
                                 void *cpu_addr, dma_addr_t dma_addr,
-                                size_t size, struct dma_attrs *attrs)
+                                size_t size, unsigned long attrs)
 {
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page **pages = __iommu_get_pages(cpu_addr, attrs);
@@ -1699,7 +1698,7 @@ static int __dma_direction_to_prot(enum dma_data_direction dir)
  */
 static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                          size_t size, dma_addr_t *handle,
-                         enum dma_data_direction dir, struct dma_attrs *attrs,
+                         enum dma_data_direction dir, unsigned long attrs,
                          bool is_coherent)
 {
        struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
@@ -1720,8 +1719,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
                phys_addr_t phys = page_to_phys(sg_page(s));
                unsigned int len = PAGE_ALIGN(s->offset + s->length);
 
-               if (!is_coherent &&
-                       !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+               if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                        __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
 
                prot = __dma_direction_to_prot(dir);
@@ -1742,7 +1740,7 @@ fail:
 }
 
 static int __iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-                    enum dma_data_direction dir, struct dma_attrs *attrs,
+                    enum dma_data_direction dir, unsigned long attrs,
                     bool is_coherent)
 {
        struct scatterlist *s = sg, *dma = sg, *start = sg;
@@ -1800,7 +1798,7 @@ bad_mapping:
  * obtained via sg_dma_{address,length}.
  */
 int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+               int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        return __iommu_map_sg(dev, sg, nents, dir, attrs, true);
 }
@@ -1818,14 +1816,14 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg,
  * sg_dma_{address,length}.
  */
 int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+               int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        return __iommu_map_sg(dev, sg, nents, dir, attrs, false);
 }
 
 static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs,
-               bool is_coherent)
+               int nents, enum dma_data_direction dir,
+               unsigned long attrs, bool is_coherent)
 {
        struct scatterlist *s;
        int i;
@@ -1834,8 +1832,7 @@ static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
                if (sg_dma_len(s))
                        __iommu_remove_mapping(dev, sg_dma_address(s),
                                               sg_dma_len(s));
-               if (!is_coherent &&
-                   !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+               if (!is_coherent && (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                        __dma_page_dev_to_cpu(sg_page(s), s->offset,
                                              s->length, dir);
        }
@@ -1852,7 +1849,8 @@ static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
  * rules concerning calls here are the same as for dma_unmap_single().
  */
 void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+               int nents, enum dma_data_direction dir,
+               unsigned long attrs)
 {
        __iommu_unmap_sg(dev, sg, nents, dir, attrs, true);
 }
@@ -1868,7 +1866,8 @@ void arm_coherent_iommu_unmap_sg(struct device *dev, struct scatterlist *sg,
  * rules concerning calls here are the same as for dma_unmap_single().
  */
 void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-                       enum dma_data_direction dir, struct dma_attrs *attrs)
+                       enum dma_data_direction dir,
+                       unsigned long attrs)
 {
        __iommu_unmap_sg(dev, sg, nents, dir, attrs, false);
 }
@@ -1921,7 +1920,7 @@ void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
  */
 static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *page,
             unsigned long offset, size_t size, enum dma_data_direction dir,
-            struct dma_attrs *attrs)
+            unsigned long attrs)
 {
        struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t dma_addr;
@@ -1955,9 +1954,9 @@ fail:
  */
 static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
             unsigned long offset, size_t size, enum dma_data_direction dir,
-            struct dma_attrs *attrs)
+            unsigned long attrs)
 {
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __dma_page_cpu_to_dev(page, offset, size, dir);
 
        return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
@@ -1973,8 +1972,7 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
  * Coherent IOMMU aware version of arm_dma_unmap_page()
  */
 static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
-               size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
@@ -1998,8 +1996,7 @@ static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle,
  * IOMMU aware version of arm_dma_unmap_page()
  */
 static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
-               size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
        dma_addr_t iova = handle & PAGE_MASK;
@@ -2010,7 +2007,7 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
        if (!iova)
                return;
 
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __dma_page_dev_to_cpu(page, offset, size, dir);
 
        iommu_unmap(mapping->domain, iova, len);
index c5f9a9e..d062f08 100644 (file)
@@ -98,11 +98,11 @@ static void __xen_dma_page_cpu_to_dev(struct device *hwdev, dma_addr_t handle,
 
 void __xen_dma_map_page(struct device *hwdev, struct page *page,
             dma_addr_t dev_addr, unsigned long offset, size_t size,
-            enum dma_data_direction dir, struct dma_attrs *attrs)
+            enum dma_data_direction dir, unsigned long attrs)
 {
        if (is_device_dma_coherent(hwdev))
                return;
-       if (dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if (attrs & DMA_ATTR_SKIP_CPU_SYNC)
                return;
 
        __xen_dma_page_cpu_to_dev(hwdev, dev_addr, size, dir);
@@ -110,12 +110,12 @@ void __xen_dma_map_page(struct device *hwdev, struct page *page,
 
 void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 
 {
        if (is_device_dma_coherent(hwdev))
                return;
-       if (dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if (attrs & DMA_ATTR_SKIP_CPU_SYNC)
                return;
 
        __xen_dma_page_dev_to_cpu(hwdev, handle, size, dir);
index 9f8b99e..bc3f00f 100644 (file)
@@ -3,6 +3,7 @@ config ARM64
        select ACPI_CCA_REQUIRED if ACPI
        select ACPI_GENERIC_GSI if ACPI
        select ACPI_REDUCED_HARDWARE_ONLY if ACPI
+       select ACPI_MCFG if ACPI
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -22,9 +23,9 @@ config ARM64
        select ARM_ARCH_TIMER
        select ARM_GIC
        select AUDIT_ARCH_COMPAT_GENERIC
-       select ARM_GIC_V2M if PCI_MSI
+       select ARM_GIC_V2M if PCI
        select ARM_GIC_V3
-       select ARM_GIC_V3_ITS if PCI_MSI
+       select ARM_GIC_V3_ITS if PCI
        select ARM_PSCI_FW
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
@@ -53,6 +54,7 @@ config ARM64
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_BITREVERSE
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_HUGE_VMAP
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
@@ -78,6 +80,7 @@ config ARM64
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_GCC_PLUGINS
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
        select HAVE_IRQ_TIME_ACCOUNTING
@@ -101,6 +104,7 @@ config ARM64
        select OF_EARLY_FLATTREE
        select OF_NUMA if NUMA && OF
        select OF_RESERVED_MEM
+       select PCI_ECAM if ACPI
        select PERF_USE_VMALLOC
        select POWER_RESET
        select POWER_SUPPLY
index d59b690..5b54f8c 100644 (file)
@@ -15,7 +15,7 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 GZFLAGS                :=-9
 
 ifneq ($(CONFIG_RELOCATABLE),)
-LDFLAGS_vmlinux                += -pie
+LDFLAGS_vmlinux                += -pie -Bsymbolic
 endif
 
 KBUILD_DEFCONFIG := defconfig
index 86110a6..1372e9a 100644 (file)
@@ -76,3 +76,8 @@
 &usb3 {
        status = "okay";
 };
+
+/* CON17 (PCIe) / CON12 (mini-PCIe) */
+&pcie0 {
+       status = "okay";
+};
index eb29280..c476253 100644 (file)
                                      <0x1d40000 0x40000>; /* GICR */
                        };
                };
+
+               pcie0: pcie@d0070000 {
+                       compatible = "marvell,armada-3700-pcie";
+                       device_type = "pci";
+                       status = "disabled";
+                       reg = <0 0xd0070000 0 0x20000>;
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       bus-range = <0x00 0xff>;
+                       interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+                       #interrupt-cells = <1>;
+                       msi-parent = <&pcie0>;
+                       msi-controller;
+                       ranges = <0x82000000 0 0xe8000000   0 0xe8000000 0 0x1000000 /* Port 0 MEM */
+                                 0x81000000 0 0xe9000000   0 0xe9000000 0 0x10000>; /* Port 0 IO*/
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0 0 0 1 &pcie_intc 0>,
+                                       <0 0 0 2 &pcie_intc 1>,
+                                       <0 0 0 3 &pcie_intc 2>,
+                                       <0 0 0 4 &pcie_intc 3>;
+                       pcie_intc: interrupt-controller {
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+               };
        };
 };
index 49dd1bd..7099f26 100644 (file)
@@ -36,8 +36,9 @@
 #define ARM64_HAS_VIRT_HOST_EXTN               11
 #define ARM64_WORKAROUND_CAVIUM_27456          12
 #define ARM64_HAS_32BIT_EL0                    13
+#define ARM64_HYP_OFFSET_LOW                   14
 
-#define ARM64_NCAPS                            14
+#define ARM64_NCAPS                            15
 
 #ifndef __ASSEMBLY__
 
index 579b6e6..a55384f 100644 (file)
@@ -140,6 +140,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 
 #define SET_PERSONALITY(ex)            clear_thread_flag(TIF_32BIT);
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO                                                    \
 do {                                                                   \
        NEW_AUX_ENT(AT_SYSINFO_EHDR,                                    \
index 2cdb6b5..4b5c977 100644 (file)
 /* Hyp System Trap Register */
 #define HSTR_EL2_T(x)  (1 << x)
 
-/* Hyp Coproccessor Trap Register Shifts */
+/* Hyp Coprocessor Trap Register Shifts */
 #define CPTR_EL2_TFP_SHIFT 10
 
 /* Hyp Coprocessor Trap Register */
index 49095fc..3eda975 100644 (file)
@@ -47,8 +47,7 @@
 
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
-int kvm_arch_dev_ioctl_check_extension(long ext);
-unsigned long kvm_hyp_reset_entry(void);
+int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext);
 void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
 
 struct kvm_arch {
@@ -348,8 +347,7 @@ int kvm_perf_teardown(void);
 
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
-static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
-                                      phys_addr_t pgd_ptr,
+static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
                                       unsigned long hyp_stack_ptr,
                                       unsigned long vector_ptr)
 {
@@ -357,19 +355,14 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
         * Call initialization code, and switch to the full blown
         * HYP code.
         */
-       __kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
-                      hyp_stack_ptr, vector_ptr);
+       __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
 }
 
-static inline void __cpu_reset_hyp_mode(phys_addr_t boot_pgd_ptr,
+void __kvm_hyp_teardown(void);
+static inline void __cpu_reset_hyp_mode(unsigned long vector_ptr,
                                        phys_addr_t phys_idmap_start)
 {
-       /*
-        * Call reset code, and switch back to stub hyp vectors.
-        * Uses __kvm_call_hyp() to avoid kaslr's kvm_ksym_ref() translation.
-        */
-       __kvm_call_hyp((void *)kvm_hyp_reset_entry(),
-                      boot_pgd_ptr, phys_idmap_start);
+       kvm_call_hyp(__kvm_hyp_teardown, phys_idmap_start);
 }
 
 static inline void kvm_arch_hardware_unsetup(void) {}
index 44eaff7..cff5105 100644 (file)
 
 #define __hyp_text __section(.hyp.text) notrace
 
-static inline unsigned long __kern_hyp_va(unsigned long v)
-{
-       asm volatile(ALTERNATIVE("and %0, %0, %1",
-                                "nop",
-                                ARM64_HAS_VIRT_HOST_EXTN)
-                    : "+r" (v) : "i" (HYP_PAGE_OFFSET_MASK));
-       return v;
-}
-
-#define kern_hyp_va(v) (typeof(v))(__kern_hyp_va((unsigned long)(v)))
-
-static inline unsigned long __hyp_kern_va(unsigned long v)
-{
-       u64 offset = PAGE_OFFSET - HYP_PAGE_OFFSET;
-       asm volatile(ALTERNATIVE("add %0, %0, %1",
-                                "nop",
-                                ARM64_HAS_VIRT_HOST_EXTN)
-                    : "+r" (v) : "r" (offset));
-       return v;
-}
-
-#define hyp_kern_va(v) (typeof(v))(__hyp_kern_va((unsigned long)(v)))
-
 #define read_sysreg_elx(r,nvh,vh)                                      \
        ({                                                              \
                u64 reg;                                                \
index f05ac27..b6bb834 100644 (file)
  *
  * Instead, give the HYP mode its own VA region at a fixed offset from
  * the kernel by just masking the top bits (which are all ones for a
- * kernel address).
+ * kernel address). We need to find out how many bits to mask.
  *
- * ARMv8.1 (using VHE) does have a TTBR1_EL2, and doesn't use these
- * macros (the entire kernel runs at EL2).
+ * We want to build a set of page tables that cover both parts of the
+ * idmap (the trampoline page used to initialize EL2), and our normal
+ * runtime VA space, at the same time.
+ *
+ * Given that the kernel uses VA_BITS for its entire address space,
+ * and that half of that space (VA_BITS - 1) is used for the linear
+ * mapping, we can also limit the EL2 space to (VA_BITS - 1).
+ *
+ * The main question is "Within the VA_BITS space, does EL2 use the
+ * top or the bottom half of that space to shadow the kernel's linear
+ * mapping?". As we need to idmap the trampoline page, this is
+ * determined by the range in which this page lives.
+ *
+ * If the page is in the bottom half, we have to use the top half. If
+ * the page is in the top half, we have to use the bottom half:
+ *
+ * T = __virt_to_phys(__hyp_idmap_text_start)
+ * if (T & BIT(VA_BITS - 1))
+ *     HYP_VA_MIN = 0  //idmap in upper half
+ * else
+ *     HYP_VA_MIN = 1 << (VA_BITS - 1)
+ * HYP_VA_MAX = HYP_VA_MIN + (1 << (VA_BITS - 1)) - 1
+ *
+ * This of course assumes that the trampoline page exists within the
+ * VA_BITS range. If it doesn't, then it means we're in the odd case
+ * where the kernel idmap (as well as HYP) uses more levels than the
+ * kernel runtime page tables (as seen when the kernel is configured
+ * for 4k pages, 39bits VA, and yet memory lives just above that
+ * limit, forcing the idmap to use 4 levels of page tables while the
+ * kernel itself only uses 3). In this particular case, it doesn't
+ * matter which side of VA_BITS we use, as we're guaranteed not to
+ * conflict with anything.
+ *
+ * When using VHE, there are no separate hyp mappings and all KVM
+ * functionality is already mapped as part of the main kernel
+ * mappings, and none of this applies in that case.
  */
-#define HYP_PAGE_OFFSET_SHIFT  VA_BITS
-#define HYP_PAGE_OFFSET_MASK   ((UL(1) << HYP_PAGE_OFFSET_SHIFT) - 1)
-#define HYP_PAGE_OFFSET                (PAGE_OFFSET & HYP_PAGE_OFFSET_MASK)
 
-/*
- * Our virtual mapping for the idmap-ed MMU-enable code. Must be
- * shared across all the page-tables. Conveniently, we use the last
- * possible page, where no kernel mapping will ever exist.
- */
-#define TRAMPOLINE_VA          (HYP_PAGE_OFFSET_MASK & PAGE_MASK)
+#define HYP_PAGE_OFFSET_HIGH_MASK      ((UL(1) << VA_BITS) - 1)
+#define HYP_PAGE_OFFSET_LOW_MASK       ((UL(1) << (VA_BITS - 1)) - 1)
 
 #ifdef __ASSEMBLY__
 
 /*
  * Convert a kernel VA into a HYP VA.
  * reg: VA to be converted.
+ *
+ * This generates the following sequences:
+ * - High mask:
+ *             and x0, x0, #HYP_PAGE_OFFSET_HIGH_MASK
+ *             nop
+ * - Low mask:
+ *             and x0, x0, #HYP_PAGE_OFFSET_HIGH_MASK
+ *             and x0, x0, #HYP_PAGE_OFFSET_LOW_MASK
+ * - VHE:
+ *             nop
+ *             nop
+ *
+ * The "low mask" version works because the mask is a strict subset of
+ * the "high mask", hence performing the first mask for nothing.
+ * Should be completely invisible on any viable CPU.
  */
 .macro kern_hyp_va     reg
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN    
-       and     \reg, \reg, #HYP_PAGE_OFFSET_MASK
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
+       and     \reg, \reg, #HYP_PAGE_OFFSET_HIGH_MASK
 alternative_else
        nop
 alternative_endif
+alternative_if_not ARM64_HYP_OFFSET_LOW
+       nop
+alternative_else
+       and     \reg, \reg, #HYP_PAGE_OFFSET_LOW_MASK
+alternative_endif
 .endm
 
 #else
@@ -70,7 +117,22 @@ alternative_endif
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 
-#define KERN_TO_HYP(kva)       ((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OFFSET)
+static inline unsigned long __kern_hyp_va(unsigned long v)
+{
+       asm volatile(ALTERNATIVE("and %0, %0, %1",
+                                "nop",
+                                ARM64_HAS_VIRT_HOST_EXTN)
+                    : "+r" (v)
+                    : "i" (HYP_PAGE_OFFSET_HIGH_MASK));
+       asm volatile(ALTERNATIVE("nop",
+                                "and %0, %0, %1",
+                                ARM64_HYP_OFFSET_LOW)
+                    : "+r" (v)
+                    : "i" (HYP_PAGE_OFFSET_LOW_MASK));
+       return v;
+}
+
+#define kern_hyp_va(v)         (typeof(v))(__kern_hyp_va((unsigned long)(v)))
 
 /*
  * We currently only support a 40bit IPA.
@@ -81,9 +143,8 @@ alternative_endif
 
 #include <asm/stage2_pgtable.h>
 
-int create_hyp_mappings(void *from, void *to);
+int create_hyp_mappings(void *from, void *to, pgprot_t prot);
 int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
-void free_boot_hyp_pgd(void);
 void free_hyp_pgds(void);
 
 void stage2_unmap_vm(struct kvm *kvm);
@@ -97,7 +158,6 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
 void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
 
 phys_addr_t kvm_mmu_get_httbr(void);
-phys_addr_t kvm_mmu_get_boot_httbr(void);
 phys_addr_t kvm_get_idmap_vector(void);
 phys_addr_t kvm_get_idmap_start(void);
 int kvm_mmu_init(void);
index 2813748..c3ae239 100644 (file)
 #define PTE_CONT               (_AT(pteval_t, 1) << 52)        /* Contiguous range */
 #define PTE_PXN                        (_AT(pteval_t, 1) << 53)        /* Privileged XN */
 #define PTE_UXN                        (_AT(pteval_t, 1) << 54)        /* User XN */
+#define PTE_HYP_XN             (_AT(pteval_t, 1) << 54)        /* HYP XN */
 
 /*
  * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers).
index 29fcb33..39f5252 100644 (file)
@@ -55,7 +55,9 @@
 #define PAGE_KERNEL_EXEC       __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_EXEC_CONT  __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
 
-#define PAGE_HYP               __pgprot(_PAGE_DEFAULT | PTE_HYP)
+#define PAGE_HYP               __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
+#define PAGE_HYP_EXEC          __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
+#define PAGE_HYP_RO            __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
 #define PAGE_HYP_DEVICE                __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
 
 #define PAGE_S2                        __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
index 46472a9..e20bd43 100644 (file)
@@ -224,6 +224,23 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        set_pte(ptep, pte);
 }
 
+#define __HAVE_ARCH_PTE_SAME
+static inline int pte_same(pte_t pte_a, pte_t pte_b)
+{
+       pteval_t lhs, rhs;
+
+       lhs = pte_val(pte_a);
+       rhs = pte_val(pte_b);
+
+       if (pte_present(pte_a))
+               lhs &= ~PTE_RDONLY;
+
+       if (pte_present(pte_b))
+               rhs &= ~PTE_RDONLY;
+
+       return (lhs == rhs);
+}
+
 /*
  * Huge pte definitions.
  */
index 5e834d1..c47257c 100644 (file)
@@ -265,22 +265,25 @@ extern unsigned long __must_check __clear_user(void __user *addr, unsigned long
 static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        kasan_check_write(to, n);
-       return  __arch_copy_from_user(to, from, n);
+       check_object_size(to, n, false);
+       return __arch_copy_from_user(to, from, n);
 }
 
 static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        kasan_check_read(from, n);
-       return  __arch_copy_to_user(to, from, n);
+       check_object_size(from, n, true);
+       return __arch_copy_to_user(to, from, n);
 }
 
 static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        kasan_check_write(to, n);
 
-       if (access_ok(VERIFY_READ, from, n))
+       if (access_ok(VERIFY_READ, from, n)) {
+               check_object_size(to, n, false);
                n = __arch_copy_from_user(to, from, n);
-       else /* security hole - plug it */
+       else /* security hole - plug it */
                memset(to, 0, n);
        return n;
 }
@@ -289,8 +292,10 @@ static inline unsigned long __must_check copy_to_user(void __user *to, const voi
 {
        kasan_check_read(from, n);
 
-       if (access_ok(VERIFY_WRITE, to, n))
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               check_object_size(from, n, true);
                n = __arch_copy_to_user(to, from, n);
+       }
        return n;
 }
 
index bbc6a8c..1788545 100644 (file)
@@ -87,6 +87,10 @@ extern void verify_cpu_run_el(void);
 static inline void verify_cpu_run_el(void) {}
 #endif
 
+/* The section containing the hypervisor idmap text */
+extern char __hyp_idmap_text_start[];
+extern char __hyp_idmap_text_end[];
+
 /* The section containing the hypervisor text */
 extern char __hyp_text_start[];
 extern char __hyp_text_end[];
index 22d6d88..4cf0c17 100644 (file)
@@ -19,4 +19,6 @@
 /* vDSO location */
 #define AT_SYSINFO_EHDR        33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif
index f209ea1..3051f86 100644 (file)
@@ -87,9 +87,11 @@ struct kvm_regs {
 /* Supported VGICv3 address types  */
 #define KVM_VGIC_V3_ADDR_TYPE_DIST     2
 #define KVM_VGIC_V3_ADDR_TYPE_REDIST   3
+#define KVM_VGIC_ITS_ADDR_TYPE         4
 
 #define KVM_VGIC_V3_DIST_SIZE          SZ_64K
 #define KVM_VGIC_V3_REDIST_SIZE                (2 * SZ_64K)
+#define KVM_VGIC_V3_ITS_SIZE           (2 * SZ_64K)
 
 #define KVM_ARM_VCPU_POWER_OFF         0 /* CPU is started in OFF state */
 #define KVM_ARM_VCPU_EL1_32BIT         1 /* CPU running a 32bit VM */
index 916d27a..62272ea 100644 (file)
@@ -726,6 +726,19 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused
        return is_kernel_in_hyp_mode();
 }
 
+static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
+                          int __unused)
+{
+       phys_addr_t idmap_addr = virt_to_phys(__hyp_idmap_text_start);
+
+       /*
+        * Activate the lower HYP offset only if:
+        * - the idmap doesn't clash with it,
+        * - the kernel is not running at EL2.
+        */
+       return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode();
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
        {
                .desc = "GIC system register CPU interface",
@@ -803,6 +816,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .field_pos = ID_AA64PFR0_EL0_SHIFT,
                .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
        },
+       {
+               .desc = "Reduced HYP mapping offset",
+               .capability = ARM64_HYP_OFFSET_LOW,
+               .def_scope = SCOPE_SYSTEM,
+               .matches = hyp_offset_low,
+       },
        {},
 };
 
index 2c6e598..b77f583 100644 (file)
@@ -781,40 +781,25 @@ __primary_switch:
         * Iterate over each entry in the relocation table, and apply the
         * relocations in place.
         */
-       ldr     w8, =__dynsym_offset            // offset to symbol table
        ldr     w9, =__rela_offset              // offset to reloc table
        ldr     w10, =__rela_size               // size of reloc table
 
        mov_q   x11, KIMAGE_VADDR               // default virtual offset
        add     x11, x11, x23                   // actual virtual offset
-       add     x8, x8, x11                     // __va(.dynsym)
        add     x9, x9, x11                     // __va(.rela)
        add     x10, x9, x10                    // __va(.rela) + sizeof(.rela)
 
 0:     cmp     x9, x10
-       b.hs    2f
+       b.hs    1f
        ldp     x11, x12, [x9], #24
        ldr     x13, [x9, #-8]
        cmp     w12, #R_AARCH64_RELATIVE
-       b.ne    1f
+       b.ne    0b
        add     x13, x13, x23                   // relocate
        str     x13, [x11, x23]
        b       0b
 
-1:     cmp     w12, #R_AARCH64_ABS64
-       b.ne    0b
-       add     x12, x12, x12, lsl #1           // symtab offset: 24x top word
-       add     x12, x8, x12, lsr #(32 - 3)     // ... shifted into bottom word
-       ldrsh   w14, [x12, #6]                  // Elf64_Sym::st_shndx
-       ldr     x15, [x12, #8]                  // Elf64_Sym::st_value
-       cmp     w14, #-0xf                      // SHN_ABS (0xfff1) ?
-       add     x14, x15, x23                   // relocate
-       csel    x15, x14, x15, ne
-       add     x15, x13, x15
-       str     x15, [x11, x23]
-       b       0b
-
-2:
+1:
 #endif
        ldr     x8, =__primary_switched
        br      x8
index 3c4e308..acf3872 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+#include <linux/pci-ecam.h>
 #include <linux/slab.h>
 
 /*
@@ -36,25 +39,17 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return res->start;
 }
 
-/**
- * pcibios_enable_device - Enable I/O and memory.
- * @dev: PCI device to be enabled
- * @mask: bitmask of BARs to enable
- */
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-       if (pci_has_flag(PCI_PROBE_ONLY))
-               return 0;
-
-       return pci_enable_resources(dev, mask);
-}
-
 /*
- * Try to assign the IRQ number from DT when adding a new device
+ * Try to assign the IRQ number when probing a new device
  */
-int pcibios_add_device(struct pci_dev *dev)
+int pcibios_alloc_irq(struct pci_dev *dev)
 {
-       dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+       if (acpi_disabled)
+               dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+#ifdef CONFIG_ACPI
+       else
+               return acpi_pci_irq_enable(dev);
+#endif
 
        return 0;
 }
@@ -65,13 +60,21 @@ int pcibios_add_device(struct pci_dev *dev)
 int raw_pci_read(unsigned int domain, unsigned int bus,
                  unsigned int devfn, int reg, int len, u32 *val)
 {
-       return -ENXIO;
+       struct pci_bus *b = pci_find_bus(domain, bus);
+
+       if (!b)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       return b->ops->read(b, devfn, reg, len, val);
 }
 
 int raw_pci_write(unsigned int domain, unsigned int bus,
                unsigned int devfn, int reg, int len, u32 val)
 {
-       return -ENXIO;
+       struct pci_bus *b = pci_find_bus(domain, bus);
+
+       if (!b)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       return b->ops->write(b, devfn, reg, len, val);
 }
 
 #ifdef CONFIG_NUMA
@@ -85,10 +88,124 @@ EXPORT_SYMBOL(pcibus_to_node);
 #endif
 
 #ifdef CONFIG_ACPI
-/* Root bridge scanning */
+
+struct acpi_pci_generic_root_info {
+       struct acpi_pci_root_info       common;
+       struct pci_config_window        *cfg;   /* config space mapping */
+};
+
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{
+       struct pci_config_window *cfg = bus->sysdata;
+       struct acpi_device *adev = to_acpi_device(cfg->parent);
+       struct acpi_pci_root *root = acpi_driver_data(adev);
+
+       return root->segment;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+       if (!acpi_disabled) {
+               struct pci_config_window *cfg = bridge->bus->sysdata;
+               struct acpi_device *adev = to_acpi_device(cfg->parent);
+               ACPI_COMPANION_SET(&bridge->dev, adev);
+       }
+
+       return 0;
+}
+
+/*
+ * Lookup the bus range for the domain in MCFG, and set up config space
+ * mapping.
+ */
+static struct pci_config_window *
+pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
+{
+       struct resource *bus_res = &root->secondary;
+       u16 seg = root->segment;
+       struct pci_config_window *cfg;
+       struct resource cfgres;
+       unsigned int bsz;
+
+       /* Use address from _CBA if present, otherwise lookup MCFG */
+       if (!root->mcfg_addr)
+               root->mcfg_addr = pci_mcfg_lookup(seg, bus_res);
+
+       if (!root->mcfg_addr) {
+               dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n",
+                       seg, bus_res);
+               return NULL;
+       }
+
+       bsz = 1 << pci_generic_ecam_ops.bus_shift;
+       cfgres.start = root->mcfg_addr + bus_res->start * bsz;
+       cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1;
+       cfgres.flags = IORESOURCE_MEM;
+       cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res,
+                             &pci_generic_ecam_ops);
+       if (IS_ERR(cfg)) {
+               dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n",
+                       seg, bus_res, PTR_ERR(cfg));
+               return NULL;
+       }
+
+       return cfg;
+}
+
+/* release_info: free resources allocated by init_info */
+static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
+{
+       struct acpi_pci_generic_root_info *ri;
+
+       ri = container_of(ci, struct acpi_pci_generic_root_info, common);
+       pci_ecam_free(ri->cfg);
+       kfree(ri);
+}
+
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+       .release_info = pci_acpi_generic_release_info,
+};
+
+/* Interface called from ACPI code to setup PCI host controller */
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-       /* TODO: Should be revisited when implementing PCI on ACPI */
-       return NULL;
+       int node = acpi_get_node(root->device->handle);
+       struct acpi_pci_generic_root_info *ri;
+       struct pci_bus *bus, *child;
+
+       ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node);
+       if (!ri)
+               return NULL;
+
+       ri->cfg = pci_acpi_setup_ecam_mapping(root);
+       if (!ri->cfg) {
+               kfree(ri);
+               return NULL;
+       }
+
+       acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops;
+       bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common,
+                                  ri->cfg);
+       if (!bus)
+               return NULL;
+
+       pci_bus_size_bridges(bus);
+       pci_bus_assign_resources(bus);
+
+       list_for_each_entry(child, &bus->children, node)
+               pcie_bus_configure_settings(child);
+
+       return bus;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+       acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+       acpi_pci_remove_bus(bus);
+}
+
 #endif
index 89d6e17..659963d 100644 (file)
@@ -103,6 +103,7 @@ SECTIONS
                *(.discard)
                *(.discard.*)
                *(.interp .dynamic)
+               *(.dynsym .dynstr .hash)
        }
 
        . = KIMAGE_VADDR + TEXT_OFFSET;
@@ -174,19 +175,9 @@ SECTIONS
        .rela : ALIGN(8) {
                *(.rela .rela*)
        }
-       .dynsym : ALIGN(8) {
-               *(.dynsym)
-       }
-       .dynstr : {
-               *(.dynstr)
-       }
-       .hash : {
-               *(.hash)
-       }
 
-       __rela_offset   = ADDR(.rela) - KIMAGE_VADDR;
+       __rela_offset   = ABSOLUTE(ADDR(.rela) - KIMAGE_VADDR);
        __rela_size     = SIZEOF(.rela);
-       __dynsym_offset = ADDR(.dynsym) - KIMAGE_VADDR;
 
        . = ALIGN(SEGMENT_ALIGN);
        __init_end = .;
index c4f26ef..9c9edc9 100644 (file)
@@ -36,6 +36,9 @@ config KVM
        select HAVE_KVM_IRQFD
        select KVM_ARM_VGIC_V3
        select KVM_ARM_PMU if HW_PERF_EVENTS
+       select HAVE_KVM_MSI
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQ_ROUTING
        ---help---
          Support hosting virtualized guest machines.
          We don't support KVM with 16K page tables yet, due to the multiple
@@ -54,13 +57,6 @@ config KVM_ARM_PMU
          Adds support for a virtual Performance Monitoring Unit (PMU) in
          virtual machines.
 
-config KVM_NEW_VGIC
-       bool "New VGIC implementation"
-       depends on KVM
-       default y
-        ---help---
-          uses the new VGIC implementation
-
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
index a7a958c..695eb3c 100644 (file)
@@ -20,7 +20,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
 
-ifeq ($(CONFIG_KVM_NEW_VGIC),y)
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-init.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-irqfd.o
@@ -30,12 +29,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
-else
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
-kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
-endif
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
index 32fad75..3f9e157 100644 (file)
@@ -211,7 +211,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 /**
  * kvm_arm_copy_reg_indices - get indices of all registers.
  *
- * We do core registers right here, then we apppend system regs.
+ * We do core registers right here, then we append system regs.
  */
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
index a873a6d..6b29d3d 100644 (file)
@@ -53,10 +53,9 @@ __invalid:
        b       .
 
        /*
-        * x0: HYP boot pgd
-        * x1: HYP pgd
-        * x2: HYP stack
-        * x3: HYP vectors
+        * x0: HYP pgd
+        * x1: HYP stack
+        * x2: HYP vectors
         */
 __do_hyp_init:
 
@@ -110,71 +109,27 @@ __do_hyp_init:
        msr     sctlr_el2, x4
        isb
 
-       /* Skip the trampoline dance if we merged the boot and runtime PGDs */
-       cmp     x0, x1
-       b.eq    merged
-
-       /* MMU is now enabled. Get ready for the trampoline dance */
-       ldr     x4, =TRAMPOLINE_VA
-       adr     x5, target
-       bfi     x4, x5, #0, #PAGE_SHIFT
-       br      x4
-
-target: /* We're now in the trampoline code, switch page tables */
-       msr     ttbr0_el2, x1
-       isb
-
-       /* Invalidate the old TLBs */
-       tlbi    alle2
-       dsb     sy
-
-merged:
        /* Set the stack and new vectors */
+       kern_hyp_va     x1
+       mov     sp, x1
        kern_hyp_va     x2
-       mov     sp, x2
-       kern_hyp_va     x3
-       msr     vbar_el2, x3
+       msr     vbar_el2, x2
 
        /* Hello, World! */
        eret
 ENDPROC(__kvm_hyp_init)
 
        /*
-        * Reset kvm back to the hyp stub. This is the trampoline dance in
-        * reverse. If kvm used an extended idmap, __extended_idmap_trampoline
-        * calls this code directly in the idmap. In this case switching to the
-        * boot tables is a no-op.
-        *
-        * x0: HYP boot pgd
-        * x1: HYP phys_idmap_start
+        * Reset kvm back to the hyp stub.
         */
 ENTRY(__kvm_hyp_reset)
-       /* We're in trampoline code in VA, switch back to boot page tables */
-       msr     ttbr0_el2, x0
-       isb
-
-       /* Ensure the PA branch doesn't find a stale tlb entry or stale code. */
-       ic      iallu
-       tlbi    alle2
-       dsb     sy
-       isb
-
-       /* Branch into PA space */
-       adr     x0, 1f
-       bfi     x1, x0, #0, #PAGE_SHIFT
-       br      x1
-
        /* We're now in idmap, disable MMU */
-1:     mrs     x0, sctlr_el2
+       mrs     x0, sctlr_el2
        ldr     x1, =SCTLR_ELx_FLAGS
        bic     x0, x0, x1              // Clear SCTL_M and etc
        msr     sctlr_el2, x0
        isb
 
-       /* Invalidate the old TLBs */
-       tlbi    alle2
-       dsb     sy
-
        /* Install stub vectors */
        adr_l   x0, __hyp_stub_vectors
        msr     vbar_el2, x0
index 70254a6..ce9e5e5 100644 (file)
@@ -164,22 +164,3 @@ alternative_endif
 
        eret
 ENDPROC(__fpsimd_guest_restore)
-
-/*
- * When using the extended idmap, we don't have a trampoline page we can use
- * while we switch pages tables during __kvm_hyp_reset. Accessing the idmap
- * directly would be ideal, but if we're using the extended idmap then the
- * idmap is located above HYP_PAGE_OFFSET, and the address will be masked by
- * kvm_call_hyp using kern_hyp_va.
- *
- * x0: HYP boot pgd
- * x1: HYP phys_idmap_start
- */
-ENTRY(__extended_idmap_trampoline)
-       mov     x4, x1
-       adr_l   x3, __kvm_hyp_reset
-
-       /* insert __kvm_hyp_reset()s offset into phys_idmap_start */
-       bfi     x4, x3, #0, #PAGE_SHIFT
-       br      x4
-ENDPROC(__extended_idmap_trampoline)
index 2d87f36..f6d9694 100644 (file)
@@ -62,6 +62,21 @@ ENTRY(__vhe_hyp_call)
        isb
        ret
 ENDPROC(__vhe_hyp_call)
+
+/*
+ * Compute the idmap address of __kvm_hyp_reset based on the idmap
+ * start passed as a parameter, and jump there.
+ *
+ * x0: HYP phys_idmap_start
+ */
+ENTRY(__kvm_hyp_teardown)
+       mov     x4, x0
+       adr_l   x3, __kvm_hyp_reset
+
+       /* insert __kvm_hyp_reset()s offset into phys_idmap_start */
+       bfi     x4, x3, #0, #PAGE_SHIFT
+       br      x4
+ENDPROC(__kvm_hyp_teardown)
        
 el1_sync:                              // Guest trapped into EL2
        save_x0_to_x3
index 4373997..ae7855f 100644 (file)
@@ -299,9 +299,16 @@ static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%
 
 static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
 {
-       unsigned long str_va = (unsigned long)__hyp_panic_string;
+       unsigned long str_va;
 
-       __hyp_do_panic(hyp_kern_va(str_va),
+       /*
+        * Force the panic string to be loaded from the literal pool,
+        * making sure it is a kernel address and not a PC-relative
+        * reference.
+        */
+       asm volatile("ldr %0, =__hyp_panic_string" : "=r" (str_va));
+
+       __hyp_do_panic(str_va,
                       spsr,  elr,
                       read_sysreg(esr_el2),   read_sysreg_el2(far),
                       read_sysreg(hpfar_el2), par,
index e9e0e6d..898c0e6 100644 (file)
@@ -132,16 +132,14 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
 {
        unsigned long cpsr = *vcpu_cpsr(vcpu);
-       bool is_aarch32;
+       bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
        u32 esr = 0;
 
-       is_aarch32 = vcpu_mode_is_32bit(vcpu);
-
-       *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
-
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
+
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_spsr(vcpu) = cpsr;
 
        vcpu_sys_reg(vcpu, FAR_EL1) = addr;
 
@@ -172,11 +170,11 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
        unsigned long cpsr = *vcpu_cpsr(vcpu);
        u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
 
-       *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
-
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
+
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_spsr(vcpu) = cpsr;
 
        /*
         * Build an unknown exception, depending on the instruction
diff --git a/arch/arm64/kvm/irq.h b/arch/arm64/kvm/irq.h
new file mode 100644 (file)
index 0000000..b74099b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * 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 header is included by irqchip.c. However, on ARM, interrupt
+ * controller declarations are located in include/kvm/arm_vgic.h since
+ * they are mostly shared between arm and arm64.
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include <kvm/arm_vgic.h>
+
+#endif
index b1ad730..5bc4608 100644 (file)
@@ -65,7 +65,7 @@ static bool cpu_has_32bit_el1(void)
  * We currently assume that the number of HW registers is uniform
  * across all CPUs (see cpuinfo_sanity_check).
  */
-int kvm_arch_dev_ioctl_check_extension(long ext)
+int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 {
        int r;
 
@@ -86,6 +86,12 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
        case KVM_CAP_VCPU_ATTRIBUTES:
                r = 1;
                break;
+       case KVM_CAP_MSI_DEVID:
+               if (!kvm)
+                       r = -EINVAL;
+               else
+                       r = kvm->arch.vgic.msis_require_devid;
+               break;
        default:
                r = 0;
        }
@@ -98,7 +104,7 @@ int kvm_arch_dev_ioctl_check_extension(long ext)
  * @vcpu: The VCPU pointer
  *
  * This function finds the right table above and sets the registers on
- * the virtual CPU struct to their architectually defined reset
+ * the virtual CPU struct to their architecturally defined reset
  * values.
  */
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
@@ -132,31 +138,3 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        /* Reset timer */
        return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
 }
-
-extern char __hyp_idmap_text_start[];
-
-unsigned long kvm_hyp_reset_entry(void)
-{
-       if (!__kvm_cpu_uses_extended_idmap()) {
-               unsigned long offset;
-
-               /*
-                * Find the address of __kvm_hyp_reset() in the trampoline page.
-                * This is present in the running page tables, and the boot page
-                * tables, so we call the code here to start the trampoline
-                * dance in reverse.
-                */
-               offset = (unsigned long)__kvm_hyp_reset
-                        - ((unsigned long)__hyp_idmap_text_start & PAGE_MASK);
-
-               return TRAMPOLINE_VA + offset;
-       } else {
-               /*
-                * KVM is running with merged page tables, which don't have the
-                * trampoline page mapped. We know the idmap is still mapped,
-                * but can't be called into directly. Use
-                * __extended_idmap_trampoline to do the call.
-                */
-               return (unsigned long)kvm_ksym_ref(__extended_idmap_trampoline);
-       }
-}
index a57d650..b0b225c 100644 (file)
@@ -1546,7 +1546,7 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,
                                struct sys_reg_params *params)
 {
        u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
-       int cp;
+       int cp = -1;
 
        switch(hsr_ec) {
        case ESR_ELx_EC_CP15_32:
@@ -1558,7 +1558,7 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,
                cp = 14;
                break;
        default:
-               WARN_ON((cp = -1));
+               WARN_ON(1);
        }
 
        kvm_err("Unsupported guest CP%d access at: %08lx\n",
index f6c55af..c4284c4 100644 (file)
 
 static int swiotlb __read_mostly;
 
-static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
                                 bool coherent)
 {
-       if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+       if (!coherent || (attrs & DMA_ATTR_WRITE_COMBINE))
                return pgprot_writecombine(prot);
        return prot;
 }
@@ -91,7 +91,7 @@ static int __free_from_pool(void *start, size_t size)
 
 static void *__dma_alloc_coherent(struct device *dev, size_t size,
                                  dma_addr_t *dma_handle, gfp_t flags,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        if (dev == NULL) {
                WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
@@ -121,7 +121,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
 
 static void __dma_free_coherent(struct device *dev, size_t size,
                                void *vaddr, dma_addr_t dma_handle,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        bool freed;
        phys_addr_t paddr = dma_to_phys(dev, dma_handle);
@@ -140,7 +140,7 @@ static void __dma_free_coherent(struct device *dev, size_t size,
 
 static void *__dma_alloc(struct device *dev, size_t size,
                         dma_addr_t *dma_handle, gfp_t flags,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        struct page *page;
        void *ptr, *coherent_ptr;
@@ -188,7 +188,7 @@ no_mem:
 
 static void __dma_free(struct device *dev, size_t size,
                       void *vaddr, dma_addr_t dma_handle,
-                      struct dma_attrs *attrs)
+                      unsigned long attrs)
 {
        void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
 
@@ -205,7 +205,7 @@ static void __dma_free(struct device *dev, size_t size,
 static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction dir,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        dma_addr_t dev_addr;
 
@@ -219,7 +219,7 @@ static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
 
 static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
                                 size_t size, enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        if (!is_device_dma_coherent(dev))
                __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
@@ -228,7 +228,7 @@ static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
 
 static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
                                  int nelems, enum dma_data_direction dir,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        struct scatterlist *sg;
        int i, ret;
@@ -245,7 +245,7 @@ static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
 static void __swiotlb_unmap_sg_attrs(struct device *dev,
                                     struct scatterlist *sgl, int nelems,
                                     enum dma_data_direction dir,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -306,7 +306,7 @@ static void __swiotlb_sync_sg_for_device(struct device *dev,
 static int __swiotlb_mmap(struct device *dev,
                          struct vm_area_struct *vma,
                          void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        int ret = -ENXIO;
        unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
@@ -333,7 +333,7 @@ static int __swiotlb_mmap(struct device *dev,
 
 static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
                                 void *cpu_addr, dma_addr_t handle, size_t size,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        int ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
 
@@ -435,21 +435,21 @@ out:
 
 static void *__dummy_alloc(struct device *dev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flags,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        return NULL;
 }
 
 static void __dummy_free(struct device *dev, size_t size,
                         void *vaddr, dma_addr_t dma_handle,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
 }
 
 static int __dummy_mmap(struct device *dev,
                        struct vm_area_struct *vma,
                        void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        return -ENXIO;
 }
@@ -457,20 +457,20 @@ static int __dummy_mmap(struct device *dev,
 static dma_addr_t __dummy_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        return DMA_ERROR_CODE;
 }
 
 static void __dummy_unmap_page(struct device *dev, dma_addr_t dev_addr,
                               size_t size, enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
 }
 
 static int __dummy_map_sg(struct device *dev, struct scatterlist *sgl,
                          int nelems, enum dma_data_direction dir,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        return 0;
 }
@@ -478,7 +478,7 @@ static int __dummy_map_sg(struct device *dev, struct scatterlist *sgl,
 static void __dummy_unmap_sg(struct device *dev,
                             struct scatterlist *sgl, int nelems,
                             enum dma_data_direction dir,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
 }
 
@@ -553,7 +553,7 @@ static void flush_page(struct device *dev, const void *virt, phys_addr_t phys)
 
 static void *__iommu_alloc_attrs(struct device *dev, size_t size,
                                 dma_addr_t *handle, gfp_t gfp,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        bool coherent = is_device_dma_coherent(dev);
        int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent);
@@ -613,7 +613,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 }
 
 static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
-                              dma_addr_t handle, struct dma_attrs *attrs)
+                              dma_addr_t handle, unsigned long attrs)
 {
        size_t iosize = size;
 
@@ -629,7 +629,7 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
         * Hence how dodgy the below logic looks...
         */
        if (__in_atomic_pool(cpu_addr, size)) {
-               iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
+               iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
                __free_from_pool(cpu_addr, size);
        } else if (is_vmalloc_addr(cpu_addr)){
                struct vm_struct *area = find_vm_area(cpu_addr);
@@ -639,14 +639,14 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
                iommu_dma_free(dev, area->pages, iosize, &handle);
                dma_common_free_remap(cpu_addr, size, VM_USERMAP);
        } else {
-               iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
+               iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
                __free_pages(virt_to_page(cpu_addr), get_order(size));
        }
 }
 
 static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
                              void *cpu_addr, dma_addr_t dma_addr, size_t size,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct vm_struct *area;
        int ret;
@@ -666,7 +666,7 @@ static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
 
 static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
                               void *cpu_addr, dma_addr_t dma_addr,
-                              size_t size, struct dma_attrs *attrs)
+                              size_t size, unsigned long attrs)
 {
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct vm_struct *area = find_vm_area(cpu_addr);
@@ -707,14 +707,14 @@ static void __iommu_sync_single_for_device(struct device *dev,
 static dma_addr_t __iommu_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        bool coherent = is_device_dma_coherent(dev);
        int prot = dma_direction_to_prot(dir, coherent);
        dma_addr_t dev_addr = iommu_dma_map_page(dev, page, offset, size, prot);
 
        if (!iommu_dma_mapping_error(dev, dev_addr) &&
-           !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+           (attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __iommu_sync_single_for_device(dev, dev_addr, size, dir);
 
        return dev_addr;
@@ -722,9 +722,9 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page,
 
 static void __iommu_unmap_page(struct device *dev, dma_addr_t dev_addr,
                               size_t size, enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __iommu_sync_single_for_cpu(dev, dev_addr, size, dir);
 
        iommu_dma_unmap_page(dev, dev_addr, size, dir, attrs);
@@ -760,11 +760,11 @@ static void __iommu_sync_sg_for_device(struct device *dev,
 
 static int __iommu_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
                                int nelems, enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        bool coherent = is_device_dma_coherent(dev);
 
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __iommu_sync_sg_for_device(dev, sgl, nelems, dir);
 
        return iommu_dma_map_sg(dev, sgl, nelems,
@@ -774,9 +774,9 @@ static int __iommu_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
 static void __iommu_unmap_sg_attrs(struct device *dev,
                                   struct scatterlist *sgl, int nelems,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
-       if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+       if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
                __iommu_sync_sg_for_cpu(dev, sgl, nelems, dir);
 
        iommu_dma_unmap_sg(dev, sgl, nelems, dir, attrs);
index 51a5581..4989948 100644 (file)
@@ -686,9 +686,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
        /*
         * Check whether the physical FDT address is set and meets the minimum
         * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
-        * at least 8 bytes so that we can always access the size field of the
-        * FDT header after mapping the first chunk, double check here if that
-        * is indeed the case.
+        * at least 8 bytes so that we can always access the magic and size
+        * fields of the FDT header after mapping the first chunk, double check
+        * here if that is indeed the case.
         */
        BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
        if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
@@ -716,7 +716,7 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
        create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
                        dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
 
-       if (fdt_check_header(dt_virt) != 0)
+       if (fdt_magic(dt_virt) != FDT_MAGIC)
                return NULL;
 
        *size = fdt_totalsize(dt_virt);
index 92cf1fb..58610d0 100644 (file)
@@ -99,7 +99,7 @@ static void __dma_free(struct device *dev, size_t size,
 }
 
 static void *avr32_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
 {
        struct page *page;
        dma_addr_t phys;
@@ -109,7 +109,7 @@ static void *avr32_dma_alloc(struct device *dev, size_t size,
                return NULL;
        phys = page_to_phys(page);
 
-       if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) {
+       if (attrs & DMA_ATTR_WRITE_COMBINE) {
                /* Now, map the page into P3 with write-combining turned on */
                *handle = phys;
                return __ioremap(phys, size, _PAGE_BUFFER);
@@ -119,11 +119,11 @@ static void *avr32_dma_alloc(struct device *dev, size_t size,
 }
 
 static void avr32_dma_free(struct device *dev, size_t size,
-               void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs)
+               void *cpu_addr, dma_addr_t handle, unsigned long attrs)
 {
        struct page *page;
 
-       if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) {
+       if (attrs & DMA_ATTR_WRITE_COMBINE) {
                iounmap(cpu_addr);
 
                page = phys_to_page(handle);
@@ -142,7 +142,7 @@ static void avr32_dma_free(struct device *dev, size_t size,
 
 static dma_addr_t avr32_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        void *cpu_addr = page_address(page) + offset;
 
@@ -152,7 +152,7 @@ static dma_addr_t avr32_dma_map_page(struct device *dev, struct page *page,
 
 static int avr32_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
index 771afe6..53fbbb6 100644 (file)
@@ -79,7 +79,7 @@ static void __free_dma_pages(unsigned long addr, unsigned int pages)
 }
 
 static void *bfin_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -94,7 +94,7 @@ static void *bfin_dma_alloc(struct device *dev, size_t size,
 }
 
 static void bfin_dma_free(struct device *dev, size_t size, void *vaddr,
-                 dma_addr_t dma_handle, struct dma_attrs *attrs)
+                 dma_addr_t dma_handle, unsigned long attrs)
 {
        __free_dma_pages((unsigned long)vaddr, get_pages(size));
 }
@@ -111,7 +111,7 @@ EXPORT_SYMBOL(__dma_sync);
 
 static int bfin_dma_map_sg(struct device *dev, struct scatterlist *sg_list,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -139,7 +139,7 @@ static void bfin_dma_sync_sg_for_device(struct device *dev,
 
 static dma_addr_t bfin_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        dma_addr_t handle = (dma_addr_t)(page_address(page) + offset);
 
index 166842d..b59cd7c 100644 (file)
@@ -112,7 +112,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
 #if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
        free_initmem_default(-1);
index 6b5cd7b..5717b1e 100644 (file)
@@ -26,8 +26,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 
 extern void coherent_mem_init(u32 start, u32 size);
 void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-               gfp_t gfp, struct dma_attrs *attrs);
+               gfp_t gfp, unsigned long attrs);
 void c6x_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs);
+               dma_addr_t dma_handle, unsigned long attrs);
 
 #endif /* _ASM_C6X_DMA_MAPPING_H */
index 8a80f3a..db4a6a3 100644 (file)
@@ -38,7 +38,7 @@ static void c6x_dma_sync(dma_addr_t handle, size_t size,
 
 static dma_addr_t c6x_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        dma_addr_t handle = virt_to_phys(page_address(page) + offset);
 
@@ -47,13 +47,13 @@ static dma_addr_t c6x_dma_map_page(struct device *dev, struct page *page,
 }
 
 static void c6x_dma_unmap_page(struct device *dev, dma_addr_t handle,
-               size_t size, enum dma_data_direction dir, struct dma_attrs *attrs)
+               size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
        c6x_dma_sync(handle, size, dir);
 }
 
 static int c6x_dma_map_sg(struct device *dev, struct scatterlist *sglist,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+               int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -67,8 +67,7 @@ static int c6x_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 }
 
 static void c6x_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
-                 int nents, enum dma_data_direction dir,
-                 struct dma_attrs *attrs)
+                 int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
index f7ee63a..95e38ad 100644 (file)
@@ -74,7 +74,7 @@ static void __free_dma_pages(u32 addr, int order)
  * virtual and DMA address for that space.
  */
 void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-               gfp_t gfp, struct dma_attrs *attrs)
+               gfp_t gfp, unsigned long attrs)
 {
        u32 paddr;
        int order;
@@ -99,7 +99,7 @@ void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
  * Free DMA coherent memory as defined by the above mapping.
  */
 void c6x_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        int order;
 
index 60d57c5..bdc25aa 100644 (file)
@@ -397,7 +397,7 @@ static int __init init_axis_flash(void)
        if (!romfs_in_flash) {
                /* Create an RAM device for the root partition (romfs). */
 
-#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0)
                /* No use trying to boot this kernel from RAM. Panic! */
                printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
                       "device due to kernel (mis)configuration!\n");
index bd10d3b..87656c4 100644 (file)
@@ -320,7 +320,7 @@ static int __init init_axis_flash(void)
         * but its size must be configured as 0 so as not to conflict
         * with our usage.
         */
-#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0)
        if (!romfs_in_flash && !nand_boot) {
                printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
                       "device; configure CONFIG_MTD_MTDRAM with size = 0!\n");
index 8d5efa5..1f06367 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/io.h>
 
 static void *v32_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp,  struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -37,22 +37,21 @@ static void *v32_dma_alloc(struct device *dev, size_t size,
 }
 
 static void v32_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        free_pages((unsigned long)vaddr, get_order(size));
 }
 
 static inline dma_addr_t v32_dma_map_page(struct device *dev,
                struct page *page, unsigned long offset, size_t size,
-               enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        return page_to_phys(page) + offset;
 }
 
 static inline int v32_dma_map_sg(struct device *dev, struct scatterlist *sg,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        printk("Map sg\n");
        return nents;
diff --git a/arch/frv/include/asm/mc146818rtc.h b/arch/frv/include/asm/mc146818rtc.h
deleted file mode 100644 (file)
index 90dfb7a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* mc146818rtc.h: RTC defs
- *
- * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _ASM_MC146818RTC_H
-#define _ASM_MC146818RTC_H
-
-
-#endif /* _ASM_MC146818RTC_H */
index 082be49..90f2e4c 100644 (file)
@@ -35,7 +35,7 @@ static DEFINE_SPINLOCK(dma_alloc_lock);
 static LIST_HEAD(dma_alloc_list);
 
 static void *frv_dma_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, struct dma_attrs *attrs)
+               gfp_t gfp, unsigned long attrs)
 {
        struct dma_alloc_record *new;
        struct list_head *this = &dma_alloc_list;
@@ -86,7 +86,7 @@ static void *frv_dma_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_ha
 }
 
 static void frv_dma_free(struct device *hwdev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        struct dma_alloc_record *rec;
        unsigned long flags;
@@ -107,7 +107,7 @@ static void frv_dma_free(struct device *hwdev, size_t size, void *vaddr,
 
 static int frv_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
@@ -124,7 +124,7 @@ static int frv_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static dma_addr_t frv_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        BUG_ON(direction == DMA_NONE);
        flush_dcache_page(page);
index 316b7b6..f585745 100644 (file)
@@ -19,8 +19,7 @@
 #include <asm/io.h>
 
 static void *frv_dma_alloc(struct device *hwdev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp,
-               struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -32,14 +31,14 @@ static void *frv_dma_alloc(struct device *hwdev, size_t size,
 }
 
 static void frv_dma_free(struct device *hwdev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        consistent_free(vaddr);
 }
 
 static int frv_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        unsigned long dampr2;
        void *vaddr;
@@ -69,7 +68,7 @@ static int frv_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static dma_addr_t frv_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        flush_dcache_page(page);
        return (dma_addr_t) page_to_phys(page) + offset;
diff --git a/arch/h8300/include/asm/mc146818rtc.h b/arch/h8300/include/asm/mc146818rtc.h
deleted file mode 100644 (file)
index ab9d964..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifndef _H8300_MC146818RTC_H
-#define _H8300_MC146818RTC_H
-
-/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
-
-#endif /* _H8300_MC146818RTC_H */
index eeb13d3..3651da0 100644 (file)
@@ -12,7 +12,7 @@
 
 static void *dma_alloc(struct device *dev, size_t size,
                       dma_addr_t *dma_handle, gfp_t gfp,
-                      struct dma_attrs *attrs)
+                      unsigned long attrs)
 {
        void *ret;
 
@@ -32,7 +32,7 @@ static void *dma_alloc(struct device *dev, size_t size,
 
 static void dma_free(struct device *dev, size_t size,
                     void *vaddr, dma_addr_t dma_handle,
-                    struct dma_attrs *attrs)
+                    unsigned long attrs)
 
 {
        free_pages((unsigned long)vaddr, get_order(size));
@@ -41,14 +41,14 @@ static void dma_free(struct device *dev, size_t size,
 static dma_addr_t map_page(struct device *dev, struct page *page,
                                  unsigned long offset, size_t size,
                                  enum dma_data_direction direction,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        return page_to_phys(page) + offset;
 }
 
 static int map_sg(struct device *dev, struct scatterlist *sgl,
                  int nents, enum dma_data_direction direction,
-                 struct dma_attrs *attrs)
+                 unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
index aa62034..7ef58df 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
-#include <linux/dma-attrs.h>
 #include <asm/io.h>
 
 struct device;
index 9e3ddf7..b901778 100644 (file)
@@ -51,7 +51,7 @@ static struct gen_pool *coherent_pool;
 
 static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t flag,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        void *ret;
 
@@ -84,7 +84,7 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
 }
 
 static void hexagon_free_coherent(struct device *dev, size_t size, void *vaddr,
-                                 dma_addr_t dma_addr, struct dma_attrs *attrs)
+                                 dma_addr_t dma_addr, unsigned long attrs)
 {
        gen_pool_free(coherent_pool, (unsigned long) vaddr, size);
 }
@@ -105,7 +105,7 @@ static int check_addr(const char *name, struct device *hwdev,
 
 static int hexagon_map_sg(struct device *hwdev, struct scatterlist *sg,
                          int nents, enum dma_data_direction dir,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
@@ -172,7 +172,7 @@ static inline void dma_sync(void *addr, size_t size,
 static dma_addr_t hexagon_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        dma_addr_t bus = page_to_phys(page) + offset;
        WARN_ON(size == 0);
index 88977e4..192584d 100644 (file)
@@ -93,7 +93,7 @@ void __init mem_init(void)
  * Todo:  free pages between __init_begin and __init_end; possibly
  * some devtree related stuff as well.
  */
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
 }
 
index 6a15083..18ca6a9 100644 (file)
@@ -52,6 +52,7 @@ config IA64
        select MODULES_USE_ELF_RELA
        select ARCH_USE_CMPXCHG_LOCKREF
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_HARDENED_USERCOPY
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
index a6d6190..630ee80 100644 (file)
@@ -919,7 +919,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
 static dma_addr_t sba_map_page(struct device *dev, struct page *page,
                               unsigned long poff, size_t size,
                               enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        struct ioc *ioc;
        void *addr = page_address(page) + poff;
@@ -1005,7 +1005,7 @@ static dma_addr_t sba_map_page(struct device *dev, struct page *page,
 
 static dma_addr_t sba_map_single_attrs(struct device *dev, void *addr,
                                       size_t size, enum dma_data_direction dir,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        return sba_map_page(dev, virt_to_page(addr),
                            (unsigned long)addr & ~PAGE_MASK, size, dir, attrs);
@@ -1046,7 +1046,7 @@ sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size)
  * See Documentation/DMA-API-HOWTO.txt
  */
 static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
-                          enum dma_data_direction dir, struct dma_attrs *attrs)
+                          enum dma_data_direction dir, unsigned long attrs)
 {
        struct ioc *ioc;
 #if DELAYED_RESOURCE_CNT > 0
@@ -1115,7 +1115,7 @@ static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
 }
 
 void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
-                           enum dma_data_direction dir, struct dma_attrs *attrs)
+                           enum dma_data_direction dir, unsigned long attrs)
 {
        sba_unmap_page(dev, iova, size, dir, attrs);
 }
@@ -1130,7 +1130,7 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
  */
 static void *
 sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                  gfp_t flags, struct dma_attrs *attrs)
+                  gfp_t flags, unsigned long attrs)
 {
        struct ioc *ioc;
        void *addr;
@@ -1175,7 +1175,7 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
         * device to map single to get an iova mapping.
         */
        *dma_handle = sba_map_single_attrs(&ioc->sac_only_dev->dev, addr,
-                                          size, 0, NULL);
+                                          size, 0, 0);
 
        return addr;
 }
@@ -1191,9 +1191,9 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
  * See Documentation/DMA-API-HOWTO.txt
  */
 static void sba_free_coherent(struct device *dev, size_t size, void *vaddr,
-                             dma_addr_t dma_handle, struct dma_attrs *attrs)
+                             dma_addr_t dma_handle, unsigned long attrs)
 {
-       sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL);
+       sba_unmap_single_attrs(dev, dma_handle, size, 0, 0);
        free_pages((unsigned long) vaddr, get_order(size));
 }
 
@@ -1442,7 +1442,7 @@ sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
 
 static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
                               int nents, enum dma_data_direction dir,
-                              struct dma_attrs *attrs);
+                              unsigned long attrs);
 /**
  * sba_map_sg - map Scatter/Gather list
  * @dev: instance of PCI owned by the driver that's asking.
@@ -1455,7 +1455,7 @@ static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
  */
 static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist,
                            int nents, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct ioc *ioc;
        int coalesced, filled = 0;
@@ -1551,7 +1551,7 @@ static int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist,
  */
 static void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
                               int nents, enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
 #ifdef ASSERT_PDIR_SANITY
        struct ioc *ioc;
index 9c39bdf..ed7f090 100644 (file)
@@ -22,7 +22,6 @@ struct pci_bus;
 struct task_struct;
 struct pci_dev;
 struct msi_desc;
-struct dma_attrs;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
diff --git a/arch/ia64/include/asm/mc146818rtc.h b/arch/ia64/include/asm/mc146818rtc.h
deleted file mode 100644 (file)
index 407787a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _ASM_IA64_MC146818RTC_H
-#define _ASM_IA64_MC146818RTC_H
-
-/*
- * Machine dependent access functions for RTC registers.
- */
-
-/* empty include file to satisfy the include in genrtc.c */
-
-#endif /* _ASM_IA64_MC146818RTC_H */
index d1212b8..29bd597 100644 (file)
@@ -121,32 +121,4 @@ struct thread_info {
 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */
 #define TIF_WORK_MASK          (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 
-#define TS_RESTORE_SIGMASK     2       /* restore signal mask in do_signal() */
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
-#endif /* !__ASSEMBLY__ */
-
 #endif /* _ASM_IA64_THREAD_INFO_H */
index 2189d5d..465c709 100644 (file)
@@ -241,12 +241,18 @@ extern unsigned long __must_check __copy_user (void __user *to, const void __use
 static inline unsigned long
 __copy_to_user (void __user *to, const void *from, unsigned long count)
 {
+       if (!__builtin_constant_p(count))
+               check_object_size(from, count, true);
+
        return __copy_user(to, (__force void __user *) from, count);
 }
 
 static inline unsigned long
 __copy_from_user (void *to, const void __user *from, unsigned long count)
 {
+       if (!__builtin_constant_p(count))
+               check_object_size(to, count, false);
+
        return __copy_user((__force void __user *) to, from, count);
 }
 
@@ -258,8 +264,11 @@ __copy_from_user (void *to, const void __user *from, unsigned long count)
        const void *__cu_from = (from);                                                 \
        long __cu_len = (n);                                                            \
                                                                                        \
-       if (__access_ok(__cu_to, __cu_len, get_fs()))                                   \
-               __cu_len = __copy_user(__cu_to, (__force void __user *) __cu_from, __cu_len);   \
+       if (__access_ok(__cu_to, __cu_len, get_fs())) {                                 \
+               if (!__builtin_constant_p(n))                                           \
+                       check_object_size(__cu_from, __cu_len, true);                   \
+               __cu_len = __copy_user(__cu_to, (__force void __user *)  __cu_from, __cu_len);  \
+       }                                                                               \
        __cu_len;                                                                       \
 })
 
@@ -270,8 +279,11 @@ __copy_from_user (void *to, const void __user *from, unsigned long count)
        long __cu_len = (n);                                                            \
                                                                                        \
        __chk_user_ptr(__cu_from);                                                      \
-       if (__access_ok(__cu_from, __cu_len, get_fs()))                                 \
+       if (__access_ok(__cu_from, __cu_len, get_fs())) {                               \
+               if (!__builtin_constant_p(n))                                           \
+                       check_object_size(__cu_to, __cu_len, false);                    \
                __cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len);   \
+       }                                                                               \
        __cu_len;                                                                       \
 })
 
index b72cd7a..599507b 100644 (file)
@@ -163,7 +163,7 @@ void arch_crash_save_vmcoreinfo(void)
 #endif
 }
 
-unsigned long paddr_vmcoreinfo_note(void)
+phys_addr_t paddr_vmcoreinfo_note(void)
 {
        return ia64_tpa((unsigned long)(char *)&vmcoreinfo_note);
 }
index 07a4e32..eb9220c 100644 (file)
@@ -1831,7 +1831,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset,
 }
 
 /* Caller prevents this from being called after init */
-static void * __init_refok mca_bootmem(void)
+static void * __ref mca_bootmem(void)
 {
        return __alloc_bootmem(sizeof(struct ia64_mca_cpu),
                            KERNEL_STACK_SIZE, 0);
index 939260a..2933208 100644 (file)
@@ -16,7 +16,7 @@ EXPORT_SYMBOL(swiotlb);
 
 static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size,
                                         dma_addr_t *dma_handle, gfp_t gfp,
-                                        struct dma_attrs *attrs)
+                                        unsigned long attrs)
 {
        if (dev->coherent_dma_mask != DMA_BIT_MASK(64))
                gfp |= GFP_DMA;
@@ -25,7 +25,7 @@ static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size,
 
 static void ia64_swiotlb_free_coherent(struct device *dev, size_t size,
                                       void *vaddr, dma_addr_t dma_addr,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_addr);
 }
index 8f59907..74c934a 100644 (file)
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(sn_dma_set_mask);
  */
 static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
                                   dma_addr_t * dma_handle, gfp_t flags,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        void *cpuaddr;
        unsigned long phys_addr;
@@ -138,7 +138,7 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
  * any associated IOMMU mappings.
  */
 static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                                dma_addr_t dma_handle, struct dma_attrs *attrs)
+                                dma_addr_t dma_handle, unsigned long attrs)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -176,21 +176,18 @@ static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr
 static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page,
                                  unsigned long offset, size_t size,
                                  enum dma_data_direction dir,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        void *cpu_addr = page_address(page) + offset;
        dma_addr_t dma_addr;
        unsigned long phys_addr;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
-       int dmabarr;
-
-       dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
 
        BUG_ON(!dev_is_pci(dev));
 
        phys_addr = __pa(cpu_addr);
-       if (dmabarr)
+       if (attrs & DMA_ATTR_WRITE_BARRIER)
                dma_addr = provider->dma_map_consistent(pdev, phys_addr,
                                                        size, SN_DMA_ADDR_PHYS);
        else
@@ -218,7 +215,7 @@ static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page,
  */
 static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
                              size_t size, enum dma_data_direction dir,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -240,7 +237,7 @@ static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
  */
 static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
                            int nhwentries, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        int i;
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -273,16 +270,13 @@ static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
  */
 static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
                         int nhwentries, enum dma_data_direction dir,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        unsigned long phys_addr;
        struct scatterlist *saved_sg = sgl, *sg;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
        int i;
-       int dmabarr;
-
-       dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
 
        BUG_ON(!dev_is_pci(dev));
 
@@ -292,7 +286,7 @@ static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
        for_each_sg(sgl, sg, nhwentries, i) {
                dma_addr_t dma_addr;
                phys_addr = SG_ENT_PHYS_ADDRESS(sg);
-               if (dmabarr)
+               if (attrs & DMA_ATTR_WRITE_BARRIER)
                        dma_addr = provider->dma_map_consistent(pdev,
                                                                phys_addr,
                                                                sg->length,
index 01693df..ec9cc1f 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #include <asm/irq.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 
index 6e62d66..432bc8b 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/pgtable.h>
 #include <asm/apollohw.h>
 #include <asm/irq.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 
 u_long sio01_physaddr;
index 478623d..611d4d9 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/bvme6000hw.h>
 
index a9befe6..7cfab15 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
+#include <linux/rtc.h>
 
 #include <asm/bootinfo.h>
 #include <asm/bootinfo-hp300.h>
@@ -20,7 +21,6 @@
 #include <asm/blinken.h>
 #include <asm/io.h>                               /* readb() and writeb() */
 #include <asm/hp300hw.h>
-#include <asm/rtc.h>
 
 #include "time.h"
 
index f9454b8..00c392b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-m68knommu/flat.h -- uClinux flat-format executables
+ * flat.h -- uClinux flat-format executables
  */
 
 #ifndef __M68KNOMMU_FLAT_H__
@@ -8,8 +8,9 @@
 #define        flat_argvp_envp_on_stack()              1
 #define        flat_old_ram_flag(flags)                (flags)
 #define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
-#define        flat_get_addr_from_rp(rp, relval, flags, p)     get_unaligned(rp)
-#define        flat_put_addr_at_rp(rp, val, relval)    put_unaligned(val,rp)
+#define        flat_get_addr_from_rp(rp, relval, flags, p) \
+       ({ unsigned long __val; __get_user_unaligned(__val, rp); __val; })
+#define        flat_put_addr_at_rp(rp, val, relval)    __put_user_unaligned(val, rp)
 #define        flat_get_relocate_addr(rel)             (rel)
 
 static inline int flat_set_persistent(unsigned long relval,
@@ -18,4 +19,10 @@ static inline int flat_set_persistent(unsigned long relval,
        return 0;
 }
 
+#define FLAT_PLAT_INIT(regs) \
+       do { \
+               if (current->mm) \
+                       (regs)->d5 = current->mm->start_data; \
+       } while (0)
+
 #endif /* __M68KNOMMU_FLAT_H__ */
index a6ce2ec..c84a218 100644 (file)
@@ -110,7 +110,6 @@ struct thread_struct {
 #define setframeformat(_regs)  do { } while (0)
 #endif
 
-#ifdef CONFIG_MMU
 /*
  * Do necessary setup to start up a newly executed thread.
  */
@@ -123,26 +122,14 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
        wrusp(usp);
 }
 
+#ifdef CONFIG_MMU
 extern int handle_kernel_fault(struct pt_regs *regs);
-
 #else
-
-#define start_thread(_regs, _pc, _usp)                  \
-do {                                                    \
-       (_regs)->pc = (_pc);                            \
-       setframeformat(_regs);                          \
-       if (current->mm)                                \
-               (_regs)->d5 = current->mm->start_data;  \
-       (_regs)->sr &= ~0x2000;                         \
-       wrusp(_usp);                                    \
-} while(0)
-
 static inline  int handle_kernel_fault(struct pt_regs *regs)
 {
        /* Any fault in kernel is fatal on non-mmu */
        return 0;
 }
-
 #endif
 
 /* Forward declaration, a strange C thing */
diff --git a/arch/m68k/include/asm/rtc.h b/arch/m68k/include/asm/rtc.h
deleted file mode 100644 (file)
index a4d08ea..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* include/asm-m68k/rtc.h
- *
- * Copyright Richard Zidlicky
- * implementation details for genrtc/q40rtc driver
- */
-/* permission is hereby granted to copy, modify and redistribute this code
- * in terms of the GNU Library General Public License, Version 2 or later,
- * at your option.
- */
-
-#ifndef _ASM_RTC_H
-#define _ASM_RTC_H
-
-#ifdef __KERNEL__
-
-#include <linux/rtc.h>
-#include <asm/errno.h>
-#include <asm/machdep.h>
-
-#define RTC_PIE 0x40           /* periodic interrupt enable */
-#define RTC_AIE 0x20           /* alarm interrupt enable */
-#define RTC_UIE 0x10           /* update-finished interrupt enable */
-
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100     /* battery bad */
-#define RTC_SQWE 0x08          /* enable square-wave output */
-#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
-#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
-
-static inline unsigned int get_rtc_time(struct rtc_time *time)
-{
-       /*
-        * Only the values that we read from the RTC are set. We leave
-        * tm_wday, tm_yday and tm_isdst untouched. Even though the
-        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
-        * by the RTC when initially set to a non-zero value.
-        */
-       if (mach_hwclk)
-               mach_hwclk(0, time);
-       return RTC_24H;
-}
-
-static inline int set_rtc_time(struct rtc_time *time)
-{
-       if (mach_hwclk)
-               return mach_hwclk(1, time);
-       return -EINVAL;
-}
-
-static inline unsigned int get_rtc_ss(void)
-{
-       if (mach_get_ss)
-               return mach_get_ss();
-       else{
-               struct rtc_time h;
-
-               get_rtc_time(&h);
-               return h.tm_sec;
-       }
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
-       if (mach_get_rtc_pll)
-               return mach_get_rtc_pll(pll);
-       else
-               return -EINVAL;
-}
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
-       if (mach_set_rtc_pll)
-               return mach_set_rtc_pll(pll);
-       else
-               return -EINVAL;
-}
-#endif /* __KERNEL__ */
-
-#endif /* _ASM__RTC_H */
index cbc78b4..8cf97cb 100644 (file)
@@ -19,7 +19,7 @@
 #if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE)
 
 static void *m68k_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
-               gfp_t flag, struct dma_attrs *attrs)
+               gfp_t flag, unsigned long attrs)
 {
        struct page *page, **map;
        pgprot_t pgprot;
@@ -62,7 +62,7 @@ static void *m68k_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 }
 
 static void m68k_dma_free(struct device *dev, size_t size, void *addr,
-               dma_addr_t handle, struct dma_attrs *attrs)
+               dma_addr_t handle, unsigned long attrs)
 {
        pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
        vfree(addr);
@@ -73,7 +73,7 @@ static void m68k_dma_free(struct device *dev, size_t size, void *addr,
 #include <asm/cacheflush.h>
 
 static void *m68k_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
        /* ignore region specifiers */
@@ -91,7 +91,7 @@ static void *m68k_dma_alloc(struct device *dev, size_t size,
 }
 
 static void m68k_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        free_pages((unsigned long)vaddr, get_order(size));
 }
@@ -130,7 +130,7 @@ static void m68k_dma_sync_sg_for_device(struct device *dev,
 
 static dma_addr_t m68k_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        dma_addr_t handle = page_to_phys(page) + offset;
 
@@ -139,7 +139,7 @@ static dma_addr_t m68k_dma_map_page(struct device *dev, struct page *page,
 }
 
 static int m68k_dma_map_sg(struct device *dev, struct scatterlist *sglist,
-               int nents, enum dma_data_direction dir, struct dma_attrs *attrs)
+               int nents, enum dma_data_direction dir, unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
index 3857737..4e5aa2f 100644 (file)
@@ -86,7 +86,49 @@ void read_persistent_clock(struct timespec *ts)
        }
 }
 
-#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
+#if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
+static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
+{
+       mach_hwclk(0, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
+{
+       if (mach_hwclk(1, tm) < 0)
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+       struct rtc_pll_info pll;
+       struct rtc_pll_info __user *argp = (void __user *)arg;
+
+       switch (cmd) {
+       case RTC_PLL_GET:
+               if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll))
+                       return -EINVAL;
+               return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
+
+       case RTC_PLL_SET:
+               if (!mach_set_rtc_pll)
+                       return -EINVAL;
+               if (!capable(CAP_SYS_TIME))
+                       return -EACCES;
+               if (copy_from_user(&pll, argp, sizeof(pll)))
+                       return -EFAULT;
+               return mach_set_rtc_pll(&pll);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static const struct rtc_class_ops generic_rtc_ops = {
+       .ioctl = rtc_ioctl,
+       .read_time = rtc_generic_get_time,
+       .set_time = rtc_generic_set_time,
+};
 
 static int __init rtc_init(void)
 {
@@ -95,7 +137,9 @@ static int __init rtc_init(void)
        if (!mach_hwclk)
                return -ENODEV;
 
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &generic_rtc_ops,
+                                            sizeof(generic_rtc_ops));
        return PTR_ERR_OR_ZERO(pdev);
 }
 
index 689b47d..2f33a33 100644 (file)
@@ -10,6 +10,7 @@
  * Miscellaneous linux stuff
  */
 
+#include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -25,6 +26,7 @@
 #include <linux/platform_device.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
+#include <linux/rtc.h>
 
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
@@ -34,7 +36,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 
 #include <asm/macintosh.h>
index 707b61a..0fb54a9 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/rtc.h>
 #include <asm/segment.h>
 #include <asm/setup.h>
 #include <asm/macintosh.h>
index e6a3b56..c11d38d 100644 (file)
@@ -32,7 +32,6 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/mvme147hw.h>
 
index a53803c..58e2409 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/mvme16xhw.h>
 
index e90fe90..fcb7f05 100644 (file)
@@ -12,6 +12,7 @@
  * for more details.
  */
 
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -27,7 +28,6 @@
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
-#include <asm/rtc.h>
 #include <asm/bootinfo.h>
 #include <asm/pgtable.h>
 #include <asm/setup.h>
index 71884bf..3af34fa 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/pgalloc.h>
 #include <asm/sun3-head.h>
 #include <asm/sun3mmu.h>
-#include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/machines.h>
 #include <asm/idprom.h>
index 889829e..2cd0bcb 100644 (file)
@@ -14,8 +14,8 @@
 #include <linux/rtc.h>
 
 #include <asm/errno.h>
-#include <asm/rtc.h>
 #include <asm/intersil.h>
+#include <asm/machdep.h>
 
 
 /* bits to set for start/run of the intersil */
index c8eb08a..431d3c4 100644 (file)
 
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
 #include <asm/traps.h>
 #include <asm/sun3x.h>
 #include <asm/sun3ints.h>
-#include <asm/rtc.h>
 
 #include "time.h"
 
index 0154e28..2369ad3 100644 (file)
@@ -73,7 +73,7 @@ static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
                      " DCACHE  [%2], %0\n"
 #endif
                      "2:\n"
-                     : "=&d" (temp), "=&da" (retval)
+                     : "=&d" (temp), "=&d" (retval)
                      : "da" (m), "bd" (old), "da" (new)
                      : "cc"
                      );
index aa5a076..7848bc6 100644 (file)
 #define    PERFCTRL_DCSTALL 11 /* Dcache+TLB o/p delayed (per-thread) */
 #define    PERFCTRL_ICSTALL 12 /* Icache+TLB o/p delayed (per-thread) */
 
-#define    PERFCTRL_INT     13 /* Internal core delailed events (see next) */
+#define    PERFCTRL_INT     13 /* Internal core detailed events (see next) */
 #define    PERFCTRL_EXT     15 /* External source in core periphery */
 #endif /* METAC_2_1 */
 
index 40c3f67..60b7509 100644 (file)
 ;   is best to dump these registers immediately at the start of a routine
 ;   using a MSETL or SETL instruction-
 ;
-;   MSETL   [A0StP],D0Ar6,D0Ar4,D0Ar2; Only dump argments expected
+;   MSETL   [A0StP],D0Ar6,D0Ar4,D0Ar2; Only dump arguments expected
 ;or SETL    [A0StP+#8++],D0Ar2       ; Up to two 32-bit args expected
 ;
 ; For non-leaf routines it is always necessary to save and restore at least
index 04b7d4f..db944c2 100644 (file)
@@ -15,7 +15,7 @@
 #define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
 #define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
 
-#define CACHE_ASSOCIATIVITY 4 /* 4 way set-assosiative */
+#define CACHE_ASSOCIATIVITY 4 /* 4 way set-associative */
 #define ICACHE 0
 #define DCACHE 1
 
index e12368d..0db31e2 100644 (file)
@@ -172,7 +172,7 @@ out:
  * virtual and bus address for that space.
  */
 static void *metag_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
 {
        struct page *page;
        struct metag_vm_region *c;
@@ -268,7 +268,7 @@ no_page:
  * free a page as defined by the above mapping.
  */
 static void metag_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        struct metag_vm_region *c;
        unsigned long flags, addr;
@@ -331,13 +331,13 @@ no_area:
 
 static int metag_dma_mmap(struct device *dev, struct vm_area_struct *vma,
                void *cpu_addr, dma_addr_t dma_addr, size_t size,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        unsigned long flags, user_size, kern_size;
        struct metag_vm_region *c;
        int ret = -ENXIO;
 
-       if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+       if (attrs & DMA_ATTR_WRITE_COMBINE)
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        else
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
@@ -482,7 +482,7 @@ static void dma_sync_for_cpu(void *vaddr, size_t size, int dma_direction)
 
 static dma_addr_t metag_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        dma_sync_for_device((void *)(page_to_phys(page) + offset), size,
                            direction);
@@ -491,14 +491,14 @@ static dma_addr_t metag_dma_map_page(struct device *dev, struct page *page,
 
 static void metag_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
                size_t size, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        dma_sync_for_cpu(phys_to_virt(dma_address), size, direction);
 }
 
 static int metag_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -516,7 +516,7 @@ static int metag_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static void metag_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                int nhwentries, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
index 7c8a8ae..11124cc 100644 (file)
@@ -50,7 +50,7 @@ $LIDMCQuick:
        ADDCC   D0Re0,D0Re0,#1          ! If yes result += 1
        SUBCC   D1Ar1,D1Ar1,D1Re0       !        and A -= Bu
        ORS     D0Ar4,D0Ar4,D0Ar4       ! Return neg result?
-       NEG     D0Ar2,D0Re0             ! Calulate neg result
+       NEG     D0Ar2,D0Re0             ! Calculate neg result
        MOVMI   D0Re0,D0Ar2             ! Yes: Take neg result
 $LIDMCRet:
        MOV     PC,D1RtP
@@ -94,7 +94,7 @@ $LIDMCLoop:
        LSR     D1Re0, D1Re0, #1        ! Shift down B
        BNZ     $LIDMCLoop               ! Was single bit in curbit lost?
        ORS     D0Ar4,D0Ar4,D0Ar4       ! Return neg result?
-       NEG     D0Ar2,D0Re0             ! Calulate neg result
+       NEG     D0Ar2,D0Re0             ! Calculate neg result
        MOVMI   D0Re0,D0Ar2             ! Yes: Take neg result
        MOV     PC,D1RtP
        .size   ___divsi3,.-___divsi3
index 372783a..c765b36 100644 (file)
@@ -187,7 +187,7 @@ bad_area_nosemaphore:
 
                if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
                    printk_ratelimit()) {
-                       pr_info("%s%s[%d]: segfault at %lx pc %08x sp %08x write %d trap %#x (%s)",
+                       printk("%s%s[%d]: segfault at %lx pc %08x sp %08x write %d trap %#x (%s)",
                               task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
                               tsk->comm, task_pid_nr(tsk), address,
                               regs->ctx.CurrPC, regs->ctx.AX[0].U0,
index 11fa51c..c0ec116 100644 (file)
@@ -390,7 +390,6 @@ void __init mem_init(void)
 
        free_all_bootmem();
        mem_init_print_info(NULL);
-       show_mem(0);
 }
 
 void free_initmem(void)
index 1884783..1768d4b 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
-#include <linux/dma-attrs.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
 
index fc3ecb5..2a120bb 100644 (file)
@@ -82,9 +82,6 @@ extern pgprot_t       pci_phys_mem_access_prot(struct file *file,
                                         pgprot_t prot);
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                                const struct resource *rsrc,
-                                resource_size_t *start, resource_size_t *end);
 
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
index 383f387..e7e8954 100644 (file)
@@ -148,33 +148,6 @@ static inline struct thread_info *current_thread_info(void)
  */
 /* FPU was used by this task this quantum (SMP) */
 #define TS_USEDFPU             0x0001
-#define TS_RESTORE_SIGMASK     0x0002
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK 1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
-#endif
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_THREAD_INFO_H */
index bf4dec2..ec04dc1 100644 (file)
@@ -17,7 +17,7 @@
 
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
 #ifdef NOT_COHERENT_CACHE
        return consistent_alloc(flag, size, dma_handle);
@@ -42,7 +42,7 @@ static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 
 static void dma_direct_free_coherent(struct device *dev, size_t size,
                                     void *vaddr, dma_addr_t dma_handle,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
 #ifdef NOT_COHERENT_CACHE
        consistent_free(size, vaddr);
@@ -53,7 +53,7 @@ static void dma_direct_free_coherent(struct device *dev, size_t size,
 
 static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
                             int nents, enum dma_data_direction direction,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -78,7 +78,7 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
                                             unsigned long offset,
                                             size_t size,
                                             enum dma_data_direction direction,
-                                            struct dma_attrs *attrs)
+                                            unsigned long attrs)
 {
        __dma_sync(page_to_phys(page) + offset, size, direction);
        return page_to_phys(page) + offset;
@@ -88,7 +88,7 @@ static inline void dma_direct_unmap_page(struct device *dev,
                                         dma_addr_t dma_address,
                                         size_t size,
                                         enum dma_data_direction direction,
-                                        struct dma_attrs *attrs)
+                                        unsigned long attrs)
 {
 /* There is not necessary to do cache cleanup
  *
@@ -157,7 +157,7 @@ dma_direct_sync_sg_for_device(struct device *dev,
 static
 int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
                             void *cpu_addr, dma_addr_t handle, size_t size,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
 #ifdef CONFIG_MMU
        unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
index 77bc7c7..434639f 100644 (file)
@@ -414,7 +414,7 @@ void __init *early_get_page(void)
 
 #endif /* CONFIG_MMU */
 
-void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
+void * __ref alloc_maybe_bootmem(size_t size, gfp_t mask)
 {
        if (mem_init_done)
                return kmalloc(size, mask);
@@ -422,7 +422,7 @@ void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
                return alloc_bootmem(size);
 }
 
-void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
+void * __ref zalloc_maybe_bootmem(size_t size, gfp_t mask)
 {
        void *p;
 
index eb99fcc..cc732fe 100644 (file)
@@ -234,7 +234,7 @@ unsigned long iopa(unsigned long addr)
        return pa;
 }
 
-__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+__ref pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                unsigned long address)
 {
        pte_t *pte;
index 14cba60..81556b8 100644 (file)
@@ -218,33 +218,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
        return NULL;
 }
 
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
-                                     pgprot_t protection,
-                                     enum pci_mmap_state mmap_state,
-                                     int write_combine)
-{
-       pgprot_t prot = protection;
-
-       /* Write combine is always 0 on non-memory space mappings. On
-        * memory space, if the user didn't pass 1, we check for a
-        * "prefetchable" resource. This is a bit hackish, but we use
-        * this to workaround the inability of /sysfs to provide a write
-        * combine bit
-        */
-       if (mmap_state != pci_mmap_mem)
-               write_combine = 0;
-       else if (write_combine == 0) {
-               if (rp->flags & IORESOURCE_PREFETCH)
-                       write_combine = 1;
-       }
-
-       return pgprot_noncached(prot);
-}
-
 /*
  * This one is used by /dev/mem and fbdev who have no clue about the
  * PCI device, it tries to find the PCI device first and calls the
@@ -317,9 +290,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
-                                                 vma->vm_page_prot,
-                                                 mmap_state, write_combine);
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start, vma->vm_page_prot);
@@ -473,39 +444,25 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end)
 {
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0;
+       struct pci_bus_region region;
 
-       if (hose == NULL)
+       if (rsrc->flags & IORESOURCE_IO) {
+               pcibios_resource_to_bus(dev->bus, &region,
+                                       (struct resource *) rsrc);
+               *start = region.start;
+               *end = region.end;
                return;
+       }
 
-       if (rsrc->flags & IORESOURCE_IO)
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-
-       /* We pass a fully fixed up address to userland for MMIO instead of
-        * a BAR value because X is lame and expects to be able to use that
-        * to pass to /dev/mem !
+       /* We pass a CPU physical address to userland for MMIO instead of a
+        * BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem!
         *
-        * That means that we'll have potentially 64 bits values where some
-        * userland apps only expect 32 (like X itself since it thinks only
-        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
-        * 32 bits CHRPs :-(
-        *
-        * Hopefully, the sysfs insterface is immune to that gunk. Once X
-        * has been fixed (and the fix spread enough), we can re-enable the
-        * 2 lines below and pass down a BAR value to userland. In that case
-        * we'll also have to re-enable the matching code in
-        * __pci_mmap_make_offset().
-        *
-        * BenH.
+        * That means we may have 64-bit values where some apps only expect
+        * 32 (like X itself since it thinks only Sparc has 64-bit MMIO).
         */
-#if 0
-       else if (rsrc->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-#endif
-
-       *start = rsrc->start - offset;
-       *end = rsrc->end - offset;
+       *start = rsrc->start;
+       *end = rsrc->end;
 }
 
 /**
index ac91939..2638856 100644 (file)
@@ -64,6 +64,7 @@ config MIPS
        select GENERIC_TIME_VSYSCALL
        select ARCH_CLOCKSOURCE_DATA
        select HANDLE_DOMAIN_IRQ
+       select HAVE_EXIT_THREAD
 
 menu "Machine selection"
 
@@ -384,7 +385,7 @@ config MACH_PISTACHIO
        select CLKSRC_MIPS_GIC
        select COMMON_CLK
        select CSRC_R4K
-       select DMA_MAYBE_COHERENT
+       select DMA_NONCOHERENT
        select GPIOLIB
        select IRQ_MIPS_CPU
        select LIBFDT
@@ -880,7 +881,6 @@ config CAVIUM_OCTEON_SOC
        select SYS_SUPPORTS_HOTPLUG_CPU if CPU_BIG_ENDIAN
        select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_CAVIUM_OCTEON
-       select SWAP_IO_SPACE
        select HW_HAS_PCI
        select ZONE_DMA32
        select HOLES_IN_ZONE
@@ -1111,16 +1111,6 @@ config NEED_DMA_MAP_STATE
 config SYS_HAS_EARLY_PRINTK
        bool
 
-config HOTPLUG_CPU
-       bool "Support for hot-pluggable CPUs"
-       depends on SMP && SYS_SUPPORTS_HOTPLUG_CPU
-       help
-         Say Y here to allow turning CPUs off and on. CPUs can be
-         controlled through /sys/devices/system/cpu.
-         (Note: power management support will enable this option
-           automatically on SMP systems. )
-         Say N if you want to disable CPU hotplug.
-
 config SYS_SUPPORTS_HOTPLUG_CPU
        bool
 
@@ -1406,7 +1396,6 @@ config CPU_LOONGSON1B
        bool "Loongson 1B"
        depends on SYS_HAS_CPU_LOONGSON1B
        select CPU_LOONGSON1
-       select ARCH_WANT_OPTIONAL_GPIOLIB
        select LEDS_GPIO_REGISTER
        help
          The Loongson 1B is a 32-bit SoC, which implements the MIPS32
@@ -1488,6 +1477,7 @@ config CPU_MIPS64_R2
        select CPU_SUPPORTS_HIGHMEM
        select CPU_SUPPORTS_HUGEPAGES
        select CPU_SUPPORTS_MSA
+       select HAVE_KVM
        help
          Choose this option to build a kernel for release 2 or later of the
          MIPS64 architecture.  Many modern embedded systems with a 64-bit
@@ -1505,6 +1495,7 @@ config CPU_MIPS64_R6
        select CPU_SUPPORTS_MSA
        select GENERIC_CSUM
        select MIPS_O32_FP64_SUPPORT if MIPS32_O32
+       select HAVE_KVM
        help
          Choose this option to build a kernel for release 6 or later of the
          MIPS64 architecture.  New MIPS processors, starting with the Warrior
@@ -2634,6 +2625,16 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SMP && SYS_SUPPORTS_HOTPLUG_CPU
+       help
+         Say Y here to allow turning CPUs off and on. CPUs can be
+         controlled through /sys/devices/system/cpu.
+         (Note: power management support will enable this option
+           automatically on SMP systems. )
+         Say N if you want to disable CPU hotplug.
+
 config SMP_UP
        bool
 
@@ -2885,10 +2886,10 @@ choice
                  the documented boot protocol using a device tree.
 
        config MIPS_RAW_APPENDED_DTB
-               bool "vmlinux.bin"
+               bool "vmlinux.bin or vmlinuz.bin"
                help
                  With this option, the boot code will look for a device tree binary
-                 DTB) appended to raw vmlinux.bin (without decompressor).
+                 DTB) appended to raw vmlinux.bin or vmlinuz.bin.
                  (e.g. cat vmlinux.bin <filename>.dtb > vmlinux_w_dtb).
 
                  This is meant as a backward compatibility convenience for those
@@ -2900,24 +2901,6 @@ choice
                  look like a DTB header after a reboot if no actual DTB is appended
                  to vmlinux.bin.  Do not leave this option active in a production kernel
                  if you don't intend to always append a DTB.
-
-       config MIPS_ZBOOT_APPENDED_DTB
-               bool "vmlinuz.bin"
-               depends on SYS_SUPPORTS_ZBOOT
-               help
-                 With this option, the boot code will look for a device tree binary
-                 DTB) appended to raw vmlinuz.bin (with decompressor).
-                 (e.g. cat vmlinuz.bin <filename>.dtb > vmlinuz_w_dtb).
-
-                 This is meant as a backward compatibility convenience for those
-                 systems with a bootloader that can't be upgraded to accommodate
-                 the documented boot protocol using a device tree.
-
-                 Beware that there is very little in terms of protection against
-                 this option being confused by leftover garbage in memory that might
-                 look like a DTB header after a reboot if no actual DTB is appended
-                 to vmlinuz.bin.  Do not leave this option active in a production kernel
-                 if you don't intend to always append a DTB.
 endchoice
 
 choice
index 3a0019d..f206daf 100644 (file)
@@ -203,8 +203,8 @@ void __init plat_mem_setup(void)
        fdt_start = fw_getenvl("fdt_start");
        if (fdt_start)
                __dt_setup_arch((void *)KSEG0ADDR(fdt_start));
-       else if (fw_arg0 == -2)
-               __dt_setup_arch((void *)KSEG0ADDR(fw_arg1));
+       else if (fw_passed_dtb)
+               __dt_setup_arch((void *)KSEG0ADDR(fw_passed_dtb));
 
        if (mips_machtype != ATH79_MACH_GENERIC_OF) {
                ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
index f146d12..6776042 100644 (file)
@@ -162,8 +162,8 @@ void __init plat_mem_setup(void)
        /* intended to somewhat resemble ARM; see Documentation/arm/Booting */
        if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
                dtb = phys_to_virt(fw_arg2);
-       else if (fw_arg0 == -2) /* UHI interface */
-               dtb = (void *)fw_arg1;
+       else if (fw_passed_dtb) /* UHI interface */
+               dtb = (void *)fw_passed_dtb;
        else if (__dtb_start != __dtb_end)
                dtb = (void *)__dtb_start;
        else
index 080cd53..fdf99e9 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/libfdt.h>
 
 #include <asm/addrspace.h>
 
@@ -36,6 +37,8 @@ extern void puthex(unsigned long long val);
 #define puthex(val) do {} while (0)
 #endif
 
+extern char __appended_dtb[];
+
 void error(char *x)
 {
        puts("\n\n");
@@ -114,6 +117,20 @@ void decompress_kernel(unsigned long boot_heap_start)
        __decompress((char *)zimage_start, zimage_size, 0, 0,
                   (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, 0, error);
 
+       if (IS_ENABLED(CONFIG_MIPS_RAW_APPENDED_DTB) &&
+           fdt_magic((void *)&__appended_dtb) == FDT_MAGIC) {
+               unsigned int image_size, dtb_size;
+
+               dtb_size = fdt_totalsize((void *)&__appended_dtb);
+
+               /* last four bytes is always image size in little endian */
+               image_size = le32_to_cpup((void *)&__image_end - 4);
+
+               /* copy dtb to where the booted kernel will expect it */
+               memcpy((void *)VMLINUX_LOAD_ADDRESS_ULL + image_size,
+                      __appended_dtb, dtb_size);
+       }
+
        /* FIXME: should we flush cache here? */
        puts("Now, booting the kernel...\n");
 }
index c580e85..409cb48 100644 (file)
@@ -25,22 +25,6 @@ start:
        move    s2, a2
        move    s3, a3
 
-#ifdef CONFIG_MIPS_ZBOOT_APPENDED_DTB
-       PTR_LA  t0, __appended_dtb
-#ifdef CONFIG_CPU_BIG_ENDIAN
-       li      t1, 0xd00dfeed
-#else
-       li      t1, 0xedfe0dd0
-#endif
-       lw      t2, (t0)
-       bne     t1, t2, not_found
-        nop
-
-       move    s1, t0
-       PTR_LI  s0, -2
-not_found:
-#endif
-
        /* Clear BSS */
        PTR_LA  a0, _edata
        PTR_LA  a2, _end
index d6bc994..b134798 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 /include/ "octeon_3xxx.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
        model = "dlink,dsr-1000n";
 
                usb1 {
                        label = "usb1";
-                       gpios = <&gpio 9 1>; /* Active low */
+                       gpios = <&gpio 9 GPIO_ACTIVE_LOW>;
                };
 
                usb2 {
                        label = "usb2";
-                       gpios = <&gpio 10 1>; /* Active low */
+                       gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+               };
+
+               wps {
+                       label = "wps";
+                       gpios = <&gpio 11 GPIO_ACTIVE_LOW>;
+               };
+
+               wireless1 {
+                       label = "5g";
+                       gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
+               };
+
+               wireless2 {
+                       label = "2.4g";
+                       gpios = <&gpio 18 GPIO_ACTIVE_LOW>;
                };
        };
 
index de61f02..ca6b446 100644 (file)
                usbn = &usbn;
                led0 = &led0;
        };
-
-       dsr1000n-leds {
-               compatible = "gpio-leds";
-               usb1 {
-                       label = "usb1";
-                       gpios = <&gpio 9 1>; /* Active low */
-               };
-               usb2 {
-                       label = "usb2";
-                       gpios = <&gpio 10 1>; /* Active low */
-               };
-       };
  };
index b671b5e..06066e6 100644 (file)
@@ -9,17 +9,20 @@
 
 typedef uint8_t Elf64_Byte;
 
-typedef struct {
-       Elf64_Word r_sym;       /* Symbol index.  */
-       Elf64_Byte r_ssym;      /* Special symbol.  */
-       Elf64_Byte r_type3;     /* Third relocation.  */
-       Elf64_Byte r_type2;     /* Second relocation.  */
-       Elf64_Byte r_type;      /* First relocation.  */
+typedef union {
+       struct {
+               Elf64_Word r_sym;       /* Symbol index.  */
+               Elf64_Byte r_ssym;      /* Special symbol.  */
+               Elf64_Byte r_type3;     /* Third relocation.  */
+               Elf64_Byte r_type2;     /* Second relocation.  */
+               Elf64_Byte r_type;      /* First relocation.  */
+       } fields;
+       Elf64_Xword unused;
 } Elf64_Mips_Rela;
 
 #define ELF_CLASS               ELFCLASS64
-#define ELF_R_SYM(val)          (((Elf64_Mips_Rela *)(&val))->r_sym)
-#define ELF_R_TYPE(val)         (((Elf64_Mips_Rela *)(&val))->r_type)
+#define ELF_R_SYM(val)          (((Elf64_Mips_Rela *)(&val))->fields.r_sym)
+#define ELF_R_TYPE(val)         (((Elf64_Mips_Rela *)(&val))->fields.r_type)
 #define ELF_ST_TYPE(o)          ELF64_ST_TYPE(o)
 #define ELF_ST_BIND(o)          ELF64_ST_BIND(o)
 #define ELF_ST_VISIBILITY(o)    ELF64_ST_VISIBILITY(o)
index 2cd45f5..fd69528 100644 (file)
@@ -125,7 +125,7 @@ static phys_addr_t octeon_small_dma_to_phys(struct device *dev,
 
 static dma_addr_t octeon_dma_map_page(struct device *dev, struct page *page,
        unsigned long offset, size_t size, enum dma_data_direction direction,
-       struct dma_attrs *attrs)
+       unsigned long attrs)
 {
        dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
                                            direction, attrs);
@@ -135,7 +135,7 @@ static dma_addr_t octeon_dma_map_page(struct device *dev, struct page *page,
 }
 
 static int octeon_dma_map_sg(struct device *dev, struct scatterlist *sg,
-       int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+       int nents, enum dma_data_direction direction, unsigned long attrs)
 {
        int r = swiotlb_map_sg_attrs(dev, sg, nents, direction, attrs);
        mb();
@@ -157,7 +157,7 @@ static void octeon_dma_sync_sg_for_device(struct device *dev,
 }
 
 static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+       dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -189,7 +189,7 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
 }
 
 static void octeon_dma_free_coherent(struct device *dev, size_t size,
-       void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+       void *vaddr, dma_addr_t dma_handle, unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_handle);
 }
index 504ed61..b65a6c1 100644 (file)
@@ -668,7 +668,7 @@ int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr,
        /*
         * Round size up to mult of minimum alignment bytes We need
         * the actual size allocated to allow for blocks to be
-        * coallesced when they are freed.  The alloc routine does the
+        * coalesced when they are freed. The alloc routine does the
         * same rounding up on all allocations.
         */
        size = ALIGN(size, CVMX_BOOTMEM_ALIGNMENT_SIZE);
index 36e30d6..ff49fc0 100644 (file)
@@ -186,15 +186,6 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
                        return 7 - ipd_port;
                else
                        return -1;
-       case CVMX_BOARD_TYPE_CUST_DSR1000N:
-               /*
-                * Port 2 connects to Broadcom PHY (B5081). Other ports (0-1)
-                * connect to a switch (BCM53115).
-                */
-               if (ipd_port == 2)
-                       return 8;
-               else
-                       return -1;
        case CVMX_BOARD_TYPE_KONTRON_S1901:
                if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
                        return 1;
@@ -289,18 +280,6 @@ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
                        return result;
                }
                break;
-       case CVMX_BOARD_TYPE_CUST_DSR1000N:
-               if (ipd_port == 0 || ipd_port == 1) {
-                       /* Ports 0 and 1 connect to a switch (BCM53115). */
-                       result.s.link_up = 1;
-                       result.s.full_duplex = 1;
-                       result.s.speed = 1000;
-                       return result;
-               } else {
-                       /* Port 2 uses a Broadcom PHY (B5081). */
-                       is_broadcom_phy = 1;
-               }
-               break;
        }
 
        phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
@@ -765,7 +744,6 @@ enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(vo
        case CVMX_BOARD_TYPE_LANAI2_G:
        case CVMX_BOARD_TYPE_NIC10E_66:
        case CVMX_BOARD_TYPE_UBNT_E100:
-       case CVMX_BOARD_TYPE_CUST_DSR1000N:
                return USB_CLOCK_TYPE_CRYSTAL_12;
        case CVMX_BOARD_TYPE_NIC10E:
                return USB_CLOCK_TYPE_REF_12;
index 368eb49..5a9b87b 100644 (file)
@@ -1260,7 +1260,7 @@ static int octeon_irq_gpio_map(struct irq_domain *d,
 
        line = (hw + gpiod->base_hwirq) >> 6;
        bit = (hw + gpiod->base_hwirq) & 63;
-       if (line > ARRAY_SIZE(octeon_irq_ciu_to_irq) ||
+       if (line >= ARRAY_SIZE(octeon_irq_ciu_to_irq) ||
                octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
@@ -1542,10 +1542,6 @@ static int __init octeon_irq_init_ciu(
                        goto err;
        }
 
-       r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56);
-       if (r)
-               goto err;
-
        r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_TWSI2, 0, 59);
        if (r)
                goto err;
@@ -1559,10 +1555,6 @@ static int __init octeon_irq_init_ciu(
                        goto err;
        }
 
-       r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB1, 1, 17);
-       if (r)
-               goto err;
-
        /* Enable the CIU lines */
        set_c0_status(STATUSF_IP3 | STATUSF_IP2);
        if (octeon_irq_use_ip4)
@@ -2077,10 +2069,6 @@ static int __init octeon_irq_init_ciu2(
                        goto err;
        }
 
-       r = octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 3, 44);
-       if (r)
-               goto err;
-
        for (i = 0; i < 4; i++) {
                r = octeon_irq_force_ciu_mapping(
                        ciu_domain, i + OCTEON_IRQ_PCI_INT0, 4, i);
index 7aeafed..b31fbc9 100644 (file)
@@ -3,33 +3,27 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004-2011 Cavium Networks
+ * Copyright (C) 2004-2016 Cavium Networks
  * Copyright (C) 2008 Wind River Systems
  */
 
-#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/i2c.h>
-#include <linux/usb.h>
-#include <linux/dma-mapping.h>
+#include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <linux/usb/ehci_def.h>
 #include <linux/usb/ehci_pdriver.h>
 #include <linux/usb/ohci_pdriver.h>
 
 #include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-rnm-defs.h>
-#include <asm/octeon/cvmx-helper.h>
 #include <asm/octeon/cvmx-helper-board.h>
 #include <asm/octeon/cvmx-uctlx-defs.h>
 
+#define CVMX_UAHCX_EHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000010ull))
+#define CVMX_UAHCX_OHCI_USBCMD (CVMX_ADD_IO_SEG(0x00016F0000000408ull))
+
 /* Octeon Random Number Generator.  */
 static int __init octeon_rng_device_init(void)
 {
@@ -78,12 +72,36 @@ static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
 
 static int octeon2_usb_clock_start_cnt;
 
+static int __init octeon2_usb_reset(void)
+{
+       union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
+       u32 ucmd;
+
+       if (!OCTEON_IS_OCTEON2())
+               return 0;
+
+       clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
+       if (clk_rst_ctl.s.hrst) {
+               ucmd = cvmx_read64_uint32(CVMX_UAHCX_EHCI_USBCMD);
+               ucmd &= ~CMD_RUN;
+               cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd);
+               mdelay(2);
+               ucmd |= CMD_RESET;
+               cvmx_write64_uint32(CVMX_UAHCX_EHCI_USBCMD, ucmd);
+               ucmd = cvmx_read64_uint32(CVMX_UAHCX_OHCI_USBCMD);
+               ucmd |= CMD_RUN;
+               cvmx_write64_uint32(CVMX_UAHCX_OHCI_USBCMD, ucmd);
+       }
+
+       return 0;
+}
+arch_initcall(octeon2_usb_reset);
+
 static void octeon2_usb_clocks_start(struct device *dev)
 {
        u64 div;
        union cvmx_uctlx_if_ena if_ena;
        union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
-       union cvmx_uctlx_uphy_ctl_status uphy_ctl_status;
        union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
        int i;
        unsigned long io_clk_64_to_ns;
@@ -131,6 +149,17 @@ static void octeon2_usb_clocks_start(struct device *dev)
        if_ena.s.en = 1;
        cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
 
+       for (i = 0; i <= 1; i++) {
+               port_ctl_status.u64 =
+                       cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
+               /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
+               port_ctl_status.s.txvreftune = 15;
+               port_ctl_status.s.txrisetune = 1;
+               port_ctl_status.s.txpreemphasistune = 1;
+               cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
+                              port_ctl_status.u64);
+       }
+
        /* Step 3: Configure the reference clock, PHY, and HCLK */
        clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
 
@@ -218,29 +247,10 @@ static void octeon2_usb_clocks_start(struct device *dev)
        clk_rst_ctl.s.p_por = 0;
        cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 
-       /* Step 5:    Wait 1 ms for the PHY clock to start. */
-       mdelay(1);
+       /* Step 5:    Wait 3 ms for the PHY clock to start. */
+       mdelay(3);
 
-       /*
-        * Step 6: Program the reset input from automatic test
-        * equipment field in the UPHY CSR
-        */
-       uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0));
-       uphy_ctl_status.s.ate_reset = 1;
-       cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
-
-       /* Step 7: Wait for at least 10ns. */
-       ndelay(10);
-
-       /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */
-       uphy_ctl_status.s.ate_reset = 0;
-       cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
-
-       /*
-        * Step 9: Wait for at least 20ns for UPHY to output PHY clock
-        * signals and OHCI_CLK48
-        */
-       ndelay(20);
+       /* Steps 6..9 for ATE only, are skipped. */
 
        /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */
        /* 10a */
@@ -261,6 +271,20 @@ static void octeon2_usb_clocks_start(struct device *dev)
        clk_rst_ctl.s.p_prst = 1;
        cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 
+       /* Step 11b */
+       udelay(1);
+
+       /* Step 11c */
+       clk_rst_ctl.s.p_prst = 0;
+       cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
+
+       /* Step 11d */
+       mdelay(1);
+
+       /* Step 11e */
+       clk_rst_ctl.s.p_prst = 1;
+       cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
+
        /* Step 12: Wait 1 uS. */
        udelay(1);
 
@@ -269,21 +293,9 @@ static void octeon2_usb_clocks_start(struct device *dev)
        cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 
 end_clock:
-       /* Now we can set some other registers.  */
-
-       for (i = 0; i <= 1; i++) {
-               port_ctl_status.u64 =
-                       cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
-               /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
-               port_ctl_status.s.txvreftune = 15;
-               port_ctl_status.s.txrisetune = 1;
-               port_ctl_status.s.txpreemphasistune = 1;
-               cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
-                              port_ctl_status.u64);
-       }
-
        /* Set uSOF cycle period to 60,000 bits. */
        cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
+
 exit:
        mutex_unlock(&octeon2_usb_clocks_mutex);
 }
@@ -311,7 +323,11 @@ static struct usb_ehci_pdata octeon_ehci_pdata = {
 #ifdef __BIG_ENDIAN
        .big_endian_mmio        = 1,
 #endif
-       .dma_mask_64    = 1,
+       /*
+        * We can DMA from anywhere. But the descriptors must be in
+        * the lower 4GB.
+        */
+       .dma_mask_64    = 0,
        .power_on       = octeon_ehci_power_on,
        .power_off      = octeon_ehci_power_off,
 };
@@ -689,6 +705,10 @@ int __init octeon_prune_device_tree(void)
        if (fdt_check_header(initial_boot_params))
                panic("Corrupt Device Tree.");
 
+       WARN(octeon_bootinfo->board_type == CVMX_BOARD_TYPE_CUST_DSR1000N,
+            "Built-in DTB booting is deprecated on %s. Please switch to use appended DTB.",
+            cvmx_board_type_to_string(octeon_bootinfo->board_type));
+
        aliases = fdt_path_offset(initial_boot_params, "/aliases");
        if (aliases < 0) {
                pr_err("Error: No /aliases node in device tree.");
@@ -1032,13 +1052,6 @@ end_led:
                }
        }
 
-       if (octeon_bootinfo->board_type != CVMX_BOARD_TYPE_CUST_DSR1000N) {
-               int dsr1000n_leds = fdt_path_offset(initial_boot_params,
-                                                   "/dsr1000n-leds");
-               if (dsr1000n_leds >= 0)
-                       fdt_nop_node(initial_boot_params, dsr1000n_leds);
-       }
-
        return 0;
 }
 
index 64f852b..cb16fcc 100644 (file)
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/pci-octeon.h>
-#include <asm/octeon/cvmx-mio-defs.h>
 #include <asm/octeon/cvmx-rst-defs.h>
 
+/*
+ * TRUE for devices having registers with little-endian byte
+ * order, FALSE for registers with native-endian byte order.
+ * PCI mandates little-endian, USB and SATA are configuraable,
+ * but we chose little-endian for these.
+ */
+const bool octeon_should_swizzle_table[256] = {
+       [0x00] = true,  /* bootbus/CF */
+       [0x1b] = true,  /* PCI mmio window */
+       [0x1c] = true,  /* PCI mmio window */
+       [0x1d] = true,  /* PCI mmio window */
+       [0x1e] = true,  /* PCI mmio window */
+       [0x68] = true,  /* OCTEON III USB */
+       [0x69] = true,  /* OCTEON III USB */
+       [0x6c] = true,  /* OCTEON III SATA */
+       [0x6f] = true,  /* OCTEON II USB */
+};
+EXPORT_SYMBOL(octeon_should_swizzle_table);
+
 #ifdef CONFIG_PCI
 extern void pci_console_init(const char *arg);
 #endif
index 33aab89..4d457d6 100644 (file)
@@ -271,6 +271,7 @@ static int octeon_cpu_disable(void)
                return -ENOTSUPP;
 
        set_cpu_online(cpu, false);
+       calculate_cpu_foreign_map();
        cpumask_clear_cpu(cpu, &cpu_callin_map);
        octeon_fixup_irqs();
 
index 9a8c2fe..c136a18 100644 (file)
@@ -42,8 +42,8 @@ const char *get_system_type(void)
 
 /*
  * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
- * keyboard conntroller is never used.
- * Also PCI-ISA bridge DMA contoroller is never used.
+ * keyboard controller is never used.
+ * Also PCI-ISA bridge DMA controller is never used.
  */
 static struct resource cobalt_reserved_resources[] = {
        {       /* dma1 */
diff --git a/arch/mips/configs/ath25_defconfig b/arch/mips/configs/ath25_defconfig
new file mode 100644 (file)
index 0000000..2c82995
--- /dev/null
@@ -0,0 +1,119 @@
+CONFIG_ATH25=y
+# CONFIG_COMPACTION is not set
+CONFIG_HZ_100=y
+# CONFIG_SECCOMP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+# CONFIG_FHANDLE is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_MAC80211_DEBUGFS=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_NETDEVICES=y
+# CONFIG_ETHERNET is not set
+# CONFIG_WLAN_VENDOR_ADMTEK is not set
+CONFIG_ATH5K=m
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+# CONFIG_WLAN_VENDOR_BROADCOM is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+# CONFIG_WLAN_VENDOR_INTEL is not set
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+# CONFIG_WLAN_VENDOR_MARVELL is not set
+# CONFIG_WLAN_VENDOR_MEDIATEK is not set
+# CONFIG_WLAN_VENDOR_RALINK is not set
+# CONFIG_WLAN_VENDOR_REALTEK is not set
+# CONFIG_WLAN_VENDOR_RSI is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+CONFIG_INPUT=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_USB=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_LEDS_CLASS=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+# CONFIG_JFFS2_ZLIB is not set
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+# CONFIG_SQUASHFS_ZLIB is not set
+CONFIG_SQUASHFS_XZ=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
index dcac308..d470d08 100644 (file)
@@ -59,6 +59,8 @@ CONFIG_EEPROM_AT25=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_AHCI_OCTEON=y
 CONFIG_PATA_OCTEON_CF=y
 CONFIG_SATA_SIL=y
 CONFIG_NETDEVICES=y
index 3b0e51d..c5b04e7 100644 (file)
@@ -45,7 +45,7 @@
 /*
  * Returns the kernel segment base of a given address
  */
-#define KSEGX(a)               ((_ACAST32_ (a)) & 0xe0000000)
+#define KSEGX(a)               ((_ACAST32_(a)) & _ACAST32_(0xe0000000))
 
 /*
  * Returns the physical address of a CKSEGx / XKPHYS address
index 9f67033..ee9f5f2 100644 (file)
@@ -127,6 +127,10 @@ extern char arcs_cmdline[COMMAND_LINE_SIZE];
  */
 extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
+#ifdef CONFIG_USE_OF
+extern unsigned long fw_passed_dtb;
+#endif
+
 /*
  * Platform memory detection hook called by setup_arch
  */
diff --git a/arch/mips/include/asm/dsemul.h b/arch/mips/include/asm/dsemul.h
new file mode 100644 (file)
index 0000000..a6e0678
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_DSEMUL_H__
+#define __MIPS_ASM_DSEMUL_H__
+
+#include <asm/break.h>
+#include <asm/inst.h>
+
+/* Break instruction with special math emu break code set */
+#define BREAK_MATH(micromips)  (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16))
+
+/* When used as a frame index, indicates the lack of a frame */
+#define BD_EMUFRAME_NONE       ((int)BIT(31))
+
+struct mm_struct;
+struct pt_regs;
+struct task_struct;
+
+/**
+ * mips_dsemul() - 'Emulate' an instruction from a branch delay slot
+ * @regs:      User thread register context.
+ * @ir:                The instruction to be 'emulated'.
+ * @branch_pc: The PC of the branch instruction.
+ * @cont_pc:   The PC to continue at following 'emulation'.
+ *
+ * Emulate or execute an arbitrary MIPS instruction within the context of
+ * the current user thread. This is used primarily to handle instructions
+ * in the delay slots of emulated branch instructions, for example FP
+ * branch instructions on systems without an FPU.
+ *
+ * Return: Zero on success, negative if ir is a NOP, signal number on failure.
+ */
+extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
+                      unsigned long branch_pc, unsigned long cont_pc);
+
+/**
+ * do_dsemulret() - Return from a delay slot 'emulation' frame
+ * @xcp:       User thread register context.
+ *
+ * Call in response to the BRK_MEMU break instruction used to return to
+ * the kernel from branch delay slot 'emulation' frames following a call
+ * to mips_dsemul(). Restores the user thread PC to the value that was
+ * passed as the cpc parameter to mips_dsemul().
+ *
+ * Return: True if an emulation frame was returned from, else false.
+ */
+extern bool do_dsemulret(struct pt_regs *xcp);
+
+/**
+ * dsemul_thread_cleanup() - Cleanup thread 'emulation' frame
+ * @tsk: The task structure associated with the thread
+ *
+ * If the thread @tsk has a branch delay slot 'emulation' frame
+ * allocated to it then free that frame.
+ *
+ * Return: True if a frame was freed, else false.
+ */
+extern bool dsemul_thread_cleanup(struct task_struct *tsk);
+
+/**
+ * dsemul_thread_rollback() - Rollback from an 'emulation' frame
+ * @regs:      User thread register context.
+ *
+ * If the current thread, whose register context is represented by @regs,
+ * is executing within a delay slot 'emulation' frame then exit that
+ * frame. The PC will be rolled back to the branch if the instruction
+ * that was being 'emulated' has not yet executed, or advanced to the
+ * continuation PC if it has.
+ *
+ * Return: True if a frame was exited, else false.
+ */
+extern bool dsemul_thread_rollback(struct pt_regs *regs);
+
+/**
+ * dsemul_mm_cleanup() - Cleanup per-mm delay slot 'emulation' state
+ * @mm:                The struct mm_struct to cleanup state for.
+ *
+ * Cleanup state for the given @mm, ensuring that any memory allocated
+ * for delay slot 'emulation' book-keeping is freed. This is to be called
+ * before @mm is freed in order to avoid memory leaks.
+ */
+extern void dsemul_mm_cleanup(struct mm_struct *mm);
+
+#endif /* __MIPS_ASM_DSEMUL_H__ */
index f5f4571..2b3dc29 100644 (file)
@@ -458,6 +458,7 @@ extern const char *__elf_platform;
 #define ELF_ET_DYN_BASE                (TASK_SIZE / 3 * 2)
 #endif
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO                                                    \
 do {                                                                   \
        NEW_AUX_ENT(AT_SYSINFO_EHDR,                                    \
@@ -498,4 +499,7 @@ extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
 extern void mips_set_personality_nan(struct arch_elf_state *state);
 extern void mips_set_personality_fp(struct arch_elf_state *state);
 
+#define elf_read_implies_exec(ex, stk) mips_elf_read_implies_exec(&(ex), stk)
+extern int mips_elf_read_implies_exec(void *elf_ex, int exstack);
+
 #endif /* _ASM_ELF_H */
index 3225c3c..355dc25 100644 (file)
@@ -24,7 +24,7 @@
 #define _ASM_FPU_EMULATOR_H
 
 #include <linux/sched.h>
-#include <asm/break.h>
+#include <asm/dsemul.h>
 #include <asm/thread_info.h>
 #include <asm/inst.h>
 #include <asm/local.h>
@@ -60,27 +60,16 @@ do {                                                                        \
 #define MIPS_FPU_EMU_INC_STATS(M) do { } while (0)
 #endif /* CONFIG_DEBUG_FS */
 
-extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
-       unsigned long cpc);
-extern int do_dsemulret(struct pt_regs *xcp);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
                                    struct mips_fpu_struct *ctx, int has_fpu,
                                    void *__user *fault_addr);
 int process_fpemu_return(int sig, void __user *fault_addr,
                         unsigned long fcr31);
+int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+                 unsigned long *contpc);
 int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                     unsigned long *contpc);
 
-/*
- * Instruction inserted following the badinst to further tag the sequence
- */
-#define BD_COOKIE 0x0000bd36   /* tne $0, $0 with baggage */
-
-/*
- * Break instruction with special math emu break code set
- */
-#define BREAK_MATH(micromips) (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16))
-
 #define SIGNALLING_NAN 0x7ff800007ff80000LL
 
 static inline void fpu_emulator_init_fpu(void)
index 36a391d..b54bcad 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 
+#include <asm/inst.h>
+#include <asm/mipsregs.h>
+
 /* MIPS KVM register ids */
 #define MIPS_CP0_32(_R, _S)                                    \
        (KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U32 | (8 * (_R) + (_S)))
 #define KVM_REG_MIPS_CP0_CONFIG7       MIPS_CP0_32(16, 7)
 #define KVM_REG_MIPS_CP0_XCONTEXT      MIPS_CP0_64(20, 0)
 #define KVM_REG_MIPS_CP0_ERROREPC      MIPS_CP0_64(30, 0)
+#define KVM_REG_MIPS_CP0_KSCRATCH1     MIPS_CP0_64(31, 2)
+#define KVM_REG_MIPS_CP0_KSCRATCH2     MIPS_CP0_64(31, 3)
+#define KVM_REG_MIPS_CP0_KSCRATCH3     MIPS_CP0_64(31, 4)
+#define KVM_REG_MIPS_CP0_KSCRATCH4     MIPS_CP0_64(31, 5)
+#define KVM_REG_MIPS_CP0_KSCRATCH5     MIPS_CP0_64(31, 6)
+#define KVM_REG_MIPS_CP0_KSCRATCH6     MIPS_CP0_64(31, 7)
 
 
 #define KVM_MAX_VCPUS          1
 
 
 
-/* Special address that contains the comm page, used for reducing # of traps */
-#define KVM_GUEST_COMMPAGE_ADDR                0x0
+/*
+ * Special address that contains the comm page, used for reducing # of traps
+ * This needs to be within 32Kb of 0x0 (so the zero register can be used), but
+ * preferably not at 0x0 so that most kernel NULL pointer dereferences can be
+ * caught.
+ */
+#define KVM_GUEST_COMMPAGE_ADDR                ((PAGE_SIZE > 0x8000) ? 0 : \
+                                        (0x8000 - PAGE_SIZE))
 
 #define KVM_GUEST_KERNEL_MODE(vcpu)    ((kvm_read_c0_guest_status(vcpu->arch.cop0) & (ST0_EXL | ST0_ERL)) || \
                                        ((kvm_read_c0_guest_status(vcpu->arch.cop0) & KSU_USER) == 0))
 #define KVM_INVALID_ADDR               0xdeadbeef
 
 extern atomic_t kvm_mips_instance;
-extern kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
-extern void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
-extern bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
 
 struct kvm_vm_stat {
        u32 remote_tlb_flush;
@@ -126,28 +138,6 @@ struct kvm_vcpu_stat {
        u32 halt_wakeup;
 };
 
-enum kvm_mips_exit_types {
-       WAIT_EXITS,
-       CACHE_EXITS,
-       SIGNAL_EXITS,
-       INT_EXITS,
-       COP_UNUSABLE_EXITS,
-       TLBMOD_EXITS,
-       TLBMISS_LD_EXITS,
-       TLBMISS_ST_EXITS,
-       ADDRERR_ST_EXITS,
-       ADDRERR_LD_EXITS,
-       SYSCALL_EXITS,
-       RESVD_INST_EXITS,
-       BREAK_INST_EXITS,
-       TRAP_INST_EXITS,
-       MSA_FPE_EXITS,
-       FPE_EXITS,
-       MSA_DISABLED_EXITS,
-       FLUSH_DCACHE_EXITS,
-       MAX_KVM_MIPS_EXIT_TYPES
-};
-
 struct kvm_arch_memory_slot {
 };
 
@@ -215,73 +205,6 @@ struct mips_coproc {
 #define MIPS_CP0_CONFIG4_SEL   4
 #define MIPS_CP0_CONFIG5_SEL   5
 
-/* Config0 register bits */
-#define CP0C0_M                        31
-#define CP0C0_K23              28
-#define CP0C0_KU               25
-#define CP0C0_MDU              20
-#define CP0C0_MM               17
-#define CP0C0_BM               16
-#define CP0C0_BE               15
-#define CP0C0_AT               13
-#define CP0C0_AR               10
-#define CP0C0_MT               7
-#define CP0C0_VI               3
-#define CP0C0_K0               0
-
-/* Config1 register bits */
-#define CP0C1_M                        31
-#define CP0C1_MMU              25
-#define CP0C1_IS               22
-#define CP0C1_IL               19
-#define CP0C1_IA               16
-#define CP0C1_DS               13
-#define CP0C1_DL               10
-#define CP0C1_DA               7
-#define CP0C1_C2               6
-#define CP0C1_MD               5
-#define CP0C1_PC               4
-#define CP0C1_WR               3
-#define CP0C1_CA               2
-#define CP0C1_EP               1
-#define CP0C1_FP               0
-
-/* Config2 Register bits */
-#define CP0C2_M                        31
-#define CP0C2_TU               28
-#define CP0C2_TS               24
-#define CP0C2_TL               20
-#define CP0C2_TA               16
-#define CP0C2_SU               12
-#define CP0C2_SS               8
-#define CP0C2_SL               4
-#define CP0C2_SA               0
-
-/* Config3 Register bits */
-#define CP0C3_M                        31
-#define CP0C3_ISA_ON_EXC       16
-#define CP0C3_ULRI             13
-#define CP0C3_DSPP             10
-#define CP0C3_LPA              7
-#define CP0C3_VEIC             6
-#define CP0C3_VInt             5
-#define CP0C3_SP               4
-#define CP0C3_MT               2
-#define CP0C3_SM               1
-#define CP0C3_TL               0
-
-/* MMU types, the first four entries have the same layout as the
-   CP0C0_MT field.  */
-enum mips_mmu_types {
-       MMU_TYPE_NONE,
-       MMU_TYPE_R4000,
-       MMU_TYPE_RESERVED,
-       MMU_TYPE_FMT,
-       MMU_TYPE_R3000,
-       MMU_TYPE_R6000,
-       MMU_TYPE_R8000
-};
-
 /* Resume Flags */
 #define RESUME_FLAG_DR         (1<<0)  /* Reload guest nonvolatile state? */
 #define RESUME_FLAG_HOST       (1<<1)  /* Resume host? */
@@ -298,11 +221,6 @@ enum emulation_result {
        EMULATE_PRIV_FAIL,
 };
 
-#define MIPS3_PG_G     0x00000001 /* Global; ignore ASID if in lo0 & lo1 */
-#define MIPS3_PG_V     0x00000002 /* Valid */
-#define MIPS3_PG_NV    0x00000000
-#define MIPS3_PG_D     0x00000004 /* Dirty */
-
 #define mips3_paddr_to_tlbpfn(x) \
        (((unsigned long)(x) >> MIPS3_PG_SHIFT) & MIPS3_PG_FRAME)
 #define mips3_tlbpfn_to_paddr(x) \
@@ -313,13 +231,11 @@ enum emulation_result {
 
 #define VPN2_MASK              0xffffe000
 #define KVM_ENTRYHI_ASID       MIPS_ENTRYHI_ASID
-#define TLB_IS_GLOBAL(x)       (((x).tlb_lo0 & MIPS3_PG_G) &&          \
-                                ((x).tlb_lo1 & MIPS3_PG_G))
+#define TLB_IS_GLOBAL(x)       ((x).tlb_lo[0] & (x).tlb_lo[1] & ENTRYLO_G)
 #define TLB_VPN2(x)            ((x).tlb_hi & VPN2_MASK)
 #define TLB_ASID(x)            ((x).tlb_hi & KVM_ENTRYHI_ASID)
-#define TLB_IS_VALID(x, va)    (((va) & (1 << PAGE_SHIFT))             \
-                                ? ((x).tlb_lo1 & MIPS3_PG_V)           \
-                                : ((x).tlb_lo0 & MIPS3_PG_V))
+#define TLB_LO_IDX(x, va)      (((va) >> PAGE_SHIFT) & 1)
+#define TLB_IS_VALID(x, va)    ((x).tlb_lo[TLB_LO_IDX(x, va)] & ENTRYLO_V)
 #define TLB_HI_VPN2_HIT(x, y)  ((TLB_VPN2(x) & ~(x).tlb_mask) ==       \
                                 ((y) & VPN2_MASK & ~(x).tlb_mask))
 #define TLB_HI_ASID_HIT(x, y)  (TLB_IS_GLOBAL(x) ||                    \
@@ -328,26 +244,23 @@ enum emulation_result {
 struct kvm_mips_tlb {
        long tlb_mask;
        long tlb_hi;
-       long tlb_lo0;
-       long tlb_lo1;
+       long tlb_lo[2];
 };
 
-#define KVM_MIPS_FPU_FPU       0x1
-#define KVM_MIPS_FPU_MSA       0x2
+#define KVM_MIPS_AUX_FPU       0x1
+#define KVM_MIPS_AUX_MSA       0x2
 
 #define KVM_MIPS_GUEST_TLB_SIZE        64
 struct kvm_vcpu_arch {
-       void *host_ebase, *guest_ebase;
+       void *guest_ebase;
        int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu);
        unsigned long host_stack;
        unsigned long host_gp;
 
        /* Host CP0 registers used when handling exits from guest */
        unsigned long host_cp0_badvaddr;
-       unsigned long host_cp0_cause;
        unsigned long host_cp0_epc;
-       unsigned long host_cp0_entryhi;
-       uint32_t guest_inst;
+       u32 host_cp0_cause;
 
        /* GPRS */
        unsigned long gprs[32];
@@ -357,8 +270,8 @@ struct kvm_vcpu_arch {
 
        /* FPU State */
        struct mips_fpu_struct fpu;
-       /* Which FPU state is loaded (KVM_MIPS_FPU_*) */
-       unsigned int fpu_inuse;
+       /* Which auxiliary state is loaded (KVM_MIPS_AUX_*) */
+       unsigned int aux_inuse;
 
        /* COP0 State */
        struct mips_coproc *cop0;
@@ -370,11 +283,11 @@ struct kvm_vcpu_arch {
 
        struct hrtimer comparecount_timer;
        /* Count timer control KVM register */
-       uint32_t count_ctl;
+       u32 count_ctl;
        /* Count bias from the raw time */
-       uint32_t count_bias;
+       u32 count_bias;
        /* Frequency of timer in Hz */
-       uint32_t count_hz;
+       u32 count_hz;
        /* Dynamic nanosecond bias (multiple of count_period) to avoid overflow */
        s64 count_dyn_bias;
        /* Resume time */
@@ -388,7 +301,7 @@ struct kvm_vcpu_arch {
        /* Bitmask of pending exceptions to be cleared */
        unsigned long pending_exceptions_clr;
 
-       unsigned long pending_load_cause;
+       u32 pending_load_cause;
 
        /* Save/Restore the entryhi register when are are preempted/scheduled back in */
        unsigned long preempt_entryhi;
@@ -397,8 +310,8 @@ struct kvm_vcpu_arch {
        struct kvm_mips_tlb guest_tlb[KVM_MIPS_GUEST_TLB_SIZE];
 
        /* Cached guest kernel/user ASIDs */
-       uint32_t guest_user_asid[NR_CPUS];
-       uint32_t guest_kernel_asid[NR_CPUS];
+       u32 guest_user_asid[NR_CPUS];
+       u32 guest_kernel_asid[NR_CPUS];
        struct mm_struct guest_kernel_mm, guest_user_mm;
 
        int last_sched_cpu;
@@ -408,6 +321,7 @@ struct kvm_vcpu_arch {
 
        u8 fpu_enabled;
        u8 msa_enabled;
+       u8 kscratch_enabled;
 };
 
 
@@ -461,6 +375,18 @@ struct kvm_vcpu_arch {
 #define kvm_write_c0_guest_config7(cop0, val)  (cop0->reg[MIPS_CP0_CONFIG][7] = (val))
 #define kvm_read_c0_guest_errorepc(cop0)       (cop0->reg[MIPS_CP0_ERROR_PC][0])
 #define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val))
+#define kvm_read_c0_guest_kscratch1(cop0)      (cop0->reg[MIPS_CP0_DESAVE][2])
+#define kvm_read_c0_guest_kscratch2(cop0)      (cop0->reg[MIPS_CP0_DESAVE][3])
+#define kvm_read_c0_guest_kscratch3(cop0)      (cop0->reg[MIPS_CP0_DESAVE][4])
+#define kvm_read_c0_guest_kscratch4(cop0)      (cop0->reg[MIPS_CP0_DESAVE][5])
+#define kvm_read_c0_guest_kscratch5(cop0)      (cop0->reg[MIPS_CP0_DESAVE][6])
+#define kvm_read_c0_guest_kscratch6(cop0)      (cop0->reg[MIPS_CP0_DESAVE][7])
+#define kvm_write_c0_guest_kscratch1(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][2] = (val))
+#define kvm_write_c0_guest_kscratch2(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][3] = (val))
+#define kvm_write_c0_guest_kscratch3(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][4] = (val))
+#define kvm_write_c0_guest_kscratch4(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][5] = (val))
+#define kvm_write_c0_guest_kscratch5(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][6] = (val))
+#define kvm_write_c0_guest_kscratch6(cop0, val)        (cop0->reg[MIPS_CP0_DESAVE][7] = (val))
 
 /*
  * Some of the guest registers may be modified asynchronously (e.g. from a
@@ -474,7 +400,7 @@ static inline void _kvm_atomic_set_c0_guest_reg(unsigned long *reg,
        unsigned long temp;
        do {
                __asm__ __volatile__(
-               "       .set    mips3                           \n"
+               "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
                "       " __LL "%0, %1                          \n"
                "       or      %0, %2                          \n"
                "       " __SC  "%0, %1                         \n"
@@ -490,7 +416,7 @@ static inline void _kvm_atomic_clear_c0_guest_reg(unsigned long *reg,
        unsigned long temp;
        do {
                __asm__ __volatile__(
-               "       .set    mips3                           \n"
+               "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
                "       " __LL "%0, %1                          \n"
                "       and     %0, %2                          \n"
                "       " __SC  "%0, %1                         \n"
@@ -507,7 +433,7 @@ static inline void _kvm_atomic_change_c0_guest_reg(unsigned long *reg,
        unsigned long temp;
        do {
                __asm__ __volatile__(
-               "       .set    mips3                           \n"
+               "       .set    "MIPS_ISA_ARCH_LEVEL"           \n"
                "       " __LL "%0, %1                          \n"
                "       and     %0, %2                          \n"
                "       or      %0, %3                          \n"
@@ -542,7 +468,7 @@ static inline void _kvm_atomic_change_c0_guest_reg(unsigned long *reg,
 
 static inline bool kvm_mips_guest_can_have_fpu(struct kvm_vcpu_arch *vcpu)
 {
-       return (!__builtin_constant_p(cpu_has_fpu) || cpu_has_fpu) &&
+       return (!__builtin_constant_p(raw_cpu_has_fpu) || raw_cpu_has_fpu) &&
                vcpu->fpu_enabled;
 }
 
@@ -589,9 +515,11 @@ struct kvm_mips_callbacks {
        void (*dequeue_io_int)(struct kvm_vcpu *vcpu,
                               struct kvm_mips_interrupt *irq);
        int (*irq_deliver)(struct kvm_vcpu *vcpu, unsigned int priority,
-                          uint32_t cause);
+                          u32 cause);
        int (*irq_clear)(struct kvm_vcpu *vcpu, unsigned int priority,
-                        uint32_t cause);
+                        u32 cause);
+       unsigned long (*num_regs)(struct kvm_vcpu *vcpu);
+       int (*copy_reg_indices)(struct kvm_vcpu *vcpu, u64 __user *indices);
        int (*get_one_reg)(struct kvm_vcpu *vcpu,
                           const struct kvm_one_reg *reg, s64 *v);
        int (*set_one_reg)(struct kvm_vcpu *vcpu,
@@ -605,8 +533,13 @@ int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks);
 /* Debug: dump vcpu state */
 int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
 
-/* Trampoline ASM routine to start running in "Guest" context */
-extern int __kvm_mips_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu);
+extern int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+/* Building of entry/exception code */
+int kvm_mips_entry_setup(void);
+void *kvm_mips_build_vcpu_run(void *addr);
+void *kvm_mips_build_exception(void *addr, void *handler);
+void *kvm_mips_build_exit(void *addr);
 
 /* FPU/MSA context management */
 void __kvm_save_fpu(struct kvm_vcpu_arch *vcpu);
@@ -622,11 +555,11 @@ void kvm_drop_fpu(struct kvm_vcpu *vcpu);
 void kvm_lose_fpu(struct kvm_vcpu *vcpu);
 
 /* TLB handling */
-uint32_t kvm_get_kernel_asid(struct kvm_vcpu *vcpu);
+u32 kvm_get_kernel_asid(struct kvm_vcpu *vcpu);
 
-uint32_t kvm_get_user_asid(struct kvm_vcpu *vcpu);
+u32 kvm_get_user_asid(struct kvm_vcpu *vcpu);
 
-uint32_t kvm_get_commpage_asid (struct kvm_vcpu *vcpu);
+u32 kvm_get_commpage_asid (struct kvm_vcpu *vcpu);
 
 extern int kvm_mips_handle_kseg0_tlb_fault(unsigned long badbaddr,
                                           struct kvm_vcpu *vcpu);
@@ -635,22 +568,24 @@ extern int kvm_mips_handle_commpage_tlb_fault(unsigned long badvaddr,
                                              struct kvm_vcpu *vcpu);
 
 extern int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
-                                               struct kvm_mips_tlb *tlb,
-                                               unsigned long *hpa0,
-                                               unsigned long *hpa1);
+                                               struct kvm_mips_tlb *tlb);
 
-extern enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause,
-                                                    uint32_t *opc,
+extern enum emulation_result kvm_mips_handle_tlbmiss(u32 cause,
+                                                    u32 *opc,
                                                     struct kvm_run *run,
                                                     struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause,
-                                                   uint32_t *opc,
+extern enum emulation_result kvm_mips_handle_tlbmod(u32 cause,
+                                                   u32 *opc,
                                                    struct kvm_run *run,
                                                    struct kvm_vcpu *vcpu);
 
 extern void kvm_mips_dump_host_tlbs(void);
 extern void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu);
+extern int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
+                                  unsigned long entrylo0,
+                                  unsigned long entrylo1,
+                                  int flush_dcache_mask);
 extern void kvm_mips_flush_host_tlb(int skip_kseg0);
 extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi);
 
@@ -667,90 +602,90 @@ extern void kvm_mips_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
 extern void kvm_mips_vcpu_put(struct kvm_vcpu *vcpu);
 
 /* Emulation */
-uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu);
-enum emulation_result update_pc(struct kvm_vcpu *vcpu, uint32_t cause);
+u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu);
+enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause);
 
-extern enum emulation_result kvm_mips_emulate_inst(unsigned long cause,
-                                                  uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_inst(u32 cause,
+                                                  u32 *opc,
                                                   struct kvm_run *run,
                                                   struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_syscall(unsigned long cause,
-                                                     uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_syscall(u32 cause,
+                                                     u32 *opc,
                                                      struct kvm_run *run,
                                                      struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_tlbmiss_ld(unsigned long cause,
-                                                        uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_tlbmiss_ld(u32 cause,
+                                                        u32 *opc,
                                                         struct kvm_run *run,
                                                         struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_tlbinv_ld(unsigned long cause,
-                                                       uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_tlbinv_ld(u32 cause,
+                                                       u32 *opc,
                                                        struct kvm_run *run,
                                                        struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_tlbmiss_st(unsigned long cause,
-                                                        uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_tlbmiss_st(u32 cause,
+                                                        u32 *opc,
                                                         struct kvm_run *run,
                                                         struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_tlbinv_st(unsigned long cause,
-                                                       uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_tlbinv_st(u32 cause,
+                                                       u32 *opc,
                                                        struct kvm_run *run,
                                                        struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_tlbmod(unsigned long cause,
-                                                    uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_tlbmod(u32 cause,
+                                                    u32 *opc,
                                                     struct kvm_run *run,
                                                     struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_fpu_exc(unsigned long cause,
-                                                     uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_fpu_exc(u32 cause,
+                                                     u32 *opc,
                                                      struct kvm_run *run,
                                                      struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_handle_ri(unsigned long cause,
-                                               uint32_t *opc,
+extern enum emulation_result kvm_mips_handle_ri(u32 cause,
+                                               u32 *opc,
                                                struct kvm_run *run,
                                                struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_ri_exc(unsigned long cause,
-                                                    uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_ri_exc(u32 cause,
+                                                    u32 *opc,
                                                     struct kvm_run *run,
                                                     struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
-                                                    uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_bp_exc(u32 cause,
+                                                    u32 *opc,
                                                     struct kvm_run *run,
                                                     struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
-                                                      uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_trap_exc(u32 cause,
+                                                      u32 *opc,
                                                       struct kvm_run *run,
                                                       struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_msafpe_exc(unsigned long cause,
-                                                        uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_msafpe_exc(u32 cause,
+                                                        u32 *opc,
                                                         struct kvm_run *run,
                                                         struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause,
-                                                     uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_fpe_exc(u32 cause,
+                                                     u32 *opc,
                                                      struct kvm_run *run,
                                                      struct kvm_vcpu *vcpu);
 
-extern enum emulation_result kvm_mips_emulate_msadis_exc(unsigned long cause,
-                                                        uint32_t *opc,
+extern enum emulation_result kvm_mips_emulate_msadis_exc(u32 cause,
+                                                        u32 *opc,
                                                         struct kvm_run *run,
                                                         struct kvm_vcpu *vcpu);
 
 extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
                                                         struct kvm_run *run);
 
-uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu);
-void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count);
-void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack);
+u32 kvm_mips_read_count(struct kvm_vcpu *vcpu);
+void kvm_mips_write_count(struct kvm_vcpu *vcpu, u32 count);
+void kvm_mips_write_compare(struct kvm_vcpu *vcpu, u32 compare, bool ack);
 void kvm_mips_init_count(struct kvm_vcpu *vcpu);
 int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl);
 int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume);
@@ -759,27 +694,27 @@ void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu);
 void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu);
 enum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu);
 
-enum emulation_result kvm_mips_check_privilege(unsigned long cause,
-                                              uint32_t *opc,
+enum emulation_result kvm_mips_check_privilege(u32 cause,
+                                              u32 *opc,
                                               struct kvm_run *run,
                                               struct kvm_vcpu *vcpu);
 
-enum emulation_result kvm_mips_emulate_cache(uint32_t inst,
-                                            uint32_t *opc,
-                                            uint32_t cause,
+enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
+                                            u32 *opc,
+                                            u32 cause,
                                             struct kvm_run *run,
                                             struct kvm_vcpu *vcpu);
-enum emulation_result kvm_mips_emulate_CP0(uint32_t inst,
-                                          uint32_t *opc,
-                                          uint32_t cause,
+enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
+                                          u32 *opc,
+                                          u32 cause,
                                           struct kvm_run *run,
                                           struct kvm_vcpu *vcpu);
-enum emulation_result kvm_mips_emulate_store(uint32_t inst,
-                                            uint32_t cause,
+enum emulation_result kvm_mips_emulate_store(union mips_instruction inst,
+                                            u32 cause,
                                             struct kvm_run *run,
                                             struct kvm_vcpu *vcpu);
-enum emulation_result kvm_mips_emulate_load(uint32_t inst,
-                                           uint32_t cause,
+enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
+                                           u32 cause,
                                            struct kvm_run *run,
                                            struct kvm_vcpu *vcpu);
 
@@ -789,13 +724,13 @@ unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu);
 unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu);
 
 /* Dynamic binary translation */
-extern int kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc,
-                                     struct kvm_vcpu *vcpu);
-extern int kvm_mips_trans_cache_va(uint32_t inst, uint32_t *opc,
+extern int kvm_mips_trans_cache_index(union mips_instruction inst,
+                                     u32 *opc, struct kvm_vcpu *vcpu);
+extern int kvm_mips_trans_cache_va(union mips_instruction inst, u32 *opc,
                                   struct kvm_vcpu *vcpu);
-extern int kvm_mips_trans_mfc0(uint32_t inst, uint32_t *opc,
+extern int kvm_mips_trans_mfc0(union mips_instruction inst, u32 *opc,
                               struct kvm_vcpu *vcpu);
-extern int kvm_mips_trans_mtc0(uint32_t inst, uint32_t *opc,
+extern int kvm_mips_trans_mtc0(union mips_instruction inst, u32 *opc,
                               struct kvm_vcpu *vcpu);
 
 /* Misc */
index d68e685..bd8b9bb 100644 (file)
@@ -55,7 +55,7 @@
 #define cpu_has_mipsmt         0
 #define cpu_has_vint           0
 #define cpu_has_veic           0
-#define cpu_hwrena_impl_bits   0xc0000000
+#define cpu_hwrena_impl_bits   (MIPS_HWRENA_IMPL1 | MIPS_HWRENA_IMPL2)
 #define cpu_has_wsbh            1
 
 #define cpu_has_rixi           (cpu_data[0].cputype != CPU_CAVIUM_OCTEON)
index cceae32..64b86b9 100644 (file)
@@ -42,8 +42,6 @@ enum octeon_irq {
        OCTEON_IRQ_TIMER1,
        OCTEON_IRQ_TIMER2,
        OCTEON_IRQ_TIMER3,
-       OCTEON_IRQ_USB0,
-       OCTEON_IRQ_USB1,
 #ifndef CONFIG_PCI_MSI
        OCTEON_IRQ_LAST = 127
 #endif
index 374eefa..0cf5ac1 100644 (file)
 
 #ifdef __BIG_ENDIAN
 
+static inline bool __should_swizzle_bits(volatile void *a)
+{
+       extern const bool octeon_should_swizzle_table[];
+
+       unsigned long did = ((unsigned long)a >> 40) & 0xff;
+       return octeon_should_swizzle_table[did];
+}
+
 # define __swizzle_addr_b(port)        (port)
 # define __swizzle_addr_w(port)        (port)
 # define __swizzle_addr_l(port)        (port)
@@ -19,6 +27,8 @@
 
 #else /* __LITTLE_ENDIAN */
 
+#define __should_swizzle_bits(a)       false
+
 static inline bool __should_swizzle_addr(unsigned long p)
 {
        /* boot bus? */
@@ -35,40 +45,14 @@ static inline bool __should_swizzle_addr(unsigned long p)
 
 #endif /* __BIG_ENDIAN */
 
-/*
- * Sane hardware offers swapping of PCI/ISA I/O space accesses in hardware;
- * less sane hardware forces software to fiddle with this...
- *
- * Regardless, if the host bus endianness mismatches that of PCI/ISA, then
- * you can't have the numerical value of data and byte addresses within
- * multibyte quantities both preserved at the same time.  Hence two
- * variations of functions: non-prefixed ones that preserve the value
- * and prefixed ones that preserve byte addresses.  The latters are
- * typically used for moving raw data between a peripheral and memory (cf.
- * string I/O functions), hence the "__mem_" prefix.
- */
-#if defined(CONFIG_SWAP_IO_SPACE)
 
 # define ioswabb(a, x)         (x)
 # define __mem_ioswabb(a, x)   (x)
-# define ioswabw(a, x)         le16_to_cpu(x)
+# define ioswabw(a, x)         (__should_swizzle_bits(a) ? le16_to_cpu(x) : x)
 # define __mem_ioswabw(a, x)   (x)
-# define ioswabl(a, x)         le32_to_cpu(x)
+# define ioswabl(a, x)         (__should_swizzle_bits(a) ? le32_to_cpu(x) : x)
 # define __mem_ioswabl(a, x)   (x)
-# define ioswabq(a, x)         le64_to_cpu(x)
+# define ioswabq(a, x)         (__should_swizzle_bits(a) ? le64_to_cpu(x) : x)
 # define __mem_ioswabq(a, x)   (x)
 
-#else
-
-# define ioswabb(a, x)         (x)
-# define __mem_ioswabb(a, x)   (x)
-# define ioswabw(a, x)         (x)
-# define __mem_ioswabw(a, x)   cpu_to_le16(x)
-# define ioswabl(a, x)         (x)
-# define __mem_ioswabl(a, x)   cpu_to_le32(x)
-# define ioswabq(a, x)         (x)
-# define __mem_ioswabq(a, x)   cpu_to_le32(x)
-
-#endif
-
 #endif /* __ASM_MACH_GENERIC_MANGLE_PORT_H */
index 9411a4c..58e7874 100644 (file)
@@ -462,7 +462,7 @@ static inline unsigned int mips_cm_max_vp_width(void)
        if (mips_cm_revision() >= CM_REV_CM3)
                return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK;
 
-       if (config_enabled(CONFIG_SMP))
+       if (IS_ENABLED(CONFIG_SMP))
                return smp_num_siblings;
 
        return 1;
index e1ca65c..def9d8d 100644 (file)
@@ -53,7 +53,7 @@
 #define CP0_SEGCTL2 $5, 4
 #define CP0_WIRED $6
 #define CP0_INFO $7
-#define CP0_HWRENA $7, 0
+#define CP0_HWRENA $7
 #define CP0_BADVADDR $8
 #define CP0_BADINSTR $8, 1
 #define CP0_COUNT $9
 #define TX49_CONF_CWFON                (_ULCAST_(1) << 27)
 
 /* Bits specific to the MIPS32/64 PRA. */
+#define MIPS_CONF_VI           (_ULCAST_(1) <<  3)
 #define MIPS_CONF_MT           (_ULCAST_(7) <<  7)
 #define MIPS_CONF_MT_TLB       (_ULCAST_(1) <<  7)
 #define MIPS_CONF_MT_FTLB      (_ULCAST_(4) <<  7)
 #define MIPS_CDMMBASE_ADDR_SHIFT 11
 #define MIPS_CDMMBASE_ADDR_START 15
 
+/* RDHWR register numbers */
+#define MIPS_HWR_CPUNUM                0       /* CPU number */
+#define MIPS_HWR_SYNCISTEP     1       /* SYNCI step size */
+#define MIPS_HWR_CC            2       /* Cycle counter */
+#define MIPS_HWR_CCRES         3       /* Cycle counter resolution */
+#define MIPS_HWR_ULR           29      /* UserLocal */
+#define MIPS_HWR_IMPL1         30      /* Implementation dependent */
+#define MIPS_HWR_IMPL2         31      /* Implementation dependent */
+
+/* Bits in HWREna register */
+#define MIPS_HWRENA_CPUNUM     (_ULCAST_(1) << MIPS_HWR_CPUNUM)
+#define MIPS_HWRENA_SYNCISTEP  (_ULCAST_(1) << MIPS_HWR_SYNCISTEP)
+#define MIPS_HWRENA_CC         (_ULCAST_(1) << MIPS_HWR_CC)
+#define MIPS_HWRENA_CCRES      (_ULCAST_(1) << MIPS_HWR_CCRES)
+#define MIPS_HWRENA_ULR                (_ULCAST_(1) << MIPS_HWR_ULR)
+#define MIPS_HWRENA_IMPL1      (_ULCAST_(1) << MIPS_HWR_IMPL1)
+#define MIPS_HWRENA_IMPL2      (_ULCAST_(1) << MIPS_HWR_IMPL2)
+
 /*
  * Bitfields in the TX39 family CP0 Configuration Register 3
  */
index 1afa1f9..f6ba08d 100644 (file)
@@ -2,11 +2,20 @@
 #define __ASM_MMU_H
 
 #include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
 
 typedef struct {
        unsigned long asid[NR_CPUS];
        void *vdso;
        atomic_t fp_mode_switching;
+
+       /* lock to be held whilst modifying fp_bd_emupage_allocmap */
+       spinlock_t bd_emupage_lock;
+       /* bitmap tracking allocation of fp_bd_emupage */
+       unsigned long *bd_emupage_allocmap;
+       /* wait queue for threads requiring an emuframe */
+       wait_queue_head_t bd_emupage_queue;
 } mm_context_t;
 
 #endif /* __ASM_MMU_H */
index fc57e13..ddd57ad 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/smp.h>
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
+#include <asm/dsemul.h>
 #include <asm/hazards.h>
 #include <asm/tlbflush.h>
 #include <asm-generic/mm_hooks.h>
@@ -128,6 +129,10 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
        atomic_set(&mm->context.fp_mode_switching, 0);
 
+       mm->context.bd_emupage_allocmap = NULL;
+       spin_lock_init(&mm->context.bd_emupage_lock);
+       init_waitqueue_head(&mm->context.bd_emupage_queue);
+
        return 0;
 }
 
@@ -162,6 +167,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  */
 static inline void destroy_context(struct mm_struct *mm)
 {
+       dsemul_mm_cleanup(mm);
 }
 
 #define deactivate_mm(tsk, mm) do { } while (0)
index ddf496c..8967b47 100644 (file)
@@ -168,6 +168,7 @@ static inline unsigned int read_msa_##name(void)            \
        unsigned int reg;                                       \
        __asm__ __volatile__(                                   \
        "       .set    push\n"                                 \
+       "       .set    fp=64\n"                                \
        "       .set    msa\n"                                  \
        "       cfcmsa  %0, $" #cs "\n"                         \
        "       .set    pop\n"                                  \
@@ -179,6 +180,7 @@ static inline void write_msa_##name(unsigned int val)               \
 {                                                              \
        __asm__ __volatile__(                                   \
        "       .set    push\n"                                 \
+       "       .set    fp=64\n"                                \
        "       .set    msa\n"                                  \
        "       ctcmsa  $" #cs ", %0\n"                         \
        "       .set    pop\n"                                  \
index 21ed715..ea0cd97 100644 (file)
@@ -162,16 +162,34 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /*
  * __pa()/__va() should be used only during mem init.
  */
-#ifdef CONFIG_64BIT
-#define __pa(x)                                                                \
-({                                                                     \
-    unsigned long __x = (unsigned long)(x);                            \
-    __x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x);                    \
-})
-#else
-#define __pa(x)                                                                \
-    ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
-#endif
+static inline unsigned long ___pa(unsigned long x)
+{
+       if (config_enabled(CONFIG_64BIT)) {
+               /*
+                * For MIPS64 the virtual address may either be in one of
+                * the compatibility segements ckseg0 or ckseg1, or it may
+                * be in xkphys.
+                */
+               return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
+       }
+
+       if (!config_enabled(CONFIG_EVA)) {
+               /*
+                * We're using the standard MIPS32 legacy memory map, ie.
+                * the address x is going to be in kseg0 or kseg1. We can
+                * handle either case by masking out the desired bits using
+                * CPHYSADDR.
+                */
+               return CPHYSADDR(x);
+       }
+
+       /*
+        * EVA is in use so the memory map could be anything, making it not
+        * safe to just mask out bits.
+        */
+       return x - PAGE_OFFSET + PHYS_OFFSET;
+}
+#define __pa(x)                ___pa((unsigned long)(x))
 #define __va(x)                ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
 #include <asm/io.h>
 
@@ -229,8 +247,10 @@ extern int __virt_addr_valid(const volatile void *kaddr);
 #define virt_addr_valid(kaddr)                                         \
        __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 VM_DATA_DEFAULT_FLAGS \
+       (VM_READ | VM_WRITE | \
+        ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define UNCAC_ADDR(addr)       ((addr) - PAGE_OFFSET + UNCAC_BASE)
 #define CAC_ADDR(addr)         ((addr) - UNCAC_BASE + PAGE_OFFSET)
index 86b239d..9b63cd4 100644 (file)
@@ -80,16 +80,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
 
-static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-               const struct resource *rsrc, resource_size_t *start,
-               resource_size_t *end)
-{
-       phys_addr_t size = resource_size(rsrc);
-
-       *start = fixup_bigphys_addr(rsrc->start, size);
-       *end = rsrc->start + size;
-}
-
 /*
  * Dynamic DMA mapping stuff.
  * MIPS has everything mapped statically.
index 7d44e88..70128d3 100644 (file)
@@ -159,7 +159,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
                 * it better already be global)
                 */
                if (pte_none(*buddy)) {
-                       if (!config_enabled(CONFIG_XPA))
+                       if (!IS_ENABLED(CONFIG_XPA))
                                buddy->pte_low |= _PAGE_GLOBAL;
                        buddy->pte_high |= _PAGE_GLOBAL;
                }
@@ -172,7 +172,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
 
        htw_stop();
        /* Preserve global status for the pair */
-       if (config_enabled(CONFIG_XPA)) {
+       if (IS_ENABLED(CONFIG_XPA)) {
                if (ptep_buddy(ptep)->pte_high & _PAGE_GLOBAL)
                        null.pte_high = _PAGE_GLOBAL;
        } else {
@@ -319,7 +319,7 @@ static inline int pte_young(pte_t pte)      { return pte.pte_low & _PAGE_ACCESSED; }
 static inline pte_t pte_wrprotect(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_WRITE;
-       if (!config_enabled(CONFIG_XPA))
+       if (!IS_ENABLED(CONFIG_XPA))
                pte.pte_low &= ~_PAGE_SILENT_WRITE;
        pte.pte_high &= ~_PAGE_SILENT_WRITE;
        return pte;
@@ -328,7 +328,7 @@ static inline pte_t pte_wrprotect(pte_t pte)
 static inline pte_t pte_mkclean(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_MODIFIED;
-       if (!config_enabled(CONFIG_XPA))
+       if (!IS_ENABLED(CONFIG_XPA))
                pte.pte_low &= ~_PAGE_SILENT_WRITE;
        pte.pte_high &= ~_PAGE_SILENT_WRITE;
        return pte;
@@ -337,7 +337,7 @@ static inline pte_t pte_mkclean(pte_t pte)
 static inline pte_t pte_mkold(pte_t pte)
 {
        pte.pte_low  &= ~_PAGE_ACCESSED;
-       if (!config_enabled(CONFIG_XPA))
+       if (!IS_ENABLED(CONFIG_XPA))
                pte.pte_low &= ~_PAGE_SILENT_READ;
        pte.pte_high &= ~_PAGE_SILENT_READ;
        return pte;
@@ -347,7 +347,7 @@ static inline pte_t pte_mkwrite(pte_t pte)
 {
        pte.pte_low |= _PAGE_WRITE;
        if (pte.pte_low & _PAGE_MODIFIED) {
-               if (!config_enabled(CONFIG_XPA))
+               if (!IS_ENABLED(CONFIG_XPA))
                        pte.pte_low |= _PAGE_SILENT_WRITE;
                pte.pte_high |= _PAGE_SILENT_WRITE;
        }
@@ -358,7 +358,7 @@ static inline pte_t pte_mkdirty(pte_t pte)
 {
        pte.pte_low |= _PAGE_MODIFIED;
        if (pte.pte_low & _PAGE_WRITE) {
-               if (!config_enabled(CONFIG_XPA))
+               if (!IS_ENABLED(CONFIG_XPA))
                        pte.pte_low |= _PAGE_SILENT_WRITE;
                pte.pte_high |= _PAGE_SILENT_WRITE;
        }
@@ -369,7 +369,7 @@ static inline pte_t pte_mkyoung(pte_t pte)
 {
        pte.pte_low |= _PAGE_ACCESSED;
        if (!(pte.pte_low & _PAGE_NO_READ)) {
-               if (!config_enabled(CONFIG_XPA))
+               if (!IS_ENABLED(CONFIG_XPA))
                        pte.pte_low |= _PAGE_SILENT_READ;
                pte.pte_high |= _PAGE_SILENT_READ;
        }
index 7e78b62..0d36c87 100644 (file)
 #ifndef _ASM_PROCESSOR_H
 #define _ASM_PROCESSOR_H
 
+#include <linux/atomic.h>
 #include <linux/cpumask.h>
 #include <linux/threads.h>
 
 #include <asm/cachectl.h>
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
+#include <asm/dsemul.h>
 #include <asm/mipsregs.h>
 #include <asm/prefetch.h>
 
@@ -78,7 +80,11 @@ extern unsigned int vced_count, vcei_count;
 
 #endif
 
-#define STACK_TOP      (TASK_SIZE & PAGE_MASK)
+/*
+ * One page above the stack is used for branch delay slot "emulation".
+ * See dsemul.c for details.
+ */
+#define STACK_TOP      ((TASK_SIZE & PAGE_MASK) - PAGE_SIZE)
 
 /*
  * This decides where the kernel will search for a free chunk of vm
@@ -256,6 +262,12 @@ struct thread_struct {
 
        /* Saved fpu/fpu emulator stuff. */
        struct mips_fpu_struct fpu FPU_ALIGN;
+       /* Assigned branch delay slot 'emulation' frame */
+       atomic_t bd_emu_frame;
+       /* PC of the branch from a branch delay slot 'emulation' */
+       unsigned long bd_emu_branch_pc;
+       /* PC to continue from following a branch delay slot 'emulation' */
+       unsigned long bd_emu_cont_pc;
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* Emulated instruction count */
        unsigned long emulated_fp;
@@ -323,6 +335,10 @@ struct thread_struct {
         * FPU affinity state (null if not FPAFF)               \
         */                                                     \
        FPAFF_INIT                                              \
+       /* Delay slot emulation */                              \
+       .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),          \
+       .bd_emu_branch_pc = 0,                                  \
+       .bd_emu_cont_pc = 0,                                    \
        /*                                                      \
         * Saved DSP stuff                                      \
         */                                                     \
index 38902bf..667ca3c 100644 (file)
@@ -210,7 +210,11 @@ static inline void protected_writeback_dcache_line(unsigned long addr)
 
 static inline void protected_writeback_scache_line(unsigned long addr)
 {
+#ifdef CONFIG_EVA
+       protected_cachee_op(Hit_Writeback_Inv_SD, addr);
+#else
        protected_cache_op(Hit_Writeback_Inv_SD, addr);
+#endif
 }
 
 /*
index 684fb3a..d886d6f 100644 (file)
@@ -16,10 +16,10 @@ static inline const int *get_compat_mode1_syscalls(void)
                0, /* null terminated */
        };
 
-       if (config_enabled(CONFIG_MIPS32_O32) && test_thread_flag(TIF_32BIT_REGS))
+       if (IS_ENABLED(CONFIG_MIPS32_O32) && test_thread_flag(TIF_32BIT_REGS))
                return syscalls_O32;
 
-       if (config_enabled(CONFIG_MIPS32_N32))
+       if (IS_ENABLED(CONFIG_MIPS32_N32))
                return syscalls_N32;
 
        BUG();
index d7bfdeb..4f5279a 100644 (file)
@@ -21,6 +21,7 @@ extern void *set_vi_handler(int n, vi_handler_t addr);
 
 extern void *set_except_vector(int n, void *addr);
 extern unsigned long ebase;
+extern unsigned int hwrena;
 extern void per_cpu_trap_init(bool);
 extern void cpu_cache_init(void);
 
index 2292373..23d6b80 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <uapi/asm/signal.h>
 
-#ifdef CONFIG_MIPS32_COMPAT
+#ifdef CONFIG_MIPS32_O32
 extern struct mips_abi mips_abi_32;
 
 #define sig_uses_siginfo(ka, abi)                               \
@@ -19,8 +19,8 @@ extern struct mips_abi mips_abi_32;
                ((ka)->sa.sa_flags & SA_SIGINFO))
 #else
 #define sig_uses_siginfo(ka, abi)                               \
-       (config_enabled(CONFIG_64BIT) ? 1 :                     \
-               (config_enabled(CONFIG_TRAD_SIGNALS) ?          \
+       (IS_ENABLED(CONFIG_64BIT) ? 1 :                     \
+               (IS_ENABLED(CONFIG_TRAD_SIGNALS) ?          \
                        ((ka)->sa.sa_flags & SA_SIGINFO) : 1) )
 #endif
 
index 03722d4..8bc6c70 100644 (file)
@@ -23,7 +23,7 @@
 extern int smp_num_siblings;
 extern cpumask_t cpu_sibling_map[];
 extern cpumask_t cpu_core_map[];
-extern cpumask_t cpu_foreign_map;
+extern cpumask_t cpu_foreign_map[];
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
@@ -53,6 +53,8 @@ extern cpumask_t cpu_coherent_mask;
 
 extern void asmlinkage smp_bootstrap(void);
 
+extern void calculate_cpu_foreign_map(void);
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
index 47bc45a..d878825 100644 (file)
@@ -99,7 +99,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
 {
        int ret;
        /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
-       if ((config_enabled(CONFIG_32BIT) ||
+       if ((IS_ENABLED(CONFIG_32BIT) ||
            test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
            (regs->regs[2] == __NR_syscall))
                i++;
index 7f109d4..11b965f 100644 (file)
@@ -88,7 +88,7 @@ extern u64 __ua_limit;
  */
 static inline bool eva_kernel_access(void)
 {
-       if (!config_enabled(CONFIG_EVA))
+       if (!IS_ENABLED(CONFIG_EVA))
                return false;
 
        return segment_eq(get_fs(), get_ds());
index b6ecfee..f7929f6 100644 (file)
@@ -104,8 +104,13 @@ Ip_u1s2(_bltz);
 Ip_u1s2(_bltzl);
 Ip_u1u2s3(_bne);
 Ip_u2s3u1(_cache);
+Ip_u1u2(_cfc1);
+Ip_u2u1(_cfcmsa);
+Ip_u1u2(_ctc1);
+Ip_u2u1(_ctcmsa);
 Ip_u2u1s3(_daddiu);
 Ip_u3u1u2(_daddu);
+Ip_u1(_di);
 Ip_u2u1msbu3(_dins);
 Ip_u2u1msbu3(_dinsm);
 Ip_u1u2(_divu);
@@ -141,6 +146,8 @@ Ip_u1(_mfhi);
 Ip_u1(_mflo);
 Ip_u1u2u3(_mtc0);
 Ip_u1u2u3(_mthc0);
+Ip_u1(_mthi);
+Ip_u1(_mtlo);
 Ip_u3u1u2(_mul);
 Ip_u3u1u2(_or);
 Ip_u2u1u3(_ori);
index c9c7195..45ba259 100644 (file)
@@ -14,4 +14,6 @@
 /* Location of VDSO image. */
 #define AT_SYSINFO_EHDR                33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif /* __ASM_AUXVEC_H */
index 8051f9a..77429d1 100644 (file)
 enum major_op {
        spec_op, bcond_op, j_op, jal_op,
        beq_op, bne_op, blez_op, bgtz_op,
-       addi_op, cbcond0_op = addi_op, addiu_op, slti_op, sltiu_op,
+       addi_op, pop10_op = addi_op, addiu_op, slti_op, sltiu_op,
        andi_op, ori_op, xori_op, lui_op,
        cop0_op, cop1_op, cop2_op, cop1x_op,
        beql_op, bnel_op, blezl_op, bgtzl_op,
-       daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op,
+       daddi_op, pop30_op = daddi_op, daddiu_op, ldl_op, ldr_op,
        spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op,
        lb_op, lh_op, lwl_op, lw_op,
        lbu_op, lhu_op, lwr_op, lwu_op,
        sb_op, sh_op, swl_op, sw_op,
        sdl_op, sdr_op, swr_op, cache_op,
        ll_op, lwc1_op, lwc2_op, bc6_op = lwc2_op, pref_op,
-       lld_op, ldc1_op, ldc2_op, beqzcjic_op = ldc2_op, ld_op,
+       lld_op, ldc1_op, ldc2_op, pop66_op = ldc2_op, ld_op,
        sc_op, swc1_op, swc2_op, balc6_op = swc2_op, major_3b_op,
-       scd_op, sdc1_op, sdc2_op, bnezcjialc_op = sdc2_op, sd_op
+       scd_op, sdc1_op, sdc2_op, pop76_op = sdc2_op, sd_op
 };
 
 /*
@@ -92,6 +92,50 @@ enum spec3_op {
        rdhwr_op  = 0x3b
 };
 
+/*
+ * Bits 10-6 minor opcode for r6 spec mult/div encodings
+ */
+enum mult_op {
+       mult_mult_op = 0x0,
+       mult_mul_op = 0x2,
+       mult_muh_op = 0x3,
+};
+enum multu_op {
+       multu_multu_op = 0x0,
+       multu_mulu_op = 0x2,
+       multu_muhu_op = 0x3,
+};
+enum div_op {
+       div_div_op = 0x0,
+       div_div6_op = 0x2,
+       div_mod_op = 0x3,
+};
+enum divu_op {
+       divu_divu_op = 0x0,
+       divu_divu6_op = 0x2,
+       divu_modu_op = 0x3,
+};
+enum dmult_op {
+       dmult_dmult_op = 0x0,
+       dmult_dmul_op = 0x2,
+       dmult_dmuh_op = 0x3,
+};
+enum dmultu_op {
+       dmultu_dmultu_op = 0x0,
+       dmultu_dmulu_op = 0x2,
+       dmultu_dmuhu_op = 0x3,
+};
+enum ddiv_op {
+       ddiv_ddiv_op = 0x0,
+       ddiv_ddiv6_op = 0x2,
+       ddiv_dmod_op = 0x3,
+};
+enum ddivu_op {
+       ddivu_ddivu_op = 0x0,
+       ddivu_ddivu6_op = 0x2,
+       ddivu_dmodu_op = 0x3,
+};
+
 /*
  * rt field of bcond opcodes.
  */
@@ -103,7 +147,7 @@ enum rt_op {
        bltzal_op, bgezal_op, bltzall_op, bgezall_op,
        rt_op_0x14, rt_op_0x15, rt_op_0x16, rt_op_0x17,
        rt_op_0x18, rt_op_0x19, rt_op_0x1a, rt_op_0x1b,
-       bposge32_op, rt_op_0x1d, rt_op_0x1e, rt_op_0x1f
+       bposge32_op, rt_op_0x1d, rt_op_0x1e, synci_op
 };
 
 /*
@@ -237,6 +281,21 @@ enum bshfl_func {
        seh_op  = 0x18,
 };
 
+/*
+ * MSA minor opcodes.
+ */
+enum msa_func {
+       msa_elm_op = 0x19,
+};
+
+/*
+ * MSA ELM opcodes.
+ */
+enum msa_elm {
+       msa_ctc_op = 0x3e,
+       msa_cfc_op = 0x7e,
+};
+
 /*
  * func field for MSA MI10 format.
  */
@@ -264,7 +323,7 @@ enum mm_major_op {
        mm_pool32b_op, mm_pool16b_op, mm_lhu16_op, mm_andi16_op,
        mm_addiu32_op, mm_lhu32_op, mm_sh32_op, mm_lh32_op,
        mm_pool32i_op, mm_pool16c_op, mm_lwsp16_op, mm_pool16d_op,
-       mm_ori32_op, mm_pool32f_op, mm_reserved1_op, mm_reserved2_op,
+       mm_ori32_op, mm_pool32f_op, mm_pool32s_op, mm_reserved2_op,
        mm_pool32c_op, mm_lwgp16_op, mm_lw16_op, mm_pool16e_op,
        mm_xori32_op, mm_jals32_op, mm_addiupc_op, mm_reserved3_op,
        mm_reserved4_op, mm_pool16f_op, mm_sb16_op, mm_beqz16_op,
@@ -360,7 +419,10 @@ enum mm_32axf_minor_op {
        mm_mflo32_op = 0x075,
        mm_jalrhb_op = 0x07c,
        mm_tlbwi_op = 0x08d,
+       mm_mthi32_op = 0x0b5,
        mm_tlbwr_op = 0x0cd,
+       mm_mtlo32_op = 0x0f5,
+       mm_di_op = 0x11d,
        mm_jalrs_op = 0x13c,
        mm_jalrshb_op = 0x17c,
        mm_sync_op = 0x1ad,
@@ -478,6 +540,13 @@ enum mm_32f_73_minor_op {
        mm_fcvts1_op = 0xed,
 };
 
+/*
+ * (microMIPS) POOL32S minor opcodes.
+ */
+enum mm_32s_minor_op {
+       mm_32s_elm_op = 0x16,
+};
+
 /*
  * (microMIPS) POOL16C minor opcodes.
  */
@@ -586,6 +655,36 @@ struct r_format {                  /* Register format */
        ;))))))
 };
 
+struct c0r_format {                    /* C0 register format */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int z: 8,
+       __BITFIELD_FIELD(unsigned int sel : 3,
+       ;))))))
+};
+
+struct mfmc0_format {                  /* MFMC0 register format */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 5,
+       __BITFIELD_FIELD(unsigned int rt : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int re : 5,
+       __BITFIELD_FIELD(unsigned int sc : 1,
+       __BITFIELD_FIELD(unsigned int : 2,
+       __BITFIELD_FIELD(unsigned int sel : 3,
+       ;))))))))
+};
+
+struct co_format {                     /* C0 CO format */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int co : 1,
+       __BITFIELD_FIELD(unsigned int code : 19,
+       __BITFIELD_FIELD(unsigned int func : 6,
+       ;))))
+};
+
 struct p_format {              /* Performance counter format (R10000) */
        __BITFIELD_FIELD(unsigned int opcode : 6,
        __BITFIELD_FIELD(unsigned int rs : 5,
@@ -937,6 +1036,9 @@ union mips_instruction {
        struct u_format u_format;
        struct c_format c_format;
        struct r_format r_format;
+       struct c0r_format c0r_format;
+       struct mfmc0_format mfmc0_format;
+       struct co_format co_format;
        struct p_format p_format;
        struct f_format f_format;
        struct ma_format ma_format;
index 0914ef7..6d01523 100644 (file)
@@ -75,7 +75,7 @@ void __init device_tree_init(void)
 
 const char *get_system_type(void)
 {
-       if (config_enabled(CONFIG_MACH_JZ4780))
+       if (IS_ENABLED(CONFIG_MACH_JZ4780))
                return "JZ4780";
 
        return "JZ4740";
index e6053d0..4a603a3 100644 (file)
@@ -71,7 +71,7 @@ obj-$(CONFIG_32BIT)           += scall32-o32.o
 obj-$(CONFIG_64BIT)            += scall64-64.o
 obj-$(CONFIG_MIPS32_COMPAT)    += linux32.o ptrace32.o signal32.o
 obj-$(CONFIG_MIPS32_N32)       += binfmt_elfn32.o scall64-n32.o signal_n32.o
-obj-$(CONFIG_MIPS32_O32)       += binfmt_elfo32.o scall64-o32.o
+obj-$(CONFIG_MIPS32_O32)       += binfmt_elfo32.o scall64-o32.o signal_o32.o
 
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_PROC_FS)          += proc.o
index 1ea973b..fae2f94 100644 (file)
@@ -339,71 +339,9 @@ void output_pm_defines(void)
 }
 #endif
 
-void output_cpuinfo_defines(void)
-{
-       COMMENT(" MIPS cpuinfo offsets. ");
-       DEFINE(CPUINFO_SIZE, sizeof(struct cpuinfo_mips));
-#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
-       OFFSET(CPUINFO_ASID_MASK, cpuinfo_mips, asid_mask);
-#endif
-}
-
 void output_kvm_defines(void)
 {
        COMMENT(" KVM/MIPS Specfic offsets. ");
-       DEFINE(VCPU_ARCH_SIZE, sizeof(struct kvm_vcpu_arch));
-       OFFSET(VCPU_RUN, kvm_vcpu, run);
-       OFFSET(VCPU_HOST_ARCH, kvm_vcpu, arch);
-
-       OFFSET(VCPU_HOST_EBASE, kvm_vcpu_arch, host_ebase);
-       OFFSET(VCPU_GUEST_EBASE, kvm_vcpu_arch, guest_ebase);
-
-       OFFSET(VCPU_HOST_STACK, kvm_vcpu_arch, host_stack);
-       OFFSET(VCPU_HOST_GP, kvm_vcpu_arch, host_gp);
-
-       OFFSET(VCPU_HOST_CP0_BADVADDR, kvm_vcpu_arch, host_cp0_badvaddr);
-       OFFSET(VCPU_HOST_CP0_CAUSE, kvm_vcpu_arch, host_cp0_cause);
-       OFFSET(VCPU_HOST_EPC, kvm_vcpu_arch, host_cp0_epc);
-       OFFSET(VCPU_HOST_ENTRYHI, kvm_vcpu_arch, host_cp0_entryhi);
-
-       OFFSET(VCPU_GUEST_INST, kvm_vcpu_arch, guest_inst);
-
-       OFFSET(VCPU_R0, kvm_vcpu_arch, gprs[0]);
-       OFFSET(VCPU_R1, kvm_vcpu_arch, gprs[1]);
-       OFFSET(VCPU_R2, kvm_vcpu_arch, gprs[2]);
-       OFFSET(VCPU_R3, kvm_vcpu_arch, gprs[3]);
-       OFFSET(VCPU_R4, kvm_vcpu_arch, gprs[4]);
-       OFFSET(VCPU_R5, kvm_vcpu_arch, gprs[5]);
-       OFFSET(VCPU_R6, kvm_vcpu_arch, gprs[6]);
-       OFFSET(VCPU_R7, kvm_vcpu_arch, gprs[7]);
-       OFFSET(VCPU_R8, kvm_vcpu_arch, gprs[8]);
-       OFFSET(VCPU_R9, kvm_vcpu_arch, gprs[9]);
-       OFFSET(VCPU_R10, kvm_vcpu_arch, gprs[10]);
-       OFFSET(VCPU_R11, kvm_vcpu_arch, gprs[11]);
-       OFFSET(VCPU_R12, kvm_vcpu_arch, gprs[12]);
-       OFFSET(VCPU_R13, kvm_vcpu_arch, gprs[13]);
-       OFFSET(VCPU_R14, kvm_vcpu_arch, gprs[14]);
-       OFFSET(VCPU_R15, kvm_vcpu_arch, gprs[15]);
-       OFFSET(VCPU_R16, kvm_vcpu_arch, gprs[16]);
-       OFFSET(VCPU_R17, kvm_vcpu_arch, gprs[17]);
-       OFFSET(VCPU_R18, kvm_vcpu_arch, gprs[18]);
-       OFFSET(VCPU_R19, kvm_vcpu_arch, gprs[19]);
-       OFFSET(VCPU_R20, kvm_vcpu_arch, gprs[20]);
-       OFFSET(VCPU_R21, kvm_vcpu_arch, gprs[21]);
-       OFFSET(VCPU_R22, kvm_vcpu_arch, gprs[22]);
-       OFFSET(VCPU_R23, kvm_vcpu_arch, gprs[23]);
-       OFFSET(VCPU_R24, kvm_vcpu_arch, gprs[24]);
-       OFFSET(VCPU_R25, kvm_vcpu_arch, gprs[25]);
-       OFFSET(VCPU_R26, kvm_vcpu_arch, gprs[26]);
-       OFFSET(VCPU_R27, kvm_vcpu_arch, gprs[27]);
-       OFFSET(VCPU_R28, kvm_vcpu_arch, gprs[28]);
-       OFFSET(VCPU_R29, kvm_vcpu_arch, gprs[29]);
-       OFFSET(VCPU_R30, kvm_vcpu_arch, gprs[30]);
-       OFFSET(VCPU_R31, kvm_vcpu_arch, gprs[31]);
-       OFFSET(VCPU_LO, kvm_vcpu_arch, lo);
-       OFFSET(VCPU_HI, kvm_vcpu_arch, hi);
-       OFFSET(VCPU_PC, kvm_vcpu_arch, pc);
-       BLANK();
 
        OFFSET(VCPU_FPR0, kvm_vcpu_arch, fpu.fpr[0]);
        OFFSET(VCPU_FPR1, kvm_vcpu_arch, fpu.fpr[1]);
@@ -441,14 +379,6 @@ void output_kvm_defines(void)
        OFFSET(VCPU_FCR31, kvm_vcpu_arch, fpu.fcr31);
        OFFSET(VCPU_MSA_CSR, kvm_vcpu_arch, fpu.msacsr);
        BLANK();
-
-       OFFSET(VCPU_COP0, kvm_vcpu_arch, cop0);
-       OFFSET(VCPU_GUEST_KERNEL_ASID, kvm_vcpu_arch, guest_kernel_asid);
-       OFFSET(VCPU_GUEST_USER_ASID, kvm_vcpu_arch, guest_user_asid);
-
-       OFFSET(COP0_TLB_HI, mips_coproc, reg[MIPS_CP0_TLB_HI][0]);
-       OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]);
-       BLANK();
 }
 
 #ifdef CONFIG_MIPS_CPS
index 6dc3f1f..46c227f 100644 (file)
@@ -790,7 +790,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                epc += 4 + (insn.i_format.simmediate << 2);
                regs->cp0_epc = epc;
                break;
-       case beqzcjic_op:
+       case pop66_op:
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
                        break;
@@ -798,7 +798,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                /* Compact branch: BEQZC || JIC */
                regs->cp0_epc += 8;
                break;
-       case bnezcjialc_op:
+       case pop76_op:
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
                        break;
@@ -809,8 +809,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                regs->cp0_epc += 8;
                break;
 #endif
-       case cbcond0_op:
-       case cbcond1_op:
+       case pop10_op:
+       case pop30_op:
                /* Only valid for MIPS R6 */
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
index e4c21bb..804d2a2 100644 (file)
@@ -276,12 +276,7 @@ int r4k_clockevent_init(void)
                                  CLOCK_EVT_FEAT_C3STOP |
                                  CLOCK_EVT_FEAT_PERCPU;
 
-       clockevent_set_clock(cd, mips_hpt_frequency);
-
-       /* Calculate the min / max delta */
-       cd->max_delta_ns        = clockevent_delta2ns(0x7fffffff, cd);
        min_delta               = calculate_min_delta();
-       cd->min_delta_ns        = clockevent_delta2ns(min_delta, cd);
 
        cd->rating              = 300;
        cd->irq                 = irq;
@@ -289,7 +284,7 @@ int r4k_clockevent_init(void)
        cd->set_next_event      = mips_next_event;
        cd->event_handler       = mips_event_handler;
 
-       clockevents_register_device(cd);
+       clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
 
        if (cp0_timer_irq_installed)
                return 0;
index 6392dbe..a378e44 100644 (file)
@@ -244,7 +244,7 @@ static inline void check_daddi(void)
        panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
 }
 
-int daddiu_bug = config_enabled(CONFIG_CPU_MIPSR6) ? 0 : -1;
+int daddiu_bug = IS_ENABLED(CONFIG_CPU_MIPSR6) ? 0 : -1;
 
 static inline void check_daddiu(void)
 {
@@ -314,7 +314,7 @@ static inline void check_daddiu(void)
 
 void __init check_bugs64_early(void)
 {
-       if (!config_enabled(CONFIG_CPU_MIPSR6)) {
+       if (!IS_ENABLED(CONFIG_CPU_MIPSR6)) {
                check_mult_sh();
                check_daddiu();
        }
@@ -322,6 +322,6 @@ void __init check_bugs64_early(void)
 
 void __init check_bugs64(void)
 {
-       if (!config_enabled(CONFIG_CPU_MIPSR6))
+       if (!IS_ENABLED(CONFIG_CPU_MIPSR6))
                check_daddi();
 }
index 1f91056..d76275d 100644 (file)
@@ -23,7 +23,7 @@ static struct clocksource clocksource_mips = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static u64 notrace r4k_read_sched_clock(void)
+static u64 __maybe_unused notrace r4k_read_sched_clock(void)
 {
        return read_c0_count();
 }
@@ -82,7 +82,9 @@ int __init init_r4k_clocksource(void)
 
        clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
+#ifndef CONFIG_CPU_FREQ
        sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
+#endif
 
        return 0;
 }
index 891f5ee..6430bff 100644 (file)
@@ -8,9 +8,12 @@
  * option) any later version.
  */
 
+#include <linux/binfmts.h>
 #include <linux/elf.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 
+#include <asm/cpu-features.h>
 #include <asm/cpu-info.h>
 
 /* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
@@ -179,7 +182,7 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
                        return -ELIBBAD;
        }
 
-       if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
+       if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
                return 0;
 
        fp_abi = state->fp_abi;
@@ -285,7 +288,7 @@ void mips_set_personality_fp(struct arch_elf_state *state)
         * not be worried about N32/N64 binaries.
         */
 
-       if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
+       if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
                return;
 
        switch (state->overall_fp_mode) {
@@ -326,3 +329,19 @@ void mips_set_personality_nan(struct arch_elf_state *state)
                BUG();
        }
 }
+
+int mips_elf_read_implies_exec(void *elf_ex, int exstack)
+{
+       if (exstack != EXSTACK_DISABLE_X) {
+               /* The binary doesn't request a non-executable stack */
+               return 1;
+       }
+
+       if (!cpu_has_rixi) {
+               /* The CPU doesn't support non-executable memory */
+               return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mips_elf_read_implies_exec);
index 56e8fed..cf05220 100644 (file)
@@ -93,21 +93,24 @@ NESTED(kernel_entry, 16, sp)                        # kernel entry point
        jr      t0
 0:
 
+#ifdef CONFIG_USE_OF
 #ifdef CONFIG_MIPS_RAW_APPENDED_DTB
-       PTR_LA          t0, __appended_dtb
+       PTR_LA          t2, __appended_dtb
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
        li              t1, 0xd00dfeed
 #else
        li              t1, 0xedfe0dd0
 #endif
-       lw              t2, (t0)
-       bne             t1, t2, not_found
-        nop
+       lw              t0, (t2)
+       beq             t0, t1, dtb_found
+#endif
+       li              t1, -2
+       beq             a0, t1, dtb_found
+       move            t2, a1
 
-       move            a1, t0
-       PTR_LI          a0, -2
-not_found:
+       li              t2, 0
+dtb_found:
 #endif
        PTR_LA          t0, __bss_start         # clear .bss
        LONG_S          zero, (t0)
@@ -122,6 +125,10 @@ not_found:
        LONG_S          a2, fw_arg2
        LONG_S          a3, fw_arg3
 
+#ifdef CONFIG_USE_OF
+       LONG_S          t2, fw_passed_dtb
+#endif
+
        MTC0            zero, CP0_CONTEXT       # clear context register
        PTR_LA          $28, init_thread_union
        /* Set the SP after an empty pt_regs.  */
index 760217b..659e6d3 100644 (file)
@@ -251,7 +251,7 @@ int mips_cm_probe(void)
        mips_cm_probe_l2sync();
 
        /* determine register width for this CM */
-       mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3);
+       mips_cm_is64 = IS_ENABLED(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3);
 
        for_each_possible_cpu(cpu)
                spin_lock_init(&per_cpu(cm_core_lock, cpu));
index 7ff2a55..c3372ca 100644 (file)
@@ -84,7 +84,7 @@ static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
                                (s32)MIPSInst_SIMM(ir);
                return 0;
        case daddiu_op:
-               if (config_enabled(CONFIG_32BIT))
+               if (IS_ENABLED(CONFIG_32BIT))
                        break;
 
                if (MIPSInst_RT(ir))
@@ -143,7 +143,7 @@ static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
                                              (u32)regs->regs[MIPSInst_RT(ir)]);
                        return 0;
                case dsll_op:
-                       if (config_enabled(CONFIG_32BIT) || MIPSInst_RS(ir))
+                       if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_RS(ir))
                                break;
 
                        if (MIPSInst_RD(ir))
@@ -152,7 +152,7 @@ static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
                                                MIPSInst_FD(ir));
                        return 0;
                case dsrl_op:
-                       if (config_enabled(CONFIG_32BIT) || MIPSInst_RS(ir))
+                       if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_RS(ir))
                                break;
 
                        if (MIPSInst_RD(ir))
@@ -161,7 +161,7 @@ static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
                                                MIPSInst_FD(ir));
                        return 0;
                case daddu_op:
-                       if (config_enabled(CONFIG_32BIT) || MIPSInst_FD(ir))
+                       if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_FD(ir))
                                break;
 
                        if (MIPSInst_RD(ir))
@@ -170,7 +170,7 @@ static inline int mipsr6_emul(struct pt_regs *regs, u32 ir)
                                        (u64)regs->regs[MIPSInst_RT(ir)];
                        return 0;
                case dsubu_op:
-                       if (config_enabled(CONFIG_32BIT) || MIPSInst_FD(ir))
+                       if (IS_ENABLED(CONFIG_32BIT) || MIPSInst_FD(ir))
                                break;
 
                        if (MIPSInst_RD(ir))
@@ -283,7 +283,7 @@ static int jr_func(struct pt_regs *regs, u32 ir)
                err = mipsr6_emul(regs, nir);
                if (err > 0) {
                        regs->cp0_epc = nepc;
-                       err = mips_dsemul(regs, nir, cepc);
+                       err = mips_dsemul(regs, nir, epc, cepc);
                        if (err == SIGILL)
                                err = SIGEMT;
                        MIPS_R2_STATS(dsemul);
@@ -498,7 +498,7 @@ static int dmult_func(struct pt_regs *regs, u32 ir)
        s64 res;
        s64 rt, rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        rt = regs->regs[MIPSInst_RT(ir)];
@@ -530,7 +530,7 @@ static int dmultu_func(struct pt_regs *regs, u32 ir)
        u64 res;
        u64 rt, rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        rt = regs->regs[MIPSInst_RT(ir)];
@@ -561,7 +561,7 @@ static int ddiv_func(struct pt_regs *regs, u32 ir)
 {
        s64 rt, rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        rt = regs->regs[MIPSInst_RT(ir)];
@@ -586,7 +586,7 @@ static int ddivu_func(struct pt_regs *regs, u32 ir)
 {
        u64 rt, rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        rt = regs->regs[MIPSInst_RT(ir)];
@@ -825,7 +825,7 @@ static int dclz_func(struct pt_regs *regs, u32 ir)
        u64 res;
        u64 rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        if (!MIPSInst_RD(ir))
@@ -852,7 +852,7 @@ static int dclo_func(struct pt_regs *regs, u32 ir)
        u64 res;
        u64 rs;
 
-       if (config_enabled(CONFIG_32BIT))
+       if (IS_ENABLED(CONFIG_32BIT))
                return SIGILL;
 
        if (!MIPSInst_RD(ir))
@@ -1033,7 +1033,7 @@ repeat:
                        if (nir) {
                                err = mipsr6_emul(regs, nir);
                                if (err > 0) {
-                                       err = mips_dsemul(regs, nir, cpc);
+                                       err = mips_dsemul(regs, nir, epc, cpc);
                                        if (err == SIGILL)
                                                err = SIGEMT;
                                        MIPS_R2_STATS(dsemul);
@@ -1082,7 +1082,7 @@ repeat:
                        if (nir) {
                                err = mipsr6_emul(regs, nir);
                                if (err > 0) {
-                                       err = mips_dsemul(regs, nir, cpc);
+                                       err = mips_dsemul(regs, nir, epc, cpc);
                                        if (err == SIGILL)
                                                err = SIGEMT;
                                        MIPS_R2_STATS(dsemul);
@@ -1149,7 +1149,7 @@ repeat:
                if (nir) {
                        err = mipsr6_emul(regs, nir);
                        if (err > 0) {
-                               err = mips_dsemul(regs, nir, cpc);
+                               err = mips_dsemul(regs, nir, epc, cpc);
                                if (err == SIGILL)
                                        err = SIGEMT;
                                MIPS_R2_STATS(dsemul);
@@ -1484,7 +1484,7 @@ fpu_emul:
                break;
 
        case ldl_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
@@ -1603,7 +1603,7 @@ fpu_emul:
                break;
 
        case ldr_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
@@ -1722,7 +1722,7 @@ fpu_emul:
                break;
 
        case sdl_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
@@ -1840,7 +1840,7 @@ fpu_emul:
                break;
 
        case sdr_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
@@ -2072,7 +2072,7 @@ fpu_emul:
                break;
 
        case lld_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
@@ -2133,7 +2133,7 @@ fpu_emul:
                break;
 
        case scd_op:
-               if (config_enabled(CONFIG_32BIT)) {
+               if (IS_ENABLED(CONFIG_32BIT)) {
                    err = SIGILL;
                    break;
                }
index adda3ff..5b31a94 100644 (file)
@@ -148,7 +148,7 @@ int cps_pm_enter_state(enum cps_pm_state state)
        }
 
        /* Setup the VPE to run mips_cps_pm_restore when started again */
-       if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) {
+       if (IS_ENABLED(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) {
                /* Power gating relies upon CPS SMP */
                if (!mips_cps_smp_in_use())
                        return -EINVAL;
@@ -387,7 +387,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state)
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
-       if (config_enabled(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) {
+       if (IS_ENABLED(CONFIG_CPU_PM) && state == CPS_PM_POWER_GATED) {
                /* Power gating relies upon CPS SMP */
                if (!mips_cps_smp_in_use())
                        goto out_err;
index 813ed78..7429ad0 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
+#include <asm/dsemul.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
 #include <asm/msa.h>
@@ -68,11 +69,22 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
        lose_fpu(0);
        clear_thread_flag(TIF_MSA_CTX_LIVE);
        clear_used_math();
+       atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
        init_dsp();
        regs->cp0_epc = pc;
        regs->regs[29] = sp;
 }
 
+void exit_thread(struct task_struct *tsk)
+{
+       /*
+        * User threads may have allocated a delay slot emulation frame.
+        * If so, clean up that allocation.
+        */
+       if (!(current->flags & PF_KTHREAD))
+               dsemul_thread_cleanup(tsk);
+}
+
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
        /*
@@ -159,6 +171,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        clear_tsk_thread_flag(p, TIF_FPUBOUND);
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
+       atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+
        if (clone_flags & CLONE_SETTLS)
                ti->tp_value = regs->regs[7];
 
index 9c0b387..51d3988 100644 (file)
@@ -348,7 +348,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_ni_syscall                  /* available, was setaltroot */
        PTR     sys_add_key
        PTR     sys_request_key
-       PTR     sys_keyctl                      /* 6245 */
+       PTR     compat_sys_keyctl               /* 6245 */
        PTR     sys_set_thread_area
        PTR     sys_inotify_init
        PTR     sys_inotify_add_watch
index f4f28b1..6efa713 100644 (file)
@@ -504,7 +504,7 @@ EXPORT(sys32_call_table)
        PTR     sys_ni_syscall                  /* available, was setaltroot */
        PTR     sys_add_key                     /* 4280 */
        PTR     sys_request_key
-       PTR     sys_keyctl
+       PTR     compat_sys_keyctl
        PTR     sys_set_thread_area
        PTR     sys_inotify_init
        PTR     sys_inotify_add_watch           /* 4285 */
index 87bc74a..2703f21 100644 (file)
@@ -26,17 +26,20 @@ static void build_segment_config(char *str, unsigned int cfg)
 
        /*
         * Access modes MK, MSK and MUSK are mapped segments. Therefore
-        * there is no direct physical address mapping.
+        * there is no direct physical address mapping unless it becomes
+        * unmapped uncached at error level due to EU.
         */
-       if ((am == 0) || (am > 3)) {
+       if ((am == 0) || (am > 3) || (cfg & MIPS_SEGCFG_EU))
                str += sprintf(str, "         %03lx",
                        ((cfg & MIPS_SEGCFG_PA) >> MIPS_SEGCFG_PA_SHIFT));
+       else
+               str += sprintf(str, "         UND");
+
+       if ((am == 0) || (am > 3))
                str += sprintf(str, "         %01ld",
                        ((cfg & MIPS_SEGCFG_C) >> MIPS_SEGCFG_C_SHIFT));
-       } else {
-               str += sprintf(str, "         UND");
+       else
                str += sprintf(str, "         U");
-       }
 
        /* Exception configuration. */
        str += sprintf(str, "       %01ld\n",
index ef408a0..36cf8d6 100644 (file)
@@ -875,6 +875,10 @@ void __init setup_arch(char **cmdline_p)
 unsigned long kernelsp[NR_CPUS];
 unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
+#ifdef CONFIG_USE_OF
+unsigned long fw_passed_dtb;
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 struct dentry *mips_debugfs_dir;
 static int __init debugfs_mips(void)
index ae42314..9e22446 100644 (file)
@@ -165,7 +165,7 @@ static int save_msa_extcontext(void __user *buf)
                 * should already have been done when handling scalar FP
                 * context.
                 */
-               BUG_ON(config_enabled(CONFIG_EVA));
+               BUG_ON(IS_ENABLED(CONFIG_EVA));
 
                err = __put_user(read_msa_csr(), &msa->csr);
                err |= _save_msa_all_upper(&msa->wr);
@@ -195,7 +195,7 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size)
        unsigned int csr;
        int i, err;
 
-       if (!config_enabled(CONFIG_CPU_HAS_MSA))
+       if (!IS_ENABLED(CONFIG_CPU_HAS_MSA))
                return SIGSYS;
 
        if (size != sizeof(*msa))
@@ -215,7 +215,7 @@ static int restore_msa_extcontext(void __user *buf, unsigned int size)
                 * scalar FP context, so FPU & MSA should have already been
                 * disabled whilst handling scalar FP context.
                 */
-               BUG_ON(config_enabled(CONFIG_EVA));
+               BUG_ON(IS_ENABLED(CONFIG_EVA));
 
                write_msa_csr(csr);
                err |= _restore_msa_all_upper(&msa->wr);
@@ -315,7 +315,7 @@ int protected_save_fp_context(void __user *sc)
         * EVA does not have userland equivalents of ldc1 or sdc1, so
         * save to the kernel FP context & copy that to userland below.
         */
-       if (config_enabled(CONFIG_EVA))
+       if (IS_ENABLED(CONFIG_EVA))
                lose_fpu(1);
 
        while (1) {
@@ -378,7 +378,7 @@ int protected_restore_fp_context(void __user *sc)
         * disable the FPU here such that the code below simply copies to
         * the kernel FP context.
         */
-       if (config_enabled(CONFIG_EVA))
+       if (IS_ENABLED(CONFIG_EVA))
                lose_fpu(0);
 
        while (1) {
@@ -772,6 +772,14 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        struct mips_abi *abi = current->thread.abi;
        void *vdso = current->mm->context.vdso;
 
+       /*
+        * If we were emulating a delay slot instruction, exit that frame such
+        * that addresses in the sigframe are as expected for userland and we
+        * don't have a problem if we reuse the thread's frame for an
+        * instruction within the signal handler.
+        */
+       dsemul_thread_rollback(regs);
+
        if (regs->regs[0]) {
                switch(regs->regs[2]) {
                case ERESTART_RESTARTBLOCK:
index 78c8349..97b7c51 100644 (file)
  * Copyright (C) 1991, 1992  Linus Torvalds
  * Copyright (C) 1994 - 2000, 2006  Ralf Baechle
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2016, Imagination Technologies Ltd.
  */
-#include <linux/cache.h>
-#include <linux/compat.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/syscalls.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/suspend.h>
-#include <linux/compiler.h>
-#include <linux/uaccess.h>
 
-#include <asm/abi.h>
-#include <asm/asm.h>
+#include <asm/compat.h>
 #include <asm/compat-signal.h>
-#include <linux/bitops.h>
-#include <asm/cacheflush.h>
-#include <asm/sim.h>
-#include <asm/ucontext.h>
-#include <asm/fpu.h>
-#include <asm/war.h>
-#include <asm/dsp.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include "signal-common.h"
 
-/*
- * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
- */
-#define __NR_O32_restart_syscall       4253
-
 /* 32-bit compatibility types */
 
 typedef unsigned int __sighandler32_t;
 typedef void (*vfptr_t)(void);
 
-struct ucontext32 {
-       u32                 uc_flags;
-       s32                 uc_link;
-       compat_stack_t      uc_stack;
-       struct sigcontext32 uc_mcontext;
-       compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
-};
-
-struct sigframe32 {
-       u32 sf_ass[4];          /* argument save space for o32 */
-       u32 sf_pad[2];          /* Was: signal trampoline */
-       struct sigcontext32 sf_sc;
-       compat_sigset_t sf_mask;
-};
-
-struct rt_sigframe32 {
-       u32 rs_ass[4];                  /* argument save space for o32 */
-       u32 rs_pad[2];                  /* Was: signal trampoline */
-       compat_siginfo_t rs_info;
-       struct ucontext32 rs_uc;
-};
-
-static int setup_sigcontext32(struct pt_regs *regs,
-                             struct sigcontext32 __user *sc)
-{
-       int err = 0;
-       int i;
-
-       err |= __put_user(regs->cp0_epc, &sc->sc_pc);
-
-       err |= __put_user(0, &sc->sc_regs[0]);
-       for (i = 1; i < 32; i++)
-               err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
-
-       err |= __put_user(regs->hi, &sc->sc_mdhi);
-       err |= __put_user(regs->lo, &sc->sc_mdlo);
-       if (cpu_has_dsp) {
-               err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
-               err |= __put_user(mfhi1(), &sc->sc_hi1);
-               err |= __put_user(mflo1(), &sc->sc_lo1);
-               err |= __put_user(mfhi2(), &sc->sc_hi2);
-               err |= __put_user(mflo2(), &sc->sc_lo2);
-               err |= __put_user(mfhi3(), &sc->sc_hi3);
-               err |= __put_user(mflo3(), &sc->sc_lo3);
-       }
-
-       /*
-        * Save FPU state to signal context.  Signal handler
-        * will "inherit" current FPU state.
-        */
-       err |= protected_save_fp_context(sc);
-
-       return err;
-}
-
-static int restore_sigcontext32(struct pt_regs *regs,
-                               struct sigcontext32 __user *sc)
-{
-       int err = 0;
-       s32 treg;
-       int i;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current->restart_block.fn = do_no_restart_syscall;
-
-       err |= __get_user(regs->cp0_epc, &sc->sc_pc);
-       err |= __get_user(regs->hi, &sc->sc_mdhi);
-       err |= __get_user(regs->lo, &sc->sc_mdlo);
-       if (cpu_has_dsp) {
-               err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
-               err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
-               err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
-               err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
-               err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
-               err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
-               err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
-       }
-
-       for (i = 1; i < 32; i++)
-               err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
-
-       return err ?: protected_restore_fp_context(sc);
-}
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -247,176 +144,3 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 
        return 0;
 }
-
-asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
-{
-       struct sigframe32 __user *frame;
-       sigset_t blocked;
-       int sig;
-
-       frame = (struct sigframe32 __user *) regs.regs[29];
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
-               goto badframe;
-
-       set_current_blocked(&blocked);
-
-       sig = restore_sigcontext32(&regs, &frame->sf_sc);
-       if (sig < 0)
-               goto badframe;
-       else if (sig)
-               force_sig(sig, current);
-
-       /*
-        * Don't let your children do this ...
-        */
-       __asm__ __volatile__(
-               "move\t$29, %0\n\t"
-               "j\tsyscall_exit"
-               :/* no outputs */
-               :"r" (&regs));
-       /* Unreached */
-
-badframe:
-       force_sig(SIGSEGV, current);
-}
-
-asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
-{
-       struct rt_sigframe32 __user *frame;
-       sigset_t set;
-       int sig;
-
-       frame = (struct rt_sigframe32 __user *) regs.regs[29];
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
-               goto badframe;
-
-       set_current_blocked(&set);
-
-       sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
-       if (sig < 0)
-               goto badframe;
-       else if (sig)
-               force_sig(sig, current);
-
-       if (compat_restore_altstack(&frame->rs_uc.uc_stack))
-               goto badframe;
-
-       /*
-        * Don't let your children do this ...
-        */
-       __asm__ __volatile__(
-               "move\t$29, %0\n\t"
-               "j\tsyscall_exit"
-               :/* no outputs */
-               :"r" (&regs));
-       /* Unreached */
-
-badframe:
-       force_sig(SIGSEGV, current);
-}
-
-static int setup_frame_32(void *sig_return, struct ksignal *ksig,
-                         struct pt_regs *regs, sigset_t *set)
-{
-       struct sigframe32 __user *frame;
-       int err = 0;
-
-       frame = get_sigframe(ksig, regs, sizeof(*frame));
-       if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
-               return -EFAULT;
-
-       err |= setup_sigcontext32(regs, &frame->sf_sc);
-       err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
-
-       if (err)
-               return -EFAULT;
-
-       /*
-        * Arguments to signal handler:
-        *
-        *   a0 = signal number
-        *   a1 = 0 (should be cause)
-        *   a2 = pointer to struct sigcontext
-        *
-        * $25 and c0_epc point to the signal handler, $29 points to the
-        * struct sigframe.
-        */
-       regs->regs[ 4] = ksig->sig;
-       regs->regs[ 5] = 0;
-       regs->regs[ 6] = (unsigned long) &frame->sf_sc;
-       regs->regs[29] = (unsigned long) frame;
-       regs->regs[31] = (unsigned long) sig_return;
-       regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
-
-       DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
-              current->comm, current->pid,
-              frame, regs->cp0_epc, regs->regs[31]);
-
-       return 0;
-}
-
-static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
-                            struct pt_regs *regs, sigset_t *set)
-{
-       struct rt_sigframe32 __user *frame;
-       int err = 0;
-
-       frame = get_sigframe(ksig, regs, sizeof(*frame));
-       if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
-               return -EFAULT;
-
-       /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
-       err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info);
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->rs_uc.uc_flags);
-       err |= __put_user(0, &frame->rs_uc.uc_link);
-       err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
-       err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
-       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
-
-       if (err)
-               return -EFAULT;
-
-       /*
-        * Arguments to signal handler:
-        *
-        *   a0 = signal number
-        *   a1 = 0 (should be cause)
-        *   a2 = pointer to ucontext
-        *
-        * $25 and c0_epc point to the signal handler, $29 points to
-        * the struct rt_sigframe32.
-        */
-       regs->regs[ 4] = ksig->sig;
-       regs->regs[ 5] = (unsigned long) &frame->rs_info;
-       regs->regs[ 6] = (unsigned long) &frame->rs_uc;
-       regs->regs[29] = (unsigned long) frame;
-       regs->regs[31] = (unsigned long) sig_return;
-       regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
-
-       DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
-              current->comm, current->pid,
-              frame, regs->cp0_epc, regs->regs[31]);
-
-       return 0;
-}
-
-/*
- * o32 compatibility on 64-bit kernels, without DSP ASE
- */
-struct mips_abi mips_abi_32 = {
-       .setup_frame    = setup_frame_32,
-       .setup_rt_frame = setup_rt_frame_32,
-       .restart        = __NR_O32_restart_syscall,
-
-       .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
-       .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
-       .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
-
-       .vdso           = &vdso_image_o32,
-};
diff --git a/arch/mips/kernel/signal_o32.c b/arch/mips/kernel/signal_o32.c
new file mode 100644 (file)
index 0000000..5e169fc
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * 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) 1991, 1992  Linus Torvalds
+ * Copyright (C) 1994 - 2000, 2006  Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2016, Imagination Technologies Ltd.
+ */
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+
+#include <asm/abi.h>
+#include <asm/compat-signal.h>
+#include <asm/dsp.h>
+#include <asm/sim.h>
+#include <asm/unistd.h>
+
+#include "signal-common.h"
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_O32_restart_syscall       4253
+
+struct sigframe32 {
+       u32 sf_ass[4];          /* argument save space for o32 */
+       u32 sf_pad[2];          /* Was: signal trampoline */
+       struct sigcontext32 sf_sc;
+       compat_sigset_t sf_mask;
+};
+
+struct ucontext32 {
+       u32                 uc_flags;
+       s32                 uc_link;
+       compat_stack_t      uc_stack;
+       struct sigcontext32 uc_mcontext;
+       compat_sigset_t     uc_sigmask;   /* mask last for extensibility */
+};
+
+struct rt_sigframe32 {
+       u32 rs_ass[4];                  /* argument save space for o32 */
+       u32 rs_pad[2];                  /* Was: signal trampoline */
+       compat_siginfo_t rs_info;
+       struct ucontext32 rs_uc;
+};
+
+static int setup_sigcontext32(struct pt_regs *regs,
+                             struct sigcontext32 __user *sc)
+{
+       int err = 0;
+       int i;
+
+       err |= __put_user(regs->cp0_epc, &sc->sc_pc);
+
+       err |= __put_user(0, &sc->sc_regs[0]);
+       for (i = 1; i < 32; i++)
+               err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
+
+       err |= __put_user(regs->hi, &sc->sc_mdhi);
+       err |= __put_user(regs->lo, &sc->sc_mdlo);
+       if (cpu_has_dsp) {
+               err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
+               err |= __put_user(mfhi1(), &sc->sc_hi1);
+               err |= __put_user(mflo1(), &sc->sc_lo1);
+               err |= __put_user(mfhi2(), &sc->sc_hi2);
+               err |= __put_user(mflo2(), &sc->sc_lo2);
+               err |= __put_user(mfhi3(), &sc->sc_hi3);
+               err |= __put_user(mflo3(), &sc->sc_lo3);
+       }
+
+       /*
+        * Save FPU state to signal context.  Signal handler
+        * will "inherit" current FPU state.
+        */
+       err |= protected_save_fp_context(sc);
+
+       return err;
+}
+
+static int restore_sigcontext32(struct pt_regs *regs,
+                               struct sigcontext32 __user *sc)
+{
+       int err = 0;
+       s32 treg;
+       int i;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current->restart_block.fn = do_no_restart_syscall;
+
+       err |= __get_user(regs->cp0_epc, &sc->sc_pc);
+       err |= __get_user(regs->hi, &sc->sc_mdhi);
+       err |= __get_user(regs->lo, &sc->sc_mdlo);
+       if (cpu_has_dsp) {
+               err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
+               err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
+               err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
+               err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
+               err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
+               err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
+               err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
+       }
+
+       for (i = 1; i < 32; i++)
+               err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
+
+       return err ?: protected_restore_fp_context(sc);
+}
+
+static int setup_frame_32(void *sig_return, struct ksignal *ksig,
+                         struct pt_regs *regs, sigset_t *set)
+{
+       struct sigframe32 __user *frame;
+       int err = 0;
+
+       frame = get_sigframe(ksig, regs, sizeof(*frame));
+       if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+               return -EFAULT;
+
+       err |= setup_sigcontext32(regs, &frame->sf_sc);
+       err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
+
+       if (err)
+               return -EFAULT;
+
+       /*
+        * Arguments to signal handler:
+        *
+        *   a0 = signal number
+        *   a1 = 0 (should be cause)
+        *   a2 = pointer to struct sigcontext
+        *
+        * $25 and c0_epc point to the signal handler, $29 points to the
+        * struct sigframe.
+        */
+       regs->regs[ 4] = ksig->sig;
+       regs->regs[ 5] = 0;
+       regs->regs[ 6] = (unsigned long) &frame->sf_sc;
+       regs->regs[29] = (unsigned long) frame;
+       regs->regs[31] = (unsigned long) sig_return;
+       regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
+
+       DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
+              current->comm, current->pid,
+              frame, regs->cp0_epc, regs->regs[31]);
+
+       return 0;
+}
+
+asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+       struct rt_sigframe32 __user *frame;
+       sigset_t set;
+       int sig;
+
+       frame = (struct rt_sigframe32 __user *) regs.regs[29];
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask))
+               goto badframe;
+
+       set_current_blocked(&set);
+
+       sig = restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext);
+       if (sig < 0)
+               goto badframe;
+       else if (sig)
+               force_sig(sig, current);
+
+       if (compat_restore_altstack(&frame->rs_uc.uc_stack))
+               goto badframe;
+
+       /*
+        * Don't let your children do this ...
+        */
+       __asm__ __volatile__(
+               "move\t$29, %0\n\t"
+               "j\tsyscall_exit"
+               :/* no outputs */
+               :"r" (&regs));
+       /* Unreached */
+
+badframe:
+       force_sig(SIGSEGV, current);
+}
+
+static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
+                            struct pt_regs *regs, sigset_t *set)
+{
+       struct rt_sigframe32 __user *frame;
+       int err = 0;
+
+       frame = get_sigframe(ksig, regs, sizeof(*frame));
+       if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+               return -EFAULT;
+
+       /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
+       err |= copy_siginfo_to_user32(&frame->rs_info, &ksig->info);
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->rs_uc.uc_flags);
+       err |= __put_user(0, &frame->rs_uc.uc_link);
+       err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]);
+       err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
+       err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set);
+
+       if (err)
+               return -EFAULT;
+
+       /*
+        * Arguments to signal handler:
+        *
+        *   a0 = signal number
+        *   a1 = 0 (should be cause)
+        *   a2 = pointer to ucontext
+        *
+        * $25 and c0_epc point to the signal handler, $29 points to
+        * the struct rt_sigframe32.
+        */
+       regs->regs[ 4] = ksig->sig;
+       regs->regs[ 5] = (unsigned long) &frame->rs_info;
+       regs->regs[ 6] = (unsigned long) &frame->rs_uc;
+       regs->regs[29] = (unsigned long) frame;
+       regs->regs[31] = (unsigned long) sig_return;
+       regs->cp0_epc = regs->regs[25] = (unsigned long) ksig->ka.sa.sa_handler;
+
+       DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
+              current->comm, current->pid,
+              frame, regs->cp0_epc, regs->regs[31]);
+
+       return 0;
+}
+
+/*
+ * o32 compatibility on 64-bit kernels, without DSP ASE
+ */
+struct mips_abi mips_abi_32 = {
+       .setup_frame    = setup_frame_32,
+       .setup_rt_frame = setup_rt_frame_32,
+       .restart        = __NR_O32_restart_syscall,
+
+       .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
+       .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
+       .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
+
+       .vdso           = &vdso_image_o32,
+};
+
+
+asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
+{
+       struct sigframe32 __user *frame;
+       sigset_t blocked;
+       int sig;
+
+       frame = (struct sigframe32 __user *) regs.regs[29];
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask))
+               goto badframe;
+
+       set_current_blocked(&blocked);
+
+       sig = restore_sigcontext32(&regs, &frame->sf_sc);
+       if (sig < 0)
+               goto badframe;
+       else if (sig)
+               force_sig(sig, current);
+
+       /*
+        * Don't let your children do this ...
+        */
+       __asm__ __volatile__(
+               "move\t$29, %0\n\t"
+               "j\tsyscall_exit"
+               :/* no outputs */
+               :"r" (&regs));
+       /* Unreached */
+
+badframe:
+       force_sig(SIGSEGV, current);
+}
index e02addc..6d0f132 100644 (file)
@@ -363,6 +363,7 @@ static int bmips_cpu_disable(void)
        pr_info("SMP: CPU%d is offline\n", cpu);
 
        set_cpu_online(cpu, false);
+       calculate_cpu_foreign_map();
        cpumask_clear_cpu(cpu, &cpu_callin_map);
        clear_c0_status(IE_IRQ5);
 
index 4ed36f2..e9d9fc6 100644 (file)
@@ -46,8 +46,8 @@ static unsigned core_vpe_count(unsigned core)
        if (threads_disabled)
                return 1;
 
-       if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
-               && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
+       if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
+               && (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
                return 1;
 
        mips_cm_lock_other(core, 0);
@@ -206,7 +206,7 @@ err_out:
        }
 }
 
-static void boot_core(unsigned core)
+static void boot_core(unsigned int core, unsigned int vpe_id)
 {
        u32 access, stat, seq_state;
        unsigned timeout;
@@ -233,8 +233,9 @@ static void boot_core(unsigned core)
                mips_cpc_lock_other(core);
 
                if (mips_cm_revision() >= CM_REV_CM3) {
-                       /* Run VP0 following the reset */
-                       write_cpc_co_vp_run(0x1);
+                       /* Run only the requested VP following the reset */
+                       write_cpc_co_vp_stop(0xf);
+                       write_cpc_co_vp_run(1 << vpe_id);
 
                        /*
                         * Ensure that the VP_RUN register is written before the
@@ -306,7 +307,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
 
        if (!test_bit(core, core_power)) {
                /* Boot a VPE on a powered down core */
-               boot_core(core);
+               boot_core(core, vpe_id);
                goto out;
        }
 
@@ -397,6 +398,7 @@ static int cps_cpu_disable(void)
        atomic_sub(1 << cpu_vpe_id(&current_cpu_data), &core_cfg->vpe_mask);
        smp_mb__after_atomic();
        set_cpu_online(cpu, false);
+       calculate_cpu_foreign_map();
        cpumask_clear_cpu(cpu, &cpu_callin_map);
 
        return 0;
@@ -411,14 +413,16 @@ static enum {
 
 void play_dead(void)
 {
-       unsigned cpu, core;
+       unsigned int cpu, core, vpe_id;
 
        local_irq_disable();
        idle_task_exit();
        cpu = smp_processor_id();
        cpu_death = CPU_DEATH_POWER;
 
-       if (cpu_has_mipsmt) {
+       pr_debug("CPU%d going offline\n", cpu);
+
+       if (cpu_has_mipsmt || cpu_has_vp) {
                core = cpu_data[cpu].core;
 
                /* Look for another online VPE within the core */
@@ -439,10 +443,21 @@ void play_dead(void)
        complete(&cpu_death_chosen);
 
        if (cpu_death == CPU_DEATH_HALT) {
-               /* Halt this TC */
-               write_c0_tchalt(TCHALT_H);
-               instruction_hazard();
+               vpe_id = cpu_vpe_id(&cpu_data[cpu]);
+
+               pr_debug("Halting core %d VP%d\n", core, vpe_id);
+               if (cpu_has_mipsmt) {
+                       /* Halt this TC */
+                       write_c0_tchalt(TCHALT_H);
+                       instruction_hazard();
+               } else if (cpu_has_vp) {
+                       write_cpc_cl_vp_stop(1 << vpe_id);
+
+                       /* Ensure that the VP_STOP register is written */
+                       wmb();
+               }
        } else {
+               pr_debug("Gating power to core %d\n", core);
                /* Power down the core */
                cps_pm_enter_state(CPS_PM_POWER_GATED);
        }
@@ -469,6 +484,7 @@ static void wait_for_sibling_halt(void *ptr_cpu)
 static void cps_cpu_die(unsigned int cpu)
 {
        unsigned core = cpu_data[cpu].core;
+       unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]);
        unsigned stat;
        int err;
 
@@ -497,10 +513,12 @@ static void cps_cpu_die(unsigned int cpu)
                 * in which case the CPC will refuse to power down the core.
                 */
                do {
+                       mips_cm_lock_other(core, vpe_id);
                        mips_cpc_lock_other(core);
                        stat = read_cpc_co_stat_conf();
                        stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK;
                        mips_cpc_unlock_other();
+                       mips_cm_unlock_other();
                } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 &&
                         stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 &&
                         stat != CPC_Cx_STAT_CONF_SEQSTATE_U2);
@@ -517,6 +535,12 @@ static void cps_cpu_die(unsigned int cpu)
                                               (void *)(unsigned long)cpu, 1);
                if (err)
                        panic("Failed to call remote sibling CPU\n");
+       } else if (cpu_has_vp) {
+               do {
+                       mips_cm_lock_other(core, vpe_id);
+                       stat = read_cpc_co_vp_running();
+                       mips_cm_unlock_other();
+               } while (stat & (1 << vpe_id));
        }
 }
 
index f9d01e9..f95f094 100644 (file)
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(cpu_core_map);
  * A logcal cpu mask containing only one VPE per core to
  * reduce the number of IPIs on large MT systems.
  */
-cpumask_t cpu_foreign_map __read_mostly;
+cpumask_t cpu_foreign_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_foreign_map);
 
 /* representing cpus for which sibling maps can be computed */
@@ -124,7 +124,7 @@ static inline void set_cpu_core_map(int cpu)
  * Calculate a new cpu_foreign_map mask whenever a
  * new cpu appears or disappears.
  */
-static inline void calculate_cpu_foreign_map(void)
+void calculate_cpu_foreign_map(void)
 {
        int i, k, core_present;
        cpumask_t temp_foreign_map;
@@ -141,7 +141,9 @@ static inline void calculate_cpu_foreign_map(void)
                        cpumask_set_cpu(i, &temp_foreign_map);
        }
 
-       cpumask_copy(&cpu_foreign_map, &temp_foreign_map);
+       for_each_online_cpu(i)
+               cpumask_andnot(&cpu_foreign_map[i],
+                              &temp_foreign_map, &cpu_sibling_map[i]);
 }
 
 struct plat_smp_ops *mp_ops;
@@ -344,16 +346,9 @@ asmlinkage void start_secondary(void)
 static void stop_this_cpu(void *dummy)
 {
        /*
-        * Remove this CPU. Be a bit slow here and
-        * set the bits for every online CPU so we don't miss
-        * any IPI whilst taking this VPE down.
+        * Remove this CPU:
         */
 
-       cpumask_copy(&cpu_foreign_map, cpu_online_mask);
-
-       /* Make it visible to every other CPU */
-       smp_mb();
-
        set_cpu_online(smp_processor_id(), false);
        calculate_cpu_foreign_map();
        local_irq_disable();
@@ -512,10 +507,17 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned l
                smp_on_other_tlbs(flush_tlb_range_ipi, &fd);
        } else {
                unsigned int cpu;
+               int exec = vma->vm_flags & VM_EXEC;
 
                for_each_online_cpu(cpu) {
+                       /*
+                        * flush_cache_range() will only fully flush icache if
+                        * the VMA is executable, otherwise we must invalidate
+                        * ASID without it appearing to has_valid_asid() as if
+                        * mm has been completely unused by that CPU.
+                        */
                        if (cpu != smp_processor_id() && cpu_context(cpu, mm))
-                               cpu_context(cpu, mm) = 0;
+                               cpu_context(cpu, mm) = !exec;
                }
        }
        local_flush_tlb_range(vma, start, end);
@@ -560,8 +562,14 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
                unsigned int cpu;
 
                for_each_online_cpu(cpu) {
+                       /*
+                        * flush_cache_page() only does partial flushes, so
+                        * invalidate ASID without it appearing to
+                        * has_valid_asid() as if mm has been completely unused
+                        * by that CPU.
+                        */
                        if (cpu != smp_processor_id() && cpu_context(cpu, vma->vm_mm))
-                               cpu_context(cpu, vma->vm_mm) = 0;
+                               cpu_context(cpu, vma->vm_mm) = 1;
                }
        }
        local_flush_tlb_page(vma, page);
index 4a1712b..3de85be 100644 (file)
@@ -619,17 +619,17 @@ static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt)
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
                        1, regs, 0);
        switch (rd) {
-       case 0:         /* CPU number */
+       case MIPS_HWR_CPUNUM:           /* CPU number */
                regs->regs[rt] = smp_processor_id();
                return 0;
-       case 1:         /* SYNCI length */
+       case MIPS_HWR_SYNCISTEP:        /* SYNCI length */
                regs->regs[rt] = min(current_cpu_data.dcache.linesz,
                                     current_cpu_data.icache.linesz);
                return 0;
-       case 2:         /* Read count register */
+       case MIPS_HWR_CC:               /* Read count register */
                regs->regs[rt] = read_c0_count();
                return 0;
-       case 3:         /* Count register resolution */
+       case MIPS_HWR_CCRES:            /* Count register resolution */
                switch (current_cpu_type()) {
                case CPU_20KC:
                case CPU_25KF:
@@ -639,7 +639,7 @@ static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt)
                        regs->regs[rt] = 2;
                }
                return 0;
-       case 29:
+       case MIPS_HWR_ULR:              /* Read UserLocal register */
                regs->regs[rt] = ti->tp_value;
                return 0;
        default:
@@ -704,6 +704,7 @@ asmlinkage void do_ov(struct pt_regs *regs)
 int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
 {
        struct siginfo si = { 0 };
+       struct vm_area_struct *vma;
 
        switch (sig) {
        case 0:
@@ -744,7 +745,8 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
                si.si_addr = fault_addr;
                si.si_signo = sig;
                down_read(&current->mm->mmap_sem);
-               if (find_vma(current->mm, (unsigned long)fault_addr))
+               vma = find_vma(current->mm, (unsigned long)fault_addr);
+               if (vma && (vma->vm_start <= (unsigned long)fault_addr))
                        si.si_code = SEGV_ACCERR;
                else
                        si.si_code = SEGV_MAPERR;
@@ -1859,6 +1861,7 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
 #define VECTORSPACING 0x100    /* for EI/VI mode */
 
 unsigned long ebase;
+EXPORT_SYMBOL_GPL(ebase);
 unsigned long exception_handlers[32];
 unsigned long vi_handlers[64];
 
@@ -2063,16 +2066,22 @@ static void configure_status(void)
                         status_set);
 }
 
+unsigned int hwrena;
+EXPORT_SYMBOL_GPL(hwrena);
+
 /* configure HWRENA register */
 static void configure_hwrena(void)
 {
-       unsigned int hwrena = cpu_hwrena_impl_bits;
+       hwrena = cpu_hwrena_impl_bits;
 
        if (cpu_has_mips_r2_r6)
-               hwrena |= 0x0000000f;
+               hwrena |= MIPS_HWRENA_CPUNUM |
+                         MIPS_HWRENA_SYNCISTEP |
+                         MIPS_HWRENA_CC |
+                         MIPS_HWRENA_CCRES;
 
        if (!noulri && cpu_has_userlocal)
-               hwrena |= (1 << 29);
+               hwrena |= MIPS_HWRENA_ULR;
 
        if (hwrena)
                write_c0_hwrena(hwrena);
index 28b3af7..f1c308d 100644 (file)
@@ -1025,7 +1025,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                if (!access_ok(VERIFY_READ, addr, 2))
                        goto sigbus;
 
-               if (config_enabled(CONFIG_EVA)) {
+               if (IS_ENABLED(CONFIG_EVA)) {
                        if (segment_eq(get_fs(), get_ds()))
                                LoadHW(addr, value, res);
                        else
@@ -1044,7 +1044,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                if (!access_ok(VERIFY_READ, addr, 4))
                        goto sigbus;
 
-               if (config_enabled(CONFIG_EVA)) {
+               if (IS_ENABLED(CONFIG_EVA)) {
                        if (segment_eq(get_fs(), get_ds()))
                                LoadW(addr, value, res);
                        else
@@ -1063,7 +1063,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                if (!access_ok(VERIFY_READ, addr, 2))
                        goto sigbus;
 
-               if (config_enabled(CONFIG_EVA)) {
+               if (IS_ENABLED(CONFIG_EVA)) {
                        if (segment_eq(get_fs(), get_ds()))
                                LoadHWU(addr, value, res);
                        else
@@ -1131,7 +1131,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                compute_return_epc(regs);
                value = regs->regs[insn.i_format.rt];
 
-               if (config_enabled(CONFIG_EVA)) {
+               if (IS_ENABLED(CONFIG_EVA)) {
                        if (segment_eq(get_fs(), get_ds()))
                                StoreHW(addr, value, res);
                        else
@@ -1151,7 +1151,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                compute_return_epc(regs);
                value = regs->regs[insn.i_format.rt];
 
-               if (config_enabled(CONFIG_EVA)) {
+               if (IS_ENABLED(CONFIG_EVA)) {
                        if (segment_eq(get_fs(), get_ds()))
                                StoreW(addr, value, res);
                        else
index 54e1663..9abe447 100644 (file)
@@ -107,6 +107,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (down_write_killable(&mm->mmap_sem))
                return -EINTR;
 
+       /* Map delay slot emulation page */
+       base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
+                          VM_READ|VM_WRITE|VM_EXEC|
+                          VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+                          0);
+       if (IS_ERR_VALUE(base)) {
+               ret = base;
+               goto out;
+       }
+
        /*
         * Determine total area size. This includes the VDSO data itself, the
         * data page, and the GIC user page if present. Always create a mapping
index 2ae1282..7c56d6b 100644 (file)
@@ -17,6 +17,7 @@ if VIRTUALIZATION
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
        depends on HAVE_KVM
+       select EXPORT_UASM
        select PREEMPT_NOTIFIERS
        select ANON_INODES
        select KVM_MMIO
index 637ebbe..847429d 100644 (file)
@@ -7,9 +7,10 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/mips/kvm
 
 common-objs-$(CONFIG_CPU_HAS_MSA) += msa.o
 
-kvm-objs := $(common-objs-y) mips.o emulate.o locore.o \
+kvm-objs := $(common-objs-y) mips.o emulate.o entry.o \
            interrupt.o stats.o commpage.o \
            dyntrans.o trap_emul.o fpu.o
+kvm-objs += mmu.o
 
 obj-$(CONFIG_KVM)      += kvm.o
 obj-y                  += callback.o tlb.o
index 2d6e976..a36b77e 100644 (file)
@@ -4,7 +4,7 @@
  * for more details.
  *
  * commpage, currently used for Virtual COP0 registers.
- * Mapped into the guest kernel @ 0x0.
+ * Mapped into the guest kernel @ KVM_GUEST_COMMPAGE_ADDR.
  *
  * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
  * Authors: Sanjay Lal <sanjayl@kymasys.com>
index f1527a4..d280894 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/highmem.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 
 #include "commpage.h"
 
-#define SYNCI_TEMPLATE  0x041f0000
-#define SYNCI_BASE(x)   (((x) >> 21) & 0x1f)
-#define SYNCI_OFFSET    ((x) & 0xffff)
+/**
+ * kvm_mips_trans_replace() - Replace trapping instruction in guest memory.
+ * @vcpu:      Virtual CPU.
+ * @opc:       PC of instruction to replace.
+ * @replace:   Instruction to write
+ */
+static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc,
+                                 union mips_instruction replace)
+{
+       unsigned long paddr, flags;
+       void *vaddr;
+
+       if (KVM_GUEST_KSEGX((unsigned long)opc) == KVM_GUEST_KSEG0) {
+               paddr = kvm_mips_translate_guest_kseg0_to_hpa(vcpu,
+                                                           (unsigned long)opc);
+               vaddr = kmap_atomic(pfn_to_page(PHYS_PFN(paddr)));
+               vaddr += paddr & ~PAGE_MASK;
+               memcpy(vaddr, (void *)&replace, sizeof(u32));
+               local_flush_icache_range((unsigned long)vaddr,
+                                        (unsigned long)vaddr + 32);
+               kunmap_atomic(vaddr);
+       } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
+               local_irq_save(flags);
+               memcpy((void *)opc, (void *)&replace, sizeof(u32));
+               local_flush_icache_range((unsigned long)opc,
+                                        (unsigned long)opc + 32);
+               local_irq_restore(flags);
+       } else {
+               kvm_err("%s: Invalid address: %p\n", __func__, opc);
+               return -EFAULT;
+       }
 
-#define LW_TEMPLATE     0x8c000000
-#define CLEAR_TEMPLATE  0x00000020
-#define SW_TEMPLATE     0xac000000
+       return 0;
+}
 
-int kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc,
+int kvm_mips_trans_cache_index(union mips_instruction inst, u32 *opc,
                               struct kvm_vcpu *vcpu)
 {
-       int result = 0;
-       unsigned long kseg0_opc;
-       uint32_t synci_inst = 0x0;
+       union mips_instruction nop_inst = { 0 };
 
        /* Replace the CACHE instruction, with a NOP */
-       kseg0_opc =
-           CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
-                      (vcpu, (unsigned long) opc));
-       memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t));
-       local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
-
-       return result;
+       return kvm_mips_trans_replace(vcpu, opc, nop_inst);
 }
 
 /*
  * Address based CACHE instructions are transformed into synci(s). A little
  * heavy for just D-cache invalidates, but avoids an expensive trap
  */
-int kvm_mips_trans_cache_va(uint32_t inst, uint32_t *opc,
+int kvm_mips_trans_cache_va(union mips_instruction inst, u32 *opc,
                            struct kvm_vcpu *vcpu)
 {
-       int result = 0;
-       unsigned long kseg0_opc;
-       uint32_t synci_inst = SYNCI_TEMPLATE, base, offset;
-
-       base = (inst >> 21) & 0x1f;
-       offset = inst & 0xffff;
-       synci_inst |= (base << 21);
-       synci_inst |= offset;
-
-       kseg0_opc =
-           CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
-                      (vcpu, (unsigned long) opc));
-       memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t));
-       local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
-
-       return result;
+       union mips_instruction synci_inst = { 0 };
+
+       synci_inst.i_format.opcode = bcond_op;
+       synci_inst.i_format.rs = inst.i_format.rs;
+       synci_inst.i_format.rt = synci_op;
+       if (cpu_has_mips_r6)
+               synci_inst.i_format.simmediate = inst.spec3_format.simmediate;
+       else
+               synci_inst.i_format.simmediate = inst.i_format.simmediate;
+
+       return kvm_mips_trans_replace(vcpu, opc, synci_inst);
 }
 
-int kvm_mips_trans_mfc0(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu)
+int kvm_mips_trans_mfc0(union mips_instruction inst, u32 *opc,
+                       struct kvm_vcpu *vcpu)
 {
-       int32_t rt, rd, sel;
-       uint32_t mfc0_inst;
-       unsigned long kseg0_opc, flags;
-
-       rt = (inst >> 16) & 0x1f;
-       rd = (inst >> 11) & 0x1f;
-       sel = inst & 0x7;
+       union mips_instruction mfc0_inst = { 0 };
+       u32 rd, sel;
 
-       if ((rd == MIPS_CP0_ERRCTL) && (sel == 0)) {
-               mfc0_inst = CLEAR_TEMPLATE;
-               mfc0_inst |= ((rt & 0x1f) << 16);
-       } else {
-               mfc0_inst = LW_TEMPLATE;
-               mfc0_inst |= ((rt & 0x1f) << 16);
-               mfc0_inst |= offsetof(struct kvm_mips_commpage,
-                                     cop0.reg[rd][sel]);
-       }
+       rd = inst.c0r_format.rd;
+       sel = inst.c0r_format.sel;
 
-       if (KVM_GUEST_KSEGX(opc) == KVM_GUEST_KSEG0) {
-               kseg0_opc =
-                   CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
-                              (vcpu, (unsigned long) opc));
-               memcpy((void *)kseg0_opc, (void *)&mfc0_inst, sizeof(uint32_t));
-               local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
-       } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
-               local_irq_save(flags);
-               memcpy((void *)opc, (void *)&mfc0_inst, sizeof(uint32_t));
-               local_flush_icache_range((unsigned long)opc,
-                                        (unsigned long)opc + 32);
-               local_irq_restore(flags);
+       if (rd == MIPS_CP0_ERRCTL && sel == 0) {
+               mfc0_inst.r_format.opcode = spec_op;
+               mfc0_inst.r_format.rd = inst.c0r_format.rt;
+               mfc0_inst.r_format.func = add_op;
        } else {
-               kvm_err("%s: Invalid address: %p\n", __func__, opc);
-               return -EFAULT;
+               mfc0_inst.i_format.opcode = lw_op;
+               mfc0_inst.i_format.rt = inst.c0r_format.rt;
+               mfc0_inst.i_format.simmediate = KVM_GUEST_COMMPAGE_ADDR |
+                       offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]);
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               if (sizeof(vcpu->arch.cop0->reg[0][0]) == 8)
+                       mfc0_inst.i_format.simmediate |= 4;
+#endif
        }
 
-       return 0;
+       return kvm_mips_trans_replace(vcpu, opc, mfc0_inst);
 }
 
-int kvm_mips_trans_mtc0(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu)
+int kvm_mips_trans_mtc0(union mips_instruction inst, u32 *opc,
+                       struct kvm_vcpu *vcpu)
 {
-       int32_t rt, rd, sel;
-       uint32_t mtc0_inst = SW_TEMPLATE;
-       unsigned long kseg0_opc, flags;
-
-       rt = (inst >> 16) & 0x1f;
-       rd = (inst >> 11) & 0x1f;
-       sel = inst & 0x7;
-
-       mtc0_inst |= ((rt & 0x1f) << 16);
-       mtc0_inst |= offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]);
-
-       if (KVM_GUEST_KSEGX(opc) == KVM_GUEST_KSEG0) {
-               kseg0_opc =
-                   CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
-                              (vcpu, (unsigned long) opc));
-               memcpy((void *)kseg0_opc, (void *)&mtc0_inst, sizeof(uint32_t));
-               local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
-       } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
-               local_irq_save(flags);
-               memcpy((void *)opc, (void *)&mtc0_inst, sizeof(uint32_t));
-               local_flush_icache_range((unsigned long)opc,
-                                        (unsigned long)opc + 32);
-               local_irq_restore(flags);
-       } else {
-               kvm_err("%s: Invalid address: %p\n", __func__, opc);
-               return -EFAULT;
-       }
-
-       return 0;
+       union mips_instruction mtc0_inst = { 0 };
+       u32 rd, sel;
+
+       rd = inst.c0r_format.rd;
+       sel = inst.c0r_format.sel;
+
+       mtc0_inst.i_format.opcode = sw_op;
+       mtc0_inst.i_format.rt = inst.c0r_format.rt;
+       mtc0_inst.i_format.simmediate = KVM_GUEST_COMMPAGE_ADDR |
+               offsetof(struct kvm_mips_commpage, cop0.reg[rd][sel]);
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       if (sizeof(vcpu->arch.cop0->reg[0][0]) == 8)
+               mtc0_inst.i_format.simmediate |= 4;
+#endif
+
+       return kvm_mips_trans_replace(vcpu, opc, mtc0_inst);
 }
index 645c8a1..6eb52b9 100644 (file)
@@ -52,7 +52,7 @@ unsigned long kvm_compute_return_epc(struct kvm_vcpu *vcpu,
                goto unaligned;
 
        /* Read the instruction */
-       insn.word = kvm_get_inst((uint32_t *) epc, vcpu);
+       insn.word = kvm_get_inst((u32 *) epc, vcpu);
 
        if (insn.word == KVM_INVALID_INST)
                return KVM_INVALID_INST;
@@ -161,9 +161,12 @@ unsigned long kvm_compute_return_epc(struct kvm_vcpu *vcpu,
                nextpc = epc;
                break;
 
-       case blez_op:           /* not really i_format */
-       case blezl_op:
-               /* rt field assumed to be zero */
+       case blez_op:   /* POP06 */
+#ifndef CONFIG_CPU_MIPSR6
+       case blezl_op:  /* removed in R6 */
+#endif
+               if (insn.i_format.rt != 0)
+                       goto compact_branch;
                if ((long)arch->gprs[insn.i_format.rs] <= 0)
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
                else
@@ -171,9 +174,12 @@ unsigned long kvm_compute_return_epc(struct kvm_vcpu *vcpu,
                nextpc = epc;
                break;
 
-       case bgtz_op:
-       case bgtzl_op:
-               /* rt field assumed to be zero */
+       case bgtz_op:   /* POP07 */
+#ifndef CONFIG_CPU_MIPSR6
+       case bgtzl_op:  /* removed in R6 */
+#endif
+               if (insn.i_format.rt != 0)
+                       goto compact_branch;
                if ((long)arch->gprs[insn.i_format.rs] > 0)
                        epc = epc + 4 + (insn.i_format.simmediate << 2);
                else
@@ -185,6 +191,40 @@ unsigned long kvm_compute_return_epc(struct kvm_vcpu *vcpu,
        case cop1_op:
                kvm_err("%s: unsupported cop1_op\n", __func__);
                break;
+
+#ifdef CONFIG_CPU_MIPSR6
+       /* R6 added the following compact branches with forbidden slots */
+       case blezl_op:  /* POP26 */
+       case bgtzl_op:  /* POP27 */
+               /* only rt == 0 isn't compact branch */
+               if (insn.i_format.rt != 0)
+                       goto compact_branch;
+               break;
+       case pop10_op:
+       case pop30_op:
+               /* only rs == rt == 0 is reserved, rest are compact branches */
+               if (insn.i_format.rs != 0 || insn.i_format.rt != 0)
+                       goto compact_branch;
+               break;
+       case pop66_op:
+       case pop76_op:
+               /* only rs == 0 isn't compact branch */
+               if (insn.i_format.rs != 0)
+                       goto compact_branch;
+               break;
+compact_branch:
+               /*
+                * If we've hit an exception on the forbidden slot, then
+                * the branch must not have been taken.
+                */
+               epc += 8;
+               nextpc = epc;
+               break;
+#else
+compact_branch:
+               /* Compact branches not supported before R6 */
+               break;
+#endif
        }
 
        return nextpc;
@@ -198,7 +238,7 @@ sigill:
        return nextpc;
 }
 
-enum emulation_result update_pc(struct kvm_vcpu *vcpu, uint32_t cause)
+enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause)
 {
        unsigned long branch_pc;
        enum emulation_result er = EMULATE_DONE;
@@ -243,7 +283,7 @@ static inline int kvm_mips_count_disabled(struct kvm_vcpu *vcpu)
  *
  * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
  */
-static uint32_t kvm_mips_ktime_to_count(struct kvm_vcpu *vcpu, ktime_t now)
+static u32 kvm_mips_ktime_to_count(struct kvm_vcpu *vcpu, ktime_t now)
 {
        s64 now_ns, periods;
        u64 delta;
@@ -300,11 +340,11 @@ static inline ktime_t kvm_mips_count_time(struct kvm_vcpu *vcpu)
  *
  * Returns:    The current value of the guest CP0_Count register.
  */
-static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
+static u32 kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        ktime_t expires, threshold;
-       uint32_t count, compare;
+       u32 count, compare;
        int running;
 
        /* Calculate the biased and scaled guest CP0_Count */
@@ -315,7 +355,7 @@ static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
         * Find whether CP0_Count has reached the closest timer interrupt. If
         * not, we shouldn't inject it.
         */
-       if ((int32_t)(count - compare) < 0)
+       if ((s32)(count - compare) < 0)
                return count;
 
        /*
@@ -360,7 +400,7 @@ static uint32_t kvm_mips_read_count_running(struct kvm_vcpu *vcpu, ktime_t now)
  *
  * Returns:    The current guest CP0_Count value.
  */
-uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu)
+u32 kvm_mips_read_count(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
 
@@ -387,8 +427,7 @@ uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu)
  *
  * Returns:    The ktime at the point of freeze.
  */
-static ktime_t kvm_mips_freeze_hrtimer(struct kvm_vcpu *vcpu,
-                                      uint32_t *count)
+static ktime_t kvm_mips_freeze_hrtimer(struct kvm_vcpu *vcpu, u32 *count)
 {
        ktime_t now;
 
@@ -419,16 +458,16 @@ static ktime_t kvm_mips_freeze_hrtimer(struct kvm_vcpu *vcpu,
  * Assumes !kvm_mips_count_disabled(@vcpu) (guest CP0_Count timer is running).
  */
 static void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu,
-                                   ktime_t now, uint32_t count)
+                                   ktime_t now, u32 count)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       uint32_t compare;
+       u32 compare;
        u64 delta;
        ktime_t expire;
 
        /* Calculate timeout (wrap 0 to 2^32) */
        compare = kvm_read_c0_guest_compare(cop0);
-       delta = (u64)(uint32_t)(compare - count - 1) + 1;
+       delta = (u64)(u32)(compare - count - 1) + 1;
        delta = div_u64(delta * NSEC_PER_SEC, vcpu->arch.count_hz);
        expire = ktime_add_ns(now, delta);
 
@@ -444,7 +483,7 @@ static void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu,
  *
  * Sets the CP0_Count value and updates the timer accordingly.
  */
-void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count)
+void kvm_mips_write_count(struct kvm_vcpu *vcpu, u32 count)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        ktime_t now;
@@ -538,13 +577,13 @@ int kvm_mips_set_count_hz(struct kvm_vcpu *vcpu, s64 count_hz)
  * If @ack, atomically acknowledge any pending timer interrupt, otherwise ensure
  * any pending timer interrupt is preserved.
  */
-void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack)
+void kvm_mips_write_compare(struct kvm_vcpu *vcpu, u32 compare, bool ack)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        int dc;
        u32 old_compare = kvm_read_c0_guest_compare(cop0);
        ktime_t now;
-       uint32_t count;
+       u32 count;
 
        /* if unchanged, must just be an ack */
        if (old_compare == compare) {
@@ -585,7 +624,7 @@ void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare, bool ack)
 static ktime_t kvm_mips_count_disable(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       uint32_t count;
+       u32 count;
        ktime_t now;
 
        /* Stop hrtimer */
@@ -632,7 +671,7 @@ void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu)
 void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       uint32_t count;
+       u32 count;
 
        kvm_clear_c0_guest_cause(cop0, CAUSEF_DC);
 
@@ -661,7 +700,7 @@ int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl)
        s64 changed = count_ctl ^ vcpu->arch.count_ctl;
        s64 delta;
        ktime_t expire, now;
-       uint32_t count, compare;
+       u32 count, compare;
 
        /* Only allow defined bits to be changed */
        if (changed & ~(s64)(KVM_REG_MIPS_COUNT_CTL_DC))
@@ -687,7 +726,7 @@ int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl)
                         */
                        count = kvm_read_c0_guest_count(cop0);
                        compare = kvm_read_c0_guest_compare(cop0);
-                       delta = (u64)(uint32_t)(compare - count - 1) + 1;
+                       delta = (u64)(u32)(compare - count - 1) + 1;
                        delta = div_u64(delta * NSEC_PER_SEC,
                                        vcpu->arch.count_hz);
                        expire = ktime_add_ns(vcpu->arch.count_resume, delta);
@@ -776,7 +815,7 @@ enum emulation_result kvm_mips_emul_wait(struct kvm_vcpu *vcpu)
                  vcpu->arch.pending_exceptions);
 
        ++vcpu->stat.wait_exits;
-       trace_kvm_exit(vcpu, WAIT_EXITS);
+       trace_kvm_exit(vcpu, KVM_TRACE_EXIT_WAIT);
        if (!vcpu->arch.pending_exceptions) {
                vcpu->arch.wait = 1;
                kvm_vcpu_block(vcpu);
@@ -801,9 +840,9 @@ enum emulation_result kvm_mips_emul_wait(struct kvm_vcpu *vcpu)
 enum emulation_result kvm_mips_emul_tlbr(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       uint32_t pc = vcpu->arch.pc;
+       unsigned long pc = vcpu->arch.pc;
 
-       kvm_err("[%#x] COP0_TLBR [%ld]\n", pc, kvm_read_c0_guest_index(cop0));
+       kvm_err("[%#lx] COP0_TLBR [%ld]\n", pc, kvm_read_c0_guest_index(cop0));
        return EMULATE_FAIL;
 }
 
@@ -813,11 +852,11 @@ enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        int index = kvm_read_c0_guest_index(cop0);
        struct kvm_mips_tlb *tlb = NULL;
-       uint32_t pc = vcpu->arch.pc;
+       unsigned long pc = vcpu->arch.pc;
 
        if (index < 0 || index >= KVM_MIPS_GUEST_TLB_SIZE) {
                kvm_debug("%s: illegal index: %d\n", __func__, index);
-               kvm_debug("[%#x] COP0_TLBWI [%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx, mask: %#lx)\n",
+               kvm_debug("[%#lx] COP0_TLBWI [%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx, mask: %#lx)\n",
                          pc, index, kvm_read_c0_guest_entryhi(cop0),
                          kvm_read_c0_guest_entrylo0(cop0),
                          kvm_read_c0_guest_entrylo1(cop0),
@@ -834,10 +873,10 @@ enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
 
        tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
        tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
-       tlb->tlb_lo0 = kvm_read_c0_guest_entrylo0(cop0);
-       tlb->tlb_lo1 = kvm_read_c0_guest_entrylo1(cop0);
+       tlb->tlb_lo[0] = kvm_read_c0_guest_entrylo0(cop0);
+       tlb->tlb_lo[1] = kvm_read_c0_guest_entrylo1(cop0);
 
-       kvm_debug("[%#x] COP0_TLBWI [%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx, mask: %#lx)\n",
+       kvm_debug("[%#lx] COP0_TLBWI [%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx, mask: %#lx)\n",
                  pc, index, kvm_read_c0_guest_entryhi(cop0),
                  kvm_read_c0_guest_entrylo0(cop0),
                  kvm_read_c0_guest_entrylo1(cop0),
@@ -851,7 +890,7 @@ enum emulation_result kvm_mips_emul_tlbwr(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        struct kvm_mips_tlb *tlb = NULL;
-       uint32_t pc = vcpu->arch.pc;
+       unsigned long pc = vcpu->arch.pc;
        int index;
 
        get_random_bytes(&index, sizeof(index));
@@ -867,10 +906,10 @@ enum emulation_result kvm_mips_emul_tlbwr(struct kvm_vcpu *vcpu)
 
        tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
        tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
-       tlb->tlb_lo0 = kvm_read_c0_guest_entrylo0(cop0);
-       tlb->tlb_lo1 = kvm_read_c0_guest_entrylo1(cop0);
+       tlb->tlb_lo[0] = kvm_read_c0_guest_entrylo0(cop0);
+       tlb->tlb_lo[1] = kvm_read_c0_guest_entrylo1(cop0);
 
-       kvm_debug("[%#x] COP0_TLBWR[%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx)\n",
+       kvm_debug("[%#lx] COP0_TLBWR[%d] (entryhi: %#lx, entrylo0: %#lx entrylo1: %#lx)\n",
                  pc, index, kvm_read_c0_guest_entryhi(cop0),
                  kvm_read_c0_guest_entrylo0(cop0),
                  kvm_read_c0_guest_entrylo1(cop0));
@@ -882,14 +921,14 @@ enum emulation_result kvm_mips_emul_tlbp(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        long entryhi = kvm_read_c0_guest_entryhi(cop0);
-       uint32_t pc = vcpu->arch.pc;
+       unsigned long pc = vcpu->arch.pc;
        int index = -1;
 
        index = kvm_mips_guest_tlb_lookup(vcpu, entryhi);
 
        kvm_write_c0_guest_index(cop0, index);
 
-       kvm_debug("[%#x] COP0_TLBP (entryhi: %#lx), index: %d\n", pc, entryhi,
+       kvm_debug("[%#lx] COP0_TLBP (entryhi: %#lx), index: %d\n", pc, entryhi,
                  index);
 
        return EMULATE_DONE;
@@ -922,8 +961,8 @@ unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu)
  */
 unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu)
 {
-       /* Config4 is optional */
-       unsigned int mask = MIPS_CONF_M;
+       /* Config4 and ULRI are optional */
+       unsigned int mask = MIPS_CONF_M | MIPS_CONF3_ULRI;
 
        /* Permit MSA to be present if MSA is supported */
        if (kvm_mips_guest_can_have_msa(&vcpu->arch))
@@ -942,7 +981,12 @@ unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu)
 unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu)
 {
        /* Config5 is optional */
-       return MIPS_CONF_M;
+       unsigned int mask = MIPS_CONF_M;
+
+       /* KScrExist */
+       mask |= (unsigned int)vcpu->arch.kscratch_enabled << 16;
+
+       return mask;
 }
 
 /**
@@ -973,14 +1017,14 @@ unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu)
        return mask;
 }
 
-enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
-                                          uint32_t cause, struct kvm_run *run,
+enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
+                                          u32 *opc, u32 cause,
+                                          struct kvm_run *run,
                                           struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        enum emulation_result er = EMULATE_DONE;
-       int32_t rt, rd, copz, sel, co_bit, op;
-       uint32_t pc = vcpu->arch.pc;
+       u32 rt, rd, sel;
        unsigned long curr_pc;
 
        /*
@@ -992,16 +1036,8 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
        if (er == EMULATE_FAIL)
                return er;
 
-       copz = (inst >> 21) & 0x1f;
-       rt = (inst >> 16) & 0x1f;
-       rd = (inst >> 11) & 0x1f;
-       sel = inst & 0x7;
-       co_bit = (inst >> 25) & 1;
-
-       if (co_bit) {
-               op = (inst) & 0xff;
-
-               switch (op) {
+       if (inst.co_format.co) {
+               switch (inst.co_format.func) {
                case tlbr_op:   /*  Read indexed TLB entry  */
                        er = kvm_mips_emul_tlbr(vcpu);
                        break;
@@ -1020,47 +1056,58 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                case eret_op:
                        er = kvm_mips_emul_eret(vcpu);
                        goto dont_update_pc;
-                       break;
                case wait_op:
                        er = kvm_mips_emul_wait(vcpu);
                        break;
                }
        } else {
-               switch (copz) {
+               rt = inst.c0r_format.rt;
+               rd = inst.c0r_format.rd;
+               sel = inst.c0r_format.sel;
+
+               switch (inst.c0r_format.rs) {
                case mfc_op:
 #ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS
                        cop0->stat[rd][sel]++;
 #endif
                        /* Get reg */
                        if ((rd == MIPS_CP0_COUNT) && (sel == 0)) {
-                               vcpu->arch.gprs[rt] = kvm_mips_read_count(vcpu);
+                               vcpu->arch.gprs[rt] =
+                                   (s32)kvm_mips_read_count(vcpu);
                        } else if ((rd == MIPS_CP0_ERRCTL) && (sel == 0)) {
                                vcpu->arch.gprs[rt] = 0x0;
 #ifdef CONFIG_KVM_MIPS_DYN_TRANS
                                kvm_mips_trans_mfc0(inst, opc, vcpu);
 #endif
                        } else {
-                               vcpu->arch.gprs[rt] = cop0->reg[rd][sel];
+                               vcpu->arch.gprs[rt] = (s32)cop0->reg[rd][sel];
 
 #ifdef CONFIG_KVM_MIPS_DYN_TRANS
                                kvm_mips_trans_mfc0(inst, opc, vcpu);
 #endif
                        }
 
-                       kvm_debug
-                           ("[%#x] MFCz[%d][%d], vcpu->arch.gprs[%d]: %#lx\n",
-                            pc, rd, sel, rt, vcpu->arch.gprs[rt]);
-
+                       trace_kvm_hwr(vcpu, KVM_TRACE_MFC0,
+                                     KVM_TRACE_COP0(rd, sel),
+                                     vcpu->arch.gprs[rt]);
                        break;
 
                case dmfc_op:
                        vcpu->arch.gprs[rt] = cop0->reg[rd][sel];
+
+                       trace_kvm_hwr(vcpu, KVM_TRACE_DMFC0,
+                                     KVM_TRACE_COP0(rd, sel),
+                                     vcpu->arch.gprs[rt]);
                        break;
 
                case mtc_op:
 #ifdef CONFIG_KVM_MIPS_DEBUG_COP0_COUNTERS
                        cop0->stat[rd][sel]++;
 #endif
+                       trace_kvm_hwr(vcpu, KVM_TRACE_MTC0,
+                                     KVM_TRACE_COP0(rd, sel),
+                                     vcpu->arch.gprs[rt]);
+
                        if ((rd == MIPS_CP0_TLB_INDEX)
                            && (vcpu->arch.gprs[rt] >=
                                KVM_MIPS_GUEST_TLB_SIZE)) {
@@ -1078,16 +1125,15 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                kvm_err("MTCz, cop0->reg[EBASE]: %#lx\n",
                                        kvm_read_c0_guest_ebase(cop0));
                        } else if (rd == MIPS_CP0_TLB_HI && sel == 0) {
-                               uint32_t nasid =
+                               u32 nasid =
                                        vcpu->arch.gprs[rt] & KVM_ENTRYHI_ASID;
                                if ((KSEGX(vcpu->arch.gprs[rt]) != CKSEG0) &&
                                    ((kvm_read_c0_guest_entryhi(cop0) &
                                      KVM_ENTRYHI_ASID) != nasid)) {
-                                       kvm_debug("MTCz, change ASID from %#lx to %#lx\n",
+                                       trace_kvm_asid_change(vcpu,
                                                kvm_read_c0_guest_entryhi(cop0)
-                                               & KVM_ENTRYHI_ASID,
-                                               vcpu->arch.gprs[rt]
-                                               & KVM_ENTRYHI_ASID);
+                                                       & KVM_ENTRYHI_ASID,
+                                               nasid);
 
                                        /* Blow away the shadow host TLBs */
                                        kvm_mips_flush_host_tlb(1);
@@ -1100,10 +1146,6 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                kvm_mips_write_count(vcpu, vcpu->arch.gprs[rt]);
                                goto done;
                        } else if ((rd == MIPS_CP0_COMPARE) && (sel == 0)) {
-                               kvm_debug("[%#x] MTCz, COMPARE %#lx <- %#lx\n",
-                                         pc, kvm_read_c0_guest_compare(cop0),
-                                         vcpu->arch.gprs[rt]);
-
                                /* If we are writing to COMPARE */
                                /* Clear pending timer interrupt, if any */
                                kvm_mips_write_compare(vcpu,
@@ -1155,7 +1197,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                 * it first.
                                 */
                                if (change & ST0_CU1 && !(val & ST0_FR) &&
-                                   vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA)
+                                   vcpu->arch.aux_inuse & KVM_MIPS_AUX_MSA)
                                        kvm_lose_fpu(vcpu);
 
                                /*
@@ -1166,7 +1208,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                 * the near future.
                                 */
                                if (change & ST0_CU1 &&
-                                   vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU)
+                                   vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU)
                                        change_c0_status(ST0_CU1, val);
 
                                preempt_enable();
@@ -1201,7 +1243,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                 * context is already loaded.
                                 */
                                if (change & MIPS_CONF5_FRE &&
-                                   vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU)
+                                   vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU)
                                        change_c0_config5(MIPS_CONF5_FRE, val);
 
                                /*
@@ -1211,7 +1253,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                 * quickly enabled again in the near future.
                                 */
                                if (change & MIPS_CONF5_MSAEN &&
-                                   vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA)
+                                   vcpu->arch.aux_inuse & KVM_MIPS_AUX_MSA)
                                        change_c0_config5(MIPS_CONF5_MSAEN,
                                                          val);
 
@@ -1219,7 +1261,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
 
                                kvm_write_c0_guest_config5(cop0, val);
                        } else if ((rd == MIPS_CP0_CAUSE) && (sel == 0)) {
-                               uint32_t old_cause, new_cause;
+                               u32 old_cause, new_cause;
 
                                old_cause = kvm_read_c0_guest_cause(cop0);
                                new_cause = vcpu->arch.gprs[rt];
@@ -1233,20 +1275,30 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                        else
                                                kvm_mips_count_enable_cause(vcpu);
                                }
+                       } else if ((rd == MIPS_CP0_HWRENA) && (sel == 0)) {
+                               u32 mask = MIPS_HWRENA_CPUNUM |
+                                          MIPS_HWRENA_SYNCISTEP |
+                                          MIPS_HWRENA_CC |
+                                          MIPS_HWRENA_CCRES;
+
+                               if (kvm_read_c0_guest_config3(cop0) &
+                                   MIPS_CONF3_ULRI)
+                                       mask |= MIPS_HWRENA_ULR;
+                               cop0->reg[rd][sel] = vcpu->arch.gprs[rt] & mask;
                        } else {
                                cop0->reg[rd][sel] = vcpu->arch.gprs[rt];
 #ifdef CONFIG_KVM_MIPS_DYN_TRANS
                                kvm_mips_trans_mtc0(inst, opc, vcpu);
 #endif
                        }
-
-                       kvm_debug("[%#x] MTCz, cop0->reg[%d][%d]: %#lx\n", pc,
-                                 rd, sel, cop0->reg[rd][sel]);
                        break;
 
                case dmtc_op:
                        kvm_err("!!!!!!![%#lx]dmtc_op: rt: %d, rd: %d, sel: %d!!!!!!\n",
                                vcpu->arch.pc, rt, rd, sel);
+                       trace_kvm_hwr(vcpu, KVM_TRACE_DMTC0,
+                                     KVM_TRACE_COP0(rd, sel),
+                                     vcpu->arch.gprs[rt]);
                        er = EMULATE_FAIL;
                        break;
 
@@ -1258,7 +1310,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                vcpu->arch.gprs[rt] =
                                    kvm_read_c0_guest_status(cop0);
                        /* EI */
-                       if (inst & 0x20) {
+                       if (inst.mfmc0_format.sc) {
                                kvm_debug("[%#lx] mfmc0_op: EI\n",
                                          vcpu->arch.pc);
                                kvm_set_c0_guest_status(cop0, ST0_IE);
@@ -1272,9 +1324,8 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
 
                case wrpgpr_op:
                        {
-                               uint32_t css =
-                                   cop0->reg[MIPS_CP0_STATUS][2] & 0xf;
-                               uint32_t pss =
+                               u32 css = cop0->reg[MIPS_CP0_STATUS][2] & 0xf;
+                               u32 pss =
                                    (cop0->reg[MIPS_CP0_STATUS][2] >> 6) & 0xf;
                                /*
                                 * We don't support any shadow register sets, so
@@ -1291,7 +1342,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                        break;
                default:
                        kvm_err("[%#lx]MachEmulateCP0: unsupported COP0, copz: 0x%x\n",
-                               vcpu->arch.pc, copz);
+                               vcpu->arch.pc, inst.c0r_format.rs);
                        er = EMULATE_FAIL;
                        break;
                }
@@ -1312,13 +1363,14 @@ dont_update_pc:
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
+enum emulation_result kvm_mips_emulate_store(union mips_instruction inst,
+                                            u32 cause,
                                             struct kvm_run *run,
                                             struct kvm_vcpu *vcpu)
 {
        enum emulation_result er = EMULATE_DO_MMIO;
-       int32_t op, base, rt, offset;
-       uint32_t bytes;
+       u32 rt;
+       u32 bytes;
        void *data = run->mmio.data;
        unsigned long curr_pc;
 
@@ -1331,12 +1383,9 @@ enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
        if (er == EMULATE_FAIL)
                return er;
 
-       rt = (inst >> 16) & 0x1f;
-       base = (inst >> 21) & 0x1f;
-       offset = inst & 0xffff;
-       op = (inst >> 26) & 0x3f;
+       rt = inst.i_format.rt;
 
-       switch (op) {
+       switch (inst.i_format.opcode) {
        case sb_op:
                bytes = 1;
                if (bytes > sizeof(run->mmio.data)) {
@@ -1357,7 +1406,7 @@ enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
                *(u8 *) data = vcpu->arch.gprs[rt];
                kvm_debug("OP_SB: eaddr: %#lx, gpr: %#lx, data: %#x\n",
                          vcpu->arch.host_cp0_badvaddr, vcpu->arch.gprs[rt],
-                         *(uint8_t *) data);
+                         *(u8 *) data);
 
                break;
 
@@ -1379,11 +1428,11 @@ enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
                run->mmio.is_write = 1;
                vcpu->mmio_needed = 1;
                vcpu->mmio_is_write = 1;
-               *(uint32_t *) data = vcpu->arch.gprs[rt];
+               *(u32 *) data = vcpu->arch.gprs[rt];
 
                kvm_debug("[%#lx] OP_SW: eaddr: %#lx, gpr: %#lx, data: %#x\n",
                          vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
-                         vcpu->arch.gprs[rt], *(uint32_t *) data);
+                         vcpu->arch.gprs[rt], *(u32 *) data);
                break;
 
        case sh_op:
@@ -1404,15 +1453,16 @@ enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
                run->mmio.is_write = 1;
                vcpu->mmio_needed = 1;
                vcpu->mmio_is_write = 1;
-               *(uint16_t *) data = vcpu->arch.gprs[rt];
+               *(u16 *) data = vcpu->arch.gprs[rt];
 
                kvm_debug("[%#lx] OP_SH: eaddr: %#lx, gpr: %#lx, data: %#x\n",
                          vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr,
-                         vcpu->arch.gprs[rt], *(uint32_t *) data);
+                         vcpu->arch.gprs[rt], *(u32 *) data);
                break;
 
        default:
-               kvm_err("Store not yet supported");
+               kvm_err("Store not yet supported (inst=0x%08x)\n",
+                       inst.word);
                er = EMULATE_FAIL;
                break;
        }
@@ -1424,18 +1474,16 @@ enum emulation_result kvm_mips_emulate_store(uint32_t inst, uint32_t cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_load(uint32_t inst, uint32_t cause,
-                                           struct kvm_run *run,
+enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
+                                           u32 cause, struct kvm_run *run,
                                            struct kvm_vcpu *vcpu)
 {
        enum emulation_result er = EMULATE_DO_MMIO;
-       int32_t op, base, rt, offset;
-       uint32_t bytes;
+       u32 op, rt;
+       u32 bytes;
 
-       rt = (inst >> 16) & 0x1f;
-       base = (inst >> 21) & 0x1f;
-       offset = inst & 0xffff;
-       op = (inst >> 26) & 0x3f;
+       rt = inst.i_format.rt;
+       op = inst.i_format.opcode;
 
        vcpu->arch.pending_load_cause = cause;
        vcpu->arch.io_gpr = rt;
@@ -1521,7 +1569,8 @@ enum emulation_result kvm_mips_emulate_load(uint32_t inst, uint32_t cause,
                break;
 
        default:
-               kvm_err("Load not yet supported");
+               kvm_err("Load not yet supported (inst=0x%08x)\n",
+                       inst.word);
                er = EMULATE_FAIL;
                break;
        }
@@ -1529,40 +1578,15 @@ enum emulation_result kvm_mips_emulate_load(uint32_t inst, uint32_t cause,
        return er;
 }
 
-int kvm_mips_sync_icache(unsigned long va, struct kvm_vcpu *vcpu)
-{
-       unsigned long offset = (va & ~PAGE_MASK);
-       struct kvm *kvm = vcpu->kvm;
-       unsigned long pa;
-       gfn_t gfn;
-       kvm_pfn_t pfn;
-
-       gfn = va >> PAGE_SHIFT;
-
-       if (gfn >= kvm->arch.guest_pmap_npages) {
-               kvm_err("%s: Invalid gfn: %#llx\n", __func__, gfn);
-               kvm_mips_dump_host_tlbs();
-               kvm_arch_vcpu_dump_regs(vcpu);
-               return -1;
-       }
-       pfn = kvm->arch.guest_pmap[gfn];
-       pa = (pfn << PAGE_SHIFT) | offset;
-
-       kvm_debug("%s: va: %#lx, unmapped: %#x\n", __func__, va,
-                 CKSEG0ADDR(pa));
-
-       local_flush_icache_range(CKSEG0ADDR(pa), 32);
-       return 0;
-}
-
-enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
-                                            uint32_t cause,
+enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
+                                            u32 *opc, u32 cause,
                                             struct kvm_run *run,
                                             struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        enum emulation_result er = EMULATE_DONE;
-       int32_t offset, cache, op_inst, op, base;
+       u32 cache, op_inst, op, base;
+       s16 offset;
        struct kvm_vcpu_arch *arch = &vcpu->arch;
        unsigned long va;
        unsigned long curr_pc;
@@ -1576,9 +1600,12 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
        if (er == EMULATE_FAIL)
                return er;
 
-       base = (inst >> 21) & 0x1f;
-       op_inst = (inst >> 16) & 0x1f;
-       offset = (int16_t)inst;
+       base = inst.i_format.rs;
+       op_inst = inst.i_format.rt;
+       if (cpu_has_mips_r6)
+               offset = inst.spec3_format.simmediate;
+       else
+               offset = inst.i_format.simmediate;
        cache = op_inst & CacheOp_Cache;
        op = op_inst & CacheOp_Op;
 
@@ -1634,7 +1661,6 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
                                                   (cop0) & KVM_ENTRYHI_ASID));
 
                if (index < 0) {
-                       vcpu->arch.host_cp0_entryhi = (va & VPN2_MASK);
                        vcpu->arch.host_cp0_badvaddr = va;
                        vcpu->arch.pc = curr_pc;
                        er = kvm_mips_emulate_tlbmiss_ld(cause, NULL, run,
@@ -1659,9 +1685,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
                                 * We fault an entry from the guest tlb to the
                                 * shadow host TLB
                                 */
-                               kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
-                                                                    NULL,
-                                                                    NULL);
+                               kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
                        }
                }
        } else {
@@ -1714,20 +1738,20 @@ dont_update_pc:
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_inst(unsigned long cause, uint32_t *opc,
+enum emulation_result kvm_mips_emulate_inst(u32 cause, u32 *opc,
                                            struct kvm_run *run,
                                            struct kvm_vcpu *vcpu)
 {
+       union mips_instruction inst;
        enum emulation_result er = EMULATE_DONE;
-       uint32_t inst;
 
        /* Fetch the instruction. */
        if (cause & CAUSEF_BD)
                opc += 1;
 
-       inst = kvm_get_inst(opc, vcpu);
+       inst.word = kvm_get_inst(opc, vcpu);
 
-       switch (((union mips_instruction)inst).r_format.opcode) {
+       switch (inst.r_format.opcode) {
        case cop0_op:
                er = kvm_mips_emulate_CP0(inst, opc, cause, run, vcpu);
                break;
@@ -1744,15 +1768,31 @@ enum emulation_result kvm_mips_emulate_inst(unsigned long cause, uint32_t *opc,
                er = kvm_mips_emulate_load(inst, cause, run, vcpu);
                break;
 
+#ifndef CONFIG_CPU_MIPSR6
        case cache_op:
                ++vcpu->stat.cache_exits;
-               trace_kvm_exit(vcpu, CACHE_EXITS);
+               trace_kvm_exit(vcpu, KVM_TRACE_EXIT_CACHE);
                er = kvm_mips_emulate_cache(inst, opc, cause, run, vcpu);
                break;
+#else
+       case spec3_op:
+               switch (inst.spec3_format.func) {
+               case cache6_op:
+                       ++vcpu->stat.cache_exits;
+                       trace_kvm_exit(vcpu, KVM_TRACE_EXIT_CACHE);
+                       er = kvm_mips_emulate_cache(inst, opc, cause, run,
+                                                   vcpu);
+                       break;
+               default:
+                       goto unknown;
+               };
+               break;
+unknown:
+#endif
 
        default:
                kvm_err("Instruction emulation not supported (%p/%#x)\n", opc,
-                       inst);
+                       inst.word);
                kvm_arch_vcpu_dump_regs(vcpu);
                er = EMULATE_FAIL;
                break;
@@ -1761,8 +1801,8 @@ enum emulation_result kvm_mips_emulate_inst(unsigned long cause, uint32_t *opc,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_syscall(unsigned long cause,
-                                              uint32_t *opc,
+enum emulation_result kvm_mips_emulate_syscall(u32 cause,
+                                              u32 *opc,
                                               struct kvm_run *run,
                                               struct kvm_vcpu *vcpu)
 {
@@ -1796,8 +1836,8 @@ enum emulation_result kvm_mips_emulate_syscall(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_tlbmiss_ld(unsigned long cause,
-                                                 uint32_t *opc,
+enum emulation_result kvm_mips_emulate_tlbmiss_ld(u32 cause,
+                                                 u32 *opc,
                                                  struct kvm_run *run,
                                                  struct kvm_vcpu *vcpu)
 {
@@ -1842,8 +1882,8 @@ enum emulation_result kvm_mips_emulate_tlbmiss_ld(unsigned long cause,
        return EMULATE_DONE;
 }
 
-enum emulation_result kvm_mips_emulate_tlbinv_ld(unsigned long cause,
-                                                uint32_t *opc,
+enum emulation_result kvm_mips_emulate_tlbinv_ld(u32 cause,
+                                                u32 *opc,
                                                 struct kvm_run *run,
                                                 struct kvm_vcpu *vcpu)
 {
@@ -1888,8 +1928,8 @@ enum emulation_result kvm_mips_emulate_tlbinv_ld(unsigned long cause,
        return EMULATE_DONE;
 }
 
-enum emulation_result kvm_mips_emulate_tlbmiss_st(unsigned long cause,
-                                                 uint32_t *opc,
+enum emulation_result kvm_mips_emulate_tlbmiss_st(u32 cause,
+                                                 u32 *opc,
                                                  struct kvm_run *run,
                                                  struct kvm_vcpu *vcpu)
 {
@@ -1932,8 +1972,8 @@ enum emulation_result kvm_mips_emulate_tlbmiss_st(unsigned long cause,
        return EMULATE_DONE;
 }
 
-enum emulation_result kvm_mips_emulate_tlbinv_st(unsigned long cause,
-                                                uint32_t *opc,
+enum emulation_result kvm_mips_emulate_tlbinv_st(u32 cause,
+                                                u32 *opc,
                                                 struct kvm_run *run,
                                                 struct kvm_vcpu *vcpu)
 {
@@ -1977,7 +2017,7 @@ enum emulation_result kvm_mips_emulate_tlbinv_st(unsigned long cause,
 }
 
 /* TLBMOD: store into address matching TLB with Dirty bit off */
-enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause, uint32_t *opc,
+enum emulation_result kvm_mips_handle_tlbmod(u32 cause, u32 *opc,
                                             struct kvm_run *run,
                                             struct kvm_vcpu *vcpu)
 {
@@ -2005,8 +2045,8 @@ enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause, uint32_t *opc,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_tlbmod(unsigned long cause,
-                                             uint32_t *opc,
+enum emulation_result kvm_mips_emulate_tlbmod(u32 cause,
+                                             u32 *opc,
                                              struct kvm_run *run,
                                              struct kvm_vcpu *vcpu)
 {
@@ -2048,8 +2088,8 @@ enum emulation_result kvm_mips_emulate_tlbmod(unsigned long cause,
        return EMULATE_DONE;
 }
 
-enum emulation_result kvm_mips_emulate_fpu_exc(unsigned long cause,
-                                              uint32_t *opc,
+enum emulation_result kvm_mips_emulate_fpu_exc(u32 cause,
+                                              u32 *opc,
                                               struct kvm_run *run,
                                               struct kvm_vcpu *vcpu)
 {
@@ -2077,8 +2117,8 @@ enum emulation_result kvm_mips_emulate_fpu_exc(unsigned long cause,
        return EMULATE_DONE;
 }
 
-enum emulation_result kvm_mips_emulate_ri_exc(unsigned long cause,
-                                             uint32_t *opc,
+enum emulation_result kvm_mips_emulate_ri_exc(u32 cause,
+                                             u32 *opc,
                                              struct kvm_run *run,
                                              struct kvm_vcpu *vcpu)
 {
@@ -2112,8 +2152,8 @@ enum emulation_result kvm_mips_emulate_ri_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
-                                             uint32_t *opc,
+enum emulation_result kvm_mips_emulate_bp_exc(u32 cause,
+                                             u32 *opc,
                                              struct kvm_run *run,
                                              struct kvm_vcpu *vcpu)
 {
@@ -2147,8 +2187,8 @@ enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
-                                               uint32_t *opc,
+enum emulation_result kvm_mips_emulate_trap_exc(u32 cause,
+                                               u32 *opc,
                                                struct kvm_run *run,
                                                struct kvm_vcpu *vcpu)
 {
@@ -2182,8 +2222,8 @@ enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_msafpe_exc(unsigned long cause,
-                                                 uint32_t *opc,
+enum emulation_result kvm_mips_emulate_msafpe_exc(u32 cause,
+                                                 u32 *opc,
                                                  struct kvm_run *run,
                                                  struct kvm_vcpu *vcpu)
 {
@@ -2217,8 +2257,8 @@ enum emulation_result kvm_mips_emulate_msafpe_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause,
-                                              uint32_t *opc,
+enum emulation_result kvm_mips_emulate_fpe_exc(u32 cause,
+                                              u32 *opc,
                                               struct kvm_run *run,
                                               struct kvm_vcpu *vcpu)
 {
@@ -2252,8 +2292,8 @@ enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_emulate_msadis_exc(unsigned long cause,
-                                                 uint32_t *opc,
+enum emulation_result kvm_mips_emulate_msadis_exc(u32 cause,
+                                                 u32 *opc,
                                                  struct kvm_run *run,
                                                  struct kvm_vcpu *vcpu)
 {
@@ -2287,22 +2327,7 @@ enum emulation_result kvm_mips_emulate_msadis_exc(unsigned long cause,
        return er;
 }
 
-/* ll/sc, rdhwr, sync emulation */
-
-#define OPCODE 0xfc000000
-#define BASE   0x03e00000
-#define RT     0x001f0000
-#define OFFSET 0x0000ffff
-#define LL     0xc0000000
-#define SC     0xe0000000
-#define SPEC0  0x00000000
-#define SPEC3  0x7c000000
-#define RD     0x0000f800
-#define FUNC   0x0000003f
-#define SYNC   0x0000000f
-#define RDHWR  0x0000003b
-
-enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
+enum emulation_result kvm_mips_handle_ri(u32 cause, u32 *opc,
                                         struct kvm_run *run,
                                         struct kvm_vcpu *vcpu)
 {
@@ -2310,7 +2335,7 @@ enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
        struct kvm_vcpu_arch *arch = &vcpu->arch;
        enum emulation_result er = EMULATE_DONE;
        unsigned long curr_pc;
-       uint32_t inst;
+       union mips_instruction inst;
 
        /*
         * Update PC and hold onto current PC in case there is
@@ -2325,17 +2350,22 @@ enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
        if (cause & CAUSEF_BD)
                opc += 1;
 
-       inst = kvm_get_inst(opc, vcpu);
+       inst.word = kvm_get_inst(opc, vcpu);
 
-       if (inst == KVM_INVALID_INST) {
+       if (inst.word == KVM_INVALID_INST) {
                kvm_err("%s: Cannot get inst @ %p\n", __func__, opc);
                return EMULATE_FAIL;
        }
 
-       if ((inst & OPCODE) == SPEC3 && (inst & FUNC) == RDHWR) {
+       if (inst.r_format.opcode == spec3_op &&
+           inst.r_format.func == rdhwr_op &&
+           inst.r_format.rs == 0 &&
+           (inst.r_format.re >> 3) == 0) {
                int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
-               int rd = (inst & RD) >> 11;
-               int rt = (inst & RT) >> 16;
+               int rd = inst.r_format.rd;
+               int rt = inst.r_format.rt;
+               int sel = inst.r_format.re & 0x7;
+
                /* If usermode, check RDHWR rd is allowed by guest HWREna */
                if (usermode && !(kvm_read_c0_guest_hwrena(cop0) & BIT(rd))) {
                        kvm_debug("RDHWR %#x disallowed by HWREna @ %p\n",
@@ -2343,17 +2373,17 @@ enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
                        goto emulate_ri;
                }
                switch (rd) {
-               case 0: /* CPU number */
-                       arch->gprs[rt] = 0;
+               case MIPS_HWR_CPUNUM:           /* CPU number */
+                       arch->gprs[rt] = vcpu->vcpu_id;
                        break;
-               case 1: /* SYNCI length */
+               case MIPS_HWR_SYNCISTEP:        /* SYNCI length */
                        arch->gprs[rt] = min(current_cpu_data.dcache.linesz,
                                             current_cpu_data.icache.linesz);
                        break;
-               case 2: /* Read count register */
-                       arch->gprs[rt] = kvm_mips_read_count(vcpu);
+               case MIPS_HWR_CC:               /* Read count register */
+                       arch->gprs[rt] = (s32)kvm_mips_read_count(vcpu);
                        break;
-               case 3: /* Count register resolution */
+               case MIPS_HWR_CCRES:            /* Count register resolution */
                        switch (current_cpu_data.cputype) {
                        case CPU_20KC:
                        case CPU_25KF:
@@ -2363,7 +2393,7 @@ enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
                                arch->gprs[rt] = 2;
                        }
                        break;
-               case 29:
+               case MIPS_HWR_ULR:              /* Read UserLocal register */
                        arch->gprs[rt] = kvm_read_c0_guest_userlocal(cop0);
                        break;
 
@@ -2371,8 +2401,12 @@ enum emulation_result kvm_mips_handle_ri(unsigned long cause, uint32_t *opc,
                        kvm_debug("RDHWR %#x not supported @ %p\n", rd, opc);
                        goto emulate_ri;
                }
+
+               trace_kvm_hwr(vcpu, KVM_TRACE_RDHWR, KVM_TRACE_HWR(rd, sel),
+                             vcpu->arch.gprs[rt]);
        } else {
-               kvm_debug("Emulate RI not supported @ %p: %#x\n", opc, inst);
+               kvm_debug("Emulate RI not supported @ %p: %#x\n",
+                         opc, inst.word);
                goto emulate_ri;
        }
 
@@ -2405,19 +2439,19 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
 
        switch (run->mmio.len) {
        case 4:
-               *gpr = *(int32_t *) run->mmio.data;
+               *gpr = *(s32 *) run->mmio.data;
                break;
 
        case 2:
                if (vcpu->mmio_needed == 2)
-                       *gpr = *(int16_t *) run->mmio.data;
+                       *gpr = *(s16 *) run->mmio.data;
                else
-                       *gpr = *(uint16_t *)run->mmio.data;
+                       *gpr = *(u16 *)run->mmio.data;
 
                break;
        case 1:
                if (vcpu->mmio_needed == 2)
-                       *gpr = *(int8_t *) run->mmio.data;
+                       *gpr = *(s8 *) run->mmio.data;
                else
                        *gpr = *(u8 *) run->mmio.data;
                break;
@@ -2432,12 +2466,12 @@ done:
        return er;
 }
 
-static enum emulation_result kvm_mips_emulate_exc(unsigned long cause,
-                                                 uint32_t *opc,
+static enum emulation_result kvm_mips_emulate_exc(u32 cause,
+                                                 u32 *opc,
                                                  struct kvm_run *run,
                                                  struct kvm_vcpu *vcpu)
 {
-       uint32_t exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
+       u32 exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        struct kvm_vcpu_arch *arch = &vcpu->arch;
        enum emulation_result er = EMULATE_DONE;
@@ -2470,13 +2504,13 @@ static enum emulation_result kvm_mips_emulate_exc(unsigned long cause,
        return er;
 }
 
-enum emulation_result kvm_mips_check_privilege(unsigned long cause,
-                                              uint32_t *opc,
+enum emulation_result kvm_mips_check_privilege(u32 cause,
+                                              u32 *opc,
                                               struct kvm_run *run,
                                               struct kvm_vcpu *vcpu)
 {
        enum emulation_result er = EMULATE_DONE;
-       uint32_t exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
+       u32 exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
 
        int usermode = !KVM_GUEST_KERNEL_MODE(vcpu);
@@ -2566,18 +2600,18 @@ enum emulation_result kvm_mips_check_privilege(unsigned long cause,
  * (2) TLB entry is present in the Guest TLB but not in the shadow, in this
  *     case we inject the TLB from the Guest TLB into the shadow host TLB
  */
-enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause,
-                                             uint32_t *opc,
+enum emulation_result kvm_mips_handle_tlbmiss(u32 cause,
+                                             u32 *opc,
                                              struct kvm_run *run,
                                              struct kvm_vcpu *vcpu)
 {
        enum emulation_result er = EMULATE_DONE;
-       uint32_t exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
+       u32 exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
        unsigned long va = vcpu->arch.host_cp0_badvaddr;
        int index;
 
-       kvm_debug("kvm_mips_handle_tlbmiss: badvaddr: %#lx, entryhi: %#lx\n",
-                 vcpu->arch.host_cp0_badvaddr, vcpu->arch.host_cp0_entryhi);
+       kvm_debug("kvm_mips_handle_tlbmiss: badvaddr: %#lx\n",
+                 vcpu->arch.host_cp0_badvaddr);
 
        /*
         * KVM would not have got the exception if this entry was valid in the
@@ -2620,13 +2654,12 @@ enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause,
                        }
                } else {
                        kvm_debug("Injecting hi: %#lx, lo0: %#lx, lo1: %#lx into shadow host TLB\n",
-                                 tlb->tlb_hi, tlb->tlb_lo0, tlb->tlb_lo1);
+                                 tlb->tlb_hi, tlb->tlb_lo[0], tlb->tlb_lo[1]);
                        /*
                         * OK we have a Guest TLB entry, now inject it into the
                         * shadow host TLB
                         */
-                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, NULL,
-                                                            NULL);
+                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
                }
        }
 
diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c
new file mode 100644 (file)
index 0000000..6a02b3a
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * 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.
+ *
+ * Generation of main entry point for the guest, exception handling.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.
+ * Authors: Sanjay Lal <sanjayl@kymasys.com>
+ *
+ * Copyright (C) 2016 Imagination Technologies Ltd.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/msa.h>
+#include <asm/setup.h>
+#include <asm/uasm.h>
+
+/* Register names */
+#define ZERO           0
+#define AT             1
+#define V0             2
+#define V1             3
+#define A0             4
+#define A1             5
+
+#if _MIPS_SIM == _MIPS_SIM_ABI32
+#define T0             8
+#define T1             9
+#define T2             10
+#define T3             11
+#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
+
+#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
+#define T0             12
+#define T1             13
+#define T2             14
+#define T3             15
+#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 */
+
+#define S0             16
+#define S1             17
+#define T9             25
+#define K0             26
+#define K1             27
+#define GP             28
+#define SP             29
+#define RA             31
+
+/* Some CP0 registers */
+#define C0_HWRENA      7, 0
+#define C0_BADVADDR    8, 0
+#define C0_ENTRYHI     10, 0
+#define C0_STATUS      12, 0
+#define C0_CAUSE       13, 0
+#define C0_EPC         14, 0
+#define C0_EBASE       15, 1
+#define C0_CONFIG5     16, 5
+#define C0_DDATA_LO    28, 3
+#define C0_ERROREPC    30, 0
+
+#define CALLFRAME_SIZ   32
+
+#ifdef CONFIG_64BIT
+#define ST0_KX_IF_64   ST0_KX
+#else
+#define ST0_KX_IF_64   0
+#endif
+
+static unsigned int scratch_vcpu[2] = { C0_DDATA_LO };
+static unsigned int scratch_tmp[2] = { C0_ERROREPC };
+
+enum label_id {
+       label_fpu_1 = 1,
+       label_msa_1,
+       label_return_to_host,
+       label_kernel_asid,
+       label_exit_common,
+};
+
+UASM_L_LA(_fpu_1)
+UASM_L_LA(_msa_1)
+UASM_L_LA(_return_to_host)
+UASM_L_LA(_kernel_asid)
+UASM_L_LA(_exit_common)
+
+static void *kvm_mips_build_enter_guest(void *addr);
+static void *kvm_mips_build_ret_from_exit(void *addr);
+static void *kvm_mips_build_ret_to_guest(void *addr);
+static void *kvm_mips_build_ret_to_host(void *addr);
+
+/**
+ * kvm_mips_entry_setup() - Perform global setup for entry code.
+ *
+ * Perform global setup for entry code, such as choosing a scratch register.
+ *
+ * Returns:    0 on success.
+ *             -errno on failure.
+ */
+int kvm_mips_entry_setup(void)
+{
+       /*
+        * We prefer to use KScratchN registers if they are available over the
+        * defaults above, which may not work on all cores.
+        */
+       unsigned int kscratch_mask = cpu_data[0].kscratch_mask & 0xfc;
+
+       /* Pick a scratch register for storing VCPU */
+       if (kscratch_mask) {
+               scratch_vcpu[0] = 31;
+               scratch_vcpu[1] = ffs(kscratch_mask) - 1;
+               kscratch_mask &= ~BIT(scratch_vcpu[1]);
+       }
+
+       /* Pick a scratch register to use as a temp for saving state */
+       if (kscratch_mask) {
+               scratch_tmp[0] = 31;
+               scratch_tmp[1] = ffs(kscratch_mask) - 1;
+               kscratch_mask &= ~BIT(scratch_tmp[1]);
+       }
+
+       return 0;
+}
+
+static void kvm_mips_build_save_scratch(u32 **p, unsigned int tmp,
+                                       unsigned int frame)
+{
+       /* Save the VCPU scratch register value in cp0_epc of the stack frame */
+       UASM_i_MFC0(p, tmp, scratch_vcpu[0], scratch_vcpu[1]);
+       UASM_i_SW(p, tmp, offsetof(struct pt_regs, cp0_epc), frame);
+
+       /* Save the temp scratch register value in cp0_cause of stack frame */
+       if (scratch_tmp[0] == 31) {
+               UASM_i_MFC0(p, tmp, scratch_tmp[0], scratch_tmp[1]);
+               UASM_i_SW(p, tmp, offsetof(struct pt_regs, cp0_cause), frame);
+       }
+}
+
+static void kvm_mips_build_restore_scratch(u32 **p, unsigned int tmp,
+                                          unsigned int frame)
+{
+       /*
+        * Restore host scratch register values saved by
+        * kvm_mips_build_save_scratch().
+        */
+       UASM_i_LW(p, tmp, offsetof(struct pt_regs, cp0_epc), frame);
+       UASM_i_MTC0(p, tmp, scratch_vcpu[0], scratch_vcpu[1]);
+
+       if (scratch_tmp[0] == 31) {
+               UASM_i_LW(p, tmp, offsetof(struct pt_regs, cp0_cause), frame);
+               UASM_i_MTC0(p, tmp, scratch_tmp[0], scratch_tmp[1]);
+       }
+}
+
+/**
+ * build_set_exc_base() - Assemble code to write exception base address.
+ * @p:         Code buffer pointer.
+ * @reg:       Source register (generated code may set WG bit in @reg).
+ *
+ * Assemble code to modify the exception base address in the EBase register,
+ * using the appropriately sized access and setting the WG bit if necessary.
+ */
+static inline void build_set_exc_base(u32 **p, unsigned int reg)
+{
+       if (cpu_has_ebase_wg) {
+               /* Set WG so that all the bits get written */
+               uasm_i_ori(p, reg, reg, MIPS_EBASE_WG);
+               UASM_i_MTC0(p, reg, C0_EBASE);
+       } else {
+               uasm_i_mtc0(p, reg, C0_EBASE);
+       }
+}
+
+/**
+ * kvm_mips_build_vcpu_run() - Assemble function to start running a guest VCPU.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the start of the vcpu_run function to run a guest VCPU. The function
+ * conforms to the following prototype:
+ *
+ * int vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu);
+ *
+ * The exit from the guest and return to the caller is handled by the code
+ * generated by kvm_mips_build_ret_to_host().
+ *
+ * Returns:    Next address after end of written function.
+ */
+void *kvm_mips_build_vcpu_run(void *addr)
+{
+       u32 *p = addr;
+       unsigned int i;
+
+       /*
+        * A0: run
+        * A1: vcpu
+        */
+
+       /* k0/k1 not being used in host kernel context */
+       UASM_i_ADDIU(&p, K1, SP, -(int)sizeof(struct pt_regs));
+       for (i = 16; i < 32; ++i) {
+               if (i == 24)
+                       i = 28;
+               UASM_i_SW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
+       }
+
+       /* Save host status */
+       uasm_i_mfc0(&p, V0, C0_STATUS);
+       UASM_i_SW(&p, V0, offsetof(struct pt_regs, cp0_status), K1);
+
+       /* Save scratch registers, will be used to store pointer to vcpu etc */
+       kvm_mips_build_save_scratch(&p, V1, K1);
+
+       /* VCPU scratch register has pointer to vcpu */
+       UASM_i_MTC0(&p, A1, scratch_vcpu[0], scratch_vcpu[1]);
+
+       /* Offset into vcpu->arch */
+       UASM_i_ADDIU(&p, K1, A1, offsetof(struct kvm_vcpu, arch));
+
+       /*
+        * Save the host stack to VCPU, used for exception processing
+        * when we exit from the Guest
+        */
+       UASM_i_SW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
+
+       /* Save the kernel gp as well */
+       UASM_i_SW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
+
+       /*
+        * Setup status register for running the guest in UM, interrupts
+        * are disabled
+        */
+       UASM_i_LA(&p, K0, ST0_EXL | KSU_USER | ST0_BEV | ST0_KX_IF_64);
+       uasm_i_mtc0(&p, K0, C0_STATUS);
+       uasm_i_ehb(&p);
+
+       /* load up the new EBASE */
+       UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
+       build_set_exc_base(&p, K0);
+
+       /*
+        * Now that the new EBASE has been loaded, unset BEV, set
+        * interrupt mask as it was but make sure that timer interrupts
+        * are enabled
+        */
+       uasm_i_addiu(&p, K0, ZERO, ST0_EXL | KSU_USER | ST0_IE | ST0_KX_IF_64);
+       uasm_i_andi(&p, V0, V0, ST0_IM);
+       uasm_i_or(&p, K0, K0, V0);
+       uasm_i_mtc0(&p, K0, C0_STATUS);
+       uasm_i_ehb(&p);
+
+       p = kvm_mips_build_enter_guest(p);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_enter_guest() - Assemble code to resume guest execution.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the code to resume guest execution. This code is common between the
+ * initial entry into the guest from the host, and returning from the exit
+ * handler back to the guest.
+ *
+ * Returns:    Next address after end of written function.
+ */
+static void *kvm_mips_build_enter_guest(void *addr)
+{
+       u32 *p = addr;
+       unsigned int i;
+       struct uasm_label labels[2];
+       struct uasm_reloc relocs[2];
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
+
+       memset(labels, 0, sizeof(labels));
+       memset(relocs, 0, sizeof(relocs));
+
+       /* Set Guest EPC */
+       UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, pc), K1);
+       UASM_i_MTC0(&p, T0, C0_EPC);
+
+       /* Set the ASID for the Guest Kernel */
+       UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, cop0), K1);
+       UASM_i_LW(&p, T0, offsetof(struct mips_coproc, reg[MIPS_CP0_STATUS][0]),
+                 T0);
+       uasm_i_andi(&p, T0, T0, KSU_USER | ST0_ERL | ST0_EXL);
+       uasm_i_xori(&p, T0, T0, KSU_USER);
+       uasm_il_bnez(&p, &r, T0, label_kernel_asid);
+        UASM_i_ADDIU(&p, T1, K1,
+                     offsetof(struct kvm_vcpu_arch, guest_kernel_asid));
+       /* else user */
+       UASM_i_ADDIU(&p, T1, K1,
+                    offsetof(struct kvm_vcpu_arch, guest_user_asid));
+       uasm_l_kernel_asid(&l, p);
+
+       /* t1: contains the base of the ASID array, need to get the cpu id  */
+       /* smp_processor_id */
+       uasm_i_lw(&p, T2, offsetof(struct thread_info, cpu), GP);
+       /* x4 */
+       uasm_i_sll(&p, T2, T2, 2);
+       UASM_i_ADDU(&p, T3, T1, T2);
+       uasm_i_lw(&p, K0, 0, T3);
+#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
+       /* x sizeof(struct cpuinfo_mips)/4 */
+       uasm_i_addiu(&p, T3, ZERO, sizeof(struct cpuinfo_mips)/4);
+       uasm_i_mul(&p, T2, T2, T3);
+
+       UASM_i_LA_mostly(&p, AT, (long)&cpu_data[0].asid_mask);
+       UASM_i_ADDU(&p, AT, AT, T2);
+       UASM_i_LW(&p, T2, uasm_rel_lo((long)&cpu_data[0].asid_mask), AT);
+       uasm_i_and(&p, K0, K0, T2);
+#else
+       uasm_i_andi(&p, K0, K0, MIPS_ENTRYHI_ASID);
+#endif
+       uasm_i_mtc0(&p, K0, C0_ENTRYHI);
+       uasm_i_ehb(&p);
+
+       /* Disable RDHWR access */
+       uasm_i_mtc0(&p, ZERO, C0_HWRENA);
+
+       /* load the guest context from VCPU and return */
+       for (i = 1; i < 32; ++i) {
+               /* Guest k0/k1 loaded later */
+               if (i == K0 || i == K1)
+                       continue;
+               UASM_i_LW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
+       }
+
+#ifndef CONFIG_CPU_MIPSR6
+       /* Restore hi/lo */
+       UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, hi), K1);
+       uasm_i_mthi(&p, K0);
+
+       UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, lo), K1);
+       uasm_i_mtlo(&p, K0);
+#endif
+
+       /* Restore the guest's k0/k1 registers */
+       UASM_i_LW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
+       UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
+
+       /* Jump to guest */
+       uasm_i_eret(&p);
+
+       uasm_resolve_relocs(relocs, labels);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_exception() - Assemble first level guest exception handler.
+ * @addr:      Address to start writing code.
+ * @handler:   Address of common handler (within range of @addr).
+ *
+ * Assemble exception vector code for guest execution. The generated vector will
+ * branch to the common exception handler generated by kvm_mips_build_exit().
+ *
+ * Returns:    Next address after end of written function.
+ */
+void *kvm_mips_build_exception(void *addr, void *handler)
+{
+       u32 *p = addr;
+       struct uasm_label labels[2];
+       struct uasm_reloc relocs[2];
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
+
+       memset(labels, 0, sizeof(labels));
+       memset(relocs, 0, sizeof(relocs));
+
+       /* Save guest k1 into scratch register */
+       UASM_i_MTC0(&p, K1, scratch_tmp[0], scratch_tmp[1]);
+
+       /* Get the VCPU pointer from the VCPU scratch register */
+       UASM_i_MFC0(&p, K1, scratch_vcpu[0], scratch_vcpu[1]);
+       UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
+
+       /* Save guest k0 into VCPU structure */
+       UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, gprs[K0]), K1);
+
+       /* Branch to the common handler */
+       uasm_il_b(&p, &r, label_exit_common);
+        uasm_i_nop(&p);
+
+       uasm_l_exit_common(&l, handler);
+       uasm_resolve_relocs(relocs, labels);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_exit() - Assemble common guest exit handler.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the generic guest exit handling code. This is called by the
+ * exception vectors (generated by kvm_mips_build_exception()), and calls
+ * kvm_mips_handle_exit(), then either resumes the guest or returns to the host
+ * depending on the return value.
+ *
+ * Returns:    Next address after end of written function.
+ */
+void *kvm_mips_build_exit(void *addr)
+{
+       u32 *p = addr;
+       unsigned int i;
+       struct uasm_label labels[3];
+       struct uasm_reloc relocs[3];
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
+
+       memset(labels, 0, sizeof(labels));
+       memset(relocs, 0, sizeof(relocs));
+
+       /*
+        * Generic Guest exception handler. We end up here when the guest
+        * does something that causes a trap to kernel mode.
+        *
+        * Both k0/k1 registers will have already been saved (k0 into the vcpu
+        * structure, and k1 into the scratch_tmp register).
+        *
+        * The k1 register will already contain the kvm_vcpu_arch pointer.
+        */
+
+       /* Start saving Guest context to VCPU */
+       for (i = 0; i < 32; ++i) {
+               /* Guest k0/k1 saved later */
+               if (i == K0 || i == K1)
+                       continue;
+               UASM_i_SW(&p, i, offsetof(struct kvm_vcpu_arch, gprs[i]), K1);
+       }
+
+#ifndef CONFIG_CPU_MIPSR6
+       /* We need to save hi/lo and restore them on the way out */
+       uasm_i_mfhi(&p, T0);
+       UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, hi), K1);
+
+       uasm_i_mflo(&p, T0);
+       UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, lo), K1);
+#endif
+
+       /* Finally save guest k1 to VCPU */
+       uasm_i_ehb(&p);
+       UASM_i_MFC0(&p, T0, scratch_tmp[0], scratch_tmp[1]);
+       UASM_i_SW(&p, T0, offsetof(struct kvm_vcpu_arch, gprs[K1]), K1);
+
+       /* Now that context has been saved, we can use other registers */
+
+       /* Restore vcpu */
+       UASM_i_MFC0(&p, A1, scratch_vcpu[0], scratch_vcpu[1]);
+       uasm_i_move(&p, S1, A1);
+
+       /* Restore run (vcpu->run) */
+       UASM_i_LW(&p, A0, offsetof(struct kvm_vcpu, run), A1);
+       /* Save pointer to run in s0, will be saved by the compiler */
+       uasm_i_move(&p, S0, A0);
+
+       /*
+        * Save Host level EPC, BadVaddr and Cause to VCPU, useful to process
+        * the exception
+        */
+       UASM_i_MFC0(&p, K0, C0_EPC);
+       UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, pc), K1);
+
+       UASM_i_MFC0(&p, K0, C0_BADVADDR);
+       UASM_i_SW(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_badvaddr),
+                 K1);
+
+       uasm_i_mfc0(&p, K0, C0_CAUSE);
+       uasm_i_sw(&p, K0, offsetof(struct kvm_vcpu_arch, host_cp0_cause), K1);
+
+       /* Now restore the host state just enough to run the handlers */
+
+       /* Switch EBASE to the one used by Linux */
+       /* load up the host EBASE */
+       uasm_i_mfc0(&p, V0, C0_STATUS);
+
+       uasm_i_lui(&p, AT, ST0_BEV >> 16);
+       uasm_i_or(&p, K0, V0, AT);
+
+       uasm_i_mtc0(&p, K0, C0_STATUS);
+       uasm_i_ehb(&p);
+
+       UASM_i_LA_mostly(&p, K0, (long)&ebase);
+       UASM_i_LW(&p, K0, uasm_rel_lo((long)&ebase), K0);
+       build_set_exc_base(&p, K0);
+
+       if (raw_cpu_has_fpu) {
+               /*
+                * If FPU is enabled, save FCR31 and clear it so that later
+                * ctc1's don't trigger FPE for pending exceptions.
+                */
+               uasm_i_lui(&p, AT, ST0_CU1 >> 16);
+               uasm_i_and(&p, V1, V0, AT);
+               uasm_il_beqz(&p, &r, V1, label_fpu_1);
+                uasm_i_nop(&p);
+               uasm_i_cfc1(&p, T0, 31);
+               uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.fcr31),
+                         K1);
+               uasm_i_ctc1(&p, ZERO, 31);
+               uasm_l_fpu_1(&l, p);
+       }
+
+       if (cpu_has_msa) {
+               /*
+                * If MSA is enabled, save MSACSR and clear it so that later
+                * instructions don't trigger MSAFPE for pending exceptions.
+                */
+               uasm_i_mfc0(&p, T0, C0_CONFIG5);
+               uasm_i_ext(&p, T0, T0, 27, 1); /* MIPS_CONF5_MSAEN */
+               uasm_il_beqz(&p, &r, T0, label_msa_1);
+                uasm_i_nop(&p);
+               uasm_i_cfcmsa(&p, T0, MSA_CSR);
+               uasm_i_sw(&p, T0, offsetof(struct kvm_vcpu_arch, fpu.msacsr),
+                         K1);
+               uasm_i_ctcmsa(&p, MSA_CSR, ZERO);
+               uasm_l_msa_1(&l, p);
+       }
+
+       /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
+       uasm_i_addiu(&p, AT, ZERO, ~(ST0_EXL | KSU_USER | ST0_IE));
+       uasm_i_and(&p, V0, V0, AT);
+       uasm_i_lui(&p, AT, ST0_CU0 >> 16);
+       uasm_i_or(&p, V0, V0, AT);
+       uasm_i_mtc0(&p, V0, C0_STATUS);
+       uasm_i_ehb(&p);
+
+       /* Load up host GP */
+       UASM_i_LW(&p, GP, offsetof(struct kvm_vcpu_arch, host_gp), K1);
+
+       /* Need a stack before we can jump to "C" */
+       UASM_i_LW(&p, SP, offsetof(struct kvm_vcpu_arch, host_stack), K1);
+
+       /* Saved host state */
+       UASM_i_ADDIU(&p, SP, SP, -(int)sizeof(struct pt_regs));
+
+       /*
+        * XXXKYMA do we need to load the host ASID, maybe not because the
+        * kernel entries are marked GLOBAL, need to verify
+        */
+
+       /* Restore host scratch registers, as we'll have clobbered them */
+       kvm_mips_build_restore_scratch(&p, K0, SP);
+
+       /* Restore RDHWR access */
+       UASM_i_LA_mostly(&p, K0, (long)&hwrena);
+       uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
+       uasm_i_mtc0(&p, K0, C0_HWRENA);
+
+       /* Jump to handler */
+       /*
+        * XXXKYMA: not sure if this is safe, how large is the stack??
+        * Now jump to the kvm_mips_handle_exit() to see if we can deal
+        * with this in the kernel
+        */
+       UASM_i_LA(&p, T9, (unsigned long)kvm_mips_handle_exit);
+       uasm_i_jalr(&p, RA, T9);
+        UASM_i_ADDIU(&p, SP, SP, -CALLFRAME_SIZ);
+
+       uasm_resolve_relocs(relocs, labels);
+
+       p = kvm_mips_build_ret_from_exit(p);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_ret_from_exit() - Assemble guest exit return handler.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the code to handle the return from kvm_mips_handle_exit(), either
+ * resuming the guest or returning to the host depending on the return value.
+ *
+ * Returns:    Next address after end of written function.
+ */
+static void *kvm_mips_build_ret_from_exit(void *addr)
+{
+       u32 *p = addr;
+       struct uasm_label labels[2];
+       struct uasm_reloc relocs[2];
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
+
+       memset(labels, 0, sizeof(labels));
+       memset(relocs, 0, sizeof(relocs));
+
+       /* Return from handler Make sure interrupts are disabled */
+       uasm_i_di(&p, ZERO);
+       uasm_i_ehb(&p);
+
+       /*
+        * XXXKYMA: k0/k1 could have been blown away if we processed
+        * an exception while we were handling the exception from the
+        * guest, reload k1
+        */
+
+       uasm_i_move(&p, K1, S1);
+       UASM_i_ADDIU(&p, K1, K1, offsetof(struct kvm_vcpu, arch));
+
+       /*
+        * Check return value, should tell us if we are returning to the
+        * host (handle I/O etc)or resuming the guest
+        */
+       uasm_i_andi(&p, T0, V0, RESUME_HOST);
+       uasm_il_bnez(&p, &r, T0, label_return_to_host);
+        uasm_i_nop(&p);
+
+       p = kvm_mips_build_ret_to_guest(p);
+
+       uasm_l_return_to_host(&l, p);
+       p = kvm_mips_build_ret_to_host(p);
+
+       uasm_resolve_relocs(relocs, labels);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_ret_to_guest() - Assemble code to return to the guest.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the code to handle return from the guest exit handler
+ * (kvm_mips_handle_exit()) back to the guest.
+ *
+ * Returns:    Next address after end of written function.
+ */
+static void *kvm_mips_build_ret_to_guest(void *addr)
+{
+       u32 *p = addr;
+
+       /* Put the saved pointer to vcpu (s1) back into the scratch register */
+       UASM_i_MTC0(&p, S1, scratch_vcpu[0], scratch_vcpu[1]);
+
+       /* Load up the Guest EBASE to minimize the window where BEV is set */
+       UASM_i_LW(&p, T0, offsetof(struct kvm_vcpu_arch, guest_ebase), K1);
+
+       /* Switch EBASE back to the one used by KVM */
+       uasm_i_mfc0(&p, V1, C0_STATUS);
+       uasm_i_lui(&p, AT, ST0_BEV >> 16);
+       uasm_i_or(&p, K0, V1, AT);
+       uasm_i_mtc0(&p, K0, C0_STATUS);
+       uasm_i_ehb(&p);
+       build_set_exc_base(&p, T0);
+
+       /* Setup status register for running guest in UM */
+       uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE);
+       UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX));
+       uasm_i_and(&p, V1, V1, AT);
+       uasm_i_mtc0(&p, V1, C0_STATUS);
+       uasm_i_ehb(&p);
+
+       p = kvm_mips_build_enter_guest(p);
+
+       return p;
+}
+
+/**
+ * kvm_mips_build_ret_to_host() - Assemble code to return to the host.
+ * @addr:      Address to start writing code.
+ *
+ * Assemble the code to handle return from the guest exit handler
+ * (kvm_mips_handle_exit()) back to the host, i.e. to the caller of the vcpu_run
+ * function generated by kvm_mips_build_vcpu_run().
+ *
+ * Returns:    Next address after end of written function.
+ */
+static void *kvm_mips_build_ret_to_host(void *addr)
+{
+       u32 *p = addr;
+       unsigned int i;
+
+       /* EBASE is already pointing to Linux */
+       UASM_i_LW(&p, K1, offsetof(struct kvm_vcpu_arch, host_stack), K1);
+       UASM_i_ADDIU(&p, K1, K1, -(int)sizeof(struct pt_regs));
+
+       /*
+        * r2/v0 is the return code, shift it down by 2 (arithmetic)
+        * to recover the err code
+        */
+       uasm_i_sra(&p, K0, V0, 2);
+       uasm_i_move(&p, V0, K0);
+
+       /* Load context saved on the host stack */
+       for (i = 16; i < 31; ++i) {
+               if (i == 24)
+                       i = 28;
+               UASM_i_LW(&p, i, offsetof(struct pt_regs, regs[i]), K1);
+       }
+
+       /* Restore RDHWR access */
+       UASM_i_LA_mostly(&p, K0, (long)&hwrena);
+       uasm_i_lw(&p, K0, uasm_rel_lo((long)&hwrena), K0);
+       uasm_i_mtc0(&p, K0, C0_HWRENA);
+
+       /* Restore RA, which is the address we will return to */
+       UASM_i_LW(&p, RA, offsetof(struct pt_regs, regs[RA]), K1);
+       uasm_i_jr(&p, RA);
+        uasm_i_nop(&p);
+
+       return p;
+}
+
index 531fbf5..16f17c6 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/regdef.h>
 
+/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */
+#undef fp
+
        .set    noreorder
        .set    noat
 
 LEAF(__kvm_save_fpu)
        .set    push
-       .set    mips64r2
        SET_HARDFLOAT
+       .set    fp=64
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5                       # is Status.FR set?
        bgez    t0, 1f                          # no: skip odd doubles
@@ -63,8 +66,8 @@ LEAF(__kvm_save_fpu)
 
 LEAF(__kvm_restore_fpu)
        .set    push
-       .set    mips64r2
        SET_HARDFLOAT
+       .set    fp=64
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5                       # is Status.FR set?
        bgez    t0, 1f                          # no: skip odd doubles
index 95f7906..ad28dac 100644 (file)
 
 #include "interrupt.h"
 
-void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, uint32_t priority)
+void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority)
 {
        set_bit(priority, &vcpu->arch.pending_exceptions);
 }
 
-void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, uint32_t priority)
+void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority)
 {
        clear_bit(priority, &vcpu->arch.pending_exceptions);
 }
@@ -114,10 +114,10 @@ void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
 
 /* Deliver the interrupt of the corresponding priority, if possible. */
 int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
-                           uint32_t cause)
+                           u32 cause)
 {
        int allowed = 0;
-       uint32_t exccode;
+       u32 exccode;
 
        struct kvm_vcpu_arch *arch = &vcpu->arch;
        struct mips_coproc *cop0 = vcpu->arch.cop0;
@@ -196,12 +196,12 @@ int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
 }
 
 int kvm_mips_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
-                         uint32_t cause)
+                         u32 cause)
 {
        return 1;
 }
 
-void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, uint32_t cause)
+void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, u32 cause)
 {
        unsigned long *pending = &vcpu->arch.pending_exceptions;
        unsigned long *pending_clr = &vcpu->arch.pending_exceptions_clr;
index 2143884..fb118a2 100644 (file)
 #define MIPS_EXC_MAX                12
 /* XXXSL More to follow */
 
-extern char __kvm_mips_vcpu_run_end[];
-extern char mips32_exception[], mips32_exceptionEnd[];
-extern char mips32_GuestException[], mips32_GuestExceptionEnd[];
-
 #define C_TI        (_ULCAST_(1) << 30)
 
 #define KVM_MIPS_IRQ_DELIVER_ALL_AT_ONCE (0)
 #define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE   (0)
 
-void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, uint32_t priority);
-void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, uint32_t priority);
+void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
+void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
 int kvm_mips_pending_timer(struct kvm_vcpu *vcpu);
 
 void kvm_mips_queue_timer_int_cb(struct kvm_vcpu *vcpu);
@@ -48,7 +44,7 @@ void kvm_mips_queue_io_int_cb(struct kvm_vcpu *vcpu,
 void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
                                struct kvm_mips_interrupt *irq);
 int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
-                           uint32_t cause);
+                           u32 cause);
 int kvm_mips_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
-                         uint32_t cause);
-void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, uint32_t cause);
+                         u32 cause);
+void kvm_mips_deliver_interrupts(struct kvm_vcpu *vcpu, u32 cause);
diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S
deleted file mode 100644 (file)
index 828fcfc..0000000
+++ /dev/null
@@ -1,605 +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.
- *
- * Main entry point for the guest, exception handling.
- *
- * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
- * Authors: Sanjay Lal <sanjayl@kymasys.com>
- */
-
-#include <asm/asm.h>
-#include <asm/asmmacro.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/stackframe.h>
-#include <asm/asm-offsets.h>
-
-#define _C_LABEL(x)     x
-#define MIPSX(name)     mips32_ ## name
-#define CALLFRAME_SIZ   32
-
-/*
- * VECTOR
- *  exception vector entrypoint
- */
-#define VECTOR(x, regmask)      \
-    .ent    _C_LABEL(x),0;      \
-    EXPORT(x);
-
-#define VECTOR_END(x)      \
-    EXPORT(x);
-
-/* Overload, Danger Will Robinson!! */
-#define PT_HOST_USERLOCAL   PT_EPC
-
-#define CP0_DDATA_LO        $28,3
-
-/* Resume Flags */
-#define RESUME_FLAG_HOST        (1<<1)  /* Resume host? */
-
-#define RESUME_GUEST            0
-#define RESUME_HOST             RESUME_FLAG_HOST
-
-/*
- * __kvm_mips_vcpu_run: entry point to the guest
- * a0: run
- * a1: vcpu
- */
-       .set    noreorder
-
-FEXPORT(__kvm_mips_vcpu_run)
-       /* k0/k1 not being used in host kernel context */
-       INT_ADDIU k1, sp, -PT_SIZE
-       LONG_S  $16, PT_R16(k1)
-       LONG_S  $17, PT_R17(k1)
-       LONG_S  $18, PT_R18(k1)
-       LONG_S  $19, PT_R19(k1)
-       LONG_S  $20, PT_R20(k1)
-       LONG_S  $21, PT_R21(k1)
-       LONG_S  $22, PT_R22(k1)
-       LONG_S  $23, PT_R23(k1)
-
-       LONG_S  $28, PT_R28(k1)
-       LONG_S  $29, PT_R29(k1)
-       LONG_S  $30, PT_R30(k1)
-       LONG_S  $31, PT_R31(k1)
-
-       /* Save hi/lo */
-       mflo    v0
-       LONG_S  v0, PT_LO(k1)
-       mfhi    v1
-       LONG_S  v1, PT_HI(k1)
-
-       /* Save host status */
-       mfc0    v0, CP0_STATUS
-       LONG_S  v0, PT_STATUS(k1)
-
-       /* Save DDATA_LO, will be used to store pointer to vcpu */
-       mfc0    v1, CP0_DDATA_LO
-       LONG_S  v1, PT_HOST_USERLOCAL(k1)
-
-       /* DDATA_LO has pointer to vcpu */
-       mtc0    a1, CP0_DDATA_LO
-
-       /* Offset into vcpu->arch */
-       INT_ADDIU k1, a1, VCPU_HOST_ARCH
-
-       /*
-        * Save the host stack to VCPU, used for exception processing
-        * when we exit from the Guest
-        */
-       LONG_S  sp, VCPU_HOST_STACK(k1)
-
-       /* Save the kernel gp as well */
-       LONG_S  gp, VCPU_HOST_GP(k1)
-
-       /*
-        * Setup status register for running the guest in UM, interrupts
-        * are disabled
-        */
-       li      k0, (ST0_EXL | KSU_USER | ST0_BEV)
-       mtc0    k0, CP0_STATUS
-       ehb
-
-       /* load up the new EBASE */
-       LONG_L  k0, VCPU_GUEST_EBASE(k1)
-       mtc0    k0, CP0_EBASE
-
-       /*
-        * Now that the new EBASE has been loaded, unset BEV, set
-        * interrupt mask as it was but make sure that timer interrupts
-        * are enabled
-        */
-       li      k0, (ST0_EXL | KSU_USER | ST0_IE)
-       andi    v0, v0, ST0_IM
-       or      k0, k0, v0
-       mtc0    k0, CP0_STATUS
-       ehb
-
-       /* Set Guest EPC */
-       LONG_L  t0, VCPU_PC(k1)
-       mtc0    t0, CP0_EPC
-
-FEXPORT(__kvm_mips_load_asid)
-       /* Set the ASID for the Guest Kernel */
-       PTR_L   t0, VCPU_COP0(k1)
-       LONG_L  t0, COP0_STATUS(t0)
-       andi    t0, KSU_USER | ST0_ERL | ST0_EXL
-       xori    t0, KSU_USER
-       bnez    t0, 1f          /* If kernel */
-        INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
-       INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
-1:
-       /* t1: contains the base of the ASID array, need to get the cpu id */
-       LONG_L  t2, TI_CPU($28)             /* smp_processor_id */
-       INT_SLL t2, t2, 2                   /* x4 */
-       REG_ADDU t3, t1, t2
-       LONG_L  k0, (t3)
-#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
-       li      t3, CPUINFO_SIZE/4
-       mul     t2, t2, t3              /* x sizeof(struct cpuinfo_mips)/4 */
-       LONG_L  t2, (cpu_data + CPUINFO_ASID_MASK)(t2)
-       and     k0, k0, t2
-#else
-       andi    k0, k0, MIPS_ENTRYHI_ASID
-#endif
-       mtc0    k0, CP0_ENTRYHI
-       ehb
-
-       /* Disable RDHWR access */
-       mtc0    zero, CP0_HWRENA
-
-       .set    noat
-       /* Now load up the Guest Context from VCPU */
-       LONG_L  $1, VCPU_R1(k1)
-       LONG_L  $2, VCPU_R2(k1)
-       LONG_L  $3, VCPU_R3(k1)
-
-       LONG_L  $4, VCPU_R4(k1)
-       LONG_L  $5, VCPU_R5(k1)
-       LONG_L  $6, VCPU_R6(k1)
-       LONG_L  $7, VCPU_R7(k1)
-
-       LONG_L  $8, VCPU_R8(k1)
-       LONG_L  $9, VCPU_R9(k1)
-       LONG_L  $10, VCPU_R10(k1)
-       LONG_L  $11, VCPU_R11(k1)
-       LONG_L  $12, VCPU_R12(k1)
-       LONG_L  $13, VCPU_R13(k1)
-       LONG_L  $14, VCPU_R14(k1)
-       LONG_L  $15, VCPU_R15(k1)
-       LONG_L  $16, VCPU_R16(k1)
-       LONG_L  $17, VCPU_R17(k1)
-       LONG_L  $18, VCPU_R18(k1)
-       LONG_L  $19, VCPU_R19(k1)
-       LONG_L  $20, VCPU_R20(k1)
-       LONG_L  $21, VCPU_R21(k1)
-       LONG_L  $22, VCPU_R22(k1)
-       LONG_L  $23, VCPU_R23(k1)
-       LONG_L  $24, VCPU_R24(k1)
-       LONG_L  $25, VCPU_R25(k1)
-
-       /* k0/k1 loaded up later */
-
-       LONG_L  $28, VCPU_R28(k1)
-       LONG_L  $29, VCPU_R29(k1)
-       LONG_L  $30, VCPU_R30(k1)
-       LONG_L  $31, VCPU_R31(k1)
-
-       /* Restore hi/lo */
-       LONG_L  k0, VCPU_LO(k1)
-       mtlo    k0
-
-       LONG_L  k0, VCPU_HI(k1)
-       mthi    k0
-
-FEXPORT(__kvm_mips_load_k0k1)
-       /* Restore the guest's k0/k1 registers */
-       LONG_L  k0, VCPU_R26(k1)
-       LONG_L  k1, VCPU_R27(k1)
-
-       /* Jump to guest */
-       eret
-EXPORT(__kvm_mips_vcpu_run_end)
-
-VECTOR(MIPSX(exception), unknown)
-/* Find out what mode we came from and jump to the proper handler. */
-       mtc0    k0, CP0_ERROREPC        #01: Save guest k0
-       ehb                             #02:
-
-       mfc0    k0, CP0_EBASE           #02: Get EBASE
-       INT_SRL k0, k0, 10              #03: Get rid of CPUNum
-       INT_SLL k0, k0, 10              #04
-       LONG_S  k1, 0x3000(k0)          #05: Save k1 @ offset 0x3000
-       INT_ADDIU k0, k0, 0x2000        #06: Exception handler is
-                                       #    installed @ offset 0x2000
-       j       k0                      #07: jump to the function
-        nop                            #08: branch delay slot
-VECTOR_END(MIPSX(exceptionEnd))
-.end MIPSX(exception)
-
-/*
- * Generic Guest exception handler. We end up here when the guest
- * does something that causes a trap to kernel mode.
- */
-NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra)
-       /* Get the VCPU pointer from DDTATA_LO */
-       mfc0    k1, CP0_DDATA_LO
-       INT_ADDIU k1, k1, VCPU_HOST_ARCH
-
-       /* Start saving Guest context to VCPU */
-       LONG_S  $0, VCPU_R0(k1)
-       LONG_S  $1, VCPU_R1(k1)
-       LONG_S  $2, VCPU_R2(k1)
-       LONG_S  $3, VCPU_R3(k1)
-       LONG_S  $4, VCPU_R4(k1)
-       LONG_S  $5, VCPU_R5(k1)
-       LONG_S  $6, VCPU_R6(k1)
-       LONG_S  $7, VCPU_R7(k1)
-       LONG_S  $8, VCPU_R8(k1)
-       LONG_S  $9, VCPU_R9(k1)
-       LONG_S  $10, VCPU_R10(k1)
-       LONG_S  $11, VCPU_R11(k1)
-       LONG_S  $12, VCPU_R12(k1)
-       LONG_S  $13, VCPU_R13(k1)
-       LONG_S  $14, VCPU_R14(k1)
-       LONG_S  $15, VCPU_R15(k1)
-       LONG_S  $16, VCPU_R16(k1)
-       LONG_S  $17, VCPU_R17(k1)
-       LONG_S  $18, VCPU_R18(k1)
-       LONG_S  $19, VCPU_R19(k1)
-       LONG_S  $20, VCPU_R20(k1)
-       LONG_S  $21, VCPU_R21(k1)
-       LONG_S  $22, VCPU_R22(k1)
-       LONG_S  $23, VCPU_R23(k1)
-       LONG_S  $24, VCPU_R24(k1)
-       LONG_S  $25, VCPU_R25(k1)
-
-       /* Guest k0/k1 saved later */
-
-       LONG_S  $28, VCPU_R28(k1)
-       LONG_S  $29, VCPU_R29(k1)
-       LONG_S  $30, VCPU_R30(k1)
-       LONG_S  $31, VCPU_R31(k1)
-
-       .set at
-
-       /* We need to save hi/lo and restore them on the way out */
-       mfhi    t0
-       LONG_S  t0, VCPU_HI(k1)
-
-       mflo    t0
-       LONG_S  t0, VCPU_LO(k1)
-
-       /* Finally save guest k0/k1 to VCPU */
-       mfc0    t0, CP0_ERROREPC
-       LONG_S  t0, VCPU_R26(k1)
-
-       /* Get GUEST k1 and save it in VCPU */
-       PTR_LI  t1, ~0x2ff
-       mfc0    t0, CP0_EBASE
-       and     t0, t0, t1
-       LONG_L  t0, 0x3000(t0)
-       LONG_S  t0, VCPU_R27(k1)
-
-       /* Now that context has been saved, we can use other registers */
-
-       /* Restore vcpu */
-       mfc0    a1, CP0_DDATA_LO
-       move    s1, a1
-
-       /* Restore run (vcpu->run) */
-       LONG_L  a0, VCPU_RUN(a1)
-       /* Save pointer to run in s0, will be saved by the compiler */
-       move    s0, a0
-
-       /*
-        * Save Host level EPC, BadVaddr and Cause to VCPU, useful to
-        * process the exception
-        */
-       mfc0    k0,CP0_EPC
-       LONG_S  k0, VCPU_PC(k1)
-
-       mfc0    k0, CP0_BADVADDR
-       LONG_S  k0, VCPU_HOST_CP0_BADVADDR(k1)
-
-       mfc0    k0, CP0_CAUSE
-       LONG_S  k0, VCPU_HOST_CP0_CAUSE(k1)
-
-       mfc0    k0, CP0_ENTRYHI
-       LONG_S  k0, VCPU_HOST_ENTRYHI(k1)
-
-       /* Now restore the host state just enough to run the handlers */
-
-       /* Switch EBASE to the one used by Linux */
-       /* load up the host EBASE */
-       mfc0    v0, CP0_STATUS
-
-       or      k0, v0, ST0_BEV
-
-       mtc0    k0, CP0_STATUS
-       ehb
-
-       LONG_L  k0, VCPU_HOST_EBASE(k1)
-       mtc0    k0,CP0_EBASE
-
-       /*
-        * If FPU is enabled, save FCR31 and clear it so that later ctc1's don't
-        * trigger FPE for pending exceptions.
-        */
-       and     v1, v0, ST0_CU1
-       beqz    v1, 1f
-        nop
-       .set    push
-       SET_HARDFLOAT
-       cfc1    t0, fcr31
-       sw      t0, VCPU_FCR31(k1)
-       ctc1    zero,fcr31
-       .set    pop
-1:
-
-#ifdef CONFIG_CPU_HAS_MSA
-       /*
-        * If MSA is enabled, save MSACSR and clear it so that later
-        * instructions don't trigger MSAFPE for pending exceptions.
-        */
-       mfc0    t0, CP0_CONFIG3
-       ext     t0, t0, 28, 1 /* MIPS_CONF3_MSAP */
-       beqz    t0, 1f
-        nop
-       mfc0    t0, CP0_CONFIG5
-       ext     t0, t0, 27, 1 /* MIPS_CONF5_MSAEN */
-       beqz    t0, 1f
-        nop
-       _cfcmsa t0, MSA_CSR
-       sw      t0, VCPU_MSA_CSR(k1)
-       _ctcmsa MSA_CSR, zero
-1:
-#endif
-
-       /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
-       and     v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE)
-       or      v0, v0, ST0_CU0
-       mtc0    v0, CP0_STATUS
-       ehb
-
-       /* Load up host GP */
-       LONG_L  gp, VCPU_HOST_GP(k1)
-
-       /* Need a stack before we can jump to "C" */
-       LONG_L  sp, VCPU_HOST_STACK(k1)
-
-       /* Saved host state */
-       INT_ADDIU sp, sp, -PT_SIZE
-
-       /*
-        * XXXKYMA do we need to load the host ASID, maybe not because the
-        * kernel entries are marked GLOBAL, need to verify
-        */
-
-       /* Restore host DDATA_LO */
-       LONG_L  k0, PT_HOST_USERLOCAL(sp)
-       mtc0    k0, CP0_DDATA_LO
-
-       /* Restore RDHWR access */
-       PTR_LI  k0, 0x2000000F
-       mtc0    k0, CP0_HWRENA
-
-       /* Jump to handler */
-FEXPORT(__kvm_mips_jump_to_handler)
-       /*
-        * XXXKYMA: not sure if this is safe, how large is the stack??
-        * Now jump to the kvm_mips_handle_exit() to see if we can deal
-        * with this in the kernel
-        */
-       PTR_LA  t9, kvm_mips_handle_exit
-       jalr.hb t9
-        INT_ADDIU sp, sp, -CALLFRAME_SIZ           /* BD Slot */
-
-       /* Return from handler Make sure interrupts are disabled */
-       di
-       ehb
-
-       /*
-        * XXXKYMA: k0/k1 could have been blown away if we processed
-        * an exception while we were handling the exception from the
-        * guest, reload k1
-        */
-
-       move    k1, s1
-       INT_ADDIU k1, k1, VCPU_HOST_ARCH
-
-       /*
-        * Check return value, should tell us if we are returning to the
-        * host (handle I/O etc)or resuming the guest
-        */
-       andi    t0, v0, RESUME_HOST
-       bnez    t0, __kvm_mips_return_to_host
-        nop
-
-__kvm_mips_return_to_guest:
-       /* Put the saved pointer to vcpu (s1) back into the DDATA_LO Register */
-       mtc0    s1, CP0_DDATA_LO
-
-       /* Load up the Guest EBASE to minimize the window where BEV is set */
-       LONG_L  t0, VCPU_GUEST_EBASE(k1)
-
-       /* Switch EBASE back to the one used by KVM */
-       mfc0    v1, CP0_STATUS
-       or      k0, v1, ST0_BEV
-       mtc0    k0, CP0_STATUS
-       ehb
-       mtc0    t0, CP0_EBASE
-
-       /* Setup status register for running guest in UM */
-       or      v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
-       and     v1, v1, ~(ST0_CU0 | ST0_MX)
-       mtc0    v1, CP0_STATUS
-       ehb
-
-       /* Set Guest EPC */
-       LONG_L  t0, VCPU_PC(k1)
-       mtc0    t0, CP0_EPC
-
-       /* Set the ASID for the Guest Kernel */
-       PTR_L   t0, VCPU_COP0(k1)
-       LONG_L  t0, COP0_STATUS(t0)
-       andi    t0, KSU_USER | ST0_ERL | ST0_EXL
-       xori    t0, KSU_USER
-       bnez    t0, 1f          /* If kernel */
-        INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
-       INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
-1:
-       /* t1: contains the base of the ASID array, need to get the cpu id  */
-       LONG_L  t2, TI_CPU($28)         /* smp_processor_id */
-       INT_SLL t2, t2, 2               /* x4 */
-       REG_ADDU t3, t1, t2
-       LONG_L  k0, (t3)
-#ifdef CONFIG_MIPS_ASID_BITS_VARIABLE
-       li      t3, CPUINFO_SIZE/4
-       mul     t2, t2, t3              /* x sizeof(struct cpuinfo_mips)/4 */
-       LONG_L  t2, (cpu_data + CPUINFO_ASID_MASK)(t2)
-       and     k0, k0, t2
-#else
-       andi    k0, k0, MIPS_ENTRYHI_ASID
-#endif
-       mtc0    k0, CP0_ENTRYHI
-       ehb
-
-       /* Disable RDHWR access */
-       mtc0    zero, CP0_HWRENA
-
-       .set    noat
-       /* load the guest context from VCPU and return */
-       LONG_L  $0, VCPU_R0(k1)
-       LONG_L  $1, VCPU_R1(k1)
-       LONG_L  $2, VCPU_R2(k1)
-       LONG_L  $3, VCPU_R3(k1)
-       LONG_L  $4, VCPU_R4(k1)
-       LONG_L  $5, VCPU_R5(k1)
-       LONG_L  $6, VCPU_R6(k1)
-       LONG_L  $7, VCPU_R7(k1)
-       LONG_L  $8, VCPU_R8(k1)
-       LONG_L  $9, VCPU_R9(k1)
-       LONG_L  $10, VCPU_R10(k1)
-       LONG_L  $11, VCPU_R11(k1)
-       LONG_L  $12, VCPU_R12(k1)
-       LONG_L  $13, VCPU_R13(k1)
-       LONG_L  $14, VCPU_R14(k1)
-       LONG_L  $15, VCPU_R15(k1)
-       LONG_L  $16, VCPU_R16(k1)
-       LONG_L  $17, VCPU_R17(k1)
-       LONG_L  $18, VCPU_R18(k1)
-       LONG_L  $19, VCPU_R19(k1)
-       LONG_L  $20, VCPU_R20(k1)
-       LONG_L  $21, VCPU_R21(k1)
-       LONG_L  $22, VCPU_R22(k1)
-       LONG_L  $23, VCPU_R23(k1)
-       LONG_L  $24, VCPU_R24(k1)
-       LONG_L  $25, VCPU_R25(k1)
-
-       /* $/k1 loaded later */
-       LONG_L  $28, VCPU_R28(k1)
-       LONG_L  $29, VCPU_R29(k1)
-       LONG_L  $30, VCPU_R30(k1)
-       LONG_L  $31, VCPU_R31(k1)
-
-FEXPORT(__kvm_mips_skip_guest_restore)
-       LONG_L  k0, VCPU_HI(k1)
-       mthi    k0
-
-       LONG_L  k0, VCPU_LO(k1)
-       mtlo    k0
-
-       LONG_L  k0, VCPU_R26(k1)
-       LONG_L  k1, VCPU_R27(k1)
-
-       eret
-       .set    at
-
-__kvm_mips_return_to_host:
-       /* EBASE is already pointing to Linux */
-       LONG_L  k1, VCPU_HOST_STACK(k1)
-       INT_ADDIU k1,k1, -PT_SIZE
-
-       /* Restore host DDATA_LO */
-       LONG_L  k0, PT_HOST_USERLOCAL(k1)
-       mtc0    k0, CP0_DDATA_LO
-
-       /*
-        * r2/v0 is the return code, shift it down by 2 (arithmetic)
-        * to recover the err code
-        */
-       INT_SRA k0, v0, 2
-       move    $2, k0
-
-       /* Load context saved on the host stack */
-       LONG_L  $16, PT_R16(k1)
-       LONG_L  $17, PT_R17(k1)
-       LONG_L  $18, PT_R18(k1)
-       LONG_L  $19, PT_R19(k1)
-       LONG_L  $20, PT_R20(k1)
-       LONG_L  $21, PT_R21(k1)
-       LONG_L  $22, PT_R22(k1)
-       LONG_L  $23, PT_R23(k1)
-
-       LONG_L  $28, PT_R28(k1)
-       LONG_L  $29, PT_R29(k1)
-       LONG_L  $30, PT_R30(k1)
-
-       LONG_L  k0, PT_HI(k1)
-       mthi    k0
-
-       LONG_L  k0, PT_LO(k1)
-       mtlo    k0
-
-       /* Restore RDHWR access */
-       PTR_LI  k0, 0x2000000F
-       mtc0    k0, CP0_HWRENA
-
-       /* Restore RA, which is the address we will return to */
-       LONG_L  ra, PT_R31(k1)
-       j       ra
-        nop
-
-VECTOR_END(MIPSX(GuestExceptionEnd))
-.end MIPSX(GuestException)
-
-MIPSX(exceptions):
-       ####
-       ##### The exception handlers.
-       #####
-       .word _C_LABEL(MIPSX(GuestException))   #  0
-       .word _C_LABEL(MIPSX(GuestException))   #  1
-       .word _C_LABEL(MIPSX(GuestException))   #  2
-       .word _C_LABEL(MIPSX(GuestException))   #  3
-       .word _C_LABEL(MIPSX(GuestException))   #  4
-       .word _C_LABEL(MIPSX(GuestException))   #  5
-       .word _C_LABEL(MIPSX(GuestException))   #  6
-       .word _C_LABEL(MIPSX(GuestException))   #  7
-       .word _C_LABEL(MIPSX(GuestException))   #  8
-       .word _C_LABEL(MIPSX(GuestException))   #  9
-       .word _C_LABEL(MIPSX(GuestException))   # 10
-       .word _C_LABEL(MIPSX(GuestException))   # 11
-       .word _C_LABEL(MIPSX(GuestException))   # 12
-       .word _C_LABEL(MIPSX(GuestException))   # 13
-       .word _C_LABEL(MIPSX(GuestException))   # 14
-       .word _C_LABEL(MIPSX(GuestException))   # 15
-       .word _C_LABEL(MIPSX(GuestException))   # 16
-       .word _C_LABEL(MIPSX(GuestException))   # 17
-       .word _C_LABEL(MIPSX(GuestException))   # 18
-       .word _C_LABEL(MIPSX(GuestException))   # 19
-       .word _C_LABEL(MIPSX(GuestException))   # 20
-       .word _C_LABEL(MIPSX(GuestException))   # 21
-       .word _C_LABEL(MIPSX(GuestException))   # 22
-       .word _C_LABEL(MIPSX(GuestException))   # 23
-       .word _C_LABEL(MIPSX(GuestException))   # 24
-       .word _C_LABEL(MIPSX(GuestException))   # 25
-       .word _C_LABEL(MIPSX(GuestException))   # 26
-       .word _C_LABEL(MIPSX(GuestException))   # 27
-       .word _C_LABEL(MIPSX(GuestException))   # 28
-       .word _C_LABEL(MIPSX(GuestException))   # 29
-       .word _C_LABEL(MIPSX(GuestException))   # 30
-       .word _C_LABEL(MIPSX(GuestException))   # 31
index 44da525..a6ea084 100644 (file)
@@ -9,6 +9,7 @@
  * Authors: Sanjay Lal <sanjayl@kymasys.com>
  */
 
+#include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kdebug.h>
@@ -147,7 +148,7 @@ void kvm_mips_free_vcpus(struct kvm *kvm)
        /* Put the pages we reserved for the guest pmap */
        for (i = 0; i < kvm->arch.guest_pmap_npages; i++) {
                if (kvm->arch.guest_pmap[i] != KVM_INVALID_PAGE)
-                       kvm_mips_release_pfn_clean(kvm->arch.guest_pmap[i]);
+                       kvm_release_pfn_clean(kvm->arch.guest_pmap[i]);
        }
        kfree(kvm->arch.guest_pmap);
 
@@ -244,10 +245,27 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
        }
 }
 
+static inline void dump_handler(const char *symbol, void *start, void *end)
+{
+       u32 *p;
+
+       pr_debug("LEAF(%s)\n", symbol);
+
+       pr_debug("\t.set push\n");
+       pr_debug("\t.set noreorder\n");
+
+       for (p = start; p < (u32 *)end; ++p)
+               pr_debug("\t.word\t0x%08x\t\t# %p\n", *p, p);
+
+       pr_debug("\t.set\tpop\n");
+
+       pr_debug("\tEND(%s)\n", symbol);
+}
+
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
-       int err, size, offset;
-       void *gebase;
+       int err, size;
+       void *gebase, *p, *handler;
        int i;
 
        struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
@@ -273,9 +291,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
        else
                size = 0x4000;
 
-       /* Save Linux EBASE */
-       vcpu->arch.host_ebase = (void *)read_c0_ebase();
-
        gebase = kzalloc(ALIGN(size, PAGE_SIZE), GFP_KERNEL);
 
        if (!gebase) {
@@ -285,44 +300,53 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
        kvm_debug("Allocated %d bytes for KVM Exception Handlers @ %p\n",
                  ALIGN(size, PAGE_SIZE), gebase);
 
+       /*
+        * Check new ebase actually fits in CP0_EBase. The lack of a write gate
+        * limits us to the low 512MB of physical address space. If the memory
+        * we allocate is out of range, just give up now.
+        */
+       if (!cpu_has_ebase_wg && virt_to_phys(gebase) >= 0x20000000) {
+               kvm_err("CP0_EBase.WG required for guest exception base %pK\n",
+                       gebase);
+               err = -ENOMEM;
+               goto out_free_gebase;
+       }
+
        /* Save new ebase */
        vcpu->arch.guest_ebase = gebase;
 
-       /* Copy L1 Guest Exception handler to correct offset */
+       /* Build guest exception vectors dynamically in unmapped memory */
+       handler = gebase + 0x2000;
 
        /* TLB Refill, EXL = 0 */
-       memcpy(gebase, mips32_exception,
-              mips32_exceptionEnd - mips32_exception);
+       kvm_mips_build_exception(gebase, handler);
 
        /* General Exception Entry point */
-       memcpy(gebase + 0x180, mips32_exception,
-              mips32_exceptionEnd - mips32_exception);
+       kvm_mips_build_exception(gebase + 0x180, handler);
 
        /* For vectored interrupts poke the exception code @ all offsets 0-7 */
        for (i = 0; i < 8; i++) {
                kvm_debug("L1 Vectored handler @ %p\n",
                          gebase + 0x200 + (i * VECTORSPACING));
-               memcpy(gebase + 0x200 + (i * VECTORSPACING), mips32_exception,
-                      mips32_exceptionEnd - mips32_exception);
+               kvm_mips_build_exception(gebase + 0x200 + i * VECTORSPACING,
+                                        handler);
        }
 
-       /* General handler, relocate to unmapped space for sanity's sake */
-       offset = 0x2000;
-       kvm_debug("Installing KVM Exception handlers @ %p, %#x bytes\n",
-                 gebase + offset,
-                 mips32_GuestExceptionEnd - mips32_GuestException);
+       /* General exit handler */
+       p = handler;
+       p = kvm_mips_build_exit(p);
 
-       memcpy(gebase + offset, mips32_GuestException,
-              mips32_GuestExceptionEnd - mips32_GuestException);
+       /* Guest entry routine */
+       vcpu->arch.vcpu_run = p;
+       p = kvm_mips_build_vcpu_run(p);
 
-#ifdef MODULE
-       offset += mips32_GuestExceptionEnd - mips32_GuestException;
-       memcpy(gebase + offset, (char *)__kvm_mips_vcpu_run,
-              __kvm_mips_vcpu_run_end - (char *)__kvm_mips_vcpu_run);
-       vcpu->arch.vcpu_run = gebase + offset;
-#else
-       vcpu->arch.vcpu_run = __kvm_mips_vcpu_run;
-#endif
+       /* Dump the generated code */
+       pr_debug("#include <asm/asm.h>\n");
+       pr_debug("#include <asm/regdef.h>\n");
+       pr_debug("\n");
+       dump_handler("kvm_vcpu_run", vcpu->arch.vcpu_run, p);
+       dump_handler("kvm_gen_exc", gebase + 0x180, gebase + 0x200);
+       dump_handler("kvm_exit", gebase + 0x2000, vcpu->arch.vcpu_run);
 
        /* Invalidate the icache for these ranges */
        local_flush_icache_range((unsigned long)gebase,
@@ -408,17 +432,19 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
        kvm_mips_deliver_interrupts(vcpu,
                                    kvm_read_c0_guest_cause(vcpu->arch.cop0));
 
-       __kvm_guest_enter();
+       guest_enter_irqoff();
 
        /* Disable hardware page table walking while in guest */
        htw_stop();
 
+       trace_kvm_enter(vcpu);
        r = vcpu->arch.vcpu_run(run, vcpu);
+       trace_kvm_out(vcpu);
 
        /* Re-enable HTW before enabling interrupts */
        htw_start();
 
-       __kvm_guest_exit();
+       guest_exit_irqoff();
        local_irq_enable();
 
        if (vcpu->sigset_active)
@@ -507,8 +533,10 @@ static u64 kvm_mips_get_one_regs[] = {
        KVM_REG_MIPS_R30,
        KVM_REG_MIPS_R31,
 
+#ifndef CONFIG_CPU_MIPSR6
        KVM_REG_MIPS_HI,
        KVM_REG_MIPS_LO,
+#endif
        KVM_REG_MIPS_PC,
 
        KVM_REG_MIPS_CP0_INDEX,
@@ -539,6 +567,104 @@ static u64 kvm_mips_get_one_regs[] = {
        KVM_REG_MIPS_COUNT_HZ,
 };
 
+static u64 kvm_mips_get_one_regs_fpu[] = {
+       KVM_REG_MIPS_FCR_IR,
+       KVM_REG_MIPS_FCR_CSR,
+};
+
+static u64 kvm_mips_get_one_regs_msa[] = {
+       KVM_REG_MIPS_MSA_IR,
+       KVM_REG_MIPS_MSA_CSR,
+};
+
+static u64 kvm_mips_get_one_regs_kscratch[] = {
+       KVM_REG_MIPS_CP0_KSCRATCH1,
+       KVM_REG_MIPS_CP0_KSCRATCH2,
+       KVM_REG_MIPS_CP0_KSCRATCH3,
+       KVM_REG_MIPS_CP0_KSCRATCH4,
+       KVM_REG_MIPS_CP0_KSCRATCH5,
+       KVM_REG_MIPS_CP0_KSCRATCH6,
+};
+
+static unsigned long kvm_mips_num_regs(struct kvm_vcpu *vcpu)
+{
+       unsigned long ret;
+
+       ret = ARRAY_SIZE(kvm_mips_get_one_regs);
+       if (kvm_mips_guest_can_have_fpu(&vcpu->arch)) {
+               ret += ARRAY_SIZE(kvm_mips_get_one_regs_fpu) + 48;
+               /* odd doubles */
+               if (boot_cpu_data.fpu_id & MIPS_FPIR_F64)
+                       ret += 16;
+       }
+       if (kvm_mips_guest_can_have_msa(&vcpu->arch))
+               ret += ARRAY_SIZE(kvm_mips_get_one_regs_msa) + 32;
+       ret += __arch_hweight8(vcpu->arch.kscratch_enabled);
+       ret += kvm_mips_callbacks->num_regs(vcpu);
+
+       return ret;
+}
+
+static int kvm_mips_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices)
+{
+       u64 index;
+       unsigned int i;
+
+       if (copy_to_user(indices, kvm_mips_get_one_regs,
+                        sizeof(kvm_mips_get_one_regs)))
+               return -EFAULT;
+       indices += ARRAY_SIZE(kvm_mips_get_one_regs);
+
+       if (kvm_mips_guest_can_have_fpu(&vcpu->arch)) {
+               if (copy_to_user(indices, kvm_mips_get_one_regs_fpu,
+                                sizeof(kvm_mips_get_one_regs_fpu)))
+                       return -EFAULT;
+               indices += ARRAY_SIZE(kvm_mips_get_one_regs_fpu);
+
+               for (i = 0; i < 32; ++i) {
+                       index = KVM_REG_MIPS_FPR_32(i);
+                       if (copy_to_user(indices, &index, sizeof(index)))
+                               return -EFAULT;
+                       ++indices;
+
+                       /* skip odd doubles if no F64 */
+                       if (i & 1 && !(boot_cpu_data.fpu_id & MIPS_FPIR_F64))
+                               continue;
+
+                       index = KVM_REG_MIPS_FPR_64(i);
+                       if (copy_to_user(indices, &index, sizeof(index)))
+                               return -EFAULT;
+                       ++indices;
+               }
+       }
+
+       if (kvm_mips_guest_can_have_msa(&vcpu->arch)) {
+               if (copy_to_user(indices, kvm_mips_get_one_regs_msa,
+                                sizeof(kvm_mips_get_one_regs_msa)))
+                       return -EFAULT;
+               indices += ARRAY_SIZE(kvm_mips_get_one_regs_msa);
+
+               for (i = 0; i < 32; ++i) {
+                       index = KVM_REG_MIPS_VEC_128(i);
+                       if (copy_to_user(indices, &index, sizeof(index)))
+                               return -EFAULT;
+                       ++indices;
+               }
+       }
+
+       for (i = 0; i < 6; ++i) {
+               if (!(vcpu->arch.kscratch_enabled & BIT(i + 2)))
+                       continue;
+
+               if (copy_to_user(indices, &kvm_mips_get_one_regs_kscratch[i],
+                                sizeof(kvm_mips_get_one_regs_kscratch[i])))
+                       return -EFAULT;
+               ++indices;
+       }
+
+       return kvm_mips_callbacks->copy_reg_indices(vcpu, indices);
+}
+
 static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
                            const struct kvm_one_reg *reg)
 {
@@ -554,12 +680,14 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
        case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31:
                v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0];
                break;
+#ifndef CONFIG_CPU_MIPSR6
        case KVM_REG_MIPS_HI:
                v = (long)vcpu->arch.hi;
                break;
        case KVM_REG_MIPS_LO:
                v = (long)vcpu->arch.lo;
                break;
+#endif
        case KVM_REG_MIPS_PC:
                v = (long)vcpu->arch.pc;
                break;
@@ -688,17 +816,37 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
        case KVM_REG_MIPS_CP0_ERROREPC:
                v = (long)kvm_read_c0_guest_errorepc(cop0);
                break;
+       case KVM_REG_MIPS_CP0_KSCRATCH1 ... KVM_REG_MIPS_CP0_KSCRATCH6:
+               idx = reg->id - KVM_REG_MIPS_CP0_KSCRATCH1 + 2;
+               if (!(vcpu->arch.kscratch_enabled & BIT(idx)))
+                       return -EINVAL;
+               switch (idx) {
+               case 2:
+                       v = (long)kvm_read_c0_guest_kscratch1(cop0);
+                       break;
+               case 3:
+                       v = (long)kvm_read_c0_guest_kscratch2(cop0);
+                       break;
+               case 4:
+                       v = (long)kvm_read_c0_guest_kscratch3(cop0);
+                       break;
+               case 5:
+                       v = (long)kvm_read_c0_guest_kscratch4(cop0);
+                       break;
+               case 6:
+                       v = (long)kvm_read_c0_guest_kscratch5(cop0);
+                       break;
+               case 7:
+                       v = (long)kvm_read_c0_guest_kscratch6(cop0);
+                       break;
+               }
+               break;
        /* registers to be handled specially */
-       case KVM_REG_MIPS_CP0_COUNT:
-       case KVM_REG_MIPS_COUNT_CTL:
-       case KVM_REG_MIPS_COUNT_RESUME:
-       case KVM_REG_MIPS_COUNT_HZ:
+       default:
                ret = kvm_mips_callbacks->get_one_reg(vcpu, reg, &v);
                if (ret)
                        return ret;
                break;
-       default:
-               return -EINVAL;
        }
        if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
                u64 __user *uaddr64 = (u64 __user *)(long)reg->addr;
@@ -755,12 +903,14 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
        case KVM_REG_MIPS_R1 ... KVM_REG_MIPS_R31:
                vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0] = v;
                break;
+#ifndef CONFIG_CPU_MIPSR6
        case KVM_REG_MIPS_HI:
                vcpu->arch.hi = v;
                break;
        case KVM_REG_MIPS_LO:
                vcpu->arch.lo = v;
                break;
+#endif
        case KVM_REG_MIPS_PC:
                vcpu->arch.pc = v;
                break;
@@ -859,22 +1009,34 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
        case KVM_REG_MIPS_CP0_ERROREPC:
                kvm_write_c0_guest_errorepc(cop0, v);
                break;
+       case KVM_REG_MIPS_CP0_KSCRATCH1 ... KVM_REG_MIPS_CP0_KSCRATCH6:
+               idx = reg->id - KVM_REG_MIPS_CP0_KSCRATCH1 + 2;
+               if (!(vcpu->arch.kscratch_enabled & BIT(idx)))
+                       return -EINVAL;
+               switch (idx) {
+               case 2:
+                       kvm_write_c0_guest_kscratch1(cop0, v);
+                       break;
+               case 3:
+                       kvm_write_c0_guest_kscratch2(cop0, v);
+                       break;
+               case 4:
+                       kvm_write_c0_guest_kscratch3(cop0, v);
+                       break;
+               case 5:
+                       kvm_write_c0_guest_kscratch4(cop0, v);
+                       break;
+               case 6:
+                       kvm_write_c0_guest_kscratch5(cop0, v);
+                       break;
+               case 7:
+                       kvm_write_c0_guest_kscratch6(cop0, v);
+                       break;
+               }
+               break;
        /* registers to be handled specially */
-       case KVM_REG_MIPS_CP0_COUNT:
-       case KVM_REG_MIPS_CP0_COMPARE:
-       case KVM_REG_MIPS_CP0_CAUSE:
-       case KVM_REG_MIPS_CP0_CONFIG:
-       case KVM_REG_MIPS_CP0_CONFIG1:
-       case KVM_REG_MIPS_CP0_CONFIG2:
-       case KVM_REG_MIPS_CP0_CONFIG3:
-       case KVM_REG_MIPS_CP0_CONFIG4:
-       case KVM_REG_MIPS_CP0_CONFIG5:
-       case KVM_REG_MIPS_COUNT_CTL:
-       case KVM_REG_MIPS_COUNT_RESUME:
-       case KVM_REG_MIPS_COUNT_HZ:
-               return kvm_mips_callbacks->set_one_reg(vcpu, reg, v);
        default:
-               return -EINVAL;
+               return kvm_mips_callbacks->set_one_reg(vcpu, reg, v);
        }
        return 0;
 }
@@ -927,23 +1089,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl,
        }
        case KVM_GET_REG_LIST: {
                struct kvm_reg_list __user *user_list = argp;
-               u64 __user *reg_dest;
                struct kvm_reg_list reg_list;
                unsigned n;
 
                if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
                        return -EFAULT;
                n = reg_list.n;
-               reg_list.n = ARRAY_SIZE(kvm_mips_get_one_regs);
+               reg_list.n = kvm_mips_num_regs(vcpu);
                if (copy_to_user(user_list, &reg_list, sizeof(reg_list)))
                        return -EFAULT;
                if (n < reg_list.n)
                        return -E2BIG;
-               reg_dest = user_list->reg;
-               if (copy_to_user(reg_dest, kvm_mips_get_one_regs,
-                                sizeof(kvm_mips_get_one_regs)))
-                       return -EFAULT;
-               return 0;
+               return kvm_mips_copy_reg_indices(vcpu, user_list->reg);
        }
        case KVM_NMI:
                /* Treat the NMI as a CPU reset */
@@ -1222,7 +1379,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
 static void kvm_mips_set_c0_status(void)
 {
-       uint32_t status = read_c0_status();
+       u32 status = read_c0_status();
 
        if (cpu_has_dsp)
                status |= (ST0_MX);
@@ -1236,9 +1393,9 @@ static void kvm_mips_set_c0_status(void)
  */
 int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
-       uint32_t cause = vcpu->arch.host_cp0_cause;
-       uint32_t exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
+       u32 exccode = (cause >> CAUSEB_EXCCODE) & 0x1f;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
@@ -1260,6 +1417,7 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
        kvm_debug("kvm_mips_handle_exit: cause: %#x, PC: %p, kvm_run: %p, kvm_vcpu: %p\n",
                        cause, opc, run, vcpu);
+       trace_kvm_exit(vcpu, exccode);
 
        /*
         * Do a privilege check, if in UM most of these exit conditions end up
@@ -1279,7 +1437,6 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
                kvm_debug("[%d]EXCCODE_INT @ %p\n", vcpu->vcpu_id, opc);
 
                ++vcpu->stat.int_exits;
-               trace_kvm_exit(vcpu, INT_EXITS);
 
                if (need_resched())
                        cond_resched();
@@ -1291,7 +1448,6 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
                kvm_debug("EXCCODE_CPU: @ PC: %p\n", opc);
 
                ++vcpu->stat.cop_unusable_exits;
-               trace_kvm_exit(vcpu, COP_UNUSABLE_EXITS);
                ret = kvm_mips_callbacks->handle_cop_unusable(vcpu);
                /* XXXKYMA: Might need to return to user space */
                if (run->exit_reason == KVM_EXIT_IRQ_WINDOW_OPEN)
@@ -1300,7 +1456,6 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
        case EXCCODE_MOD:
                ++vcpu->stat.tlbmod_exits;
-               trace_kvm_exit(vcpu, TLBMOD_EXITS);
                ret = kvm_mips_callbacks->handle_tlb_mod(vcpu);
                break;
 
@@ -1310,7 +1465,6 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
                          badvaddr);
 
                ++vcpu->stat.tlbmiss_st_exits;
-               trace_kvm_exit(vcpu, TLBMISS_ST_EXITS);
                ret = kvm_mips_callbacks->handle_tlb_st_miss(vcpu);
                break;
 
@@ -1319,61 +1473,51 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
                          cause, opc, badvaddr);
 
                ++vcpu->stat.tlbmiss_ld_exits;
-               trace_kvm_exit(vcpu, TLBMISS_LD_EXITS);
                ret = kvm_mips_callbacks->handle_tlb_ld_miss(vcpu);
                break;
 
        case EXCCODE_ADES:
                ++vcpu->stat.addrerr_st_exits;
-               trace_kvm_exit(vcpu, ADDRERR_ST_EXITS);
                ret = kvm_mips_callbacks->handle_addr_err_st(vcpu);
                break;
 
        case EXCCODE_ADEL:
                ++vcpu->stat.addrerr_ld_exits;
-               trace_kvm_exit(vcpu, ADDRERR_LD_EXITS);
                ret = kvm_mips_callbacks->handle_addr_err_ld(vcpu);
                break;
 
        case EXCCODE_SYS:
                ++vcpu->stat.syscall_exits;
-               trace_kvm_exit(vcpu, SYSCALL_EXITS);
                ret = kvm_mips_callbacks->handle_syscall(vcpu);
                break;
 
        case EXCCODE_RI:
                ++vcpu->stat.resvd_inst_exits;
-               trace_kvm_exit(vcpu, RESVD_INST_EXITS);
                ret = kvm_mips_callbacks->handle_res_inst(vcpu);
                break;
 
        case EXCCODE_BP:
                ++vcpu->stat.break_inst_exits;
-               trace_kvm_exit(vcpu, BREAK_INST_EXITS);
                ret = kvm_mips_callbacks->handle_break(vcpu);
                break;
 
        case EXCCODE_TR:
                ++vcpu->stat.trap_inst_exits;
-               trace_kvm_exit(vcpu, TRAP_INST_EXITS);
                ret = kvm_mips_callbacks->handle_trap(vcpu);
                break;
 
        case EXCCODE_MSAFPE:
                ++vcpu->stat.msa_fpe_exits;
-               trace_kvm_exit(vcpu, MSA_FPE_EXITS);
                ret = kvm_mips_callbacks->handle_msa_fpe(vcpu);
                break;
 
        case EXCCODE_FPE:
                ++vcpu->stat.fpe_exits;
-               trace_kvm_exit(vcpu, FPE_EXITS);
                ret = kvm_mips_callbacks->handle_fpe(vcpu);
                break;
 
        case EXCCODE_MSADIS:
                ++vcpu->stat.msa_disabled_exits;
-               trace_kvm_exit(vcpu, MSA_DISABLED_EXITS);
                ret = kvm_mips_callbacks->handle_msa_disabled(vcpu);
                break;
 
@@ -1400,11 +1544,13 @@ skip_emul:
                        run->exit_reason = KVM_EXIT_INTR;
                        ret = (-EINTR << 2) | RESUME_HOST;
                        ++vcpu->stat.signal_exits;
-                       trace_kvm_exit(vcpu, SIGNAL_EXITS);
+                       trace_kvm_exit(vcpu, KVM_TRACE_EXIT_SIGNAL);
                }
        }
 
        if (ret == RESUME_GUEST) {
+               trace_kvm_reenter(vcpu);
+
                /*
                 * If FPU / MSA are enabled (i.e. the guest's FPU / MSA context
                 * is live), restore FCR31 / MSACSR.
@@ -1450,7 +1596,7 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu)
         * not to clobber the status register directly via the commpage.
         */
        if (cpu_has_msa && sr & ST0_CU1 && !(sr & ST0_FR) &&
-           vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA)
+           vcpu->arch.aux_inuse & KVM_MIPS_AUX_MSA)
                kvm_lose_fpu(vcpu);
 
        /*
@@ -1465,9 +1611,12 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu)
        enable_fpu_hazard();
 
        /* If guest FPU state not active, restore it now */
-       if (!(vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU)) {
+       if (!(vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU)) {
                __kvm_restore_fpu(&vcpu->arch);
-               vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_FPU;
+               vcpu->arch.aux_inuse |= KVM_MIPS_AUX_FPU;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_FPU);
+       } else {
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_ENABLE, KVM_TRACE_AUX_FPU);
        }
 
        preempt_enable();
@@ -1494,8 +1643,8 @@ void kvm_own_msa(struct kvm_vcpu *vcpu)
                 * interacts with MSA state, so play it safe and save it first.
                 */
                if (!(sr & ST0_FR) &&
-                   (vcpu->arch.fpu_inuse & (KVM_MIPS_FPU_FPU |
-                               KVM_MIPS_FPU_MSA)) == KVM_MIPS_FPU_FPU)
+                   (vcpu->arch.aux_inuse & (KVM_MIPS_AUX_FPU |
+                               KVM_MIPS_AUX_MSA)) == KVM_MIPS_AUX_FPU)
                        kvm_lose_fpu(vcpu);
 
                change_c0_status(ST0_CU1 | ST0_FR, sr);
@@ -1509,22 +1658,26 @@ void kvm_own_msa(struct kvm_vcpu *vcpu)
        set_c0_config5(MIPS_CONF5_MSAEN);
        enable_fpu_hazard();
 
-       switch (vcpu->arch.fpu_inuse & (KVM_MIPS_FPU_FPU | KVM_MIPS_FPU_MSA)) {
-       case KVM_MIPS_FPU_FPU:
+       switch (vcpu->arch.aux_inuse & (KVM_MIPS_AUX_FPU | KVM_MIPS_AUX_MSA)) {
+       case KVM_MIPS_AUX_FPU:
                /*
                 * Guest FPU state already loaded, only restore upper MSA state
                 */
                __kvm_restore_msa_upper(&vcpu->arch);
-               vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_MSA;
+               vcpu->arch.aux_inuse |= KVM_MIPS_AUX_MSA;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_MSA);
                break;
        case 0:
                /* Neither FPU or MSA already active, restore full MSA state */
                __kvm_restore_msa(&vcpu->arch);
-               vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_MSA;
+               vcpu->arch.aux_inuse |= KVM_MIPS_AUX_MSA;
                if (kvm_mips_guest_has_fpu(&vcpu->arch))
-                       vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_FPU;
+                       vcpu->arch.aux_inuse |= KVM_MIPS_AUX_FPU;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE,
+                             KVM_TRACE_AUX_FPU_MSA);
                break;
        default:
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_ENABLE, KVM_TRACE_AUX_MSA);
                break;
        }
 
@@ -1536,13 +1689,15 @@ void kvm_own_msa(struct kvm_vcpu *vcpu)
 void kvm_drop_fpu(struct kvm_vcpu *vcpu)
 {
        preempt_disable();
-       if (cpu_has_msa && vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) {
+       if (cpu_has_msa && vcpu->arch.aux_inuse & KVM_MIPS_AUX_MSA) {
                disable_msa();
-               vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_MSA;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_DISCARD, KVM_TRACE_AUX_MSA);
+               vcpu->arch.aux_inuse &= ~KVM_MIPS_AUX_MSA;
        }
-       if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) {
+       if (vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU) {
                clear_c0_status(ST0_CU1 | ST0_FR);
-               vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_FPU;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_DISCARD, KVM_TRACE_AUX_FPU);
+               vcpu->arch.aux_inuse &= ~KVM_MIPS_AUX_FPU;
        }
        preempt_enable();
 }
@@ -1558,25 +1713,27 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
         */
 
        preempt_disable();
-       if (cpu_has_msa && vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) {
+       if (cpu_has_msa && vcpu->arch.aux_inuse & KVM_MIPS_AUX_MSA) {
                set_c0_config5(MIPS_CONF5_MSAEN);
                enable_fpu_hazard();
 
                __kvm_save_msa(&vcpu->arch);
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU_MSA);
 
                /* Disable MSA & FPU */
                disable_msa();
-               if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) {
+               if (vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU) {
                        clear_c0_status(ST0_CU1 | ST0_FR);
                        disable_fpu_hazard();
                }
-               vcpu->arch.fpu_inuse &= ~(KVM_MIPS_FPU_FPU | KVM_MIPS_FPU_MSA);
-       } else if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) {
+               vcpu->arch.aux_inuse &= ~(KVM_MIPS_AUX_FPU | KVM_MIPS_AUX_MSA);
+       } else if (vcpu->arch.aux_inuse & KVM_MIPS_AUX_FPU) {
                set_c0_status(ST0_CU1);
                enable_fpu_hazard();
 
                __kvm_save_fpu(&vcpu->arch);
-               vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_FPU;
+               vcpu->arch.aux_inuse &= ~KVM_MIPS_AUX_FPU;
+               trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
 
                /* Disable FPU */
                clear_c0_status(ST0_CU1 | ST0_FR);
@@ -1638,6 +1795,10 @@ static int __init kvm_mips_init(void)
 {
        int ret;
 
+       ret = kvm_mips_entry_setup();
+       if (ret)
+               return ret;
+
        ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
 
        if (ret)
@@ -1645,18 +1806,6 @@ static int __init kvm_mips_init(void)
 
        register_die_notifier(&kvm_mips_csr_die_notifier);
 
-       /*
-        * On MIPS, kernel modules are executed from "mapped space", which
-        * requires TLBs. The TLB handling code is statically linked with
-        * the rest of the kernel (tlb.c) to avoid the possibility of
-        * double faulting. The issue is that the TLB code references
-        * routines that are part of the the KVM module, which are only
-        * available once the module is loaded.
-        */
-       kvm_mips_gfn_to_pfn = gfn_to_pfn;
-       kvm_mips_release_pfn_clean = kvm_release_pfn_clean;
-       kvm_mips_is_error_pfn = is_error_pfn;
-
        return 0;
 }
 
@@ -1664,10 +1813,6 @@ static void __exit kvm_mips_exit(void)
 {
        kvm_exit();
 
-       kvm_mips_gfn_to_pfn = NULL;
-       kvm_mips_release_pfn_clean = NULL;
-       kvm_mips_is_error_pfn = NULL;
-
        unregister_die_notifier(&kvm_mips_csr_die_notifier);
 }
 
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
new file mode 100644 (file)
index 0000000..57319ee
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ *
+ * KVM/MIPS MMU handling in the KVM module.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
+ * Authors: Sanjay Lal <sanjayl@kymasys.com>
+ */
+
+#include <linux/highmem.h>
+#include <linux/kvm_host.h>
+#include <asm/mmu_context.h>
+
+static u32 kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
+{
+       int cpu = smp_processor_id();
+
+       return vcpu->arch.guest_kernel_asid[cpu] &
+                       cpu_asid_mask(&cpu_data[cpu]);
+}
+
+static u32 kvm_mips_get_user_asid(struct kvm_vcpu *vcpu)
+{
+       int cpu = smp_processor_id();
+
+       return vcpu->arch.guest_user_asid[cpu] &
+                       cpu_asid_mask(&cpu_data[cpu]);
+}
+
+static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
+{
+       int srcu_idx, err = 0;
+       kvm_pfn_t pfn;
+
+       if (kvm->arch.guest_pmap[gfn] != KVM_INVALID_PAGE)
+               return 0;
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       pfn = gfn_to_pfn(kvm, gfn);
+
+       if (is_error_pfn(pfn)) {
+               kvm_err("Couldn't get pfn for gfn %#llx!\n", gfn);
+               err = -EFAULT;
+               goto out;
+       }
+
+       kvm->arch.guest_pmap[gfn] = pfn;
+out:
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+       return err;
+}
+
+/* Translate guest KSEG0 addresses to Host PA */
+unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
+                                                   unsigned long gva)
+{
+       gfn_t gfn;
+       unsigned long offset = gva & ~PAGE_MASK;
+       struct kvm *kvm = vcpu->kvm;
+
+       if (KVM_GUEST_KSEGX(gva) != KVM_GUEST_KSEG0) {
+               kvm_err("%s/%p: Invalid gva: %#lx\n", __func__,
+                       __builtin_return_address(0), gva);
+               return KVM_INVALID_PAGE;
+       }
+
+       gfn = (KVM_GUEST_CPHYSADDR(gva) >> PAGE_SHIFT);
+
+       if (gfn >= kvm->arch.guest_pmap_npages) {
+               kvm_err("%s: Invalid gfn: %#llx, GVA: %#lx\n", __func__, gfn,
+                       gva);
+               return KVM_INVALID_PAGE;
+       }
+
+       if (kvm_mips_map_page(vcpu->kvm, gfn) < 0)
+               return KVM_INVALID_ADDR;
+
+       return (kvm->arch.guest_pmap[gfn] << PAGE_SHIFT) + offset;
+}
+
+/* XXXKYMA: Must be called with interrupts disabled */
+int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
+                                   struct kvm_vcpu *vcpu)
+{
+       gfn_t gfn;
+       kvm_pfn_t pfn0, pfn1;
+       unsigned long vaddr = 0;
+       unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
+       struct kvm *kvm = vcpu->kvm;
+       const int flush_dcache_mask = 0;
+       int ret;
+
+       if (KVM_GUEST_KSEGX(badvaddr) != KVM_GUEST_KSEG0) {
+               kvm_err("%s: Invalid BadVaddr: %#lx\n", __func__, badvaddr);
+               kvm_mips_dump_host_tlbs();
+               return -1;
+       }
+
+       gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
+       if (gfn >= kvm->arch.guest_pmap_npages) {
+               kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
+                       gfn, badvaddr);
+               kvm_mips_dump_host_tlbs();
+               return -1;
+       }
+       vaddr = badvaddr & (PAGE_MASK << 1);
+
+       if (kvm_mips_map_page(vcpu->kvm, gfn) < 0)
+               return -1;
+
+       if (kvm_mips_map_page(vcpu->kvm, gfn ^ 0x1) < 0)
+               return -1;
+
+       pfn0 = kvm->arch.guest_pmap[gfn & ~0x1];
+       pfn1 = kvm->arch.guest_pmap[gfn | 0x1];
+
+       entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
+               ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
+               ENTRYLO_D | ENTRYLO_V;
+       entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
+               ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
+               ENTRYLO_D | ENTRYLO_V;
+
+       preempt_disable();
+       entryhi = (vaddr | kvm_mips_get_kernel_asid(vcpu));
+       ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1,
+                                     flush_dcache_mask);
+       preempt_enable();
+
+       return ret;
+}
+
+int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
+                                        struct kvm_mips_tlb *tlb)
+{
+       unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
+       struct kvm *kvm = vcpu->kvm;
+       kvm_pfn_t pfn0, pfn1;
+       int ret;
+
+       if ((tlb->tlb_hi & VPN2_MASK) == 0) {
+               pfn0 = 0;
+               pfn1 = 0;
+       } else {
+               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[0])
+                                          >> PAGE_SHIFT) < 0)
+                       return -1;
+
+               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1])
+                                          >> PAGE_SHIFT) < 0)
+                       return -1;
+
+               pfn0 = kvm->arch.guest_pmap[
+                       mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT];
+               pfn1 = kvm->arch.guest_pmap[
+                       mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT];
+       }
+
+       /* Get attributes from the Guest TLB */
+       entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
+               ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
+               (tlb->tlb_lo[0] & ENTRYLO_D) |
+               (tlb->tlb_lo[0] & ENTRYLO_V);
+       entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
+               ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
+               (tlb->tlb_lo[1] & ENTRYLO_D) |
+               (tlb->tlb_lo[1] & ENTRYLO_V);
+
+       kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
+                 tlb->tlb_lo[0], tlb->tlb_lo[1]);
+
+       preempt_disable();
+       entryhi = (tlb->tlb_hi & VPN2_MASK) | (KVM_GUEST_KERNEL_MODE(vcpu) ?
+                                              kvm_mips_get_kernel_asid(vcpu) :
+                                              kvm_mips_get_user_asid(vcpu));
+       ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1,
+                                     tlb->tlb_mask);
+       preempt_enable();
+
+       return ret;
+}
+
+void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
+                            struct kvm_vcpu *vcpu)
+{
+       unsigned long asid = asid_cache(cpu);
+
+       asid += cpu_asid_inc();
+       if (!(asid & cpu_asid_mask(&cpu_data[cpu]))) {
+               if (cpu_has_vtag_icache)
+                       flush_icache_all();
+
+               kvm_local_flush_tlb_all();      /* start new asid cycle */
+
+               if (!asid)      /* fix version if needed */
+                       asid = asid_first_version(cpu);
+       }
+
+       cpu_context(cpu, mm) = asid_cache(cpu) = asid;
+}
+
+/**
+ * kvm_mips_migrate_count() - Migrate timer.
+ * @vcpu:      Virtual CPU.
+ *
+ * Migrate CP0_Count hrtimer to the current CPU by cancelling and restarting it
+ * if it was running prior to being cancelled.
+ *
+ * Must be called when the VCPU is migrated to a different CPU to ensure that
+ * timer expiry during guest execution interrupts the guest and causes the
+ * interrupt to be delivered in a timely manner.
+ */
+static void kvm_mips_migrate_count(struct kvm_vcpu *vcpu)
+{
+       if (hrtimer_cancel(&vcpu->arch.comparecount_timer))
+               hrtimer_restart(&vcpu->arch.comparecount_timer);
+}
+
+/* Restore ASID once we are scheduled back after preemption */
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+       unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]);
+       unsigned long flags;
+       int newasid = 0;
+
+       kvm_debug("%s: vcpu %p, cpu: %d\n", __func__, vcpu, cpu);
+
+       /* Allocate new kernel and user ASIDs if needed */
+
+       local_irq_save(flags);
+
+       if ((vcpu->arch.guest_kernel_asid[cpu] ^ asid_cache(cpu)) &
+                                               asid_version_mask(cpu)) {
+               kvm_get_new_mmu_context(&vcpu->arch.guest_kernel_mm, cpu, vcpu);
+               vcpu->arch.guest_kernel_asid[cpu] =
+                   vcpu->arch.guest_kernel_mm.context.asid[cpu];
+               kvm_get_new_mmu_context(&vcpu->arch.guest_user_mm, cpu, vcpu);
+               vcpu->arch.guest_user_asid[cpu] =
+                   vcpu->arch.guest_user_mm.context.asid[cpu];
+               newasid++;
+
+               kvm_debug("[%d]: cpu_context: %#lx\n", cpu,
+                         cpu_context(cpu, current->mm));
+               kvm_debug("[%d]: Allocated new ASID for Guest Kernel: %#x\n",
+                         cpu, vcpu->arch.guest_kernel_asid[cpu]);
+               kvm_debug("[%d]: Allocated new ASID for Guest User: %#x\n", cpu,
+                         vcpu->arch.guest_user_asid[cpu]);
+       }
+
+       if (vcpu->arch.last_sched_cpu != cpu) {
+               kvm_debug("[%d->%d]KVM VCPU[%d] switch\n",
+                         vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
+               /*
+                * Migrate the timer interrupt to the current CPU so that it
+                * always interrupts the guest and synchronously triggers a
+                * guest timer interrupt.
+                */
+               kvm_mips_migrate_count(vcpu);
+       }
+
+       if (!newasid) {
+               /*
+                * If we preempted while the guest was executing, then reload
+                * the pre-empted ASID
+                */
+               if (current->flags & PF_VCPU) {
+                       write_c0_entryhi(vcpu->arch.
+                                        preempt_entryhi & asid_mask);
+                       ehb();
+               }
+       } else {
+               /* New ASIDs were allocated for the VM */
+
+               /*
+                * Were we in guest context? If so then the pre-empted ASID is
+                * no longer valid, we need to set it to what it should be based
+                * on the mode of the Guest (Kernel/User)
+                */
+               if (current->flags & PF_VCPU) {
+                       if (KVM_GUEST_KERNEL_MODE(vcpu))
+                               write_c0_entryhi(vcpu->arch.
+                                                guest_kernel_asid[cpu] &
+                                                asid_mask);
+                       else
+                               write_c0_entryhi(vcpu->arch.
+                                                guest_user_asid[cpu] &
+                                                asid_mask);
+                       ehb();
+               }
+       }
+
+       /* restore guest state to registers */
+       kvm_mips_callbacks->vcpu_set_regs(vcpu);
+
+       local_irq_restore(flags);
+
+}
+
+/* ASID can change if another task is scheduled during preemption */
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+       unsigned long flags;
+       int cpu;
+
+       local_irq_save(flags);
+
+       cpu = smp_processor_id();
+
+       vcpu->arch.preempt_entryhi = read_c0_entryhi();
+       vcpu->arch.last_sched_cpu = cpu;
+
+       /* save guest state in registers */
+       kvm_mips_callbacks->vcpu_get_regs(vcpu);
+
+       if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) &
+            asid_version_mask(cpu))) {
+               kvm_debug("%s: Dropping MMU Context:  %#lx\n", __func__,
+                         cpu_context(cpu, current->mm));
+               drop_mmu_context(current->mm, cpu);
+       }
+       write_c0_entryhi(cpu_asid(cpu, current->mm));
+       ehb();
+
+       local_irq_restore(flags);
+}
+
+u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu)
+{
+       struct mips_coproc *cop0 = vcpu->arch.cop0;
+       unsigned long paddr, flags, vpn2, asid;
+       unsigned long va = (unsigned long)opc;
+       void *vaddr;
+       u32 inst;
+       int index;
+
+       if (KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0 ||
+           KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
+               local_irq_save(flags);
+               index = kvm_mips_host_tlb_lookup(vcpu, va);
+               if (index >= 0) {
+                       inst = *(opc);
+               } else {
+                       vpn2 = va & VPN2_MASK;
+                       asid = kvm_read_c0_guest_entryhi(cop0) &
+                                               KVM_ENTRYHI_ASID;
+                       index = kvm_mips_guest_tlb_lookup(vcpu, vpn2 | asid);
+                       if (index < 0) {
+                               kvm_err("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n",
+                                       __func__, opc, vcpu, read_c0_entryhi());
+                               kvm_mips_dump_host_tlbs();
+                               kvm_mips_dump_guest_tlbs(vcpu);
+                               local_irq_restore(flags);
+                               return KVM_INVALID_INST;
+                       }
+                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
+                                                            &vcpu->arch.
+                                                            guest_tlb[index]);
+                       inst = *(opc);
+               }
+               local_irq_restore(flags);
+       } else if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
+               paddr = kvm_mips_translate_guest_kseg0_to_hpa(vcpu, va);
+               vaddr = kmap_atomic(pfn_to_page(PHYS_PFN(paddr)));
+               vaddr += paddr & ~PAGE_MASK;
+               inst = *(u32 *)vaddr;
+               kunmap_atomic(vaddr);
+       } else {
+               kvm_err("%s: illegal address: %p\n", __func__, opc);
+               return KVM_INVALID_INST;
+       }
+
+       return inst;
+}
index 888bb67..53f851a 100644 (file)
 
 #include <linux/kvm_host.h>
 
-char *kvm_mips_exit_types_str[MAX_KVM_MIPS_EXIT_TYPES] = {
-       "WAIT",
-       "CACHE",
-       "Signal",
-       "Interrupt",
-       "COP0/1 Unusable",
-       "TLB Mod",
-       "TLB Miss (LD)",
-       "TLB Miss (ST)",
-       "Address Err (ST)",
-       "Address Error (LD)",
-       "System Call",
-       "Reserved Inst",
-       "Break Inst",
-       "Trap Inst",
-       "MSA FPE",
-       "FPE",
-       "MSA Disabled",
-       "D-Cache Flushes",
-};
-
 char *kvm_cop0_str[N_MIPS_COPROC_REGS] = {
        "Index",
        "Random",
index ed021ae..254377d 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kvm_host.h>
 #include <linux/srcu.h>
 
@@ -24,6 +24,7 @@
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
+#include <asm/tlbdebug.h>
 
 #undef CONFIG_MIPS_MT
 #include <asm/r4kcache.h>
 #define KVM_GUEST_PC_TLB    0
 #define KVM_GUEST_SP_TLB    1
 
-#define PRIx64 "llx"
-
 atomic_t kvm_mips_instance;
 EXPORT_SYMBOL_GPL(kvm_mips_instance);
 
-/* These function pointers are initialized once the KVM module is loaded */
-kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
-EXPORT_SYMBOL_GPL(kvm_mips_gfn_to_pfn);
-
-void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
-EXPORT_SYMBOL_GPL(kvm_mips_release_pfn_clean);
-
-bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
-EXPORT_SYMBOL_GPL(kvm_mips_is_error_pfn);
-
-uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
+static u32 kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
 {
        int cpu = smp_processor_id();
 
@@ -55,7 +44,7 @@ uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
                        cpu_asid_mask(&cpu_data[cpu]);
 }
 
-uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu)
+static u32 kvm_mips_get_user_asid(struct kvm_vcpu *vcpu)
 {
        int cpu = smp_processor_id();
 
@@ -63,7 +52,7 @@ uint32_t kvm_mips_get_user_asid(struct kvm_vcpu *vcpu)
                        cpu_asid_mask(&cpu_data[cpu]);
 }
 
-inline uint32_t kvm_mips_get_commpage_asid(struct kvm_vcpu *vcpu)
+inline u32 kvm_mips_get_commpage_asid(struct kvm_vcpu *vcpu)
 {
        return vcpu->kvm->arch.commpage_tlb;
 }
@@ -72,50 +61,15 @@ inline uint32_t kvm_mips_get_commpage_asid(struct kvm_vcpu *vcpu)
 
 void kvm_mips_dump_host_tlbs(void)
 {
-       unsigned long old_entryhi;
-       unsigned long old_pagemask;
-       struct kvm_mips_tlb tlb;
        unsigned long flags;
-       int i;
 
        local_irq_save(flags);
 
-       old_entryhi = read_c0_entryhi();
-       old_pagemask = read_c0_pagemask();
-
        kvm_info("HOST TLBs:\n");
-       kvm_info("ASID: %#lx\n", read_c0_entryhi() &
-                cpu_asid_mask(&current_cpu_data));
-
-       for (i = 0; i < current_cpu_data.tlbsize; i++) {
-               write_c0_index(i);
-               mtc0_tlbw_hazard();
-
-               tlb_read();
-               tlbw_use_hazard();
+       dump_tlb_regs();
+       pr_info("\n");
+       dump_tlb_all();
 
-               tlb.tlb_hi = read_c0_entryhi();
-               tlb.tlb_lo0 = read_c0_entrylo0();
-               tlb.tlb_lo1 = read_c0_entrylo1();
-               tlb.tlb_mask = read_c0_pagemask();
-
-               kvm_info("TLB%c%3d Hi 0x%08lx ",
-                        (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*',
-                        i, tlb.tlb_hi);
-               kvm_info("Lo0=0x%09" PRIx64 " %c%c attr %lx ",
-                        (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo0),
-                        (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ',
-                        (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ',
-                        (tlb.tlb_lo0 >> 3) & 7);
-               kvm_info("Lo1=0x%09" PRIx64 " %c%c attr %lx sz=%lx\n",
-                        (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo1),
-                        (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ',
-                        (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ',
-                        (tlb.tlb_lo1 >> 3) & 7, tlb.tlb_mask);
-       }
-       write_c0_entryhi(old_entryhi);
-       write_c0_pagemask(old_pagemask);
-       mtc0_tlbw_hazard();
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(kvm_mips_dump_host_tlbs);
@@ -132,74 +86,24 @@ void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu)
        for (i = 0; i < KVM_MIPS_GUEST_TLB_SIZE; i++) {
                tlb = vcpu->arch.guest_tlb[i];
                kvm_info("TLB%c%3d Hi 0x%08lx ",
-                        (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*',
+                        (tlb.tlb_lo[0] | tlb.tlb_lo[1]) & ENTRYLO_V
+                                                       ? ' ' : '*',
                         i, tlb.tlb_hi);
-               kvm_info("Lo0=0x%09" PRIx64 " %c%c attr %lx ",
-                        (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo0),
-                        (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ',
-                        (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ',
-                        (tlb.tlb_lo0 >> 3) & 7);
-               kvm_info("Lo1=0x%09" PRIx64 " %c%c attr %lx sz=%lx\n",
-                        (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo1),
-                        (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ',
-                        (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ',
-                        (tlb.tlb_lo1 >> 3) & 7, tlb.tlb_mask);
+               kvm_info("Lo0=0x%09llx %c%c attr %lx ",
+                        (u64) mips3_tlbpfn_to_paddr(tlb.tlb_lo[0]),
+                        (tlb.tlb_lo[0] & ENTRYLO_D) ? 'D' : ' ',
+                        (tlb.tlb_lo[0] & ENTRYLO_G) ? 'G' : ' ',
+                        (tlb.tlb_lo[0] & ENTRYLO_C) >> ENTRYLO_C_SHIFT);
+               kvm_info("Lo1=0x%09llx %c%c attr %lx sz=%lx\n",
+                        (u64) mips3_tlbpfn_to_paddr(tlb.tlb_lo[1]),
+                        (tlb.tlb_lo[1] & ENTRYLO_D) ? 'D' : ' ',
+                        (tlb.tlb_lo[1] & ENTRYLO_G) ? 'G' : ' ',
+                        (tlb.tlb_lo[1] & ENTRYLO_C) >> ENTRYLO_C_SHIFT,
+                        tlb.tlb_mask);
        }
 }
 EXPORT_SYMBOL_GPL(kvm_mips_dump_guest_tlbs);
 
-static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
-{
-       int srcu_idx, err = 0;
-       kvm_pfn_t pfn;
-
-       if (kvm->arch.guest_pmap[gfn] != KVM_INVALID_PAGE)
-               return 0;
-
-       srcu_idx = srcu_read_lock(&kvm->srcu);
-       pfn = kvm_mips_gfn_to_pfn(kvm, gfn);
-
-       if (kvm_mips_is_error_pfn(pfn)) {
-               kvm_err("Couldn't get pfn for gfn %#" PRIx64 "!\n", gfn);
-               err = -EFAULT;
-               goto out;
-       }
-
-       kvm->arch.guest_pmap[gfn] = pfn;
-out:
-       srcu_read_unlock(&kvm->srcu, srcu_idx);
-       return err;
-}
-
-/* Translate guest KSEG0 addresses to Host PA */
-unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
-                                                   unsigned long gva)
-{
-       gfn_t gfn;
-       uint32_t offset = gva & ~PAGE_MASK;
-       struct kvm *kvm = vcpu->kvm;
-
-       if (KVM_GUEST_KSEGX(gva) != KVM_GUEST_KSEG0) {
-               kvm_err("%s/%p: Invalid gva: %#lx\n", __func__,
-                       __builtin_return_address(0), gva);
-               return KVM_INVALID_PAGE;
-       }
-
-       gfn = (KVM_GUEST_CPHYSADDR(gva) >> PAGE_SHIFT);
-
-       if (gfn >= kvm->arch.guest_pmap_npages) {
-               kvm_err("%s: Invalid gfn: %#llx, GVA: %#lx\n", __func__, gfn,
-                       gva);
-               return KVM_INVALID_PAGE;
-       }
-
-       if (kvm_mips_map_page(vcpu->kvm, gfn) < 0)
-               return KVM_INVALID_ADDR;
-
-       return (kvm->arch.guest_pmap[gfn] << PAGE_SHIFT) + offset;
-}
-EXPORT_SYMBOL_GPL(kvm_mips_translate_guest_kseg0_to_hpa);
-
 /* XXXKYMA: Must be called with interrupts disabled */
 /* set flush_dcache_mask == 0 if no dcache flush required */
 int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
@@ -243,12 +147,12 @@ int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
 
        /* Flush D-cache */
        if (flush_dcache_mask) {
-               if (entrylo0 & MIPS3_PG_V) {
+               if (entrylo0 & ENTRYLO_V) {
                        ++vcpu->stat.flush_dcache_exits;
                        flush_data_cache_page((entryhi & VPN2_MASK) &
                                              ~flush_dcache_mask);
                }
-               if (entrylo1 & MIPS3_PG_V) {
+               if (entrylo1 & ENTRYLO_V) {
                        ++vcpu->stat.flush_dcache_exits;
                        flush_data_cache_page(((entryhi & VPN2_MASK) &
                                               ~flush_dcache_mask) |
@@ -259,96 +163,35 @@ int kvm_mips_host_tlb_write(struct kvm_vcpu *vcpu, unsigned long entryhi,
        /* Restore old ASID */
        write_c0_entryhi(old_entryhi);
        mtc0_tlbw_hazard();
-       tlbw_use_hazard();
        local_irq_restore(flags);
        return 0;
 }
-
-/* XXXKYMA: Must be called with interrupts disabled */
-int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
-                                   struct kvm_vcpu *vcpu)
-{
-       gfn_t gfn;
-       kvm_pfn_t pfn0, pfn1;
-       unsigned long vaddr = 0;
-       unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
-       int even;
-       struct kvm *kvm = vcpu->kvm;
-       const int flush_dcache_mask = 0;
-       int ret;
-
-       if (KVM_GUEST_KSEGX(badvaddr) != KVM_GUEST_KSEG0) {
-               kvm_err("%s: Invalid BadVaddr: %#lx\n", __func__, badvaddr);
-               kvm_mips_dump_host_tlbs();
-               return -1;
-       }
-
-       gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
-       if (gfn >= kvm->arch.guest_pmap_npages) {
-               kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
-                       gfn, badvaddr);
-               kvm_mips_dump_host_tlbs();
-               return -1;
-       }
-       even = !(gfn & 0x1);
-       vaddr = badvaddr & (PAGE_MASK << 1);
-
-       if (kvm_mips_map_page(vcpu->kvm, gfn) < 0)
-               return -1;
-
-       if (kvm_mips_map_page(vcpu->kvm, gfn ^ 0x1) < 0)
-               return -1;
-
-       if (even) {
-               pfn0 = kvm->arch.guest_pmap[gfn];
-               pfn1 = kvm->arch.guest_pmap[gfn ^ 0x1];
-       } else {
-               pfn0 = kvm->arch.guest_pmap[gfn ^ 0x1];
-               pfn1 = kvm->arch.guest_pmap[gfn];
-       }
-
-       entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) |
-                  (1 << 2) | (0x1 << 1);
-       entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) |
-                  (1 << 2) | (0x1 << 1);
-
-       preempt_disable();
-       entryhi = (vaddr | kvm_mips_get_kernel_asid(vcpu));
-       ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1,
-                                     flush_dcache_mask);
-       preempt_enable();
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(kvm_mips_handle_kseg0_tlb_fault);
+EXPORT_SYMBOL_GPL(kvm_mips_host_tlb_write);
 
 int kvm_mips_handle_commpage_tlb_fault(unsigned long badvaddr,
        struct kvm_vcpu *vcpu)
 {
-       kvm_pfn_t pfn0, pfn1;
+       kvm_pfn_t pfn;
        unsigned long flags, old_entryhi = 0, vaddr = 0;
-       unsigned long entrylo0 = 0, entrylo1 = 0;
+       unsigned long entrylo[2] = { 0, 0 };
+       unsigned int pair_idx;
 
-       pfn0 = CPHYSADDR(vcpu->arch.kseg0_commpage) >> PAGE_SHIFT;
-       pfn1 = 0;
-       entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) |
-                  (1 << 2) | (0x1 << 1);
-       entrylo1 = 0;
+       pfn = PFN_DOWN(virt_to_phys(vcpu->arch.kseg0_commpage));
+       pair_idx = (badvaddr >> PAGE_SHIFT) & 1;
+       entrylo[pair_idx] = mips3_paddr_to_tlbpfn(pfn << PAGE_SHIFT) |
+               ((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
+               ENTRYLO_D | ENTRYLO_V;
 
        local_irq_save(flags);
 
        old_entryhi = read_c0_entryhi();
        vaddr = badvaddr & (PAGE_MASK << 1);
        write_c0_entryhi(vaddr | kvm_mips_get_kernel_asid(vcpu));
-       mtc0_tlbw_hazard();
-       write_c0_entrylo0(entrylo0);
-       mtc0_tlbw_hazard();
-       write_c0_entrylo1(entrylo1);
-       mtc0_tlbw_hazard();
+       write_c0_entrylo0(entrylo[0]);
+       write_c0_entrylo1(entrylo[1]);
        write_c0_index(kvm_mips_get_commpage_asid(vcpu));
        mtc0_tlbw_hazard();
        tlb_write_indexed();
-       mtc0_tlbw_hazard();
        tlbw_use_hazard();
 
        kvm_debug("@ %#lx idx: %2d [entryhi(R): %#lx] entrylo0 (R): 0x%08lx, entrylo1(R): 0x%08lx\n",
@@ -358,68 +201,12 @@ int kvm_mips_handle_commpage_tlb_fault(unsigned long badvaddr,
        /* Restore old ASID */
        write_c0_entryhi(old_entryhi);
        mtc0_tlbw_hazard();
-       tlbw_use_hazard();
        local_irq_restore(flags);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_mips_handle_commpage_tlb_fault);
 
-int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
-                                        struct kvm_mips_tlb *tlb,
-                                        unsigned long *hpa0,
-                                        unsigned long *hpa1)
-{
-       unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
-       struct kvm *kvm = vcpu->kvm;
-       kvm_pfn_t pfn0, pfn1;
-       int ret;
-
-       if ((tlb->tlb_hi & VPN2_MASK) == 0) {
-               pfn0 = 0;
-               pfn1 = 0;
-       } else {
-               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-                                          >> PAGE_SHIFT) < 0)
-                       return -1;
-
-               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-                                          >> PAGE_SHIFT) < 0)
-                       return -1;
-
-               pfn0 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-                                           >> PAGE_SHIFT];
-               pfn1 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-                                           >> PAGE_SHIFT];
-       }
-
-       if (hpa0)
-               *hpa0 = pfn0 << PAGE_SHIFT;
-
-       if (hpa1)
-               *hpa1 = pfn1 << PAGE_SHIFT;
-
-       /* Get attributes from the Guest TLB */
-       entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) |
-                  (tlb->tlb_lo0 & MIPS3_PG_D) | (tlb->tlb_lo0 & MIPS3_PG_V);
-       entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) |
-                  (tlb->tlb_lo1 & MIPS3_PG_D) | (tlb->tlb_lo1 & MIPS3_PG_V);
-
-       kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
-                 tlb->tlb_lo0, tlb->tlb_lo1);
-
-       preempt_disable();
-       entryhi = (tlb->tlb_hi & VPN2_MASK) | (KVM_GUEST_KERNEL_MODE(vcpu) ?
-                                              kvm_mips_get_kernel_asid(vcpu) :
-                                              kvm_mips_get_user_asid(vcpu));
-       ret = kvm_mips_host_tlb_write(vcpu, entryhi, entrylo0, entrylo1,
-                                     tlb->tlb_mask);
-       preempt_enable();
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(kvm_mips_handle_mapped_seg_tlb_fault);
-
 int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long entryhi)
 {
        int i;
@@ -435,7 +222,7 @@ int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long entryhi)
        }
 
        kvm_debug("%s: entryhi: %#lx, index: %d lo0: %#lx, lo1: %#lx\n",
-                 __func__, entryhi, index, tlb[i].tlb_lo0, tlb[i].tlb_lo1);
+                 __func__, entryhi, index, tlb[i].tlb_lo[0], tlb[i].tlb_lo[1]);
 
        return index;
 }
@@ -467,7 +254,6 @@ int kvm_mips_host_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long vaddr)
        /* Restore old ASID */
        write_c0_entryhi(old_entryhi);
        mtc0_tlbw_hazard();
-       tlbw_use_hazard();
 
        local_irq_restore(flags);
 
@@ -498,21 +284,16 @@ int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long va)
 
        if (idx > 0) {
                write_c0_entryhi(UNIQUE_ENTRYHI(idx));
-               mtc0_tlbw_hazard();
-
                write_c0_entrylo0(0);
-               mtc0_tlbw_hazard();
-
                write_c0_entrylo1(0);
                mtc0_tlbw_hazard();
 
                tlb_write_indexed();
-               mtc0_tlbw_hazard();
+               tlbw_use_hazard();
        }
 
        write_c0_entryhi(old_entryhi);
        mtc0_tlbw_hazard();
-       tlbw_use_hazard();
 
        local_irq_restore(flags);
 
@@ -540,61 +321,39 @@ void kvm_mips_flush_host_tlb(int skip_kseg0)
        /* Blast 'em all away. */
        for (entry = 0; entry < maxentry; entry++) {
                write_c0_index(entry);
-               mtc0_tlbw_hazard();
 
                if (skip_kseg0) {
+                       mtc0_tlbr_hazard();
                        tlb_read();
-                       tlbw_use_hazard();
+                       tlb_read_hazard();
 
                        entryhi = read_c0_entryhi();
 
                        /* Don't blow away guest kernel entries */
                        if (KVM_GUEST_KSEGX(entryhi) == KVM_GUEST_KSEG0)
                                continue;
+
+                       write_c0_pagemask(old_pagemask);
                }
 
                /* Make sure all entries differ. */
                write_c0_entryhi(UNIQUE_ENTRYHI(entry));
-               mtc0_tlbw_hazard();
                write_c0_entrylo0(0);
-               mtc0_tlbw_hazard();
                write_c0_entrylo1(0);
                mtc0_tlbw_hazard();
 
                tlb_write_indexed();
-               mtc0_tlbw_hazard();
+               tlbw_use_hazard();
        }
 
-       tlbw_use_hazard();
-
        write_c0_entryhi(old_entryhi);
        write_c0_pagemask(old_pagemask);
        mtc0_tlbw_hazard();
-       tlbw_use_hazard();
 
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(kvm_mips_flush_host_tlb);
 
-void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
-                            struct kvm_vcpu *vcpu)
-{
-       unsigned long asid = asid_cache(cpu);
-
-       asid += cpu_asid_inc();
-       if (!(asid & cpu_asid_mask(&cpu_data[cpu]))) {
-               if (cpu_has_vtag_icache)
-                       flush_icache_all();
-
-               kvm_local_flush_tlb_all();      /* start new asid cycle */
-
-               if (!asid)      /* fix version if needed */
-                       asid = asid_first_version(cpu);
-       }
-
-       cpu_context(cpu, mm) = asid_cache(cpu) = asid;
-}
-
 void kvm_local_flush_tlb_all(void)
 {
        unsigned long flags;
@@ -614,185 +373,12 @@ void kvm_local_flush_tlb_all(void)
                write_c0_index(entry);
                mtc0_tlbw_hazard();
                tlb_write_indexed();
+               tlbw_use_hazard();
                entry++;
        }
-       tlbw_use_hazard();
        write_c0_entryhi(old_ctx);
        mtc0_tlbw_hazard();
 
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(kvm_local_flush_tlb_all);
-
-/**
- * kvm_mips_migrate_count() - Migrate timer.
- * @vcpu:      Virtual CPU.
- *
- * Migrate CP0_Count hrtimer to the current CPU by cancelling and restarting it
- * if it was running prior to being cancelled.
- *
- * Must be called when the VCPU is migrated to a different CPU to ensure that
- * timer expiry during guest execution interrupts the guest and causes the
- * interrupt to be delivered in a timely manner.
- */
-static void kvm_mips_migrate_count(struct kvm_vcpu *vcpu)
-{
-       if (hrtimer_cancel(&vcpu->arch.comparecount_timer))
-               hrtimer_restart(&vcpu->arch.comparecount_timer);
-}
-
-/* Restore ASID once we are scheduled back after preemption */
-void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
-{
-       unsigned long asid_mask = cpu_asid_mask(&cpu_data[cpu]);
-       unsigned long flags;
-       int newasid = 0;
-
-       kvm_debug("%s: vcpu %p, cpu: %d\n", __func__, vcpu, cpu);
-
-       /* Allocate new kernel and user ASIDs if needed */
-
-       local_irq_save(flags);
-
-       if ((vcpu->arch.guest_kernel_asid[cpu] ^ asid_cache(cpu)) &
-                                               asid_version_mask(cpu)) {
-               kvm_get_new_mmu_context(&vcpu->arch.guest_kernel_mm, cpu, vcpu);
-               vcpu->arch.guest_kernel_asid[cpu] =
-                   vcpu->arch.guest_kernel_mm.context.asid[cpu];
-               kvm_get_new_mmu_context(&vcpu->arch.guest_user_mm, cpu, vcpu);
-               vcpu->arch.guest_user_asid[cpu] =
-                   vcpu->arch.guest_user_mm.context.asid[cpu];
-               newasid++;
-
-               kvm_debug("[%d]: cpu_context: %#lx\n", cpu,
-                         cpu_context(cpu, current->mm));
-               kvm_debug("[%d]: Allocated new ASID for Guest Kernel: %#x\n",
-                         cpu, vcpu->arch.guest_kernel_asid[cpu]);
-               kvm_debug("[%d]: Allocated new ASID for Guest User: %#x\n", cpu,
-                         vcpu->arch.guest_user_asid[cpu]);
-       }
-
-       if (vcpu->arch.last_sched_cpu != cpu) {
-               kvm_debug("[%d->%d]KVM VCPU[%d] switch\n",
-                         vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
-               /*
-                * Migrate the timer interrupt to the current CPU so that it
-                * always interrupts the guest and synchronously triggers a
-                * guest timer interrupt.
-                */
-               kvm_mips_migrate_count(vcpu);
-       }
-
-       if (!newasid) {
-               /*
-                * If we preempted while the guest was executing, then reload
-                * the pre-empted ASID
-                */
-               if (current->flags & PF_VCPU) {
-                       write_c0_entryhi(vcpu->arch.
-                                        preempt_entryhi & asid_mask);
-                       ehb();
-               }
-       } else {
-               /* New ASIDs were allocated for the VM */
-
-               /*
-                * Were we in guest context? If so then the pre-empted ASID is
-                * no longer valid, we need to set it to what it should be based
-                * on the mode of the Guest (Kernel/User)
-                */
-               if (current->flags & PF_VCPU) {
-                       if (KVM_GUEST_KERNEL_MODE(vcpu))
-                               write_c0_entryhi(vcpu->arch.
-                                                guest_kernel_asid[cpu] &
-                                                asid_mask);
-                       else
-                               write_c0_entryhi(vcpu->arch.
-                                                guest_user_asid[cpu] &
-                                                asid_mask);
-                       ehb();
-               }
-       }
-
-       /* restore guest state to registers */
-       kvm_mips_callbacks->vcpu_set_regs(vcpu);
-
-       local_irq_restore(flags);
-
-}
-EXPORT_SYMBOL_GPL(kvm_arch_vcpu_load);
-
-/* ASID can change if another task is scheduled during preemption */
-void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
-{
-       unsigned long flags;
-       uint32_t cpu;
-
-       local_irq_save(flags);
-
-       cpu = smp_processor_id();
-
-       vcpu->arch.preempt_entryhi = read_c0_entryhi();
-       vcpu->arch.last_sched_cpu = cpu;
-
-       /* save guest state in registers */
-       kvm_mips_callbacks->vcpu_get_regs(vcpu);
-
-       if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) &
-            asid_version_mask(cpu))) {
-               kvm_debug("%s: Dropping MMU Context:  %#lx\n", __func__,
-                         cpu_context(cpu, current->mm));
-               drop_mmu_context(current->mm, cpu);
-       }
-       write_c0_entryhi(cpu_asid(cpu, current->mm));
-       ehb();
-
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(kvm_arch_vcpu_put);
-
-uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu)
-{
-       struct mips_coproc *cop0 = vcpu->arch.cop0;
-       unsigned long paddr, flags, vpn2, asid;
-       uint32_t inst;
-       int index;
-
-       if (KVM_GUEST_KSEGX((unsigned long) opc) < KVM_GUEST_KSEG0 ||
-           KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
-               local_irq_save(flags);
-               index = kvm_mips_host_tlb_lookup(vcpu, (unsigned long) opc);
-               if (index >= 0) {
-                       inst = *(opc);
-               } else {
-                       vpn2 = (unsigned long) opc & VPN2_MASK;
-                       asid = kvm_read_c0_guest_entryhi(cop0) &
-                                               KVM_ENTRYHI_ASID;
-                       index = kvm_mips_guest_tlb_lookup(vcpu, vpn2 | asid);
-                       if (index < 0) {
-                               kvm_err("%s: get_user_failed for %p, vcpu: %p, ASID: %#lx\n",
-                                       __func__, opc, vcpu, read_c0_entryhi());
-                               kvm_mips_dump_host_tlbs();
-                               local_irq_restore(flags);
-                               return KVM_INVALID_INST;
-                       }
-                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
-                                                            &vcpu->arch.
-                                                            guest_tlb[index],
-                                                            NULL, NULL);
-                       inst = *(opc);
-               }
-               local_irq_restore(flags);
-       } else if (KVM_GUEST_KSEGX(opc) == KVM_GUEST_KSEG0) {
-               paddr =
-                   kvm_mips_translate_guest_kseg0_to_hpa(vcpu,
-                                                         (unsigned long) opc);
-               inst = *(uint32_t *) CKSEG0ADDR(paddr);
-       } else {
-               kvm_err("%s: illegal address: %p\n", __func__, opc);
-               return KVM_INVALID_INST;
-       }
-
-       return inst;
-}
-EXPORT_SYMBOL_GPL(kvm_get_inst);
index bd6437f..c858cf1 100644 (file)
 #define TRACE_INCLUDE_PATH .
 #define TRACE_INCLUDE_FILE trace
 
-/* Tracepoints for VM eists */
-extern char *kvm_mips_exit_types_str[MAX_KVM_MIPS_EXIT_TYPES];
+/*
+ * Tracepoints for VM enters
+ */
+DECLARE_EVENT_CLASS(kvm_transition,
+       TP_PROTO(struct kvm_vcpu *vcpu),
+       TP_ARGS(vcpu),
+       TP_STRUCT__entry(
+               __field(unsigned long, pc)
+       ),
+
+       TP_fast_assign(
+               __entry->pc = vcpu->arch.pc;
+       ),
+
+       TP_printk("PC: 0x%08lx",
+                 __entry->pc)
+);
+
+DEFINE_EVENT(kvm_transition, kvm_enter,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_reenter,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_out,
+            TP_PROTO(struct kvm_vcpu *vcpu),
+            TP_ARGS(vcpu));
+
+/* The first 32 exit reasons correspond to Cause.ExcCode */
+#define KVM_TRACE_EXIT_INT              0
+#define KVM_TRACE_EXIT_TLBMOD           1
+#define KVM_TRACE_EXIT_TLBMISS_LD       2
+#define KVM_TRACE_EXIT_TLBMISS_ST       3
+#define KVM_TRACE_EXIT_ADDRERR_LD       4
+#define KVM_TRACE_EXIT_ADDRERR_ST       5
+#define KVM_TRACE_EXIT_SYSCALL          8
+#define KVM_TRACE_EXIT_BREAK_INST       9
+#define KVM_TRACE_EXIT_RESVD_INST      10
+#define KVM_TRACE_EXIT_COP_UNUSABLE    11
+#define KVM_TRACE_EXIT_TRAP_INST       13
+#define KVM_TRACE_EXIT_MSA_FPE         14
+#define KVM_TRACE_EXIT_FPE             15
+#define KVM_TRACE_EXIT_MSA_DISABLED    21
+/* Further exit reasons */
+#define KVM_TRACE_EXIT_WAIT            32
+#define KVM_TRACE_EXIT_CACHE           33
+#define KVM_TRACE_EXIT_SIGNAL          34
+
+/* Tracepoints for VM exits */
+#define kvm_trace_symbol_exit_types                            \
+       { KVM_TRACE_EXIT_INT,           "Interrupt" },          \
+       { KVM_TRACE_EXIT_TLBMOD,        "TLB Mod" },            \
+       { KVM_TRACE_EXIT_TLBMISS_LD,    "TLB Miss (LD)" },      \
+       { KVM_TRACE_EXIT_TLBMISS_ST,    "TLB Miss (ST)" },      \
+       { KVM_TRACE_EXIT_ADDRERR_LD,    "Address Error (LD)" }, \
+       { KVM_TRACE_EXIT_ADDRERR_ST,    "Address Err (ST)" },   \
+       { KVM_TRACE_EXIT_SYSCALL,       "System Call" },        \
+       { KVM_TRACE_EXIT_BREAK_INST,    "Break Inst" },         \
+       { KVM_TRACE_EXIT_RESVD_INST,    "Reserved Inst" },      \
+       { KVM_TRACE_EXIT_COP_UNUSABLE,  "COP0/1 Unusable" },    \
+       { KVM_TRACE_EXIT_TRAP_INST,     "Trap Inst" },          \
+       { KVM_TRACE_EXIT_MSA_FPE,       "MSA FPE" },            \
+       { KVM_TRACE_EXIT_FPE,           "FPE" },                \
+       { KVM_TRACE_EXIT_MSA_DISABLED,  "MSA Disabled" },       \
+       { KVM_TRACE_EXIT_WAIT,          "WAIT" },               \
+       { KVM_TRACE_EXIT_CACHE,         "CACHE" },              \
+       { KVM_TRACE_EXIT_SIGNAL,        "Signal" }
 
 TRACE_EVENT(kvm_exit,
            TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
@@ -34,10 +101,173 @@ TRACE_EVENT(kvm_exit,
            ),
 
            TP_printk("[%s]PC: 0x%08lx",
-                     kvm_mips_exit_types_str[__entry->reason],
+                     __print_symbolic(__entry->reason,
+                                      kvm_trace_symbol_exit_types),
                      __entry->pc)
 );
 
+#define KVM_TRACE_MFC0         0
+#define KVM_TRACE_MTC0         1
+#define KVM_TRACE_DMFC0                2
+#define KVM_TRACE_DMTC0                3
+#define KVM_TRACE_RDHWR                4
+
+#define KVM_TRACE_HWR_COP0     0
+#define KVM_TRACE_HWR_HWR      1
+
+#define KVM_TRACE_COP0(REG, SEL)       ((KVM_TRACE_HWR_COP0 << 8) |    \
+                                        ((REG) << 3) | (SEL))
+#define KVM_TRACE_HWR(REG, SEL)                ((KVM_TRACE_HWR_HWR  << 8) |    \
+                                        ((REG) << 3) | (SEL))
+
+#define kvm_trace_symbol_hwr_ops                               \
+       { KVM_TRACE_MFC0,               "MFC0" },               \
+       { KVM_TRACE_MTC0,               "MTC0" },               \
+       { KVM_TRACE_DMFC0,              "DMFC0" },              \
+       { KVM_TRACE_DMTC0,              "DMTC0" },              \
+       { KVM_TRACE_RDHWR,              "RDHWR" }
+
+#define kvm_trace_symbol_hwr_cop                               \
+       { KVM_TRACE_HWR_COP0,           "COP0" },               \
+       { KVM_TRACE_HWR_HWR,            "HWR" }
+
+#define kvm_trace_symbol_hwr_regs                              \
+       { KVM_TRACE_COP0( 0, 0),        "Index" },              \
+       { KVM_TRACE_COP0( 2, 0),        "EntryLo0" },           \
+       { KVM_TRACE_COP0( 3, 0),        "EntryLo1" },           \
+       { KVM_TRACE_COP0( 4, 0),        "Context" },            \
+       { KVM_TRACE_COP0( 4, 2),        "UserLocal" },          \
+       { KVM_TRACE_COP0( 5, 0),        "PageMask" },           \
+       { KVM_TRACE_COP0( 6, 0),        "Wired" },              \
+       { KVM_TRACE_COP0( 7, 0),        "HWREna" },             \
+       { KVM_TRACE_COP0( 8, 0),        "BadVAddr" },           \
+       { KVM_TRACE_COP0( 9, 0),        "Count" },              \
+       { KVM_TRACE_COP0(10, 0),        "EntryHi" },            \
+       { KVM_TRACE_COP0(11, 0),        "Compare" },            \
+       { KVM_TRACE_COP0(12, 0),        "Status" },             \
+       { KVM_TRACE_COP0(12, 1),        "IntCtl" },             \
+       { KVM_TRACE_COP0(12, 2),        "SRSCtl" },             \
+       { KVM_TRACE_COP0(13, 0),        "Cause" },              \
+       { KVM_TRACE_COP0(14, 0),        "EPC" },                \
+       { KVM_TRACE_COP0(15, 0),        "PRId" },               \
+       { KVM_TRACE_COP0(15, 1),        "EBase" },              \
+       { KVM_TRACE_COP0(16, 0),        "Config" },             \
+       { KVM_TRACE_COP0(16, 1),        "Config1" },            \
+       { KVM_TRACE_COP0(16, 2),        "Config2" },            \
+       { KVM_TRACE_COP0(16, 3),        "Config3" },            \
+       { KVM_TRACE_COP0(16, 4),        "Config4" },            \
+       { KVM_TRACE_COP0(16, 5),        "Config5" },            \
+       { KVM_TRACE_COP0(16, 7),        "Config7" },            \
+       { KVM_TRACE_COP0(26, 0),        "ECC" },                \
+       { KVM_TRACE_COP0(30, 0),        "ErrorEPC" },           \
+       { KVM_TRACE_COP0(31, 2),        "KScratch1" },          \
+       { KVM_TRACE_COP0(31, 3),        "KScratch2" },          \
+       { KVM_TRACE_COP0(31, 4),        "KScratch3" },          \
+       { KVM_TRACE_COP0(31, 5),        "KScratch4" },          \
+       { KVM_TRACE_COP0(31, 6),        "KScratch5" },          \
+       { KVM_TRACE_COP0(31, 7),        "KScratch6" },          \
+       { KVM_TRACE_HWR( 0, 0),         "CPUNum" },             \
+       { KVM_TRACE_HWR( 1, 0),         "SYNCI_Step" },         \
+       { KVM_TRACE_HWR( 2, 0),         "CC" },                 \
+       { KVM_TRACE_HWR( 3, 0),         "CCRes" },              \
+       { KVM_TRACE_HWR(29, 0),         "ULR" }
+
+TRACE_EVENT(kvm_hwr,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op, unsigned int reg,
+                    unsigned long val),
+           TP_ARGS(vcpu, op, reg, val),
+           TP_STRUCT__entry(
+                       __field(unsigned long, val)
+                       __field(u16, reg)
+                       __field(u8, op)
+           ),
+
+           TP_fast_assign(
+                       __entry->val = val;
+                       __entry->reg = reg;
+                       __entry->op = op;
+           ),
+
+           TP_printk("%s %s (%s:%u:%u) 0x%08lx",
+                     __print_symbolic(__entry->op,
+                                      kvm_trace_symbol_hwr_ops),
+                     __print_symbolic(__entry->reg,
+                                      kvm_trace_symbol_hwr_regs),
+                     __print_symbolic(__entry->reg >> 8,
+                                      kvm_trace_symbol_hwr_cop),
+                     (__entry->reg >> 3) & 0x1f,
+                     __entry->reg & 0x7,
+                     __entry->val)
+);
+
+#define KVM_TRACE_AUX_RESTORE          0
+#define KVM_TRACE_AUX_SAVE             1
+#define KVM_TRACE_AUX_ENABLE           2
+#define KVM_TRACE_AUX_DISABLE          3
+#define KVM_TRACE_AUX_DISCARD          4
+
+#define KVM_TRACE_AUX_FPU              1
+#define KVM_TRACE_AUX_MSA              2
+#define KVM_TRACE_AUX_FPU_MSA          3
+
+#define kvm_trace_symbol_aux_op                \
+       { KVM_TRACE_AUX_RESTORE, "restore" },   \
+       { KVM_TRACE_AUX_SAVE,    "save" },      \
+       { KVM_TRACE_AUX_ENABLE,  "enable" },    \
+       { KVM_TRACE_AUX_DISABLE, "disable" },   \
+       { KVM_TRACE_AUX_DISCARD, "discard" }
+
+#define kvm_trace_symbol_aux_state             \
+       { KVM_TRACE_AUX_FPU,     "FPU" },       \
+       { KVM_TRACE_AUX_MSA,     "MSA" },       \
+       { KVM_TRACE_AUX_FPU_MSA, "FPU & MSA" }
+
+TRACE_EVENT(kvm_aux,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
+                    unsigned int state),
+           TP_ARGS(vcpu, op, state),
+           TP_STRUCT__entry(
+                       __field(unsigned long, pc)
+                       __field(u8, op)
+                       __field(u8, state)
+           ),
+
+           TP_fast_assign(
+                       __entry->pc = vcpu->arch.pc;
+                       __entry->op = op;
+                       __entry->state = state;
+           ),
+
+           TP_printk("%s %s PC: 0x%08lx",
+                     __print_symbolic(__entry->op,
+                                      kvm_trace_symbol_aux_op),
+                     __print_symbolic(__entry->state,
+                                      kvm_trace_symbol_aux_state),
+                     __entry->pc)
+);
+
+TRACE_EVENT(kvm_asid_change,
+           TP_PROTO(struct kvm_vcpu *vcpu, unsigned int old_asid,
+                    unsigned int new_asid),
+           TP_ARGS(vcpu, old_asid, new_asid),
+           TP_STRUCT__entry(
+                       __field(unsigned long, pc)
+                       __field(u8, old_asid)
+                       __field(u8, new_asid)
+           ),
+
+           TP_fast_assign(
+                       __entry->pc = vcpu->arch.pc;
+                       __entry->old_asid = old_asid;
+                       __entry->new_asid = new_asid;
+           ),
+
+           TP_printk("PC: 0x%08lx old: 0x%02x new: 0x%02x",
+                     __entry->pc,
+                     __entry->old_asid,
+                     __entry->new_asid)
+);
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
index 6ba0faf..0915539 100644 (file)
@@ -21,7 +21,7 @@
 static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva)
 {
        gpa_t gpa;
-       uint32_t kseg = KSEGX(gva);
+       gva_t kseg = KSEGX(gva);
 
        if ((kseg == CKSEG0) || (kseg == CKSEG1))
                gpa = CPHYSADDR(gva);
@@ -40,8 +40,8 @@ static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -87,15 +87,15 @@ static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
        if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
            || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
-               kvm_debug("USER/KSEG23 ADDR TLB MOD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
+               kvm_debug("USER/KSEG23 ADDR TLB MOD fault: cause %#x, PC: %p, BadVaddr: %#lx\n",
                          cause, opc, badvaddr);
                er = kvm_mips_handle_tlbmod(cause, opc, run, vcpu);
 
@@ -111,14 +111,14 @@ static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
                 * when we are not using HIGHMEM. Need to address this in a
                 * HIGHMEM kernel
                 */
-               kvm_err("TLB MOD fault not handled, cause %#lx, PC: %p, BadVaddr: %#lx\n",
+               kvm_err("TLB MOD fault not handled, cause %#x, PC: %p, BadVaddr: %#lx\n",
                        cause, opc, badvaddr);
                kvm_mips_dump_host_tlbs();
                kvm_arch_vcpu_dump_regs(vcpu);
                run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                ret = RESUME_HOST;
        } else {
-               kvm_err("Illegal TLB Mod fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
+               kvm_err("Illegal TLB Mod fault address , cause %#x, PC: %p, BadVaddr: %#lx\n",
                        cause, opc, badvaddr);
                kvm_mips_dump_host_tlbs();
                kvm_arch_vcpu_dump_regs(vcpu);
@@ -128,59 +128,12 @@ static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu)
        return ret;
 }
 
-static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu)
-{
-       struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
-       enum emulation_result er = EMULATE_DONE;
-       int ret = RESUME_GUEST;
-
-       if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR)
-           && KVM_GUEST_KERNEL_MODE(vcpu)) {
-               if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) {
-                       run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-                       ret = RESUME_HOST;
-               }
-       } else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
-                  || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
-               kvm_debug("USER ADDR TLB LD fault: cause %#lx, PC: %p, BadVaddr: %#lx\n",
-                         cause, opc, badvaddr);
-               er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu);
-               if (er == EMULATE_DONE)
-                       ret = RESUME_GUEST;
-               else {
-                       run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-                       ret = RESUME_HOST;
-               }
-       } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
-               /*
-                * All KSEG0 faults are handled by KVM, as the guest kernel does
-                * not expect to ever get them
-                */
-               if (kvm_mips_handle_kseg0_tlb_fault
-                   (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
-                       run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-                       ret = RESUME_HOST;
-               }
-       } else {
-               kvm_err("Illegal TLB LD fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
-                       cause, opc, badvaddr);
-               kvm_mips_dump_host_tlbs();
-               kvm_arch_vcpu_dump_regs(vcpu);
-               run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-               ret = RESUME_HOST;
-       }
-       return ret;
-}
-
-static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
+static int kvm_trap_emul_handle_tlb_miss(struct kvm_vcpu *vcpu, bool store)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -192,8 +145,8 @@ static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
                }
        } else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0
                   || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) {
-               kvm_debug("USER ADDR TLB ST fault: PC: %#lx, BadVaddr: %#lx\n",
-                         vcpu->arch.pc, badvaddr);
+               kvm_debug("USER ADDR TLB %s fault: cause %#x, PC: %p, BadVaddr: %#lx\n",
+                         store ? "ST" : "LD", cause, opc, badvaddr);
 
                /*
                 * User Address (UA) fault, this could happen if
@@ -213,14 +166,18 @@ static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
                        ret = RESUME_HOST;
                }
        } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) {
+               /*
+                * All KSEG0 faults are handled by KVM, as the guest kernel does
+                * not expect to ever get them
+                */
                if (kvm_mips_handle_kseg0_tlb_fault
                    (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) {
                        run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                        ret = RESUME_HOST;
                }
        } else {
-               kvm_err("Illegal TLB ST fault address , cause %#lx, PC: %p, BadVaddr: %#lx\n",
-                       cause, opc, badvaddr);
+               kvm_err("Illegal TLB %s fault address , cause %#x, PC: %p, BadVaddr: %#lx\n",
+                       store ? "ST" : "LD", cause, opc, badvaddr);
                kvm_mips_dump_host_tlbs();
                kvm_arch_vcpu_dump_regs(vcpu);
                run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
@@ -229,12 +186,22 @@ static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
        return ret;
 }
 
+static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu)
+{
+       return kvm_trap_emul_handle_tlb_miss(vcpu, true);
+}
+
+static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu)
+{
+       return kvm_trap_emul_handle_tlb_miss(vcpu, false);
+}
+
 static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -251,7 +218,7 @@ static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
                        ret = RESUME_HOST;
                }
        } else {
-               kvm_err("Address Error (STORE): cause %#lx, PC: %p, BadVaddr: %#lx\n",
+               kvm_err("Address Error (STORE): cause %#x, PC: %p, BadVaddr: %#lx\n",
                        cause, opc, badvaddr);
                run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                ret = RESUME_HOST;
@@ -262,9 +229,9 @@ static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
        unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -280,7 +247,7 @@ static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
                        ret = RESUME_HOST;
                }
        } else {
-               kvm_err("Address Error (LOAD): cause %#lx, PC: %p, BadVaddr: %#lx\n",
+               kvm_err("Address Error (LOAD): cause %#x, PC: %p, BadVaddr: %#lx\n",
                        cause, opc, badvaddr);
                run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                ret = RESUME_HOST;
@@ -292,8 +259,8 @@ static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -310,8 +277,8 @@ static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -328,8 +295,8 @@ static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -346,8 +313,8 @@ static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *)vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -364,8 +331,8 @@ static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_msa_fpe(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *)vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -382,8 +349,8 @@ static int kvm_trap_emul_handle_msa_fpe(struct kvm_vcpu *vcpu)
 static int kvm_trap_emul_handle_fpe(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *)vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -407,8 +374,8 @@ static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
        struct kvm_run *run = vcpu->run;
-       uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc;
-       unsigned long cause = vcpu->arch.host_cp0_cause;
+       u32 __user *opc = (u32 __user *) vcpu->arch.pc;
+       u32 cause = vcpu->arch.host_cp0_cause;
        enum emulation_result er = EMULATE_DONE;
        int ret = RESUME_GUEST;
 
@@ -451,24 +418,41 @@ static int kvm_trap_emul_vm_init(struct kvm *kvm)
 
 static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu)
 {
+       vcpu->arch.kscratch_enabled = 0xfc;
+
        return 0;
 }
 
 static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        struct mips_coproc *cop0 = vcpu->arch.cop0;
-       uint32_t config1;
+       u32 config, config1;
        int vcpu_id = vcpu->vcpu_id;
 
        /*
         * Arch specific stuff, set up config registers properly so that the
-        * guest will come up as expected, for now we simulate a MIPS 24kc
+        * guest will come up as expected
         */
+#ifndef CONFIG_CPU_MIPSR6
+       /* r2-r5, simulate a MIPS 24kc */
        kvm_write_c0_guest_prid(cop0, 0x00019300);
-       /* Have config1, Cacheable, noncoherent, write-back, write allocate */
-       kvm_write_c0_guest_config(cop0, MIPS_CONF_M | (0x3 << CP0C0_K0) |
-                                 (0x1 << CP0C0_AR) |
-                                 (MMU_TYPE_R4000 << CP0C0_MT));
+#else
+       /* r6+, simulate a generic QEMU machine */
+       kvm_write_c0_guest_prid(cop0, 0x00010000);
+#endif
+       /*
+        * Have config1, Cacheable, noncoherent, write-back, write allocate.
+        * Endianness, arch revision & virtually tagged icache should match
+        * host.
+        */
+       config = read_c0_config() & MIPS_CONF_AR;
+       config |= MIPS_CONF_M | CONF_CM_CACHABLE_NONCOHERENT | MIPS_CONF_MT_TLB;
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       config |= CONF_BE;
+#endif
+       if (cpu_has_vtag_icache)
+               config |= MIPS_CONF_VI;
+       kvm_write_c0_guest_config(cop0, config);
 
        /* Read the cache characteristics from the host Config1 Register */
        config1 = (read_c0_config1() & ~0x7f);
@@ -478,9 +462,8 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
        config1 |= ((KVM_MIPS_GUEST_TLB_SIZE - 1) << 25);
 
        /* We unset some bits that we aren't emulating */
-       config1 &=
-           ~((1 << CP0C1_C2) | (1 << CP0C1_MD) | (1 << CP0C1_PC) |
-             (1 << CP0C1_WR) | (1 << CP0C1_CA));
+       config1 &= ~(MIPS_CONF1_C2 | MIPS_CONF1_MD | MIPS_CONF1_PC |
+                    MIPS_CONF1_WR | MIPS_CONF1_CA);
        kvm_write_c0_guest_config1(cop0, config1);
 
        /* Have config3, no tertiary/secondary caches implemented */
@@ -511,6 +494,17 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static unsigned long kvm_trap_emul_num_regs(struct kvm_vcpu *vcpu)
+{
+       return 0;
+}
+
+static int kvm_trap_emul_copy_reg_indices(struct kvm_vcpu *vcpu,
+                                         u64 __user *indices)
+{
+       return 0;
+}
+
 static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
                                     const struct kvm_one_reg *reg,
                                     s64 *v)
@@ -660,6 +654,8 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {
        .dequeue_io_int = kvm_mips_dequeue_io_int_cb,
        .irq_deliver = kvm_mips_irq_deliver_cb,
        .irq_clear = kvm_mips_irq_clear_cb,
+       .num_regs = kvm_trap_emul_num_regs,
+       .copy_reg_indices = kvm_trap_emul_copy_reg_indices,
        .get_one_reg = kvm_trap_emul_get_one_reg,
        .set_one_reg = kvm_trap_emul_set_one_reg,
        .vcpu_get_regs = kvm_trap_emul_vcpu_get_regs,
index ff17669..8ac0e59 100644 (file)
@@ -66,7 +66,7 @@ int gic_present;
 #endif
 
 static int exin_avail;
-static struct resource ltq_eiu_irq[MAX_EIU];
+static u32 ltq_eiu_irq[MAX_EIU];
 static void __iomem *ltq_icu_membase[MAX_IM];
 static void __iomem *ltq_eiu_membase;
 static struct irq_domain *ltq_domain;
@@ -75,7 +75,7 @@ static int ltq_perfcount_irq;
 int ltq_eiu_get_irq(int exin)
 {
        if (exin < exin_avail)
-               return ltq_eiu_irq[exin].start;
+               return ltq_eiu_irq[exin];
        return -1;
 }
 
@@ -125,8 +125,8 @@ static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
 {
        int i;
 
-       for (i = 0; i < MAX_EIU; i++) {
-               if (d->hwirq == ltq_eiu_irq[i].start) {
+       for (i = 0; i < exin_avail; i++) {
+               if (d->hwirq == ltq_eiu_irq[i]) {
                        int val = 0;
                        int edge = 0;
 
@@ -173,8 +173,8 @@ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
        int i;
 
        ltq_enable_irq(d);
-       for (i = 0; i < MAX_EIU; i++) {
-               if (d->hwirq == ltq_eiu_irq[i].start) {
+       for (i = 0; i < exin_avail; i++) {
+               if (d->hwirq == ltq_eiu_irq[i]) {
                        /* by default we are low level triggered */
                        ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
                        /* clear all pending */
@@ -195,8 +195,8 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
        int i;
 
        ltq_disable_irq(d);
-       for (i = 0; i < MAX_EIU; i++) {
-               if (d->hwirq == ltq_eiu_irq[i].start) {
+       for (i = 0; i < exin_avail; i++) {
+               if (d->hwirq == ltq_eiu_irq[i]) {
                        /* disable */
                        ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
                                LTQ_EIU_EXIN_INEN);
@@ -206,7 +206,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
 }
 
 static struct irq_chip ltq_irq_type = {
-       "icu",
+       .name = "icu",
        .irq_enable = ltq_enable_irq,
        .irq_disable = ltq_disable_irq,
        .irq_unmask = ltq_enable_irq,
@@ -216,7 +216,7 @@ static struct irq_chip ltq_irq_type = {
 };
 
 static struct irq_chip ltq_eiu_type = {
-       "eiu",
+       .name = "eiu",
        .irq_startup = ltq_startup_eiu_irq,
        .irq_shutdown = ltq_shutdown_eiu_irq,
        .irq_enable = ltq_enable_irq,
@@ -341,10 +341,10 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
                return 0;
 
        for (i = 0; i < exin_avail; i++)
-               if (hw == ltq_eiu_irq[i].start)
+               if (hw == ltq_eiu_irq[i])
                        chip = &ltq_eiu_type;
 
-       irq_set_chip_and_handler(hw, chip, handle_level_irq);
+       irq_set_chip_and_handler(irq, chip, handle_level_irq);
 
        return 0;
 }
@@ -439,14 +439,15 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
        eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
        if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
                /* find out how many external irq sources we have */
-               exin_avail = of_irq_count(eiu_node);
+               exin_avail = of_property_count_u32_elems(eiu_node,
+                                                        "lantiq,eiu-irqs");
 
                if (exin_avail > MAX_EIU)
                        exin_avail = MAX_EIU;
 
-               ret = of_irq_to_resource_table(eiu_node,
+               ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs",
                                                ltq_eiu_irq, exin_avail);
-               if (ret != exin_avail)
+               if (ret)
                        panic("failed to load external irq resources");
 
                if (!request_mem_region(res.start, resource_size(&res),
index 5f693ac..4cbb000 100644 (file)
@@ -74,8 +74,8 @@ void __init plat_mem_setup(void)
 
        set_io_port_base((unsigned long) KSEG1);
 
-       if (fw_arg0 == -2) /* UHI interface */
-               dtb = (void *)fw_arg1;
+       if (fw_passed_dtb) /* UHI interface */
+               dtb = (void *)fw_passed_dtb;
        else if (__dtb_start != __dtb_end)
                dtb = (void *)__dtb_start;
        else
index 4ffa6fc..1a80b6f 100644 (file)
@@ -10,7 +10,7 @@
 #include <dma-coherence.h>
 
 static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -41,7 +41,7 @@ static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
 }
 
 static void loongson_dma_free_coherent(struct device *dev, size_t size,
-               void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+               void *vaddr, dma_addr_t dma_handle, unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_handle);
 }
@@ -49,7 +49,7 @@ static void loongson_dma_free_coherent(struct device *dev, size_t size,
 static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page,
                                unsigned long offset, size_t size,
                                enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
                                        dir, attrs);
@@ -59,9 +59,9 @@ static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page,
 
 static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg,
                                int nents, enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
-       int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, NULL);
+       int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, 0);
        mb();
 
        return r;
index 249039a..4788bea 100644 (file)
@@ -13,8 +13,8 @@
 #define SMBUS_PCI_REG64                0x64
 #define SMBUS_PCI_REGB4                0xb4
 
-#define HPET_MIN_CYCLES                64
-#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1))
+#define HPET_MIN_CYCLES                16
+#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES * 12)
 
 static DEFINE_SPINLOCK(hpet_lock);
 DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
@@ -157,14 +157,14 @@ static int hpet_tick_resume(struct clock_event_device *evt)
 static int hpet_next_event(unsigned long delta,
                struct clock_event_device *evt)
 {
-       unsigned int cnt;
-       int res;
+       u32 cnt;
+       s32 res;
 
        cnt = hpet_read(HPET_COUNTER);
-       cnt += delta;
+       cnt += (u32) delta;
        hpet_write(HPET_T0_CMP, cnt);
 
-       res = (int)(cnt - hpet_read(HPET_COUNTER));
+       res = (s32)(cnt - hpet_read(HPET_COUNTER));
 
        return res < HPET_MIN_CYCLES ? -ETIME : 0;
 }
@@ -230,7 +230,7 @@ void __init setup_hpet_timer(void)
 
        cd = &per_cpu(hpet_clockevent_device, cpu);
        cd->name = "hpet";
-       cd->rating = 320;
+       cd->rating = 100;
        cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
        cd->set_state_shutdown = hpet_set_state_shutdown;
        cd->set_state_periodic = hpet_set_state_periodic;
index e59759a..2fec6f7 100644 (file)
@@ -417,6 +417,7 @@ static int loongson3_cpu_disable(void)
                return -EBUSY;
 
        set_cpu_online(cpu, false);
+       calculate_cpu_foreign_map();
        cpumask_clear_cpu(cpu, &cpu_callin_map);
        local_irq_save(flags);
        fixup_irqs();
index d96e912..36775d2 100644 (file)
@@ -434,8 +434,8 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
  * a single subroutine should be used across both
  * modules.
  */
-static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
-                        unsigned long *contpc)
+int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+                 unsigned long *contpc)
 {
        union mips_instruction insn = (union mips_instruction)dec_insn.insn;
        unsigned int fcr31;
@@ -627,8 +627,8 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-       case cbcond0_op:
-       case cbcond1_op:
+       case pop10_op:
+       case pop30_op:
                if (!cpu_has_mips_r6)
                        break;
                if (insn.i_format.rt && !insn.i_format.rs)
@@ -683,14 +683,14 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        dec_insn.next_pc_inc;
 
                return 1;
-       case beqzcjic_op:
+       case pop66_op:
                if (!cpu_has_mips_r6)
                        break;
                *contpc = regs->cp0_epc + dec_insn.pc_inc +
                        dec_insn.next_pc_inc;
 
                return 1;
-       case bnezcjialc_op:
+       case pop76_op:
                if (!cpu_has_mips_r6)
                        break;
                if (!insn.i_format.rs)
@@ -784,10 +784,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
  */
 static inline int cop1_64bit(struct pt_regs *xcp)
 {
-       if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32))
+       if (IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_MIPS32_O32))
                return 1;
-       else if (config_enabled(CONFIG_32BIT) &&
-                !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
+       else if (IS_ENABLED(CONFIG_32BIT) &&
+                !IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT))
                return 0;
 
        return !test_thread_flag(TIF_32BIT_FPREGS);
@@ -1268,7 +1268,7 @@ branch_common:
                                                 * instruction in the dslot.
                                                 */
                                                sig = mips_dsemul(xcp, ir,
-                                                                 contpc);
+                                                                 bcpc, contpc);
                                                if (sig < 0)
                                                        break;
                                                if (sig)
@@ -1323,7 +1323,7 @@ branch_common:
                                 * Single step the non-cp1
                                 * instruction in the dslot
                                 */
-                               sig = mips_dsemul(xcp, ir, contpc);
+                               sig = mips_dsemul(xcp, ir, bcpc, contpc);
                                if (sig < 0)
                                        break;
                                if (sig)
index 4707488..72a4642 100644 (file)
@@ -1,3 +1,6 @@
+#include <linux/err.h>
+#include <linux/slab.h>
+
 #include <asm/branch.h>
 #include <asm/cacheflush.h>
 #include <asm/fpu_emulator.h>
 #include <asm/mipsregs.h>
 #include <asm/uaccess.h>
 
-#include "ieee754.h"
-
-/*
- * Emulate the arbitrary instruction ir at xcp->cp0_epc.  Required when
- * we have to emulate the instruction in a COP1 branch delay slot.  Do
- * not change cp0_epc due to the instruction
+/**
+ * struct emuframe - The 'emulation' frame structure
+ * @emul:      The instruction to 'emulate'.
+ * @badinst:   A break instruction to cause a return to the kernel.
  *
- * According to the spec:
- * 1) it shouldn't be a branch :-)
- * 2) it can be a COP instruction :-(
- * 3) if we are tring to run a protected memory space we must take
- *    special care on memory access instructions :-(
- */
-
-/*
- * "Trampoline" return routine to catch exception following
- *  execution of delay-slot instruction execution.
+ * This structure defines the frames placed within the delay slot emulation
+ * page in response to a call to mips_dsemul(). Each thread may be allocated
+ * only one frame at any given time. The kernel stores within it the
+ * instruction to be 'emulated' followed by a break instruction, then
+ * executes the frame in user mode. The break causes a trap to the kernel
+ * which leads to do_dsemulret() being called unless the instruction in
+ * @emul causes a trap itself, is a branch, or a signal is delivered to
+ * the thread. In these cases the allocated frame will either be reused by
+ * a subsequent delay slot 'emulation', or be freed during signal delivery or
+ * upon thread exit.
+ *
+ * This approach is used because:
+ *
+ * - Actually emulating all instructions isn't feasible. We would need to
+ *   be able to handle instructions from all revisions of the MIPS ISA,
+ *   all ASEs & all vendor instruction set extensions. This would be a
+ *   whole lot of work & continual maintenance burden as new instructions
+ *   are introduced, and in the case of some vendor extensions may not
+ *   even be possible. Thus we need to take the approach of actually
+ *   executing the instruction.
+ *
+ * - We must execute the instruction within user context. If we were to
+ *   execute the instruction in kernel mode then it would have access to
+ *   kernel resources without very careful checks, leaving us with a
+ *   high potential for security or stability issues to arise.
+ *
+ * - We used to place the frame on the users stack, but this requires
+ *   that the stack be executable. This is bad for security so the
+ *   per-process page is now used instead.
+ *
+ * - The instruction in @emul may be something entirely invalid for a
+ *   delay slot. The user may (intentionally or otherwise) place a branch
+ *   in a delay slot, or a kernel mode instruction, or something else
+ *   which generates an exception. Thus we can't rely upon the break in
+ *   @badinst always being hit. For this reason we track the index of the
+ *   frame allocated to each thread, allowing us to clean it up at later
+ *   points such as signal delivery or thread exit.
+ *
+ * - The user may generate a fake struct emuframe if they wish, invoking
+ *   the BRK_MEMU break instruction themselves. We must therefore not
+ *   trust that BRK_MEMU means there's actually a valid frame allocated
+ *   to the thread, and must not allow the user to do anything they
+ *   couldn't already.
  */
-
 struct emuframe {
        mips_instruction        emul;
        mips_instruction        badinst;
-       mips_instruction        cookie;
-       unsigned long           epc;
 };
 
-/*
- * Set up an emulation frame for instruction IR, from a delay slot of
- * a branch jumping to CPC.  Return 0 if successful, -1 if no emulation
- * required, otherwise a signal number causing a frame setup failure.
- */
-int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
+static const int emupage_frame_count = PAGE_SIZE / sizeof(struct emuframe);
+
+static inline __user struct emuframe *dsemul_page(void)
+{
+       return (__user struct emuframe *)STACK_TOP;
+}
+
+static int alloc_emuframe(void)
+{
+       mm_context_t *mm_ctx = &current->mm->context;
+       int idx;
+
+retry:
+       spin_lock(&mm_ctx->bd_emupage_lock);
+
+       /* Ensure we have an allocation bitmap */
+       if (!mm_ctx->bd_emupage_allocmap) {
+               mm_ctx->bd_emupage_allocmap =
+                       kcalloc(BITS_TO_LONGS(emupage_frame_count),
+                                             sizeof(unsigned long),
+                               GFP_ATOMIC);
+
+               if (!mm_ctx->bd_emupage_allocmap) {
+                       idx = BD_EMUFRAME_NONE;
+                       goto out_unlock;
+               }
+       }
+
+       /* Attempt to allocate a single bit/frame */
+       idx = bitmap_find_free_region(mm_ctx->bd_emupage_allocmap,
+                                     emupage_frame_count, 0);
+       if (idx < 0) {
+               /*
+                * Failed to allocate a frame. We'll wait until one becomes
+                * available. We unlock the page so that other threads actually
+                * get the opportunity to free their frames, which means
+                * technically the result of bitmap_full may be incorrect.
+                * However the worst case is that we repeat all this and end up
+                * back here again.
+                */
+               spin_unlock(&mm_ctx->bd_emupage_lock);
+               if (!wait_event_killable(mm_ctx->bd_emupage_queue,
+                       !bitmap_full(mm_ctx->bd_emupage_allocmap,
+                                    emupage_frame_count)))
+                       goto retry;
+
+               /* Received a fatal signal - just give in */
+               return BD_EMUFRAME_NONE;
+       }
+
+       /* Success! */
+       pr_debug("allocate emuframe %d to %d\n", idx, current->pid);
+out_unlock:
+       spin_unlock(&mm_ctx->bd_emupage_lock);
+       return idx;
+}
+
+static void free_emuframe(int idx, struct mm_struct *mm)
+{
+       mm_context_t *mm_ctx = &mm->context;
+
+       spin_lock(&mm_ctx->bd_emupage_lock);
+
+       pr_debug("free emuframe %d from %d\n", idx, current->pid);
+       bitmap_clear(mm_ctx->bd_emupage_allocmap, idx, 1);
+
+       /* If some thread is waiting for a frame, now's its chance */
+       wake_up(&mm_ctx->bd_emupage_queue);
+
+       spin_unlock(&mm_ctx->bd_emupage_lock);
+}
+
+static bool within_emuframe(struct pt_regs *regs)
+{
+       unsigned long base = (unsigned long)dsemul_page();
+
+       if (regs->cp0_epc < base)
+               return false;
+       if (regs->cp0_epc >= (base + PAGE_SIZE))
+               return false;
+
+       return true;
+}
+
+bool dsemul_thread_cleanup(struct task_struct *tsk)
+{
+       int fr_idx;
+
+       /* Clear any allocated frame, retrieving its index */
+       fr_idx = atomic_xchg(&tsk->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+
+       /* If no frame was allocated, we're done */
+       if (fr_idx == BD_EMUFRAME_NONE)
+               return false;
+
+       task_lock(tsk);
+
+       /* Free the frame that this thread had allocated */
+       if (tsk->mm)
+               free_emuframe(fr_idx, tsk->mm);
+
+       task_unlock(tsk);
+       return true;
+}
+
+bool dsemul_thread_rollback(struct pt_regs *regs)
+{
+       struct emuframe __user *fr;
+       int fr_idx;
+
+       /* Do nothing if we're not executing from a frame */
+       if (!within_emuframe(regs))
+               return false;
+
+       /* Find the frame being executed */
+       fr_idx = atomic_read(&current->thread.bd_emu_frame);
+       if (fr_idx == BD_EMUFRAME_NONE)
+               return false;
+       fr = &dsemul_page()[fr_idx];
+
+       /*
+        * If the PC is at the emul instruction, roll back to the branch. If
+        * PC is at the badinst (break) instruction, we've already emulated the
+        * instruction so progress to the continue PC. If it's anything else
+        * then something is amiss & the user has branched into some other area
+        * of the emupage - we'll free the allocated frame anyway.
+        */
+       if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->emul)
+               regs->cp0_epc = current->thread.bd_emu_branch_pc;
+       else if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->badinst)
+               regs->cp0_epc = current->thread.bd_emu_cont_pc;
+
+       atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+       free_emuframe(fr_idx, current->mm);
+       return true;
+}
+
+void dsemul_mm_cleanup(struct mm_struct *mm)
+{
+       mm_context_t *mm_ctx = &mm->context;
+
+       kfree(mm_ctx->bd_emupage_allocmap);
+}
+
+int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
+               unsigned long branch_pc, unsigned long cont_pc)
 {
        int isa16 = get_isa16_mode(regs->cp0_epc);
        mips_instruction break_math;
        struct emuframe __user *fr;
-       int err;
+       int err, fr_idx;
 
        /* NOP is easy */
        if (ir == 0)
@@ -68,30 +239,20 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
                }
        }
 
-       pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc);
+       pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc);
 
-       /*
-        * The strategy is to push the instruction onto the user stack
-        * and put a trap after it which we can catch and jump to
-        * the required address any alternative apart from full
-        * instruction emulation!!.
-        *
-        * Algorithmics used a system call instruction, and
-        * borrowed that vector.  MIPS/Linux version is a bit
-        * more heavyweight in the interests of portability and
-        * multiprocessor support.  For Linux we use a BREAK 514
-        * instruction causing a breakpoint exception.
-        */
-       break_math = BREAK_MATH(isa16);
-
-       /* Ensure that the two instructions are in the same cache line */
-       fr = (struct emuframe __user *)
-               ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
-
-       /* Verify that the stack pointer is not completely insane */
-       if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
+       /* Allocate a frame if we don't already have one */
+       fr_idx = atomic_read(&current->thread.bd_emu_frame);
+       if (fr_idx == BD_EMUFRAME_NONE)
+               fr_idx = alloc_emuframe();
+       if (fr_idx == BD_EMUFRAME_NONE)
                return SIGBUS;
+       fr = &dsemul_page()[fr_idx];
+
+       /* Retrieve the appropriately encoded break instruction */
+       break_math = BREAK_MATH(isa16);
 
+       /* Write the instructions to the frame */
        if (isa16) {
                err = __put_user(ir >> 16,
                                 (u16 __user *)(&fr->emul));
@@ -106,84 +267,36 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
                err |= __put_user(break_math, &fr->badinst);
        }
 
-       err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
-       err |= __put_user(cpc, &fr->epc);
-
        if (unlikely(err)) {
                MIPS_FPU_EMU_INC_STATS(errors);
+               free_emuframe(fr_idx, current->mm);
                return SIGBUS;
        }
 
+       /* Record the PC of the branch, PC to continue from & frame index */
+       current->thread.bd_emu_branch_pc = branch_pc;
+       current->thread.bd_emu_cont_pc = cont_pc;
+       atomic_set(&current->thread.bd_emu_frame, fr_idx);
+
+       /* Change user register context to execute the frame */
        regs->cp0_epc = (unsigned long)&fr->emul | isa16;
 
+       /* Ensure the icache observes our newly written frame */
        flush_cache_sigtramp((unsigned long)&fr->emul);
 
        return 0;
 }
 
-int do_dsemulret(struct pt_regs *xcp)
+bool do_dsemulret(struct pt_regs *xcp)
 {
-       int isa16 = get_isa16_mode(xcp->cp0_epc);
-       struct emuframe __user *fr;
-       unsigned long epc;
-       u32 insn, cookie;
-       int err = 0;
-       u16 instr[2];
-
-       fr = (struct emuframe __user *)
-               (msk_isa16_mode(xcp->cp0_epc) - sizeof(mips_instruction));
-
-       /*
-        * If we can't even access the area, something is very wrong, but we'll
-        * leave that to the default handling
-        */
-       if (!access_ok(VERIFY_READ, fr, sizeof(struct emuframe)))
-               return 0;
-
-       /*
-        * Do some sanity checking on the stackframe:
-        *
-        *  - Is the instruction pointed to by the EPC an BREAK_MATH?
-        *  - Is the following memory word the BD_COOKIE?
-        */
-       if (isa16) {
-               err = __get_user(instr[0],
-                                (u16 __user *)(&fr->badinst));
-               err |= __get_user(instr[1],
-                                 (u16 __user *)((long)(&fr->badinst) + 2));
-               insn = (instr[0] << 16) | instr[1];
-       } else {
-               err = __get_user(insn, &fr->badinst);
-       }
-       err |= __get_user(cookie, &fr->cookie);
-
-       if (unlikely(err ||
-                    insn != BREAK_MATH(isa16) || cookie != BD_COOKIE)) {
+       /* Cleanup the allocated frame, returning if there wasn't one */
+       if (!dsemul_thread_cleanup(current)) {
                MIPS_FPU_EMU_INC_STATS(errors);
-               return 0;
-       }
-
-       /*
-        * At this point, we are satisfied that it's a BD emulation trap.  Yes,
-        * a user might have deliberately put two malformed and useless
-        * instructions in a row in his program, in which case he's in for a
-        * nasty surprise - the next instruction will be treated as a
-        * continuation address!  Alas, this seems to be the only way that we
-        * can handle signals, recursion, and longjmps() in the context of
-        * emulating the branch delay instruction.
-        */
-
-       pr_debug("dsemulret\n");
-
-       if (__get_user(epc, &fr->epc)) {                /* Saved EPC */
-               /* This is not a good situation to be in */
-               force_sig(SIGBUS, current);
-
-               return 0;
+               return false;
        }
 
        /* Set EPC to return to post-branch instruction */
-       xcp->cp0_epc = epc;
-       MIPS_FPU_EMU_INC_STATS(ds_emul);
-       return 1;
+       xcp->cp0_epc = current->thread.bd_emu_cont_pc;
+       pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc);
+       return true;
 }
index ef7f925..cd72805 100644 (file)
 #include <asm/dma-coherence.h>
 #include <asm/mips-cm.h>
 
+/*
+ * Bits describing what cache ops an SMP callback function may perform.
+ *
+ * R4K_HIT   - Virtual user or kernel address based cache operations. The
+ *             active_mm must be checked before using user addresses, falling
+ *             back to kmap.
+ * R4K_INDEX - Index based cache operations.
+ */
+
+#define R4K_HIT                BIT(0)
+#define R4K_INDEX      BIT(1)
+
+/**
+ * r4k_op_needs_ipi() - Decide if a cache op needs to be done on every core.
+ * @type:      Type of cache operations (R4K_HIT or R4K_INDEX).
+ *
+ * Decides whether a cache op needs to be performed on every core in the system.
+ * This may change depending on the @type of cache operation, as well as the set
+ * of online CPUs, so preemption should be disabled by the caller to prevent CPU
+ * hotplug from changing the result.
+ *
+ * Returns:    1 if the cache operation @type should be done on every core in
+ *             the system.
+ *             0 if the cache operation @type is globalized and only needs to
+ *             be performed on a simple CPU.
+ */
+static inline bool r4k_op_needs_ipi(unsigned int type)
+{
+       /* The MIPS Coherence Manager (CM) globalizes address-based cache ops */
+       if (type == R4K_HIT && mips_cm_present())
+               return false;
+
+       /*
+        * Hardware doesn't globalize the required cache ops, so SMP calls may
+        * be needed, but only if there are foreign CPUs (non-siblings with
+        * separate caches).
+        */
+       /* cpu_foreign_map[] undeclared when !CONFIG_SMP */
+#ifdef CONFIG_SMP
+       return !cpumask_empty(&cpu_foreign_map[0]);
+#else
+       return false;
+#endif
+}
+
 /*
  * Special Variant of smp_call_function for use by cache functions:
  *
  *    primary cache.
  *  o doesn't disable interrupts on the local CPU
  */
-static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
+static inline void r4k_on_each_cpu(unsigned int type,
+                                  void (*func)(void *info), void *info)
 {
        preempt_disable();
-
-       /*
-        * The Coherent Manager propagates address-based cache ops to other
-        * cores but not index-based ops. However, r4k_on_each_cpu is used
-        * in both cases so there is no easy way to tell what kind of op is
-        * executed to the other cores. The best we can probably do is
-        * to restrict that call when a CM is not present because both
-        * CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
-        */
-       if (!mips_cm_present())
-               smp_call_function_many(&cpu_foreign_map, func, info, 1);
+       if (r4k_op_needs_ipi(type))
+               smp_call_function_many(&cpu_foreign_map[smp_processor_id()],
+                                      func, info, 1);
        func(info);
        preempt_enable();
 }
 
-#if defined(CONFIG_MIPS_CMP) || defined(CONFIG_MIPS_CPS)
-#define cpu_has_safe_index_cacheops 0
-#else
-#define cpu_has_safe_index_cacheops 1
-#endif
-
 /*
  * Must die.
  */
@@ -462,22 +494,44 @@ static inline void local_r4k___flush_cache_all(void * args)
 
 static void r4k___flush_cache_all(void)
 {
-       r4k_on_each_cpu(local_r4k___flush_cache_all, NULL);
+       r4k_on_each_cpu(R4K_INDEX, local_r4k___flush_cache_all, NULL);
 }
 
-static inline int has_valid_asid(const struct mm_struct *mm)
+/**
+ * has_valid_asid() - Determine if an mm already has an ASID.
+ * @mm:                Memory map.
+ * @type:      R4K_HIT or R4K_INDEX, type of cache op.
+ *
+ * Determines whether @mm already has an ASID on any of the CPUs which cache ops
+ * of type @type within an r4k_on_each_cpu() call will affect. If
+ * r4k_on_each_cpu() does an SMP call to a single VPE in each core, then the
+ * scope of the operation is confined to sibling CPUs, otherwise all online CPUs
+ * will need to be checked.
+ *
+ * Must be called in non-preemptive context.
+ *
+ * Returns:    1 if the CPUs affected by @type cache ops have an ASID for @mm.
+ *             0 otherwise.
+ */
+static inline int has_valid_asid(const struct mm_struct *mm, unsigned int type)
 {
-#ifdef CONFIG_MIPS_MT_SMP
-       int i;
+       unsigned int i;
+       const cpumask_t *mask = cpu_present_mask;
 
-       for_each_online_cpu(i)
+       /* cpu_sibling_map[] undeclared when !CONFIG_SMP */
+#ifdef CONFIG_SMP
+       /*
+        * If r4k_on_each_cpu does SMP calls, it does them to a single VPE in
+        * each foreign core, so we only need to worry about siblings.
+        * Otherwise we need to worry about all present CPUs.
+        */
+       if (r4k_op_needs_ipi(type))
+               mask = &cpu_sibling_map[smp_processor_id()];
+#endif
+       for_each_cpu(i, mask)
                if (cpu_context(i, mm))
                        return 1;
-
        return 0;
-#else
-       return cpu_context(smp_processor_id(), mm);
-#endif
 }
 
 static void r4k__flush_cache_vmap(void)
@@ -490,12 +544,16 @@ static void r4k__flush_cache_vunmap(void)
        r4k_blast_dcache();
 }
 
+/*
+ * Note: flush_tlb_range() assumes flush_cache_range() sufficiently flushes
+ * whole caches when vma is executable.
+ */
 static inline void local_r4k_flush_cache_range(void * args)
 {
        struct vm_area_struct *vma = args;
        int exec = vma->vm_flags & VM_EXEC;
 
-       if (!(has_valid_asid(vma->vm_mm)))
+       if (!has_valid_asid(vma->vm_mm, R4K_INDEX))
                return;
 
        /*
@@ -516,14 +574,14 @@ static void r4k_flush_cache_range(struct vm_area_struct *vma,
        int exec = vma->vm_flags & VM_EXEC;
 
        if (cpu_has_dc_aliases || exec)
-               r4k_on_each_cpu(local_r4k_flush_cache_range, vma);
+               r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_range, vma);
 }
 
 static inline void local_r4k_flush_cache_mm(void * args)
 {
        struct mm_struct *mm = args;
 
-       if (!has_valid_asid(mm))
+       if (!has_valid_asid(mm, R4K_INDEX))
                return;
 
        /*
@@ -548,7 +606,7 @@ static void r4k_flush_cache_mm(struct mm_struct *mm)
        if (!cpu_has_dc_aliases)
                return;
 
-       r4k_on_each_cpu(local_r4k_flush_cache_mm, mm);
+       r4k_on_each_cpu(R4K_INDEX, local_r4k_flush_cache_mm, mm);
 }
 
 struct flush_cache_page_args {
@@ -573,10 +631,10 @@ static inline void local_r4k_flush_cache_page(void *args)
        void *vaddr;
 
        /*
-        * If ownes no valid ASID yet, cannot possibly have gotten
+        * If owns no valid ASID yet, cannot possibly have gotten
         * this page into the cache.
         */
-       if (!has_valid_asid(mm))
+       if (!has_valid_asid(mm, R4K_HIT))
                return;
 
        addr &= PAGE_MASK;
@@ -643,7 +701,7 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
        args.addr = addr;
        args.pfn = pfn;
 
-       r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
+       r4k_on_each_cpu(R4K_HIT, local_r4k_flush_cache_page, &args);
 }
 
 static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -656,18 +714,23 @@ static void r4k_flush_data_cache_page(unsigned long addr)
        if (in_atomic())
                local_r4k_flush_data_cache_page((void *)addr);
        else
-               r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr);
+               r4k_on_each_cpu(R4K_HIT, local_r4k_flush_data_cache_page,
+                               (void *) addr);
 }
 
 struct flush_icache_range_args {
        unsigned long start;
        unsigned long end;
+       unsigned int type;
 };
 
-static inline void local_r4k_flush_icache_range(unsigned long start, unsigned long end)
+static inline void __local_r4k_flush_icache_range(unsigned long start,
+                                                 unsigned long end,
+                                                 unsigned int type)
 {
        if (!cpu_has_ic_fills_f_dc) {
-               if (end - start >= dcache_size) {
+               if (type == R4K_INDEX ||
+                   (type & R4K_INDEX && end - start >= dcache_size)) {
                        r4k_blast_dcache();
                } else {
                        R4600_HIT_CACHEOP_WAR_IMPL;
@@ -675,7 +738,8 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
                }
        }
 
-       if (end - start > icache_size)
+       if (type == R4K_INDEX ||
+           (type & R4K_INDEX && end - start > icache_size))
                r4k_blast_icache();
        else {
                switch (boot_cpu_type()) {
@@ -701,23 +765,52 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
 #endif
 }
 
+static inline void local_r4k_flush_icache_range(unsigned long start,
+                                               unsigned long end)
+{
+       __local_r4k_flush_icache_range(start, end, R4K_HIT | R4K_INDEX);
+}
+
 static inline void local_r4k_flush_icache_range_ipi(void *args)
 {
        struct flush_icache_range_args *fir_args = args;
        unsigned long start = fir_args->start;
        unsigned long end = fir_args->end;
+       unsigned int type = fir_args->type;
 
-       local_r4k_flush_icache_range(start, end);
+       __local_r4k_flush_icache_range(start, end, type);
 }
 
 static void r4k_flush_icache_range(unsigned long start, unsigned long end)
 {
        struct flush_icache_range_args args;
+       unsigned long size, cache_size;
 
        args.start = start;
        args.end = end;
+       args.type = R4K_HIT | R4K_INDEX;
 
-       r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args);
+       /*
+        * Indexed cache ops require an SMP call.
+        * Consider if that can or should be avoided.
+        */
+       preempt_disable();
+       if (r4k_op_needs_ipi(R4K_INDEX) && !r4k_op_needs_ipi(R4K_HIT)) {
+               /*
+                * If address-based cache ops don't require an SMP call, then
+                * use them exclusively for small flushes.
+                */
+               size = start - end;
+               cache_size = icache_size;
+               if (!cpu_has_ic_fills_f_dc) {
+                       size *= 2;
+                       cache_size += dcache_size;
+               }
+               if (size <= cache_size)
+                       args.type &= ~R4K_INDEX;
+       }
+       r4k_on_each_cpu(args.type, local_r4k_flush_icache_range_ipi, &args);
+       preempt_enable();
        instruction_hazard();
 }
 
@@ -744,7 +837,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
         * subset property so we have to flush the primary caches
         * explicitly
         */
-       if (cpu_has_safe_index_cacheops && size >= dcache_size) {
+       if (size >= dcache_size) {
                r4k_blast_dcache();
        } else {
                R4600_HIT_CACHEOP_WAR_IMPL;
@@ -781,7 +874,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                return;
        }
 
-       if (cpu_has_safe_index_cacheops && size >= dcache_size) {
+       if (size >= dcache_size) {
                r4k_blast_dcache();
        } else {
                R4600_HIT_CACHEOP_WAR_IMPL;
@@ -794,25 +887,76 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 }
 #endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
 
+struct flush_cache_sigtramp_args {
+       struct mm_struct *mm;
+       struct page *page;
+       unsigned long addr;
+};
+
 /*
  * While we're protected against bad userland addresses we don't care
  * very much about what happens in that case.  Usually a segmentation
  * fault will dump the process later on anyway ...
  */
-static void local_r4k_flush_cache_sigtramp(void * arg)
+static void local_r4k_flush_cache_sigtramp(void *args)
 {
+       struct flush_cache_sigtramp_args *fcs_args = args;
+       unsigned long addr = fcs_args->addr;
+       struct page *page = fcs_args->page;
+       struct mm_struct *mm = fcs_args->mm;
+       int map_coherent = 0;
+       void *vaddr;
+
        unsigned long ic_lsize = cpu_icache_line_size();
        unsigned long dc_lsize = cpu_dcache_line_size();
        unsigned long sc_lsize = cpu_scache_line_size();
-       unsigned long addr = (unsigned long) arg;
+
+       /*
+        * If owns no valid ASID yet, cannot possibly have gotten
+        * this page into the cache.
+        */
+       if (!has_valid_asid(mm, R4K_HIT))
+               return;
+
+       if (mm == current->active_mm) {
+               vaddr = NULL;
+       } else {
+               /*
+                * Use kmap_coherent or kmap_atomic to do flushes for
+                * another ASID than the current one.
+                */
+               map_coherent = (cpu_has_dc_aliases &&
+                               page_mapcount(page) &&
+                               !Page_dcache_dirty(page));
+               if (map_coherent)
+                       vaddr = kmap_coherent(page, addr);
+               else
+                       vaddr = kmap_atomic(page);
+               addr = (unsigned long)vaddr + (addr & ~PAGE_MASK);
+       }
 
        R4600_HIT_CACHEOP_WAR_IMPL;
-       if (dc_lsize)
-               protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
-       if (!cpu_icache_snoops_remote_store && scache_size)
-               protected_writeback_scache_line(addr & ~(sc_lsize - 1));
+       if (!cpu_has_ic_fills_f_dc) {
+               if (dc_lsize)
+                       vaddr ? flush_dcache_line(addr & ~(dc_lsize - 1))
+                             : protected_writeback_dcache_line(
+                                                       addr & ~(dc_lsize - 1));
+               if (!cpu_icache_snoops_remote_store && scache_size)
+                       vaddr ? flush_scache_line(addr & ~(sc_lsize - 1))
+                             : protected_writeback_scache_line(
+                                                       addr & ~(sc_lsize - 1));
+       }
        if (ic_lsize)
-               protected_flush_icache_line(addr & ~(ic_lsize - 1));
+               vaddr ? flush_icache_line(addr & ~(ic_lsize - 1))
+                     : protected_flush_icache_line(addr & ~(ic_lsize - 1));
+
+       if (vaddr) {
+               if (map_coherent)
+                       kunmap_coherent();
+               else
+                       kunmap_atomic(vaddr);
+       }
+
        if (MIPS4K_ICACHE_REFILL_WAR) {
                __asm__ __volatile__ (
                        ".set push\n\t"
@@ -837,7 +981,23 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
 
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
-       r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr);
+       struct flush_cache_sigtramp_args args;
+       int npages;
+
+       down_read(&current->mm->mmap_sem);
+
+       npages = get_user_pages_fast(addr, 1, 0, &args.page);
+       if (npages < 1)
+               goto out;
+
+       args.mm = current->mm;
+       args.addr = addr;
+
+       r4k_on_each_cpu(R4K_HIT, local_r4k_flush_cache_sigtramp, &args);
+
+       put_page(args.page);
+out:
+       up_read(&current->mm->mmap_sem);
 }
 
 static void r4k_flush_icache_all(void)
@@ -851,6 +1011,15 @@ struct flush_kernel_vmap_range_args {
        int             size;
 };
 
+static inline void local_r4k_flush_kernel_vmap_range_index(void *args)
+{
+       /*
+        * Aliases only affect the primary caches so don't bother with
+        * S-caches or T-caches.
+        */
+       r4k_blast_dcache();
+}
+
 static inline void local_r4k_flush_kernel_vmap_range(void *args)
 {
        struct flush_kernel_vmap_range_args *vmra = args;
@@ -861,12 +1030,8 @@ static inline void local_r4k_flush_kernel_vmap_range(void *args)
         * Aliases only affect the primary caches so don't bother with
         * S-caches or T-caches.
         */
-       if (cpu_has_safe_index_cacheops && size >= dcache_size)
-               r4k_blast_dcache();
-       else {
-               R4600_HIT_CACHEOP_WAR_IMPL;
-               blast_dcache_range(vaddr, vaddr + size);
-       }
+       R4600_HIT_CACHEOP_WAR_IMPL;
+       blast_dcache_range(vaddr, vaddr + size);
 }
 
 static void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size)
@@ -876,7 +1041,12 @@ static void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size)
        args.vaddr = (unsigned long) vaddr;
        args.size = size;
 
-       r4k_on_each_cpu(local_r4k_flush_kernel_vmap_range, &args);
+       if (size >= dcache_size)
+               r4k_on_each_cpu(R4K_INDEX,
+                               local_r4k_flush_kernel_vmap_range_index, NULL);
+       else
+               r4k_on_each_cpu(R4K_HIT, local_r4k_flush_kernel_vmap_range,
+                               &args);
 }
 
 static inline void rm7k_erratum31(void)
@@ -1206,7 +1376,7 @@ static void probe_pcache(void)
                              c->icache.linesz;
                c->icache.waybit = __ffs(icache_size/c->icache.ways);
 
-               if (config & 0x8)               /* VI bit */
+               if (config & MIPS_CONF_VI)
                        c->icache.flags |= MIPS_CACHE_VTAG;
 
                /*
index cb557d2..b2eadd6 100644 (file)
@@ -131,7 +131,7 @@ static void *mips_dma_alloc_noncoherent(struct device *dev, size_t size,
 }
 
 static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+       dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
        struct page *page = NULL;
@@ -141,7 +141,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
         * XXX: seems like the coherent and non-coherent implementations could
         * be consolidated.
         */
-       if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs))
+       if (attrs & DMA_ATTR_NON_CONSISTENT)
                return mips_dma_alloc_noncoherent(dev, size, dma_handle, gfp);
 
        gfp = massage_gfp_flags(dev, gfp);
@@ -176,13 +176,13 @@ static void mips_dma_free_noncoherent(struct device *dev, size_t size,
 }
 
 static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-       dma_addr_t dma_handle, struct dma_attrs *attrs)
+       dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long) vaddr;
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page *page = NULL;
 
-       if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) {
+       if (attrs & DMA_ATTR_NON_CONSISTENT) {
                mips_dma_free_noncoherent(dev, size, vaddr, dma_handle);
                return;
        }
@@ -200,7 +200,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 
 static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
        void *cpu_addr, dma_addr_t dma_addr, size_t size,
-       struct dma_attrs *attrs)
+       unsigned long attrs)
 {
        unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
@@ -214,7 +214,7 @@ static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
 
        pfn = page_to_pfn(virt_to_page((void *)addr));
 
-       if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+       if (attrs & DMA_ATTR_WRITE_COMBINE)
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        else
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
@@ -291,7 +291,7 @@ static inline void __dma_sync(struct page *page,
 }
 
 static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
-       size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
+       size_t size, enum dma_data_direction direction, unsigned long attrs)
 {
        if (cpu_needs_post_dma_flush(dev))
                __dma_sync(dma_addr_to_page(dev, dma_addr),
@@ -301,7 +301,7 @@ static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
 }
 
 static int mips_dma_map_sg(struct device *dev, struct scatterlist *sglist,
-       int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+       int nents, enum dma_data_direction direction, unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
@@ -322,7 +322,7 @@ static int mips_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
        unsigned long offset, size_t size, enum dma_data_direction direction,
-       struct dma_attrs *attrs)
+       unsigned long attrs)
 {
        if (!plat_device_is_coherent(dev))
                __dma_sync(page, offset, size, direction);
@@ -332,7 +332,7 @@ static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
 
 static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
        int nhwentries, enum dma_data_direction direction,
-       struct dma_attrs *attrs)
+       unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
index 9b58eb5..a5509e7 100644 (file)
@@ -504,7 +504,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 
 void (*free_init_pages_eva)(void *begin, void *end) = NULL;
 
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
        prom_free_prom_memory();
        /*
index 5eefe32..01f1154 100644 (file)
@@ -73,8 +73,8 @@ static int __init sc_debugfs_init(void)
 
        file = debugfs_create_file("prefetch", S_IRUGO | S_IWUSR, dir,
                                   NULL, &sc_prefetch_fops);
-       if (IS_ERR(file))
-               return PTR_ERR(file);
+       if (!file)
+               return -ENOMEM;
 
        return 0;
 }
index 9ac1efc..78f900c 100644 (file)
@@ -161,7 +161,7 @@ static void rm7k_tc_disable(void)
        local_irq_save(flags);
        blast_rm7k_tcache();
        clear_c0_config(RM7K_CONF_TE);
-       local_irq_save(flags);
+       local_irq_restore(flags);
 }
 
 static void rm7k_sc_disable(void)
index 4004b65..55ce396 100644 (file)
@@ -888,7 +888,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                }
        }
        if (!did_vmalloc_branch) {
-               if (uasm_in_compat_space_p(swpd) && !uasm_rel_lo(swpd)) {
+               if (single_insn_swpd) {
                        uasm_il_b(p, r, label_vmalloc_done);
                        uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
                } else {
@@ -1025,7 +1025,7 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
        pte_off_odd += offsetof(pte_t, pte_high);
 #endif
 
-       if (config_enabled(CONFIG_XPA)) {
+       if (IS_ENABLED(CONFIG_XPA)) {
                uasm_i_lw(p, tmp, pte_off_even, ptep); /* even pte */
                UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
                UASM_i_MTC0(p, tmp, C0_ENTRYLO0);
@@ -1643,7 +1643,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
        unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY);
        unsigned int swmode = mode & ~hwmode;
 
-       if (config_enabled(CONFIG_XPA) && !cpu_has_64bits) {
+       if (IS_ENABLED(CONFIG_XPA) && !cpu_has_64bits) {
                uasm_i_lui(p, scratch, swmode >> 16);
                uasm_i_or(p, pte, pte, scratch);
                BUG_ON(swmode & 0xffff);
@@ -2432,7 +2432,7 @@ static void config_htw_params(void)
                pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT;
 
        /* Set pointer size to size of directory pointers */
-       if (config_enabled(CONFIG_64BIT))
+       if (IS_ENABLED(CONFIG_64BIT))
                pwsize |= MIPS_PWSIZE_PS_MASK;
        /* PTEs may be multiple pointers long (e.g. with XPA) */
        pwsize |= ((PTE_T_LOG2 - PGD_T_LOG2) << MIPS_PWSIZE_PTEW_SHIFT)
@@ -2448,7 +2448,7 @@ static void config_htw_params(void)
         * the pwctl fields.
         */
        config = 1 << MIPS_PWCTL_PWEN_SHIFT;
-       if (config_enabled(CONFIG_64BIT))
+       if (IS_ENABLED(CONFIG_64BIT))
                config |= MIPS_PWCTL_XU_MASK;
        write_c0_pwctl(config);
        pr_info("Hardware Page Table Walker enabled\n");
@@ -2522,7 +2522,7 @@ void build_tlb_refill_handler(void)
         */
        static int run_once = 0;
 
-       if (config_enabled(CONFIG_XPA) && !cpu_has_rixi)
+       if (IS_ENABLED(CONFIG_XPA) && !cpu_has_rixi)
                panic("Kernels supporting XPA currently require CPUs with RIXI");
 
        output_pgtable_bits_defines();
index d78178d..277cf52 100644 (file)
@@ -53,8 +53,13 @@ static struct insn insn_table_MM[] = {
        { insn_bltzl, 0, 0 },
        { insn_bne, M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM },
        { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM },
+       { insn_cfc1, M(mm_pool32f_op, 0, 0, 0, mm_cfc1_op, mm_32f_73_op), RT | RS },
+       { insn_cfcmsa, M(mm_pool32s_op, 0, msa_cfc_op, 0, 0, mm_32s_elm_op), RD | RE },
+       { insn_ctc1, M(mm_pool32f_op, 0, 0, 0, mm_ctc1_op, mm_32f_73_op), RT | RS },
+       { insn_ctcmsa, M(mm_pool32s_op, 0, msa_ctc_op, 0, 0, mm_32s_elm_op), RD | RE },
        { insn_daddu, 0, 0 },
        { insn_daddiu, 0, 0 },
+       { insn_di, M(mm_pool32a_op, 0, 0, 0, mm_di_op, mm_pool32axf_op), RS },
        { insn_divu, M(mm_pool32a_op, 0, 0, 0, mm_divu_op, mm_pool32axf_op), RT | RS },
        { insn_dmfc0, 0, 0 },
        { insn_dmtc0, 0, 0 },
@@ -84,6 +89,8 @@ static struct insn insn_table_MM[] = {
        { insn_mfhi, M(mm_pool32a_op, 0, 0, 0, mm_mfhi32_op, mm_pool32axf_op), RS },
        { insn_mflo, M(mm_pool32a_op, 0, 0, 0, mm_mflo32_op, mm_pool32axf_op), RS },
        { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD },
+       { insn_mthi, M(mm_pool32a_op, 0, 0, 0, mm_mthi32_op, mm_pool32axf_op), RS },
+       { insn_mtlo, M(mm_pool32a_op, 0, 0, 0, mm_mtlo32_op, mm_pool32axf_op), RS },
        { insn_mul, M(mm_pool32a_op, 0, 0, 0, 0, mm_mul_op), RT | RS | RD },
        { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD },
        { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
@@ -166,13 +173,15 @@ static void build_insn(u32 **buf, enum opcode opc, ...)
        op = ip->match;
        va_start(ap, opc);
        if (ip->fields & RS) {
-               if (opc == insn_mfc0 || opc == insn_mtc0)
+               if (opc == insn_mfc0 || opc == insn_mtc0 ||
+                   opc == insn_cfc1 || opc == insn_ctc1)
                        op |= build_rt(va_arg(ap, u32));
                else
                        op |= build_rs(va_arg(ap, u32));
        }
        if (ip->fields & RT) {
-               if (opc == insn_mfc0 || opc == insn_mtc0)
+               if (opc == insn_mfc0 || opc == insn_mtc0 ||
+                   opc == insn_cfc1 || opc == insn_ctc1)
                        op |= build_rs(va_arg(ap, u32));
                else
                        op |= build_rt(va_arg(ap, u32));
index 9c2220a..763d3f1 100644 (file)
@@ -65,11 +65,16 @@ static struct insn insn_table[] = {
 #ifndef CONFIG_CPU_MIPSR6
        { insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 #else
-       { insn_cache,  M6(cache_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
+       { insn_cache,  M6(spec3_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
 #endif
+       { insn_cfc1, M(cop1_op, cfc_op, 0, 0, 0, 0), RT | RD },
+       { insn_cfcmsa, M(msa_op, 0, msa_cfc_op, 0, 0, msa_elm_op), RD | RE },
+       { insn_ctc1, M(cop1_op, ctc_op, 0, 0, 0, 0), RT | RD },
+       { insn_ctcmsa, M(msa_op, 0, msa_ctc_op, 0, 0, msa_elm_op), RD | RE },
        { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
        { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
        { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
+       { insn_di, M(cop0_op, mfmc0_op, 0, 12, 0, 0), RT },
        { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
        { insn_divu, M(spec_op, 0, 0, 0, 0, divu_op), RS | RT },
        { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
@@ -114,7 +119,13 @@ static struct insn insn_table[] = {
        { insn_mflo,  M(spec_op, 0, 0, 0, 0, mflo_op), RD },
        { insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
        { insn_mthc0,  M(cop0_op, mthc0_op, 0, 0, 0, 0),  RT | RD | SET},
+       { insn_mthi,  M(spec_op, 0, 0, 0, 0, mthi_op), RS },
+       { insn_mtlo,  M(spec_op, 0, 0, 0, 0, mtlo_op), RS },
+#ifndef CONFIG_CPU_MIPSR6
        { insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
+#else
+       { insn_mul, M(spec_op, 0, 0, 0, mult_mul_op, mult_op), RS | RT | RD},
+#endif
        { insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
        { insn_or,  M(spec_op, 0, 0, 0, 0, or_op),  RS | RT | RD },
 #ifndef CONFIG_CPU_MIPSR6
index ad718de..a829704 100644 (file)
@@ -49,18 +49,19 @@ enum opcode {
        insn_invalid,
        insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1,
        insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
-       insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm,
-       insn_divu, insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
+       insn_bne, insn_cache, insn_cfc1, insn_cfcmsa, insn_ctc1, insn_ctcmsa,
+       insn_daddiu, insn_daddu, insn_di, insn_dins, insn_dinsm, insn_divu,
+       insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll,
        insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret,
        insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_lb,
        insn_ld, insn_ldx, insn_lh, insn_ll, insn_lld, insn_lui, insn_lw,
        insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi, insn_mflo, insn_mtc0,
-       insn_mthc0, insn_mul, insn_or, insn_ori, insn_pref, insn_rfe,
-       insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll, insn_sllv, insn_slt,
-       insn_sltiu, insn_sltu, insn_sra, insn_srl, insn_srlv, insn_subu,
-       insn_sw, insn_sync, insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi,
-       insn_tlbwr, insn_wait, insn_wsbh, insn_xor, insn_xori, insn_yield,
-       insn_lddir, insn_ldpte,
+       insn_mthc0, insn_mthi, insn_mtlo, insn_mul, insn_or, insn_ori,
+       insn_pref, insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll,
+       insn_sllv, insn_slt, insn_sltiu, insn_sltu, insn_sra, insn_srl,
+       insn_srlv, insn_subu, insn_sw, insn_sync, insn_syscall, insn_tlbp,
+       insn_tlbr, insn_tlbwi, insn_tlbwr, insn_wait, insn_wsbh, insn_xor,
+       insn_xori, insn_yield, insn_lddir, insn_ldpte,
 };
 
 struct insn {
@@ -268,10 +269,15 @@ I_u1s2(_bltz)
 I_u1s2(_bltzl)
 I_u1u2s3(_bne)
 I_u2s3u1(_cache)
+I_u1u2(_cfc1)
+I_u2u1(_cfcmsa)
+I_u1u2(_ctc1)
+I_u2u1(_ctcmsa)
 I_u1u2u3(_dmfc0)
 I_u1u2u3(_dmtc0)
 I_u2u1s3(_daddiu)
 I_u3u1u2(_daddu)
+I_u1(_di);
 I_u1u2(_divu)
 I_u2u1u3(_dsll)
 I_u2u1u3(_dsll32)
@@ -301,6 +307,8 @@ I_u1(_mfhi)
 I_u1(_mflo)
 I_u1u2u3(_mtc0)
 I_u1u2u3(_mthc0)
+I_u1(_mthi)
+I_u1(_mtlo)
 I_u3u1u2(_mul)
 I_u2u1u3(_ori)
 I_u3u1u2(_or)
@@ -370,11 +378,7 @@ UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label));
 int ISAFUNC(uasm_in_compat_space_p)(long addr)
 {
        /* Is this address in 32bit compat space? */
-#ifdef CONFIG_64BIT
-       return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
-#else
-       return 1;
-#endif
+       return addr == (int)addr;
 }
 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p));
 
index f7133ef..151f488 100644 (file)
@@ -31,7 +31,7 @@ static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size)
 
        entries = 1;
        mem_array[0] = cpu_to_be32(PHYS_OFFSET);
-       if (config_enabled(CONFIG_EVA)) {
+       if (IS_ENABLED(CONFIG_EVA)) {
                /*
                 * The current Malta EVA configuration is "special" in that it
                 * always makes use of addresses in the upper half of the 32 bit
@@ -82,7 +82,7 @@ static void __init append_memory(void *fdt, int root_off)
                physical_memsize = 32 << 20;
        }
 
-       if (config_enabled(CONFIG_CPU_BIG_ENDIAN)) {
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
                /*
                 * SOC-it swaps, or perhaps doesn't swap, when DMA'ing
                 * the last word of physical memory.
index d5f8dae..a475567 100644 (file)
@@ -32,7 +32,7 @@ static void free_init_pages_eva_malta(void *begin, void *end)
 
 void __init fw_meminit(void)
 {
-       bool eva = config_enabled(CONFIG_EVA);
+       bool eva = IS_ENABLED(CONFIG_EVA);
 
        free_init_pages_eva = eva ? free_init_pages_eva_malta : NULL;
 }
index 33d5ff5..ec5b216 100644 (file)
@@ -261,7 +261,7 @@ void __init plat_mem_setup(void)
        fdt = malta_dt_shim(fdt);
        __dt_setup_arch(fdt);
 
-       if (config_enabled(CONFIG_EVA))
+       if (IS_ENABLED(CONFIG_EVA))
                /* EVA has already been configured in mach-malta/kernel-init.h */
                pr_info("Enhanced Virtual Addressing (EVA) activated\n");
 
index 1a8c960..39e7b47 100644 (file)
@@ -426,7 +426,7 @@ static inline void emit_load_ptr(unsigned int dst, unsigned int src,
 static inline void emit_load_func(unsigned int reg, ptr imm,
                                  struct jit_ctx *ctx)
 {
-       if (config_enabled(CONFIG_64BIT)) {
+       if (IS_ENABLED(CONFIG_64BIT)) {
                /* At this point imm is always 64-bit */
                emit_load_imm(r_tmp, (u64)imm >> 32, ctx);
                emit_dsll(r_tmp_imm, r_tmp, 16, ctx); /* left shift by 16 */
@@ -516,7 +516,7 @@ static inline void emit_jr(unsigned int reg, struct jit_ctx *ctx)
 static inline u16 align_sp(unsigned int num)
 {
        /* Double word alignment for 32-bit, quadword for 64-bit */
-       unsigned int align = config_enabled(CONFIG_64BIT) ? 16 : 8;
+       unsigned int align = IS_ENABLED(CONFIG_64BIT) ? 16 : 8;
        num = (num + (align - 1)) & -align;
        return num;
 }
@@ -1199,7 +1199,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
 
        memset(&ctx, 0, sizeof(ctx));
 
-       ctx.offsets = kcalloc(fp->len, sizeof(*ctx.offsets), GFP_KERNEL);
+       ctx.offsets = kcalloc(fp->len + 1, sizeof(*ctx.offsets), GFP_KERNEL);
        if (ctx.offsets == NULL)
                return;
 
index 3758715..0630693 100644 (file)
@@ -45,7 +45,7 @@
 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)
+       dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
@@ -62,7 +62,7 @@ static void *nlm_dma_alloc_coherent(struct device *dev, size_t size,
 }
 
 static void nlm_dma_free_coherent(struct device *dev, size_t size,
-       void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
+       void *vaddr, dma_addr_t dma_handle, unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_handle);
 }
index f1b11f0..b4c02f2 100644 (file)
@@ -112,7 +112,14 @@ static void pcibios_scanbus(struct pci_controller *hose)
                need_domain_info = 1;
        }
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+       /*
+        * We insert PCI resources into the iomem_resource and
+        * ioport_resource trees in either pci_bus_claim_resources()
+        * or pci_bus_assign_resources().
+        */
+       if (pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_claim_resources(bus);
+       } else {
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
        }
@@ -319,6 +326,16 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc, resource_size_t *start,
+                         resource_size_t *end)
+{
+       phys_addr_t size = resource_size(rsrc);
+
+       *start = fixup_bigphys_addr(rsrc->start, size);
+       *end = rsrc->start + size;
+}
+
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
index 77ecf32..5159971 100644 (file)
@@ -33,8 +33,8 @@ static ulong get_fdtaddr(void)
 {
        ulong ftaddr = 0;
 
-       if ((fw_arg0 == -2) && fw_arg1 && !fw_arg2 && !fw_arg3)
-               return (ulong)fw_arg1;
+       if (fw_passed_dtb && !fw_arg2 && !fw_arg3)
+               return (ulong)fw_passed_dtb;
 
        if (__dtb_start < __dtb_end)
                ftaddr = (ulong)__dtb_start;
index c50a670..1c91cad 100644 (file)
@@ -59,29 +59,6 @@ const char *get_system_type(void)
        return sys_type;
 }
 
-static void __init plat_setup_iocoherency(void)
-{
-       /*
-        * Kernel has been configured with software coherency
-        * but we might choose to turn it off and use hardware
-        * coherency instead.
-        */
-       if (mips_cm_numiocu() != 0) {
-               /* Nothing special needs to be done to enable coherency */
-               pr_info("CMP IOCU detected\n");
-               hw_coherentio = 1;
-               if (coherentio == 0)
-                       pr_info("Hardware DMA cache coherency disabled\n");
-               else
-                       pr_info("Hardware DMA cache coherency enabled\n");
-       } else {
-               if (coherentio == 1)
-                       pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
-               else
-                       pr_info("Software DMA cache coherency enabled\n");
-       }
-}
-
 void __init *plat_get_fdt(void)
 {
        if (fw_arg0 != -2)
@@ -92,8 +69,6 @@ void __init *plat_get_fdt(void)
 void __init plat_mem_setup(void)
 {
        __dt_setup_arch(plat_get_fdt());
-
-       plat_setup_iocoherency();
 }
 
 #define DEFAULT_CPC_BASE_ADDR  0x1bde0000
index d40edda..3c7c9bf 100644 (file)
@@ -175,7 +175,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = {
 };
 
 static struct rt2880_pmx_func spis_grp_mt7628[] = {
-       FUNC("pwm", 3, 14, 4),
+       FUNC("pwm_uart2", 3, 14, 4),
        FUNC("util", 2, 14, 4),
        FUNC("gpio", 1, 14, 4),
        FUNC("spis", 0, 14, 4),
index 063c2dd..2f45b03 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
-#include <linux/ds1286.h>
+#include <linux/rtc/ds1286.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
index fb4b352..7ee14f4 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <asm/sni.h>
 #include <asm/time.h>
-#include <asm-generic/rtc.h>
 
 #define SNI_CLOCK_TICK_RATE    3686400
 #define SNI_COUNTER2_DIV       64
index a77698f..1f6bc9a 100644 (file)
@@ -268,7 +268,7 @@ static int txx9_i8259_irq_setup(int irq)
        return err;
 }
 
-static void __init_refok quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __ref quirk_slc90e66_bridge(struct pci_dev *dev)
 {
        int irq;        /* PCI/ISA Bridge interrupt */
        u8 reg_64;
index 9627e81..38e3494 100644 (file)
@@ -236,7 +236,9 @@ source "kernel/Kconfig.hz"
 config MN10300_RTC
        bool "Using MN10300 RTC"
        depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
-       select GENERIC_CMOS_UPDATE
+       select RTC_CLASS
+       select RTC_DRV_CMOS
+       select RTC_SYSTOHC
        default n
        help
          This option enables support for the RTC, thus enabling time to be
index c42deef..c81cace 100644 (file)
@@ -75,9 +75,9 @@
 #define RTC_PORT(x)            0xd8600000
 #define RTC_ALWAYS_BCD         1       /* RTC operates in binary mode */
 
-#define CMOS_READ(addr)                __SYSREG(0xd8600000 + (addr), u8)
+#define CMOS_READ(addr)                __SYSREG(0xd8600000 + (u32)(addr), u8)
 #define CMOS_WRITE(val, addr)  \
-       do { __SYSREG(0xd8600000 + (addr), u8) = val; } while (0)
+       do { __SYSREG(0xd8600000 + (u32)(addr), u8) = val; } while (0)
 
 #define RTC_IRQ                        RTIRQ
 
index 6c14bb1..07dc876 100644 (file)
@@ -25,6 +25,4 @@ static inline void calibrate_clock(void)
 
 #endif /* !CONFIG_MN10300_RTC */
 
-#include <asm-generic/rtc.h>
-
 #endif /* _ASM_RTC_H */
index 48d7058..f81f370 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
-#include <linux/bcd.h>
-#include <linux/timex.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
 #include <asm/rtc-regs.h>
 #include <asm/rtc.h>
 
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
-/*
- * Read the current RTC time
- */
-void read_persistent_clock(struct timespec *ts)
-{
-       struct rtc_time tm;
-
-       get_rtc_time(&tm);
-
-       ts->tv_nsec = 0;
-       ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
-                           tm.tm_hour, tm.tm_min, tm.tm_sec);
-
-       /* if rtc is way off in the past, set something reasonable */
-       if (ts->tv_sec < 0)
-               ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0);
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
- * ms after the second nowtime has started, because when nowtime is written
- * into the registers of the CMOS clock, it will jump to the next second
- * precisely 500 ms later.  Check the Motorola MC146818A or Dallas DS12887 data
- * sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you'll only notice that after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
-{
-       unsigned char save_control, save_freq_select;
-       int retval = 0;
-       int real_seconds, real_minutes, cmos_minutes;
-
-       /* gets recalled with irq locally disabled */
-       spin_lock(&rtc_lock);
-       save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being
-                                               * set */
-       CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
-
-       save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset
-                                                       * prescaler */
-       CMOS_WRITE(save_freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
-
-       cmos_minutes = CMOS_READ(RTC_MINUTES);
-       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-               cmos_minutes = bcd2bin(cmos_minutes);
-
-       /*
-        * since we're only adjusting minutes and seconds,
-        * don't interfere with hour overflow. This avoids
-        * messing with unknown time zones but requires your
-        * RTC not to be off by more than 15 minutes
-        */
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
-               /* correct for half hour time zone */
-               real_minutes += 30;
-       real_minutes %= 60;
-
-       if (abs(real_minutes - cmos_minutes) < 30) {
-               if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-                       real_seconds = bin2bcd(real_seconds);
-                       real_minutes = bin2bcd(real_minutes);
-               }
-               CMOS_WRITE(real_seconds, RTC_SECONDS);
-               CMOS_WRITE(real_minutes, RTC_MINUTES);
-       } else {
-               printk_once(KERN_NOTICE
-                      "set_rtc_mmss: can't update from %d to %d\n",
-                      cmos_minutes, real_minutes);
-               retval = -1;
-       }
-
-       /* The following flags have to be released exactly in this order,
-        * otherwise the DS12887 (popular MC146818A clone with integrated
-        * battery and quartz) will not reset the oscillator and will not
-        * update precisely 500 ms later. You won't find this mentioned in
-        * the Dallas Semiconductor data sheets, but who believes data
-        * sheets anyway ...                           -- Markus Kuhn
-        */
-       CMOS_WRITE(save_control, RTC_CONTROL);
-       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-       spin_unlock(&rtc_lock);
-
-       return retval;
-}
-
-int update_persistent_clock(struct timespec now)
-{
-       return set_rtc_mmss(now.tv_sec);
-}
+static const __initdata struct resource res[] = {
+       DEFINE_RES_IO(RTC_PORT(0), RTC_IO_EXTENT),
+       DEFINE_RES_IRQ(RTC_IRQ),
+};
 
 /*
  * calibrate the TSC clock against the RTC
@@ -129,4 +41,6 @@ void __init calibrate_clock(void)
        RTCRA |= RTCRA_DVR;
        RTCRA &= ~RTCRA_DVR;
        RTCRB &= ~RTCRB_SET;
+
+       platform_device_register_simple("rtc_cmos", -1, res, ARRAY_SIZE(res));
 }
index 8842394..4f4b902 100644 (file)
@@ -21,7 +21,7 @@
 static unsigned long pci_sram_allocated = 0xbc000000;
 
 static void *mn10300_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        unsigned long addr;
        void *ret;
@@ -63,7 +63,7 @@ done:
 }
 
 static void mn10300_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long) vaddr & ~0x20000000;
 
@@ -75,7 +75,7 @@ static void mn10300_dma_free(struct device *dev, size_t size, void *vaddr,
 
 static int mn10300_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -92,7 +92,7 @@ static int mn10300_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static dma_addr_t mn10300_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        return page_to_bus(page) + offset;
 }
index 27b9798..102d86a 100644 (file)
@@ -9,7 +9,10 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 #include <linux/kernel.h>
+#include <linux/irq.h>
+#include <asm/cacheflush.h>
 #include <asm/fpu.h>
+#include <asm/irq.h>
 #include <asm/rtc.h>
 #include <asm/busctl-regs.h>
 
index ee6d03d..950cc8d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
+#include <asm/cacheflush.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
index 90422c3..d800fad 100644 (file)
@@ -59,7 +59,7 @@ static inline void __dma_sync_for_cpu(void *vaddr, size_t size,
 }
 
 static void *nios2_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -84,7 +84,7 @@ static void *nios2_dma_alloc(struct device *dev, size_t size,
 }
 
 static void nios2_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr);
 
@@ -93,7 +93,7 @@ static void nios2_dma_free(struct device *dev, size_t size, void *vaddr,
 
 static int nios2_dma_map_sg(struct device *dev, struct scatterlist *sg,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
 
@@ -113,7 +113,7 @@ static int nios2_dma_map_sg(struct device *dev, struct scatterlist *sg,
 static dma_addr_t nios2_dma_map_page(struct device *dev, struct page *page,
                        unsigned long offset, size_t size,
                        enum dma_data_direction direction,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        void *addr = page_address(page) + offset;
 
@@ -123,14 +123,14 @@ static dma_addr_t nios2_dma_map_page(struct device *dev, struct page *page,
 
 static void nios2_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
                size_t size, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        __dma_sync_for_cpu(phys_to_virt(dma_address), size, direction);
 }
 
 static void nios2_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
                int nhwentries, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        void *addr;
        int i;
index e75c75d..c92fe42 100644 (file)
@@ -89,7 +89,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
        free_initmem_default(-1);
 }
index 0b77ddb..140c991 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-debug.h>
 #include <linux/export.h>
-#include <linux/dma-attrs.h>
 
 #include <asm/cpuinfo.h>
 #include <asm/spr_defs.h>
@@ -83,7 +82,7 @@ page_clear_nocache(pte_t *pte, unsigned long addr,
 static void *
 or1k_dma_alloc(struct device *dev, size_t size,
               dma_addr_t *dma_handle, gfp_t gfp,
-              struct dma_attrs *attrs)
+              unsigned long attrs)
 {
        unsigned long va;
        void *page;
@@ -101,7 +100,7 @@ or1k_dma_alloc(struct device *dev, size_t size,
 
        va = (unsigned long)page;
 
-       if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) {
+       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) {
                /*
                 * We need to iterate through the pages, clearing the dcache for
                 * them and setting the cache-inhibit bit.
@@ -117,7 +116,7 @@ or1k_dma_alloc(struct device *dev, size_t size,
 
 static void
 or1k_dma_free(struct device *dev, size_t size, void *vaddr,
-             dma_addr_t dma_handle, struct dma_attrs *attrs)
+             dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long va = (unsigned long)vaddr;
        struct mm_walk walk = {
@@ -125,7 +124,7 @@ or1k_dma_free(struct device *dev, size_t size, void *vaddr,
                .mm = &init_mm
        };
 
-       if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) {
+       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) {
                /* walk_page_range shouldn't be able to fail here */
                WARN_ON(walk_page_range(va, va + size, &walk));
        }
@@ -137,7 +136,7 @@ static dma_addr_t
 or1k_map_page(struct device *dev, struct page *page,
              unsigned long offset, size_t size,
              enum dma_data_direction dir,
-             struct dma_attrs *attrs)
+             unsigned long attrs)
 {
        unsigned long cl;
        dma_addr_t addr = page_to_phys(page) + offset;
@@ -170,7 +169,7 @@ or1k_map_page(struct device *dev, struct page *page,
 static void
 or1k_unmap_page(struct device *dev, dma_addr_t dma_handle,
                size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        /* Nothing special to do here... */
 }
@@ -178,14 +177,14 @@ or1k_unmap_page(struct device *dev, dma_addr_t dma_handle,
 static int
 or1k_map_sg(struct device *dev, struct scatterlist *sg,
            int nents, enum dma_data_direction dir,
-           struct dma_attrs *attrs)
+           unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
 
        for_each_sg(sg, s, nents, i) {
                s->dma_address = or1k_map_page(dev, sg_page(s), s->offset,
-                                              s->length, dir, NULL);
+                                              s->length, dir, 0);
        }
 
        return nents;
@@ -194,13 +193,13 @@ or1k_map_sg(struct device *dev, struct scatterlist *sg,
 static void
 or1k_unmap_sg(struct device *dev, struct scatterlist *sg,
              int nents, enum dma_data_direction dir,
-             struct dma_attrs *attrs)
+             unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
 
        for_each_sg(sg, s, nents, i) {
-               or1k_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, NULL);
+               or1k_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, 0);
        }
 }
 
index 5b2a951..fa60b81 100644 (file)
@@ -38,7 +38,7 @@ static unsigned int fixmaps_used __initdata;
  * have to convert them into an offset in a page-aligned mapping, but the
  * caller shouldn't need to know that small detail.
  */
-void __iomem *__init_refok
+void __iomem *__ref
 __ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot)
 {
        phys_addr_t p;
@@ -116,7 +116,7 @@ void iounmap(void *addr)
  * the memblock infrastructure.
  */
 
-pte_t __init_refok *pte_alloc_one_kernel(struct mm_struct *mm,
+pte_t __ref *pte_alloc_one_kernel(struct mm_struct *mm,
                                         unsigned long address)
 {
        pte_t *pte;
index dc11738..cd87781 100644 (file)
@@ -31,6 +31,7 @@ config PARISC
        select TTY # Needed for pdc_cons.c
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_HASH
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_UNSTABLE_SCHED_CLOCK if (SMP || !64BIT)
diff --git a/arch/parisc/include/asm/hash.h b/arch/parisc/include/asm/hash.h
new file mode 100644 (file)
index 0000000..dbe9331
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef _ASM_HASH_H
+#define _ASM_HASH_H
+
+/*
+ * HP-PA only implements integer multiply in the FPU.  However, for
+ * integer multiplies by constant, it has a number of shift-and-add
+ * (but no shift-and-subtract, sigh!) instructions that a compiler
+ * can synthesize a code sequence with.
+ *
+ * Unfortunately, GCC isn't very efficient at using them.  For example
+ * it uses three instructions for "x *= 21" when only two are needed.
+ * But we can find a sequence manually.
+ */
+
+#define HAVE_ARCH__HASH_32 1
+
+/*
+ * This is a multiply by GOLDEN_RATIO_32 = 0x61C88647 optimized for the
+ * PA7100 pairing rules.  This is an in-order 2-way superscalar processor.
+ * Only one instruction in a pair may be a shift (by more than 3 bits),
+ * but other than that, simple ALU ops (including shift-and-add by up
+ * to 3 bits) may be paired arbitrarily.
+ *
+ * PA8xxx processors also dual-issue ALU instructions, although with
+ * fewer constraints, so this schedule is good for them, too.
+ *
+ * This 6-step sequence was found by Yevgen Voronenko's implementation
+ * of the Hcub algorithm at http://spiral.ece.cmu.edu/mcm/gen.html.
+ */
+static inline u32 __attribute_const__ __hash_32(u32 x)
+{
+       u32 a, b, c;
+
+       /*
+        * Phase 1: Compute  a = (x << 19) + x,
+        * b = (x << 9) + a, c = (x << 23) + b.
+        */
+       a = x << 19;            /* Two shifts can't be paired */
+       b = x << 9;     a += x;
+       c = x << 23;    b += a;
+                       c += b;
+       /* Phase 2: Return (b<<11) + (c<<6) + (a<<3) - c */
+       b <<= 11;
+       a += c << 3;    b -= c;
+       return (a << 3) + b;
+}
+
+#if BITS_PER_LONG == 64
+
+#define HAVE_ARCH_HASH_64 1
+
+/*
+ * Finding a good shift-and-add chain for GOLDEN_RATIO_64 is tricky,
+ * because available software for the purpose chokes on constants this
+ * large.  (It's mostly designed for compiling FIR filter coefficients
+ * into FPGAs.)
+ *
+ * However, Jason Thong pointed out a work-around.  The Hcub software
+ * (http://spiral.ece.cmu.edu/mcm/gen.html) is designed for *multiple*
+ * constant multiplication, and is good at finding shift-and-add chains
+ * which share common terms.
+ *
+ * Looking at 0x0x61C8864680B583EB in binary:
+ * 0110000111001000100001100100011010000000101101011000001111101011
+ *  \______________/    \__________/       \_______/     \________/
+ *   \____________________________/         \____________________/
+ * you can see the non-zero bits are divided into several well-separated
+ * blocks.  Hcub can find algorithms for those terms separately, which
+ * can then be shifted and added together.
+ *
+ * Dividing the input into 2, 3 or 4 blocks, Hcub can find solutions
+ * with 10, 9 or 8 adds, respectively, making a total of 11 for the
+ * whole number.
+ *
+ * Using just two large blocks, 0xC3910C8D << 31 in the high bits,
+ * and 0xB583EB in the low bits, produces as good an algorithm as any,
+ * and with one more small shift than alternatives.
+ *
+ * The high bits are a larger number and more work to compute, as well
+ * as needing one extra cycle to shift left 31 bits before the final
+ * addition, so they are the critical path for scheduling.  The low bits
+ * can fit into the scheduling slots left over.
+ */
+
+
+/*
+ * This _ASSIGN(dst, src) macro performs "dst = src", but prevents GCC
+ * from inferring anything about the value assigned to "dest".
+ *
+ * This prevents it from mis-optimizing certain sequences.
+ * In particular, gcc is annoyingly eager to combine consecutive shifts.
+ * Given "x <<= 19; y += x; z += x << 1;", GCC will turn this into
+ * "y += x << 19; z += x << 20;" even though the latter sequence needs
+ * an additional instruction and temporary register.
+ *
+ * Because no actual assembly code is generated, this construct is
+ * usefully portable across all GCC platforms, and so can be test-compiled
+ * on non-PA systems.
+ *
+ * In two places, additional unused input dependencies are added.  This
+ * forces GCC's scheduling so it does not rearrange instructions too much.
+ * Because the PA-8xxx is out of order, I'm not sure how much this matters,
+ * but why make it more difficult for the processor than necessary?
+ */
+#define _ASSIGN(dst, src, ...) asm("" : "=r" (dst) : "0" (src), ##__VA_ARGS__)
+
+/*
+ * Multiply by GOLDEN_RATIO_64 = 0x0x61C8864680B583EB using a heavily
+ * optimized shift-and-add sequence.
+ *
+ * Without the final shift, the multiply proper is 19 instructions,
+ * 10 cycles and uses only 4 temporaries.  Whew!
+ *
+ * You are not expected to understand this.
+ */
+static __always_inline u32 __attribute_const__
+hash_64(u64 a, unsigned int bits)
+{
+       u64 b, c, d;
+
+       /*
+        * Encourage GCC to move a dynamic shift to %sar early,
+        * thereby freeing up an additional temporary register.
+        */
+       if (!__builtin_constant_p(bits))
+               asm("" : "=q" (bits) : "0" (64 - bits));
+       else
+               bits = 64 - bits;
+
+       _ASSIGN(b, a*5);        c = a << 13;
+       b = (b << 2) + a;       _ASSIGN(d, a << 17);
+       a = b + (a << 1);       c += d;
+       d = a << 10;            _ASSIGN(a, a << 19);
+       d = a - d;              _ASSIGN(a, a << 4, "X" (d));
+       c += b;                 a += b;
+       d -= c;                 c += a << 1;
+       a += c << 3;            _ASSIGN(b, b << (7+31), "X" (c), "X" (d));
+       a <<= 31;               b += d;
+       a += b;
+       return a >> bits;
+}
+#undef _ASSIGN /* We're a widely-used header file, so don't litter! */
+
+#endif /* BITS_PER_LONG == 64 */
+
+#endif /* _ASM_HASH_H */
diff --git a/arch/parisc/include/asm/mc146818rtc.h b/arch/parisc/include/asm/mc146818rtc.h
deleted file mode 100644 (file)
index adf4163..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifndef _ASM_MC146818RTC_H
-#define _ASM_MC146818RTC_H
-
-/* empty include file to satisfy the include in genrtc.c */
-
-#endif /* _ASM_MC146818RTC_H */
diff --git a/arch/parisc/include/asm/rtc.h b/arch/parisc/include/asm/rtc.h
deleted file mode 100644 (file)
index 099d641..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* 
- * include/asm-parisc/rtc.h
- *
- * Copyright 2002 Randolph CHung <tausq@debian.org>
- *
- * Based on: include/asm-ppc/rtc.h and the genrtc driver in the
- * 2.4 parisc linux tree
- */
-
-#ifndef __ASM_RTC_H__
-#define __ASM_RTC_H__
-
-#ifdef __KERNEL__
-
-#include <linux/rtc.h>
-
-#include <asm/pdc.h>
-
-#define SECS_PER_HOUR   (60 * 60)
-#define SECS_PER_DAY    (SECS_PER_HOUR * 24)
-
-
-#define RTC_PIE 0x40           /* periodic interrupt enable */
-#define RTC_AIE 0x20           /* alarm interrupt enable */
-#define RTC_UIE 0x10           /* update-finished interrupt enable */
-
-#define RTC_BATT_BAD 0x100     /* battery bad */
-
-/* some dummy definitions */
-#define RTC_SQWE 0x08          /* enable square-wave output */
-#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
-#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
-
-# define __isleap(year) \
-  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-
-/* How many days come before each month (0-12).  */
-static const unsigned short int __mon_yday[2][13] =
-{
-       /* Normal years.  */
-       { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
-       /* Leap years.  */
-       { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
-};
-
-static inline unsigned int get_rtc_time(struct rtc_time *wtime)
-{
-       struct pdc_tod tod_data;
-       long int days, rem, y;
-       const unsigned short int *ip;
-
-       memset(wtime, 0, sizeof(*wtime));
-       if (pdc_tod_read(&tod_data) < 0)
-               return RTC_24H | RTC_BATT_BAD;
-
-       // most of the remainder of this function is:
-//     Copyright (C) 1991, 1993, 1997, 1998 Free Software Foundation, Inc.
-//     This was originally a part of the GNU C Library.
-//      It is distributed under the GPL, and was swiped from offtime.c
-
-
-       days = tod_data.tod_sec / SECS_PER_DAY;
-       rem = tod_data.tod_sec % SECS_PER_DAY;
-
-       wtime->tm_hour = rem / SECS_PER_HOUR;
-       rem %= SECS_PER_HOUR;
-       wtime->tm_min = rem / 60;
-       wtime->tm_sec = rem % 60;
-
-       y = 1970;
-
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
-
-       while (days < 0 || days >= (__isleap (y) ? 366 : 365))
-       {
-               /* Guess a corrected year, assuming 365 days per year.  */
-               long int yg = y + days / 365 - (days % 365 < 0);
-
-               /* Adjust DAYS and Y to match the guessed year.  */
-               days -= ((yg - y) * 365
-                        + LEAPS_THRU_END_OF (yg - 1)
-                        - LEAPS_THRU_END_OF (y - 1));
-               y = yg;
-       }
-       wtime->tm_year = y - 1900;
-
-       ip = __mon_yday[__isleap(y)];
-       for (y = 11; days < (long int) ip[y]; --y)
-               continue;
-       days -= ip[y];
-       wtime->tm_mon = y;
-       wtime->tm_mday = days + 1;
-
-       return RTC_24H;
-}
-
-static int set_rtc_time(struct rtc_time *wtime)
-{
-       u_int32_t secs;
-
-       secs = mktime(wtime->tm_year + 1900, wtime->tm_mon + 1, wtime->tm_mday, 
-                     wtime->tm_hour, wtime->tm_min, wtime->tm_sec);
-
-       if(pdc_tod_set(secs, 0) < 0)
-               return -1;
-       else
-               return 0;
-
-}
-
-static inline unsigned int get_rtc_ss(void)
-{
-       struct rtc_time h;
-
-       get_rtc_time(&h);
-       return h.tm_sec;
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-
-#endif /* __KERNEL__ */
-#endif /* __ASM_RTC_H__ */
index 2239590..e5d7190 100644 (file)
@@ -1354,9 +1354,9 @@ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
        retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ,
                                        __pa(pdc_result), pci_addr, pci_size);
        switch(pci_size) {
-               case 1: *(u8 *) mem_addr =  (u8)  pdc_result[0];
-               case 2: *(u16 *)mem_addr =  (u16) pdc_result[0];
-               case 4: *(u32 *)mem_addr =  (u32) pdc_result[0];
+               case 1: *(u8 *) mem_addr =  (u8)  pdc_result[0]; break;
+               case 2: *(u16 *)mem_addr =  (u16) pdc_result[0]; break;
+               case 4: *(u32 *)mem_addr =  (u32) pdc_result[0]; break;
        }
        spin_unlock_irqrestore(&pdc_lock, flags);
 
index a27e492..02d9ed0 100644 (file)
@@ -414,7 +414,7 @@ pcxl_dma_init(void)
 __initcall(pcxl_dma_init);
 
 static void *pa11_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
 {
        unsigned long vaddr;
        unsigned long paddr;
@@ -441,7 +441,7 @@ static void *pa11_dma_alloc(struct device *dev, size_t size,
 }
 
 static void pa11_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
        int order;
 
@@ -454,7 +454,7 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr,
 
 static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page,
                unsigned long offset, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        void *addr = page_address(page) + offset;
        BUG_ON(direction == DMA_NONE);
@@ -465,7 +465,7 @@ static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page,
 
 static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
                size_t size, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        BUG_ON(direction == DMA_NONE);
 
@@ -484,7 +484,7 @@ static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
 
 static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
@@ -503,7 +503,7 @@ static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                int nents, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
@@ -577,11 +577,11 @@ struct dma_map_ops pcxl_dma_ops = {
 };
 
 static void *pcx_dma_alloc(struct device *dev, size_t size,
-               dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs)
+               dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
 {
        void *addr;
 
-       if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs))
+       if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0)
                return NULL;
 
        addr = (void *)__get_free_pages(flag, get_order(size));
@@ -592,7 +592,7 @@ static void *pcx_dma_alloc(struct device *dev, size_t size,
 }
 
 static void pcx_dma_free(struct device *dev, size_t size, void *vaddr,
-               dma_addr_t iova, struct dma_attrs *attrs)
+               dma_addr_t iova, unsigned long attrs)
 {
        free_pages((unsigned long)vaddr, get_order(size));
        return;
index 31ec99a..505cf1a 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/errno.h>
 #include <linux/module.h>
+#include <linux/rtc.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
@@ -248,14 +249,47 @@ void __init start_cpu_itimer(void)
        per_cpu(cpu_data, cpu).it_value = next_tick;
 }
 
+#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
+static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pdc_tod tod_data;
+
+       memset(tm, 0, sizeof(*tm));
+       if (pdc_tod_read(&tod_data) < 0)
+               return -EOPNOTSUPP;
+
+       /* we treat tod_sec as unsigned, so this can work until year 2106 */
+       rtc_time64_to_tm(tod_data.tod_sec, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
+{
+       time64_t secs = rtc_tm_to_time64(tm);
+
+       if (pdc_tod_set(secs, 0) < 0)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static const struct rtc_class_ops rtc_generic_ops = {
+       .read_time = rtc_generic_get_time,
+       .set_time = rtc_generic_set_time,
+};
+
 static int __init rtc_init(void)
 {
        struct platform_device *pdev;
 
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &rtc_generic_ops,
+                                            sizeof(rtc_generic_ops));
+
        return PTR_ERR_OR_ZERO(pdev);
 }
 device_initcall(rtc_init);
+#endif
 
 void read_persistent_clock(struct timespec *ts)
 {
index fb8e10a..eaffbb9 100644 (file)
@@ -125,22 +125,22 @@ static void ioport_write32r(void __iomem *addr, const void *s, unsigned long n)
 }
 
 static const struct iomap_ops ioport_ops = {
-       ioport_read8,
-       ioport_read16,
-       ioport_read16,
-       ioport_read32,
-       ioport_read32,
-       ioport_write8,
-       ioport_write16,
-       ioport_write16,
-       ioport_write32,
-       ioport_write32,
-       ioport_read8r,
-       ioport_read16r,
-       ioport_read32r,
-       ioport_write8r,
-       ioport_write16r,
-       ioport_write32r,
+       .read8 = ioport_read8,
+       .read16 = ioport_read16,
+       .read16be = ioport_read16,
+       .read32 = ioport_read32,
+       .read32be = ioport_read32,
+       .write8 = ioport_write8,
+       .write16 = ioport_write16,
+       .write16be = ioport_write16,
+       .write32 = ioport_write32,
+       .write32be = ioport_write32,
+       .read8r = ioport_read8r,
+       .read16r = ioport_read16r,
+       .read32r = ioport_read32r,
+       .write8r = ioport_write8r,
+       .write16r = ioport_write16r,
+       .write32r = ioport_write32r,
 };
 
 /* Legacy I/O memory ops */
@@ -244,22 +244,22 @@ static void iomem_write32r(void __iomem *addr, const void *s, unsigned long n)
 }
 
 static const struct iomap_ops iomem_ops = {
-       iomem_read8,
-       iomem_read16,
-       iomem_read16be,
-       iomem_read32,
-       iomem_read32be,
-       iomem_write8,
-       iomem_write16,
-       iomem_write16be,
-       iomem_write32,
-       iomem_write32be,
-       iomem_read8r,
-       iomem_read16r,
-       iomem_read32r,
-       iomem_write8r,
-       iomem_write16r,
-       iomem_write32r,
+       .read8 = iomem_read8,
+       .read16 = iomem_read16,
+       .read16be = iomem_read16be,
+       .read32 = iomem_read32,
+       .read32be = iomem_read32be,
+       .write8 = iomem_write8,
+       .write16 = iomem_write16,
+       .write16be = iomem_write16be,
+       .write32 = iomem_write32,
+       .write32be = iomem_write32be,
+       .read8r = iomem_read8r,
+       .read16r = iomem_read16r,
+       .read32r = iomem_read32r,
+       .write8r = iomem_write8r,
+       .write16r = iomem_write16r,
+       .write32r = iomem_write32r,
 };
 
 static const struct iomap_ops *iomap_ops[8] = {
index ec4047e..927d2ab 100644 (file)
@@ -166,6 +166,7 @@ config PPC
        select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS
        select GENERIC_CPU_AUTOPROBE
        select HAVE_VIRT_CPU_ACCOUNTING
+       select HAVE_ARCH_HARDENED_USERCOPY
 
 config GENERIC_CSUM
        def_bool CPU_LITTLE_ENDIAN
index 1710478..63292f6 100644 (file)
@@ -60,6 +60,25 @@ config CODE_PATCHING_SELFTEST
        depends on DEBUG_KERNEL
        default n
 
+config JUMP_LABEL_FEATURE_CHECKS
+       bool "Enable use of jump label for cpu/mmu_has_feature()"
+       depends on JUMP_LABEL
+       default y
+       help
+         Selecting this options enables use of jump labels for some internal
+         feature checks. This should generate more optimal code for those
+         checks.
+
+config JUMP_LABEL_FEATURE_CHECK_DEBUG
+       bool "Do extra check on feature fixup calls"
+       depends on DEBUG_KERNEL && JUMP_LABEL_FEATURE_CHECKS
+       default n
+       help
+         This tries to catch incorrect usage of cpu_has_feature() and
+         mmu_has_feature() in the code.
+
+         If you don't know what this means, say N.
+
 config FTR_FIXUP_SELFTEST
        bool "Run self-tests of the feature-fixup code"
        depends on DEBUG_KERNEL
index 4cd612a..1a2a6e8 100644 (file)
@@ -43,7 +43,7 @@ ifeq ($(call cc-option-yn, -fstack-protector),y)
 BOOTCFLAGS     += -fno-stack-protector
 endif
 
-BOOTCFLAGS     += -I$(obj) -I$(srctree)/$(obj)
+BOOTCFLAGS     += -I$(objtree)/$(obj) -I$(srctree)/$(obj)
 
 DTC_FLAGS      ?= -p 1024
 
index 60f4764..c45189a 100644 (file)
@@ -11,4 +11,19 @@ extern unsigned long
 radix__hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                                unsigned long len, unsigned long pgoff,
                                unsigned long flags);
+
+static inline int hstate_get_psize(struct hstate *hstate)
+{
+       unsigned long shift;
+
+       shift = huge_page_shift(hstate);
+       if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
+               return MMU_PAGE_2M;
+       else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
+               return MMU_PAGE_1G;
+       else {
+               WARN(1, "Wrong huge page shift\n");
+               return mmu_virtual_psize;
+       }
+}
 #endif
index 5eaf86a..287a656 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/book3s/64/pgtable.h>
 #include <asm/bug.h>
 #include <asm/processor.h>
+#include <asm/cpu_has_feature.h>
 
 /*
  * SLB
@@ -190,6 +191,15 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize)
        BUG();
 }
 
+static inline unsigned long get_sllp_encoding(int psize)
+{
+       unsigned long sllp;
+
+       sllp = ((mmu_psize_defs[psize].sllp & SLB_VSID_L) >> 6) |
+               ((mmu_psize_defs[psize].sllp & SLB_VSID_LP) >> 4);
+       return sllp;
+}
+
 #endif /* __ASSEMBLY__ */
 
 /*
index d4eda64..8afb0e0 100644 (file)
@@ -23,13 +23,6 @@ struct mmu_psize_def {
 };
 extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
 
-#ifdef CONFIG_PPC_RADIX_MMU
-#define radix_enabled() mmu_has_feature(MMU_FTR_RADIX)
-#else
-#define radix_enabled() (0)
-#endif
-
-
 #endif /* __ASSEMBLY__ */
 
 /* 64-bit classic hash table MMU */
@@ -107,6 +100,9 @@ extern int mmu_vmemmap_psize;
 extern int mmu_io_psize;
 
 /* MMU initialization */
+void mmu_early_init_devtree(void);
+void hash__early_init_devtree(void);
+void radix__early_init_devtree(void);
 extern void radix_init_native(void);
 extern void hash__early_init_mmu(void);
 extern void radix__early_init_mmu(void);
@@ -132,11 +128,15 @@ extern void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,
 static inline void setup_initial_memory_limit(phys_addr_t first_memblock_base,
                                              phys_addr_t first_memblock_size)
 {
-       if (radix_enabled())
+       if (early_radix_enabled())
                return radix__setup_initial_memory_limit(first_memblock_base,
                                                   first_memblock_size);
        return hash__setup_initial_memory_limit(first_memblock_base,
                                           first_memblock_size);
 }
+
+extern int (*register_process_table)(unsigned long base, unsigned long page_size,
+                                    unsigned long tbl_size);
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */
index f12ddf5..2f63731 100644 (file)
@@ -75,11 +75,6 @@ static inline void hash__flush_tlb_page(struct vm_area_struct *vma,
 {
 }
 
-static inline void hash__flush_tlb_page_nohash(struct vm_area_struct *vma,
-                                          unsigned long vmaddr)
-{
-}
-
 static inline void hash__flush_tlb_range(struct vm_area_struct *vma,
                                     unsigned long start, unsigned long end)
 {
index 00703e7..6503776 100644 (file)
@@ -10,26 +10,32 @@ static inline int mmu_get_ap(int psize)
        return mmu_psize_defs[psize].ap;
 }
 
+extern void radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma,
+                                          unsigned long start, unsigned long end);
+extern void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start,
+                                        unsigned long end, int psize);
+extern void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
+                                      unsigned long start, unsigned long end);
 extern void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                            unsigned long end);
 extern void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
 extern void radix__local_flush_tlb_mm(struct mm_struct *mm);
 extern void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
-                                   unsigned long ap, int nid);
 extern void radix__local_flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr);
+extern void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
+                                             int psize);
 extern void radix__tlb_flush(struct mmu_gather *tlb);
 #ifdef CONFIG_SMP
 extern void radix__flush_tlb_mm(struct mm_struct *mm);
 extern void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
-                             unsigned long ap, int nid);
 extern void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr);
+extern void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
+                                       int psize);
 #else
 #define radix__flush_tlb_mm(mm)                radix__local_flush_tlb_mm(mm)
 #define radix__flush_tlb_page(vma,addr)        radix__local_flush_tlb_page(vma,addr)
-#define radix___flush_tlb_page(mm,addr,p,i)    radix___local_flush_tlb_page(mm,addr,p,i)
+#define radix__flush_tlb_page_psize(mm,addr,p) radix__local_flush_tlb_page_psize(mm,addr,p)
 #define radix__flush_tlb_pwc(tlb, addr)        radix__local_flush_tlb_pwc(tlb, addr)
 #endif
 extern void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
index 96e5769..72b925f 100644 (file)
@@ -7,6 +7,25 @@
 #include <asm/book3s/64/tlbflush-hash.h>
 #include <asm/book3s/64/tlbflush-radix.h>
 
+#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
+static inline void flush_pmd_tlb_range(struct vm_area_struct *vma,
+                                      unsigned long start, unsigned long end)
+{
+       if (radix_enabled())
+               return radix__flush_pmd_tlb_range(vma, start, end);
+       return hash__flush_tlb_range(vma, start, end);
+}
+
+#define __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
+static inline void flush_hugetlb_tlb_range(struct vm_area_struct *vma,
+                                          unsigned long start,
+                                          unsigned long end)
+{
+       if (radix_enabled())
+               return radix__flush_hugetlb_tlb_range(vma, start, end);
+       return hash__flush_tlb_range(vma, start, end);
+}
+
 static inline void flush_tlb_range(struct vm_area_struct *vma,
                                   unsigned long start, unsigned long end)
 {
@@ -38,14 +57,6 @@ static inline void local_flush_tlb_page(struct vm_area_struct *vma,
        return hash__local_flush_tlb_page(vma, vmaddr);
 }
 
-static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
-                                        unsigned long vmaddr)
-{
-       if (radix_enabled())
-               return radix__flush_tlb_page(vma, vmaddr);
-       return hash__flush_tlb_page_nohash(vma, vmaddr);
-}
-
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
        if (radix_enabled())
index 69fb16d..b77f036 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/mm.h>
 #include <asm/cputable.h>
+#include <asm/cpu_has_feature.h>
 
 /*
  * No cache flushing is required when address mappings are changed,
diff --git a/arch/powerpc/include/asm/cpu_has_feature.h b/arch/powerpc/include/asm/cpu_has_feature.h
new file mode 100644 (file)
index 0000000..2ef55f8
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __ASM_POWERPC_CPUFEATURES_H
+#define __ASM_POWERPC_CPUFEATURES_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/bug.h>
+#include <asm/cputable.h>
+
+static inline bool early_cpu_has_feature(unsigned long feature)
+{
+       return !!((CPU_FTRS_ALWAYS & feature) ||
+                 (CPU_FTRS_POSSIBLE & cur_cpu_spec->cpu_features & feature));
+}
+
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
+#include <linux/jump_label.h>
+
+#define NUM_CPU_FTR_KEYS       64
+
+extern struct static_key_true cpu_feature_keys[NUM_CPU_FTR_KEYS];
+
+static __always_inline bool cpu_has_feature(unsigned long feature)
+{
+       int i;
+
+       BUILD_BUG_ON(!__builtin_constant_p(feature));
+
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
+       if (!static_key_initialized) {
+               printk("Warning! cpu_has_feature() used prior to jump label init!\n");
+               dump_stack();
+               return early_cpu_has_feature(feature);
+       }
+#endif
+
+       if (CPU_FTRS_ALWAYS & feature)
+               return true;
+
+       if (!(CPU_FTRS_POSSIBLE & feature))
+               return false;
+
+       i = __builtin_ctzl(feature);
+       return static_branch_likely(&cpu_feature_keys[i]);
+}
+#else
+static inline bool cpu_has_feature(unsigned long feature)
+{
+       return early_cpu_has_feature(feature);
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_POWERPC_CPUFEATURE_H */
index df4fb5f..82026b4 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_POWERPC_CPUTABLE_H
 
 
+#include <linux/types.h>
 #include <asm/asm-compat.h>
 #include <asm/feature-fixups.h>
 #include <uapi/asm/cputable.h>
@@ -122,6 +123,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
 
 extern const char *powerpc_base_platform;
 
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
+extern void cpu_feature_keys_init(void);
+#else
+static inline void cpu_feature_keys_init(void) { }
+#endif
+
 /* TLB flush actions. Used as argument to cpu_spec.flush_tlb() hook */
 enum {
        TLB_INVAL_SCOPE_GLOBAL = 0,     /* invalidate all TLBs */
@@ -576,14 +583,6 @@ enum {
 };
 #endif /* __powerpc64__ */
 
-static inline int cpu_has_feature(unsigned long feature)
-{
-       return (CPU_FTRS_ALWAYS & feature) ||
-              (CPU_FTRS_POSSIBLE
-               & cur_cpu_spec->cpu_features
-               & feature);
-}
-
 #define HBP_NUM 1
 
 #endif /* !__ASSEMBLY__ */
index 2dfd4fc..4f60db0 100644 (file)
@@ -28,6 +28,7 @@ static inline void setup_cputime_one_jiffy(void) { }
 #include <asm/div64.h>
 #include <asm/time.h>
 #include <asm/param.h>
+#include <asm/cpu_has_feature.h>
 
 typedef u64 __nocast cputime_t;
 typedef u64 __nocast cputime64_t;
index 5fa6b20..3781673 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/threads.h>
 
 #include <asm/ppc-opcode.h>
+#include <asm/cpu_has_feature.h>
 
 #define PPC_DBELL_MSG_BRDCAST  (0x04000000)
 #define PPC_DBELL_TYPE(x)      (((x) & 0xf) << (63-36))
index 4efc11d..4a2beef 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/cputable.h>
+#include <asm/cpu_has_feature.h>
 
 typedef struct {
        unsigned int base;
index 77816ac..84e3f8d 100644 (file)
@@ -13,7 +13,6 @@
 /* need struct page definitions */
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-debug.h>
 #include <asm/io.h>
 #include <asm/swiotlb.h>
 /* Some dma direct funcs must be visible for use in other dma_ops */
 extern void *__dma_direct_alloc_coherent(struct device *dev, size_t size,
                                         dma_addr_t *dma_handle, gfp_t flag,
-                                        struct dma_attrs *attrs);
+                                        unsigned long attrs);
 extern void __dma_direct_free_coherent(struct device *dev, size_t size,
                                       void *vaddr, dma_addr_t dma_handle,
-                                      struct dma_attrs *attrs);
+                                      unsigned long attrs);
 extern int dma_direct_mmap_coherent(struct device *dev,
                                    struct vm_area_struct *vma,
                                    void *cpu_addr, dma_addr_t handle,
-                                   size_t size, struct dma_attrs *attrs);
+                                   size_t size, unsigned long attrs);
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
diff --git a/arch/powerpc/include/asm/hmi.h b/arch/powerpc/include/asm/hmi.h
new file mode 100644 (file)
index 0000000..88b4901
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Hypervisor Maintenance Interrupt header file.
+ *
+ * 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.
+ *
+ * Copyright 2015 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __ASM_PPC64_HMI_H__
+#define __ASM_PPC64_HMI_H__
+
+#ifdef CONFIG_PPC_BOOK3S_64
+
+#define        CORE_TB_RESYNC_REQ_BIT          63
+#define MAX_SUBCORE_PER_CORE           4
+
+/*
+ * sibling_subcore_state structure is used to co-ordinate all threads
+ * during HMI to avoid TB corruption. This structure is allocated once
+ * per each core and shared by all threads on that core.
+ */
+struct sibling_subcore_state {
+       unsigned long   flags;
+       u8              in_guest[MAX_SUBCORE_PER_CORE];
+};
+
+extern void wait_for_subcore_guest_exit(void);
+extern void wait_for_tb_resync(void);
+#else
+static inline void wait_for_subcore_guest_exit(void) { }
+static inline void wait_for_tb_resync(void) { }
+#endif
+#endif /* __ASM_PPC64_HMI_H__ */
index e2d9f49..c5517f4 100644 (file)
@@ -147,7 +147,7 @@ static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
 {
        pte_t pte;
        pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
-       flush_tlb_page(vma, addr);
+       flush_hugetlb_page(vma, addr);
 }
 
 static inline int huge_pte_none(pte_t pte)
index f49a72a..2c1d507 100644 (file)
@@ -53,7 +53,7 @@ struct iommu_table_ops {
                        long index, long npages,
                        unsigned long uaddr,
                        enum dma_data_direction direction,
-                       struct dma_attrs *attrs);
+                       unsigned long attrs);
 #ifdef CONFIG_IOMMU_API
        /*
         * Exchanges existing TCE with new TCE plus direction bits;
@@ -248,12 +248,12 @@ extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                            struct scatterlist *sglist, int nelems,
                            unsigned long mask,
                            enum dma_data_direction direction,
-                           struct dma_attrs *attrs);
+                           unsigned long attrs);
 extern void ppc_iommu_unmap_sg(struct iommu_table *tbl,
                               struct scatterlist *sglist,
                               int nelems,
                               enum dma_data_direction direction,
-                              struct dma_attrs *attrs);
+                              unsigned long attrs);
 
 extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
                                  size_t size, dma_addr_t *dma_handle,
@@ -264,10 +264,10 @@ extern dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
                                 struct page *page, unsigned long offset,
                                 size_t size, unsigned long mask,
                                 enum dma_data_direction direction,
-                                struct dma_attrs *attrs);
+                                unsigned long attrs);
 extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
                             size_t size, enum dma_data_direction direction,
-                            struct dma_attrs *attrs);
+                            unsigned long attrs);
 
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_dart(struct pci_controller_ops *controller_ops);
index 47e155f..9a287e0 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 
 #include <asm/feature-fixups.h>
+#include <asm/asm-compat.h>
 
 #define JUMP_ENTRY_TYPE                stringify_in_c(FTR_ENTRY_LONG)
 #define JUMP_LABEL_NOP_SIZE    4
@@ -21,7 +22,7 @@
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
        asm_volatile_goto("1:\n\t"
-                "nop\n\t"
+                "nop # arch_static_branch\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
                 ".popsection \n\t"
@@ -35,7 +36,7 @@ l_yes:
 static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
 {
        asm_volatile_goto("1:\n\t"
-                "b %l[l_yes]\n\t"
+                "b %l[l_yes] # arch_static_branch_jump\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
                 ".popsection \n\t"
index 1f4497f..88d17b4 100644 (file)
@@ -181,8 +181,7 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
 
        switch (b_psize) {
        case MMU_PAGE_4K:
-               sllp = ((mmu_psize_defs[a_psize].sllp & SLB_VSID_L) >> 6) |
-                       ((mmu_psize_defs[a_psize].sllp & SLB_VSID_LP) >> 4);
+               sllp = get_sllp_encoding(a_psize);
                rb |= sllp << 5;        /*  AP field */
                rb |= (va_low & 0x7ff) << 12;   /* remaining 11 bits of AVA */
                break;
index 76f5398..0420b38 100644 (file)
@@ -219,8 +219,6 @@ struct machdep_calls {
 #ifdef CONFIG_ARCH_RANDOM
        int (*get_random_seed)(unsigned long *v);
 #endif
-       int (*register_process_table)(unsigned long base, unsigned long page_size,
-                                     unsigned long tbl_size);
 };
 
 extern void e500_idle(void);
index 2563c43..30922f6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <asm/cputable.h>
 #include <linux/mm.h>
+#include <asm/cpu_has_feature.h>
 
 /*
  * This file is included by linux/mman.h, so we can't use cacl_vm_prot_bits()
@@ -31,13 +32,13 @@ static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
 }
 #define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
 
-static inline int arch_validate_prot(unsigned long prot)
+static inline bool arch_validate_prot(unsigned long prot)
 {
        if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM | PROT_SAO))
-               return 0;
+               return false;
        if ((prot & PROT_SAO) && !cpu_has_feature(CPU_FTR_SAO))
-               return 0;
-       return 1;
+               return false;
+       return true;
 }
 #define arch_validate_prot(prot) arch_validate_prot(prot)
 
index 5447122..e2fb408 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 /*
- * First half is MMU families
+ * MMU families
  */
 #define MMU_FTR_HPTE_TABLE             ASM_CONST(0x00000001)
 #define MMU_FTR_TYPE_8xx               ASM_CONST(0x00000002)
 #define MMU_FTR_TYPE_FSL_E             ASM_CONST(0x00000010)
 #define MMU_FTR_TYPE_47x               ASM_CONST(0x00000020)
 
+/* Radix page table supported and enabled */
+#define MMU_FTR_TYPE_RADIX             ASM_CONST(0x00000040)
+
 /*
- * This is individual features
+ * Individual features below.
  */
+
 /*
  * We need to clear top 16bits of va (from the remaining 64 bits )in
  * tlbie* instructions
  */
 #define MMU_FTR_1T_SEGMENT             ASM_CONST(0x40000000)
 
-/*
- * Radix page table available
- */
-#define MMU_FTR_RADIX                  ASM_CONST(0x80000000)
-
 /* MMU feature bit sets for various CPUs */
 #define MMU_FTRS_DEFAULT_HPTE_ARCH_V2  \
        MMU_FTR_HPTE_TABLE | MMU_FTR_PPCAS_ARCH_V2
 #define MMU_FTRS_PA6T          MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
                                MMU_FTR_CI_LARGE_PAGE | MMU_FTR_NO_SLBIE_B
 #ifndef __ASSEMBLY__
+#include <linux/bug.h>
 #include <asm/cputable.h>
 
 #ifdef CONFIG_PPC_FSL_BOOK3E
@@ -131,20 +131,71 @@ enum {
                MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_CI_LARGE_PAGE |
                MMU_FTR_1T_SEGMENT | MMU_FTR_TLBIE_CROP_VA |
 #ifdef CONFIG_PPC_RADIX_MMU
-               MMU_FTR_RADIX |
+               MMU_FTR_TYPE_RADIX |
 #endif
                0,
 };
 
-static inline int mmu_has_feature(unsigned long feature)
+static inline bool early_mmu_has_feature(unsigned long feature)
 {
-       return (MMU_FTRS_POSSIBLE & cur_cpu_spec->mmu_features & feature);
+       return !!(MMU_FTRS_POSSIBLE & cur_cpu_spec->mmu_features & feature);
+}
+
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
+#include <linux/jump_label.h>
+
+#define NUM_MMU_FTR_KEYS       32
+
+extern struct static_key_true mmu_feature_keys[NUM_MMU_FTR_KEYS];
+
+extern void mmu_feature_keys_init(void);
+
+static __always_inline bool mmu_has_feature(unsigned long feature)
+{
+       int i;
+
+       BUILD_BUG_ON(!__builtin_constant_p(feature));
+
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
+       if (!static_key_initialized) {
+               printk("Warning! mmu_has_feature() used prior to jump label init!\n");
+               dump_stack();
+               return early_mmu_has_feature(feature);
+       }
+#endif
+
+       if (!(MMU_FTRS_POSSIBLE & feature))
+               return false;
+
+       i = __builtin_ctzl(feature);
+       return static_branch_likely(&mmu_feature_keys[i]);
 }
 
 static inline void mmu_clear_feature(unsigned long feature)
 {
+       int i;
+
+       i = __builtin_ctzl(feature);
        cur_cpu_spec->mmu_features &= ~feature;
+       static_branch_disable(&mmu_feature_keys[i]);
 }
+#else
+
+static inline void mmu_feature_keys_init(void)
+{
+
+}
+
+static inline bool mmu_has_feature(unsigned long feature)
+{
+       return early_mmu_has_feature(feature);
+}
+
+static inline void mmu_clear_feature(unsigned long feature)
+{
+       cur_cpu_spec->mmu_features &= ~feature;
+}
+#endif /* CONFIG_JUMP_LABEL */
 
 extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
 
@@ -164,6 +215,28 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
 }
 #endif /* !CONFIG_DEBUG_VM */
 
+#ifdef CONFIG_PPC_RADIX_MMU
+static inline bool radix_enabled(void)
+{
+       return mmu_has_feature(MMU_FTR_TYPE_RADIX);
+}
+
+static inline bool early_radix_enabled(void)
+{
+       return early_mmu_has_feature(MMU_FTR_TYPE_RADIX);
+}
+#else
+static inline bool radix_enabled(void)
+{
+       return false;
+}
+
+static inline bool early_radix_enabled(void)
+{
+       return false;
+}
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 /* The kernel use the constants below to index in the page sizes array.
@@ -210,6 +283,7 @@ extern void early_init_mmu(void);
 extern void early_init_mmu_secondary(void);
 extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
                                       phys_addr_t first_memblock_size);
+static inline void mmu_early_init_devtree(void) { }
 #endif /* __ASSEMBLY__ */
 #endif
 
@@ -230,9 +304,5 @@ extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
 #  include <asm/mmu-8xx.h>
 #endif
 
-#ifndef radix_enabled
-#define radix_enabled() (0)
-#endif
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
index ad171e9..148303e 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/kvm_book3s_asm.h>
 #endif
 #include <asm/accounting.h>
+#include <asm/hmi.h>
 
 register struct paca_struct *local_paca asm("r13");
 
@@ -182,6 +183,11 @@ struct paca_struct {
         */
        u16 in_mce;
        u8 hmi_event_available;          /* HMI event is available */
+       /*
+        * Bitmap for sibling subcore status. See kvm/book3s_hv_ras.c for
+        * more details
+        */
+       struct sibling_subcore_state *sibling_subcore_state;
 #endif
 
        /* Stuff for accurate time accounting */
index a6f3ac0..e9bd6cf 100644 (file)
@@ -136,9 +136,6 @@ extern pgprot_t     pci_phys_mem_access_prot(struct file *file,
                                         pgprot_t prot);
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                                const struct resource *rsrc,
-                                resource_size_t *start, resource_size_t *end);
 
 extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
index 40f3615..f69f40f 100644 (file)
@@ -1256,15 +1256,6 @@ static inline void msr_check_and_clear(unsigned long bits)
                __msr_check_and_clear(bits);
 }
 
-static inline unsigned long mfvtb (void)
-{
-#ifdef CONFIG_PPC_BOOK3S_64
-       if (cpu_has_feature(CPU_FTR_ARCH_207S))
-               return mfspr(SPRN_VTB);
-#endif
-       return 0;
-}
-
 #ifdef __powerpc64__
 #if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define mftb()         ({unsigned long rval;                           \
diff --git a/arch/powerpc/include/asm/rtc.h b/arch/powerpc/include/asm/rtc.h
deleted file mode 100644 (file)
index f580292..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Real-time clock definitions and interfaces
- *
- * Author: Tom Rini <trini@mvista.com>
- *
- * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- * Based on:
- * include/asm-m68k/rtc.h
- *
- * Copyright Richard Zidlicky
- * implementation details for genrtc/q40rtc driver
- *
- * And the old drivers/macintosh/rtc.c which was heavily based on:
- * Linux/SPARC Real Time Clock Driver
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * With additional work by Paul Mackerras and Franz Sirl.
- */
-
-#ifndef __ASM_POWERPC_RTC_H__
-#define __ASM_POWERPC_RTC_H__
-
-#ifdef __KERNEL__
-
-#include <linux/rtc.h>
-
-#include <asm/machdep.h>
-#include <asm/time.h>
-
-#define RTC_PIE 0x40           /* periodic interrupt enable */
-#define RTC_AIE 0x20           /* alarm interrupt enable */
-#define RTC_UIE 0x10           /* update-finished interrupt enable */
-
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100     /* battery bad */
-#define RTC_SQWE 0x08          /* enable square-wave output */
-#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
-#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
-
-static inline unsigned int get_rtc_time(struct rtc_time *time)
-{
-       if (ppc_md.get_rtc_time)
-               ppc_md.get_rtc_time(time);
-       return RTC_24H;
-}
-
-/* Set the current date and time in the real time clock. */
-static inline int set_rtc_time(struct rtc_time *time)
-{
-       if (ppc_md.set_rtc_time)
-               return ppc_md.set_rtc_time(time);
-       return -EINVAL;
-}
-
-static inline unsigned int get_rtc_ss(void)
-{
-       struct rtc_time h;
-
-       get_rtc_time(&h);
-       return h.tm_sec;
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-
-#endif /* __KERNEL__ */
-#endif /* __ASM_POWERPC_RTC_H__ */
index 17c8380..0a74ebe 100644 (file)
@@ -75,6 +75,14 @@ static inline void disable_kernel_spe(void)
 static inline void __giveup_spe(struct task_struct *t) { }
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void flush_tmregs_to_thread(struct task_struct *);
+#else
+static inline void flush_tmregs_to_thread(struct task_struct *t)
+{
+}
+#endif
+
 static inline void clear_task_ebb(struct task_struct *t)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
index b21bb1f..87e4b2d 100644 (file)
@@ -138,40 +138,15 @@ static inline struct thread_info *current_thread_info(void)
 /* Don't move TLF_NAPPING without adjusting the code in entry_32.S */
 #define TLF_NAPPING            0       /* idle thread enabled NAP mode */
 #define TLF_SLEEPING           1       /* suspend code enabled SLEEP mode */
-#define TLF_RESTORE_SIGMASK    2       /* Restore signal mask in do_signal */
 #define TLF_LAZY_MMU           3       /* tlb_batch is active */
 #define TLF_RUNLATCH           4       /* Is the runlatch enabled? */
 
 #define _TLF_NAPPING           (1 << TLF_NAPPING)
 #define _TLF_SLEEPING          (1 << TLF_SLEEPING)
-#define _TLF_RESTORE_SIGMASK   (1 << TLF_RESTORE_SIGMASK)
 #define _TLF_LAZY_MMU          (1 << TLF_LAZY_MMU)
 #define _TLF_RUNLATCH          (1 << TLF_RUNLATCH)
 
 #ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->local_flags |= _TLF_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->local_flags & _TLF_RESTORE_SIGMASK))
-               return false;
-       ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
-       return true;
-}
 
 static inline bool test_thread_local_flags(unsigned int flags)
 {
index 0921164..b240666 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/percpu.h>
 
 #include <asm/processor.h>
+#include <asm/cpu_has_feature.h>
 
 /* time.c */
 extern unsigned long tb_ticks_per_jiffy;
@@ -103,7 +104,7 @@ static inline u64 get_vtb(void)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
        if (cpu_has_feature(CPU_FTR_ARCH_207S))
-               return mfvtb();
+               return mfspr(SPRN_VTB);
 #endif
        return 0;
 }
index 20733fa..f6f68f7 100644 (file)
@@ -46,5 +46,18 @@ static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
 #endif
 }
 
+#ifdef CONFIG_SMP
+static inline int mm_is_core_local(struct mm_struct *mm)
+{
+       return cpumask_subset(mm_cpumask(mm),
+                             topology_sibling_cpumask(smp_processor_id()));
+}
+#else
+static inline int mm_is_core_local(struct mm_struct *mm)
+{
+       return 1;
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_TLB_H */
index 1b38eea..13dbcd4 100644 (file)
@@ -54,7 +54,6 @@ extern void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
 #define flush_tlb_page(vma,addr)       local_flush_tlb_page(vma,addr)
 #define __flush_tlb_page(mm,addr,p,i)  __local_flush_tlb_page(mm,addr,p,i)
 #endif
-#define flush_tlb_page_nohash(vma,addr)        flush_tlb_page(vma,addr)
 
 #elif defined(CONFIG_PPC_STD_MMU_32)
 
index b7c20f0..c1dc6c1 100644 (file)
@@ -310,10 +310,15 @@ static inline unsigned long copy_from_user(void *to,
 {
        unsigned long over;
 
-       if (access_ok(VERIFY_READ, from, n))
+       if (access_ok(VERIFY_READ, from, n)) {
+               if (!__builtin_constant_p(n))
+                       check_object_size(to, n, false);
                return __copy_tofrom_user((__force void __user *)to, from, n);
+       }
        if ((unsigned long)from < TASK_SIZE) {
                over = (unsigned long)from + n - TASK_SIZE;
+               if (!__builtin_constant_p(n - over))
+                       check_object_size(to, n - over, false);
                return __copy_tofrom_user((__force void __user *)to, from,
                                n - over) + over;
        }
@@ -325,10 +330,15 @@ static inline unsigned long copy_to_user(void __user *to,
 {
        unsigned long over;
 
-       if (access_ok(VERIFY_WRITE, to, n))
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               if (!__builtin_constant_p(n))
+                       check_object_size(from, n, true);
                return __copy_tofrom_user(to, (__force void __user *)from, n);
+       }
        if ((unsigned long)to < TASK_SIZE) {
                over = (unsigned long)to + n - TASK_SIZE;
+               if (!__builtin_constant_p(n))
+                       check_object_size(from, n - over, true);
                return __copy_tofrom_user(to, (__force void __user *)from,
                                n - over) + over;
        }
@@ -372,6 +382,10 @@ static inline unsigned long __copy_from_user_inatomic(void *to,
                if (ret == 0)
                        return 0;
        }
+
+       if (!__builtin_constant_p(n))
+               check_object_size(to, n, false);
+
        return __copy_tofrom_user((__force void __user *)to, from, n);
 }
 
@@ -398,6 +412,9 @@ static inline unsigned long __copy_to_user_inatomic(void __user *to,
                if (ret == 0)
                        return 0;
        }
+       if (!__builtin_constant_p(n))
+               check_object_size(from, n, true);
+
        return __copy_tofrom_user(to, (__force const void __user *)from, n);
 }
 
index 0abb97f..a36c206 100644 (file)
@@ -23,6 +23,7 @@
 #ifdef CONFIG_ALTIVEC
 
 #include <asm/cputable.h>
+#include <asm/cpu_has_feature.h>
 
 void xor_altivec_2(unsigned long bytes, unsigned long *v1_in,
                   unsigned long *v2_in);
index c2d21d1..3a9e44c 100644 (file)
 
 #define ELF_NGREG      48      /* includes nip, msr, lr, etc. */
 #define ELF_NFPREG     33      /* includes fpscr */
+#define ELF_NVMX       34      /* includes all vector registers */
+#define ELF_NVSX       32      /* includes all VSX registers */
+#define ELF_NTMSPRREG  3       /* include tfhar, tfiar, texasr */
+#define ELF_NEBB       3       /* includes ebbrr, ebbhr, bescr */
+#define ELF_NPMU       5       /* includes siar, sdar, sier, mmcr2, mmcr0 */
 
 typedef unsigned long elf_greg_t64;
 typedef elf_greg_t64 elf_gregset_t64[ELF_NGREG];
index fe4c075..b2027a5 100644 (file)
@@ -41,7 +41,7 @@ obj-$(CONFIG_VDSO32)          += vdso32/
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_power.o
-obj-$(CONFIG_PPC_BOOK3S_64)    += mce.o mce_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)    += mce.o mce_power.o hmi.o
 obj-$(CONFIG_PPC_BOOK3E_64)    += exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC64)            += vdso64/
 obj-$(CONFIG_ALTIVEC)          += vecemu.o
index c7097f9..033f338 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/emulated_ops.h>
 #include <asm/switch_to.h>
 #include <asm/disassemble.h>
+#include <asm/cpu_has_feature.h>
 
 struct aligninfo {
        unsigned char len;
index d81f826..74248ab 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/threads.h>
 #include <linux/init.h>
 #include <linux/export.h>
+#include <linux/jump_label.h>
 
 #include <asm/oprofile_impl.h>
 #include <asm/cputable.h>
@@ -2224,3 +2225,39 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
 
        return NULL;
 }
+
+#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECKS
+struct static_key_true cpu_feature_keys[NUM_CPU_FTR_KEYS] = {
+                       [0 ... NUM_CPU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
+};
+EXPORT_SYMBOL_GPL(cpu_feature_keys);
+
+void __init cpu_feature_keys_init(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_CPU_FTR_KEYS; i++) {
+               unsigned long f = 1ul << i;
+
+               if (!(cur_cpu_spec->cpu_features & f))
+                       static_branch_disable(&cpu_feature_keys[i]);
+       }
+}
+
+struct static_key_true mmu_feature_keys[NUM_MMU_FTR_KEYS] = {
+                       [0 ... NUM_MMU_FTR_KEYS - 1] = STATIC_KEY_TRUE_INIT
+};
+EXPORT_SYMBOL_GPL(mmu_feature_keys);
+
+void __init mmu_feature_keys_init(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_MMU_FTR_KEYS; i++) {
+               unsigned long f = 1ul << i;
+
+               if (!(cur_cpu_spec->mmu_features & f))
+                       static_branch_disable(&mmu_feature_keys[i]);
+       }
+}
+#endif
index 41a7d9d..fb7cbaa 100644 (file)
@@ -18,7 +18,7 @@
  */
 static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
                                      dma_addr_t *dma_handle, gfp_t flag,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        return iommu_alloc_coherent(dev, get_iommu_table_base(dev), size,
                                    dma_handle, dev->coherent_dma_mask, flag,
@@ -27,7 +27,7 @@ static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
 
 static void dma_iommu_free_coherent(struct device *dev, size_t size,
                                    void *vaddr, dma_addr_t dma_handle,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        iommu_free_coherent(get_iommu_table_base(dev), size, vaddr, dma_handle);
 }
@@ -40,7 +40,7 @@ static void dma_iommu_free_coherent(struct device *dev, size_t size,
 static dma_addr_t dma_iommu_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction direction,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        return iommu_map_page(dev, get_iommu_table_base(dev), page, offset,
                              size, device_to_mask(dev), direction, attrs);
@@ -49,7 +49,7 @@ static dma_addr_t dma_iommu_map_page(struct device *dev, struct page *page,
 
 static void dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
                                 size_t size, enum dma_data_direction direction,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        iommu_unmap_page(get_iommu_table_base(dev), dma_handle, size, direction,
                         attrs);
@@ -58,7 +58,7 @@ static void dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
 
 static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        return ppc_iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems,
                                device_to_mask(dev), direction, attrs);
@@ -66,7 +66,7 @@ static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist,
                int nelems, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        ppc_iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems,
                           direction, attrs);
index 3f1472a..e64a601 100644 (file)
@@ -64,7 +64,7 @@ static int dma_direct_dma_supported(struct device *dev, u64 mask)
 
 void *__dma_direct_alloc_coherent(struct device *dev, size_t size,
                                  dma_addr_t *dma_handle, gfp_t flag,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        void *ret;
 #ifdef CONFIG_NOT_COHERENT_CACHE
@@ -121,7 +121,7 @@ void *__dma_direct_alloc_coherent(struct device *dev, size_t size,
 
 void __dma_direct_free_coherent(struct device *dev, size_t size,
                                void *vaddr, dma_addr_t dma_handle,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
 #ifdef CONFIG_NOT_COHERENT_CACHE
        __dma_free_coherent(size, vaddr);
@@ -132,7 +132,7 @@ void __dma_direct_free_coherent(struct device *dev, size_t size,
 
 static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        struct iommu_table *iommu;
 
@@ -156,7 +156,7 @@ static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 
 static void dma_direct_free_coherent(struct device *dev, size_t size,
                                     void *vaddr, dma_addr_t dma_handle,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct iommu_table *iommu;
 
@@ -177,7 +177,7 @@ static void dma_direct_free_coherent(struct device *dev, size_t size,
 
 int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
                             void *cpu_addr, dma_addr_t handle, size_t size,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        unsigned long pfn;
 
@@ -195,7 +195,7 @@ int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
 
 static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
                             int nents, enum dma_data_direction direction,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -211,7 +211,7 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
 
 static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
                                int nents, enum dma_data_direction direction,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
 }
 
@@ -232,7 +232,7 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
                                             unsigned long offset,
                                             size_t size,
                                             enum dma_data_direction dir,
-                                            struct dma_attrs *attrs)
+                                            unsigned long attrs)
 {
        BUG_ON(dir == DMA_NONE);
        __dma_sync_page(page, offset, size, dir);
@@ -243,7 +243,7 @@ static inline void dma_direct_unmap_page(struct device *dev,
                                         dma_addr_t dma_address,
                                         size_t size,
                                         enum dma_data_direction direction,
-                                        struct dma_attrs *attrs)
+                                        unsigned long attrs)
 {
 }
 
index fcb2887..6b8bc0d 100644 (file)
@@ -532,7 +532,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 #ifdef CONFIG_PPC_STD_MMU_64
 BEGIN_MMU_FTR_SECTION
        b       2f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_RADIX)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
 BEGIN_FTR_SECTION
        clrrdi  r6,r8,28        /* get its ESID */
        clrrdi  r9,r1,28        /* get current sp ESID */
index 6200e49..41091fd 100644 (file)
@@ -671,6 +671,8 @@ BEGIN_FTR_SECTION
        beq     h_doorbell_common
        cmpwi   r3,0xea0
        beq     h_virt_irq_common
+       cmpwi   r3,0xe60
+       beq     hmi_exception_common
 FTR_SECTION_ELSE
        cmpwi   r3,0xa00
        beq     doorbell_super_common
@@ -938,7 +940,7 @@ BEGIN_MMU_FTR_SECTION
        b       do_hash_page            /* Try to handle as hpte fault */
 MMU_FTR_SECTION_ELSE
        b       handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_RADIX)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 
        .align  7
        .globl  h_data_storage_common
@@ -969,7 +971,7 @@ BEGIN_MMU_FTR_SECTION
        b       do_hash_page            /* Try to handle as hpte fault */
 MMU_FTR_SECTION_ELSE
        b       handle_page_fault
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_RADIX)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 
        STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception)
 
@@ -1172,7 +1174,7 @@ fwnmi_data_area:
 
        .globl hmi_exception_early
 hmi_exception_early:
-       EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0xe60)
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0xe62)
        mr      r10,r1                  /* Save r1                      */
        ld      r1,PACAEMERGSP(r13)     /* Use emergency stack          */
        subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame            */
@@ -1390,7 +1392,7 @@ slb_miss_realmode:
 #ifdef CONFIG_PPC_STD_MMU_64
 BEGIN_MMU_FTR_SECTION
        bl      slb_allocate_realmode
-END_MMU_FTR_SECTION_IFCLR(MMU_FTR_RADIX)
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX)
 #endif
        /* All done -- return from exception. */
 
@@ -1404,7 +1406,7 @@ BEGIN_MMU_FTR_SECTION
        beq-    2f
 FTR_SECTION_ELSE
        b       2f
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_RADIX)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX)
 
 .machine       push
 .machine       "power4"
diff --git a/arch/powerpc/kernel/hmi.c b/arch/powerpc/kernel/hmi.c
new file mode 100644 (file)
index 0000000..e3f738e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Hypervisor Maintenance Interrupt (HMI) handling.
+ *
+ * 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.
+ *
+ * Copyright 2015 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <asm/paca.h>
+#include <asm/hmi.h>
+
+void wait_for_subcore_guest_exit(void)
+{
+       int i;
+
+       /*
+        * NULL bitmap pointer indicates that KVM module hasn't
+        * been loaded yet and hence no guests are running.
+        * If no KVM is in use, no need to co-ordinate among threads
+        * as all of them will always be in host and no one is going
+        * to modify TB other than the opal hmi handler.
+        * Hence, just return from here.
+        */
+       if (!local_paca->sibling_subcore_state)
+               return;
+
+       for (i = 0; i < MAX_SUBCORE_PER_CORE; i++)
+               while (local_paca->sibling_subcore_state->in_guest[i])
+                       cpu_relax();
+}
+
+void wait_for_tb_resync(void)
+{
+       if (!local_paca->sibling_subcore_state)
+               return;
+
+       while (test_bit(CORE_TB_RESYNC_REQ_BIT,
+                               &local_paca->sibling_subcore_state->flags))
+               cpu_relax();
+}
index a89f4f7..c1ca928 100644 (file)
@@ -65,7 +65,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
                                    size_t size,
                                    dma_addr_t *dma_handle,
                                    gfp_t flag,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        void *mem;
 
@@ -78,7 +78,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
 static void ibmebus_free_coherent(struct device *dev,
                                  size_t size, void *vaddr,
                                  dma_addr_t dma_handle,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        kfree(vaddr);
 }
@@ -88,7 +88,7 @@ static dma_addr_t ibmebus_map_page(struct device *dev,
                                   unsigned long offset,
                                   size_t size,
                                   enum dma_data_direction direction,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        return (dma_addr_t)(page_address(page) + offset);
 }
@@ -97,7 +97,7 @@ static void ibmebus_unmap_page(struct device *dev,
                               dma_addr_t dma_addr,
                               size_t size,
                               enum dma_data_direction direction,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        return;
 }
@@ -105,7 +105,7 @@ static void ibmebus_unmap_page(struct device *dev,
 static int ibmebus_map_sg(struct device *dev,
                          struct scatterlist *sgl,
                          int nents, enum dma_data_direction direction,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -121,7 +121,7 @@ static int ibmebus_map_sg(struct device *dev,
 static void ibmebus_unmap_sg(struct device *dev,
                             struct scatterlist *sg,
                             int nents, enum dma_data_direction direction,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        return;
 }
index 335eb6c..ba79d15 100644 (file)
@@ -336,7 +336,9 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66);            \
        ld      r2,PACATOC(r13);                                        \
        ld      r1,PACAR1(r13);                                         \
        std     r3,ORIG_GPR3(r1);       /* Save original r3 */          \
-       bl      opal_rm_handle_hmi;                                     \
+       li      r3,0;                   /* NULL argument */             \
+       bl      hmi_exception_realmode;                                 \
+       nop;                                                            \
        ld      r3,ORIG_GPR3(r1);       /* Restore original r3 */       \
 20:    nop;
 
@@ -570,7 +572,7 @@ common_exit:
 
 BEGIN_MMU_FTR_SECTION
        b       no_segments
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_RADIX)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        /* Restore SLB  from PACA */
        ld      r8,PACA_SLBSHADOWPTR(r13)
 
index a8e3490..37d6e74 100644 (file)
@@ -307,7 +307,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
                              void *page, unsigned int npages,
                              enum dma_data_direction direction,
                              unsigned long mask, unsigned int align_order,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        unsigned long entry;
        dma_addr_t ret = DMA_ERROR_CODE;
@@ -431,7 +431,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                     struct scatterlist *sglist, int nelems,
                     unsigned long mask, enum dma_data_direction direction,
-                    struct dma_attrs *attrs)
+                    unsigned long attrs)
 {
        dma_addr_t dma_next = 0, dma_addr;
        struct scatterlist *s, *outs, *segstart;
@@ -574,7 +574,7 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 
 void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                        int nelems, enum dma_data_direction direction,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        struct scatterlist *sg;
 
@@ -753,7 +753,7 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
 dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
                          struct page *page, unsigned long offset, size_t size,
                          unsigned long mask, enum dma_data_direction direction,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        dma_addr_t dma_handle = DMA_ERROR_CODE;
        void *vaddr;
@@ -790,7 +790,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 
 void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
                      size_t size, enum dma_data_direction direction,
-                     struct dma_attrs *attrs)
+                     unsigned long attrs)
 {
        unsigned int npages;
 
@@ -845,7 +845,7 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
        nio_pages = size >> tbl->it_page_shift;
        io_order = get_iommu_order(size, tbl);
        mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
-                             mask >> tbl->it_page_shift, io_order, NULL);
+                             mask >> tbl->it_page_shift, io_order, 0);
        if (mapping == DMA_ERROR_CODE) {
                free_pages((unsigned long)ret, order);
                return NULL;
index ac910d9..08887cf 100644 (file)
@@ -75,6 +75,7 @@
 #endif
 #define CREATE_TRACE_POINTS
 #include <asm/trace.h>
+#include <asm/cpu_has_feature.h>
 
 DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 EXPORT_PER_CPU_SYMBOL(irq_stat);
index 93dae29..fa20060 100644 (file)
@@ -184,7 +184,7 @@ void setup_paca(struct paca_struct *new_paca)
         * if we do a GET_PACA() before the feature fixups have been
         * applied
         */
-       if (cpu_has_feature(CPU_FTR_HVMODE))
+       if (early_cpu_has_feature(CPU_FTR_HVMODE))
                mtspr(SPRN_SPRG_HPACA, local_paca);
 #endif
        mtspr(SPRN_SPRG_PACA, local_paca);
index f93942b..a5c0153 100644 (file)
@@ -411,36 +411,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
        return NULL;
 }
 
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
-                                     pgprot_t protection,
-                                     enum pci_mmap_state mmap_state,
-                                     int write_combine)
-{
-
-       /* Write combine is always 0 on non-memory space mappings. On
-        * memory space, if the user didn't pass 1, we check for a
-        * "prefetchable" resource. This is a bit hackish, but we use
-        * this to workaround the inability of /sysfs to provide a write
-        * combine bit
-        */
-       if (mmap_state != pci_mmap_mem)
-               write_combine = 0;
-       else if (write_combine == 0) {
-               if (rp->flags & IORESOURCE_PREFETCH)
-                       write_combine = 1;
-       }
-
-       /* XXX would be nice to have a way to ask for write-through */
-       if (write_combine)
-               return pgprot_noncached_wc(protection);
-       else
-               return pgprot_noncached(protection);
-}
-
 /*
  * This one is used by /dev/mem and fbdev who have no clue about the
  * PCI device, it tries to find the PCI device first and calls the
@@ -514,9 +484,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        vma->vm_pgoff = offset >> PAGE_SHIFT;
-       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
-                                                 vma->vm_page_prot,
-                                                 mmap_state, write_combine);
+       if (write_combine)
+               vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
+       else
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
        ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
                               vma->vm_end - vma->vm_start, vma->vm_page_prot);
@@ -666,39 +637,25 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
                          const struct resource *rsrc,
                          resource_size_t *start, resource_size_t *end)
 {
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0;
+       struct pci_bus_region region;
 
-       if (hose == NULL)
+       if (rsrc->flags & IORESOURCE_IO) {
+               pcibios_resource_to_bus(dev->bus, &region,
+                                       (struct resource *) rsrc);
+               *start = region.start;
+               *end = region.end;
                return;
+       }
 
-       if (rsrc->flags & IORESOURCE_IO)
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-
-       /* We pass a fully fixed up address to userland for MMIO instead of
-        * a BAR value because X is lame and expects to be able to use that
-        * to pass to /dev/mem !
-        *
-        * That means that we'll have potentially 64 bits values where some
-        * userland apps only expect 32 (like X itself since it thinks only
-        * Sparc has 64 bits MMIO) but if we don't do that, we break it on
-        * 32 bits CHRPs :-(
-        *
-        * Hopefully, the sysfs insterface is immune to that gunk. Once X
-        * has been fixed (and the fix spread enough), we can re-enable the
-        * 2 lines below and pass down a BAR value to userland. In that case
-        * we'll also have to re-enable the matching code in
-        * __pci_mmap_make_offset().
+       /* We pass a CPU physical address to userland for MMIO instead of a
+        * BAR value because X is lame and expects to be able to use that
+        * to pass to /dev/mem!
         *
-        * BenH.
+        * That means we may have 64-bit values where some apps only expect
+        * 32 (like X itself since it thinks only Sparc has 64-bit MMIO).
         */
-#if 0
-       else if (rsrc->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-#endif
-
-       *start = rsrc->start - offset;
-       *end = rsrc->end - offset;
+       *start = rsrc->start;
+       *end = rsrc->end;
 }
 
 /**
index a8cca88..58ccf86 100644 (file)
@@ -58,6 +58,7 @@
 #include <asm/code-patching.h>
 #include <asm/exec.h>
 #include <asm/livepatch.h>
+#include <asm/cpu_has_feature.h>
 
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
@@ -1073,6 +1074,26 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 #endif
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+void flush_tmregs_to_thread(struct task_struct *tsk)
+{
+       /*
+        * Process self tracing is not yet supported through
+        * ptrace interface. Ptrace generic code should have
+        * prevented this from happening in the first place.
+        * Warn once here with the message, if some how it
+        * is attempted.
+        */
+       WARN_ONCE(tsk == current,
+               "Not expecting ptrace on self: TM regs may be incorrect\n");
+
+       /*
+        * If task is not current, it should have been flushed
+        * already to it's thread_struct during __switch_to().
+        */
+}
+#endif
+
 struct task_struct *__switch_to(struct task_struct *prev,
        struct task_struct *new)
 {
index bae3db7..b0245be 100644 (file)
@@ -170,7 +170,7 @@ static struct ibm_pa_feature {
         */
        {CPU_FTR_TM_COMP, 0, 0,
         PPC_FEATURE2_HTM_COMP|PPC_FEATURE2_HTM_NOSC_COMP, 22, 0, 0},
-       {0, MMU_FTR_RADIX, 0, 0,                40, 0, 0},
+       {0, MMU_FTR_TYPE_RADIX, 0, 0,           40, 0, 0},
 };
 
 static void __init scan_features(unsigned long node, const unsigned char *ftrs,
@@ -647,14 +647,6 @@ static void __init early_reserve_mem(void)
 #endif
 }
 
-static bool disable_radix;
-static int __init parse_disable_radix(char *p)
-{
-       disable_radix = true;
-       return 0;
-}
-early_param("disable_radix", parse_disable_radix);
-
 void __init early_init_devtree(void *params)
 {
        phys_addr_t limit;
@@ -744,11 +736,8 @@ void __init early_init_devtree(void *params)
         */
        spinning_secondaries = boot_cpu_count - 1;
 #endif
-       /*
-        * now fixup radix MMU mode based on kernel command line
-        */
-       if (disable_radix)
-               cur_cpu_spec->mmu_features &= ~MMU_FTR_RADIX;
+
+       mmu_early_init_devtree();
 
 #ifdef CONFIG_PPC_POWERNV
        /* Scan and build the list of machine check recoverable ranges */
index 134bee9..4f3c575 100644 (file)
@@ -64,6 +64,10 @@ struct pt_regs_offset {
        {.name = STR(gpr##num), .offset = offsetof(struct pt_regs, gpr[num])}
 #define REG_OFFSET_END {.name = NULL, .offset = 0}
 
+#define TVSO(f)        (offsetof(struct thread_vr_state, f))
+#define TFSO(f)        (offsetof(struct thread_fp_state, f))
+#define TSO(f) (offsetof(struct thread_struct, f))
+
 static const struct pt_regs_offset regoffset_table[] = {
        GPR_OFFSET_NAME(0),
        GPR_OFFSET_NAME(1),
@@ -181,6 +185,26 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
        return 0;
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static unsigned long get_user_ckpt_msr(struct task_struct *task)
+{
+       return task->thread.ckpt_regs.msr | task->thread.fpexc_mode;
+}
+
+static int set_user_ckpt_msr(struct task_struct *task, unsigned long msr)
+{
+       task->thread.ckpt_regs.msr &= ~MSR_DEBUGCHANGE;
+       task->thread.ckpt_regs.msr |= msr & MSR_DEBUGCHANGE;
+       return 0;
+}
+
+static int set_user_ckpt_trap(struct task_struct *task, unsigned long trap)
+{
+       task->thread.ckpt_regs.trap = trap & 0xfff0;
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_PPC64
 static int get_user_dscr(struct task_struct *task, unsigned long *data)
 {
@@ -358,6 +382,29 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
        return ret;
 }
 
+/*
+ * When the transaction is active, 'transact_fp' holds the current running
+ * value of all FPR registers and 'fp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction. When transaction
+ * is not active 'fp_state' holds the current running state of all the FPR
+ * registers. So this function which returns the current running values of
+ * all the FPR registers, needs to know whether any transaction is active
+ * or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ * };
+ *
+ * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM
+ * which determines the final code in this function. All the combinations of
+ * these two config options are possible except the one below as transactional
+ * memory config pulls in CONFIG_VSX automatically.
+ *
+ *     !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+ */
 static int fpr_get(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
@@ -368,14 +415,31 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 #endif
        flush_fp_to_thread(target);
 
-#ifdef CONFIG_VSX
+#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+       /* copy to local buffer then write that out */
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_altivec_to_thread(target);
+               flush_tmregs_to_thread(target);
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.TS_TRANS_FPR(i);
+               buf[32] = target->thread.transact_fp.fpscr;
+       } else {
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.TS_FPR(i);
+               buf[32] = target->thread.fp_state.fpscr;
+       }
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+#endif
+
+#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
        /* copy to local buffer then write that out */
        for (i = 0; i < 32 ; i++)
                buf[i] = target->thread.TS_FPR(i);
        buf[32] = target->thread.fp_state.fpscr;
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+#endif
 
-#else
+#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
        BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
                     offsetof(struct thread_fp_state, fpr[32]));
 
@@ -384,6 +448,29 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 #endif
 }
 
+/*
+ * When the transaction is active, 'transact_fp' holds the current running
+ * value of all FPR registers and 'fp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction. When transaction
+ * is not active 'fp_state' holds the current running state of all the FPR
+ * registers. So this function which setss the current running values of
+ * all the FPR registers, needs to know whether any transaction is active
+ * or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ * };
+ *
+ * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM
+ * which determines the final code in this function. All the combinations of
+ * these two config options are possible except the one below as transactional
+ * memory config pulls in CONFIG_VSX automatically.
+ *
+ *     !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+ */
 static int fpr_set(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   const void *kbuf, const void __user *ubuf)
@@ -394,7 +481,27 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
 #endif
        flush_fp_to_thread(target);
 
-#ifdef CONFIG_VSX
+#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM)
+       /* copy to local buffer then write that out */
+       i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+       if (i)
+               return i;
+
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_altivec_to_thread(target);
+               flush_tmregs_to_thread(target);
+               for (i = 0; i < 32 ; i++)
+                       target->thread.TS_TRANS_FPR(i) = buf[i];
+               target->thread.transact_fp.fpscr = buf[32];
+       } else {
+               for (i = 0; i < 32 ; i++)
+                       target->thread.TS_FPR(i) = buf[i];
+               target->thread.fp_state.fpscr = buf[32];
+       }
+       return 0;
+#endif
+
+#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
        /* copy to local buffer then write that out */
        i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
        if (i)
@@ -403,7 +510,9 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
                target->thread.TS_FPR(i) = buf[i];
        target->thread.fp_state.fpscr = buf[32];
        return 0;
-#else
+#endif
+
+#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM)
        BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) !=
                     offsetof(struct thread_fp_state, fpr[32]));
 
@@ -433,10 +542,28 @@ static int vr_active(struct task_struct *target,
        return target->thread.used_vr ? regset->n : 0;
 }
 
+/*
+ * When the transaction is active, 'transact_vr' holds the current running
+ * value of all the VMX registers and 'vr_state' holds the last checkpointed
+ * value of all the VMX registers for the current transaction to fall back
+ * on in case it aborts. When transaction is not active 'vr_state' holds
+ * the current running state of all the VMX registers. So this function which
+ * gets the current running values of all the VMX registers, needs to know
+ * whether any transaction is active or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ * };
+ */
 static int vr_get(struct task_struct *target, const struct user_regset *regset,
                  unsigned int pos, unsigned int count,
                  void *kbuf, void __user *ubuf)
 {
+       struct thread_vr_state *addr;
        int ret;
 
        flush_altivec_to_thread(target);
@@ -444,8 +571,19 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_tmregs_to_thread(target);
+               addr = &target->thread.transact_vr;
+       } else {
+               addr = &target->thread.vr_state;
+       }
+#else
+       addr = &target->thread.vr_state;
+#endif
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.vr_state, 0,
+                                 addr, 0,
                                  33 * sizeof(vector128));
        if (!ret) {
                /*
@@ -456,7 +594,16 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+#else
                vrsave.word = target->thread.vrsave;
+#endif
+
                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
                                          33 * sizeof(vector128), -1);
        }
@@ -464,10 +611,28 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset,
        return ret;
 }
 
+/*
+ * When the transaction is active, 'transact_vr' holds the current running
+ * value of all the VMX registers and 'vr_state' holds the last checkpointed
+ * value of all the VMX registers for the current transaction to fall back
+ * on in case it aborts. When transaction is not active 'vr_state' holds
+ * the current running state of all the VMX registers. So this function which
+ * sets the current running values of all the VMX registers, needs to know
+ * whether any transaction is active or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ * };
+ */
 static int vr_set(struct task_struct *target, const struct user_regset *regset,
                  unsigned int pos, unsigned int count,
                  const void *kbuf, const void __user *ubuf)
 {
+       struct thread_vr_state *addr;
        int ret;
 
        flush_altivec_to_thread(target);
@@ -475,8 +640,19 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
        BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) !=
                     offsetof(struct thread_vr_state, vr[32]));
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               flush_fp_to_thread(target);
+               flush_tmregs_to_thread(target);
+               addr = &target->thread.transact_vr;
+       } else {
+               addr = &target->thread.vr_state;
+       }
+#else
+       addr = &target->thread.vr_state;
+#endif
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                &target->thread.vr_state, 0,
+                                addr, 0,
                                 33 * sizeof(vector128));
        if (!ret && count > 0) {
                /*
@@ -487,11 +663,28 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset,
                        u32 word;
                } vrsave;
                memset(&vrsave, 0, sizeof(vrsave));
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+               if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                       vrsave.word = target->thread.transact_vrsave;
+               else
+                       vrsave.word = target->thread.vrsave;
+#else
                vrsave.word = target->thread.vrsave;
+#endif
                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
                                         33 * sizeof(vector128), -1);
-               if (!ret)
+               if (!ret) {
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+                       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+                               target->thread.transact_vrsave = vrsave.word;
+                       else
+                               target->thread.vrsave = vrsave.word;
+#else
                        target->thread.vrsave = vrsave.word;
+#endif
+               }
        }
 
        return ret;
@@ -512,6 +705,21 @@ static int vsr_active(struct task_struct *target,
        return target->thread.used_vsr ? regset->n : 0;
 }
 
+/*
+ * When the transaction is active, 'transact_fp' holds the current running
+ * value of all FPR registers and 'fp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction. When transaction
+ * is not active 'fp_state' holds the current running state of all the FPR
+ * registers. So this function which returns the current running values of
+ * all the FPR registers, needs to know whether any transaction is active
+ * or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     u64     vsx[32];
+ * };
+ */
 static int vsr_get(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
@@ -519,16 +727,47 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
        u64 buf[32];
        int ret, i;
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+#endif
        flush_vsx_to_thread(target);
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.
+                               transact_fp.fpr[i][TS_VSRLOWOFFSET];
+       } else {
+               for (i = 0; i < 32 ; i++)
+                       buf[i] = target->thread.
+                               fp_state.fpr[i][TS_VSRLOWOFFSET];
+       }
+#else
        for (i = 0; i < 32 ; i++)
                buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
+#endif
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                  buf, 0, 32 * sizeof(double));
 
        return ret;
 }
 
+/*
+ * When the transaction is active, 'transact_fp' holds the current running
+ * value of all FPR registers and 'fp_state' holds the last checkpointed
+ * value of all FPR registers for the current transaction. When transaction
+ * is not active 'fp_state' holds the current running state of all the FPR
+ * registers. So this function which sets the current running values of all
+ * the FPR registers, needs to know whether any transaction is active or not.
+ *
+ * Userspace interface buffer layout:
+ *
+ * struct data {
+ *     u64     vsx[32];
+ * };
+ */
 static int vsr_set(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   const void *kbuf, const void __user *ubuf)
@@ -536,12 +775,30 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset,
        u64 buf[32];
        int ret,i;
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+#endif
        flush_vsx_to_thread(target);
 
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
                                 buf, 0, 32 * sizeof(double));
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (MSR_TM_ACTIVE(target->thread.regs->msr)) {
+               for (i = 0; i < 32 ; i++)
+                       target->thread.transact_fp.
+                               fpr[i][TS_VSRLOWOFFSET] = buf[i];
+       } else {
+               for (i = 0; i < 32 ; i++)
+                       target->thread.fp_state.
+                               fpr[i][TS_VSRLOWOFFSET] = buf[i];
+       }
+#else
        for (i = 0; i < 32 ; i++)
                target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+#endif
 
 
        return ret;
@@ -614,143 +871,1277 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset,
 }
 #endif /* CONFIG_SPE */
 
-
-/*
- * These are our native regset flavors.
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/**
+ * tm_cgpr_active - get active number of registers in CGPR
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ *
+ * This function checks for the active number of available
+ * regisers in transaction checkpointed GPR category.
  */
-enum powerpc_regset {
-       REGSET_GPR,
-       REGSET_FPR,
-#ifdef CONFIG_ALTIVEC
-       REGSET_VMX,
-#endif
-#ifdef CONFIG_VSX
-       REGSET_VSX,
-#endif
-#ifdef CONFIG_SPE
-       REGSET_SPE,
-#endif
-};
-
-static const struct user_regset native_regsets[] = {
-       [REGSET_GPR] = {
-               .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
-               .size = sizeof(long), .align = sizeof(long),
-               .get = gpr_get, .set = gpr_set
-       },
-       [REGSET_FPR] = {
-               .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
-               .size = sizeof(double), .align = sizeof(double),
-               .get = fpr_get, .set = fpr_set
-       },
-#ifdef CONFIG_ALTIVEC
-       [REGSET_VMX] = {
-               .core_note_type = NT_PPC_VMX, .n = 34,
-               .size = sizeof(vector128), .align = sizeof(vector128),
-               .active = vr_active, .get = vr_get, .set = vr_set
-       },
-#endif
-#ifdef CONFIG_VSX
-       [REGSET_VSX] = {
-               .core_note_type = NT_PPC_VSX, .n = 32,
-               .size = sizeof(double), .align = sizeof(double),
-               .active = vsr_active, .get = vsr_get, .set = vsr_set
-       },
-#endif
-#ifdef CONFIG_SPE
-       [REGSET_SPE] = {
-               .core_note_type = NT_PPC_SPE, .n = 35,
-               .size = sizeof(u32), .align = sizeof(u32),
-               .active = evr_active, .get = evr_get, .set = evr_set
-       },
-#endif
-};
+static int tm_cgpr_active(struct task_struct *target,
+                         const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
 
-static const struct user_regset_view user_ppc_native_view = {
-       .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
-       .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
-};
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return 0;
 
-#ifdef CONFIG_PPC64
-#include <linux/compat.h>
+       return regset->n;
+}
 
-static int gpr32_get(struct task_struct *target,
-                    const struct user_regset *regset,
-                    unsigned int pos, unsigned int count,
-                    void *kbuf, void __user *ubuf)
+/**
+ * tm_cgpr_get - get CGPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy from.
+ * @ubuf:      User buffer to copy into.
+ *
+ * This function gets transaction checkpointed GPR registers.
+ *
+ * When the transaction is active, 'ckpt_regs' holds all the checkpointed
+ * GPR register values for the current transaction to fall back on if it
+ * aborts in between. This function gets those checkpointed GPR registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     struct pt_regs ckpt_regs;
+ * };
+ */
+static int tm_cgpr_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
 {
-       const unsigned long *regs = &target->thread.regs->gpr[0];
-       compat_ulong_t *k = kbuf;
-       compat_ulong_t __user *u = ubuf;
-       compat_ulong_t reg;
-       int i;
+       int ret;
 
-       if (target->thread.regs == NULL)
-               return -EIO;
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
 
-       if (!FULL_REGS(target->thread.regs)) {
-               /* We have a partial register set.  Fill 14-31 with bogus values */
-               for (i = 14; i < 32; i++)
-                       target->thread.regs->gpr[i] = NV_REG_POISON; 
-       }
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
 
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
 
-       if (kbuf)
-               for (; count > 0 && pos < PT_MSR; --count)
-                       *k++ = regs[pos++];
-       else
-               for (; count > 0 && pos < PT_MSR; --count)
-                       if (__put_user((compat_ulong_t) regs[pos++], u++))
-                               return -EFAULT;
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.ckpt_regs,
+                                 0, offsetof(struct pt_regs, msr));
+       if (!ret) {
+               unsigned long msr = get_user_ckpt_msr(target);
 
-       if (count > 0 && pos == PT_MSR) {
-               reg = get_user_msr(target);
-               if (kbuf)
-                       *k++ = reg;
-               else if (__put_user(reg, u++))
-                       return -EFAULT;
-               ++pos;
-               --count;
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
+                                         offsetof(struct pt_regs, msr),
+                                         offsetof(struct pt_regs, msr) +
+                                         sizeof(msr));
        }
 
-       if (kbuf)
-               for (; count > 0 && pos < PT_REGS_COUNT; --count)
-                       *k++ = regs[pos++];
-       else
-               for (; count > 0 && pos < PT_REGS_COUNT; --count)
-                       if (__put_user((compat_ulong_t) regs[pos++], u++))
-                               return -EFAULT;
+       BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+                    offsetof(struct pt_regs, msr) + sizeof(long));
 
-       kbuf = k;
-       ubuf = u;
-       pos *= sizeof(reg);
-       count *= sizeof(reg);
-       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
-                                       PT_REGS_COUNT * sizeof(reg), -1);
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.ckpt_regs.orig_gpr3,
+                                         offsetof(struct pt_regs, orig_gpr3),
+                                         sizeof(struct pt_regs));
+       if (!ret)
+               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                              sizeof(struct pt_regs), -1);
+
+       return ret;
 }
 
-static int gpr32_set(struct task_struct *target,
-                    const struct user_regset *regset,
-                    unsigned int pos, unsigned int count,
-                    const void *kbuf, const void __user *ubuf)
+/*
+ * tm_cgpr_set - set the CGPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy into.
+ * @ubuf:      User buffer to copy from.
+ *
+ * This function sets in transaction checkpointed GPR registers.
+ *
+ * When the transaction is active, 'ckpt_regs' holds the checkpointed
+ * GPR register values for the current transaction to fall back on if it
+ * aborts in between. This function sets those checkpointed GPR registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     struct pt_regs ckpt_regs;
+ * };
+ */
+static int tm_cgpr_set(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       const void *kbuf, const void __user *ubuf)
 {
-       unsigned long *regs = &target->thread.regs->gpr[0];
-       const compat_ulong_t *k = kbuf;
-       const compat_ulong_t __user *u = ubuf;
-       compat_ulong_t reg;
+       unsigned long reg;
+       int ret;
 
-       if (target->thread.regs == NULL)
-               return -EIO;
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
 
-       CHECK_FULL_REGS(target->thread.regs);
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
 
-       pos /= sizeof(reg);
-       count /= sizeof(reg);
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
 
-       if (kbuf)
-               for (; count > 0 && pos < PT_MSR; --count)
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &target->thread.ckpt_regs,
+                                0, PT_MSR * sizeof(reg));
+
+       if (!ret && count > 0) {
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+                                        PT_MSR * sizeof(reg),
+                                        (PT_MSR + 1) * sizeof(reg));
+               if (!ret)
+                       ret = set_user_ckpt_msr(target, reg);
+       }
+
+       BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
+                    offsetof(struct pt_regs, msr) + sizeof(long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        &target->thread.ckpt_regs.orig_gpr3,
+                                        PT_ORIG_R3 * sizeof(reg),
+                                        (PT_MAX_PUT_REG + 1) * sizeof(reg));
+
+       if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
+               ret = user_regset_copyin_ignore(
+                       &pos, &count, &kbuf, &ubuf,
+                       (PT_MAX_PUT_REG + 1) * sizeof(reg),
+                       PT_TRAP * sizeof(reg));
+
+       if (!ret && count > 0) {
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &reg,
+                                        PT_TRAP * sizeof(reg),
+                                        (PT_TRAP + 1) * sizeof(reg));
+               if (!ret)
+                       ret = set_user_ckpt_trap(target, reg);
+       }
+
+       if (!ret)
+               ret = user_regset_copyin_ignore(
+                       &pos, &count, &kbuf, &ubuf,
+                       (PT_TRAP + 1) * sizeof(reg), -1);
+
+       return ret;
+}
+
+/**
+ * tm_cfpr_active - get active number of registers in CFPR
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ *
+ * This function checks for the active number of available
+ * regisers in transaction checkpointed FPR category.
+ */
+static int tm_cfpr_active(struct task_struct *target,
+                               const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return 0;
+
+       return regset->n;
+}
+
+/**
+ * tm_cfpr_get - get CFPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy from.
+ * @ubuf:      User buffer to copy into.
+ *
+ * This function gets in transaction checkpointed FPR registers.
+ *
+ * When the transaction is active 'fp_state' holds the checkpointed
+ * values for the current transaction to fall back on if it aborts
+ * in between. This function gets those checkpointed FPR registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ *};
+ */
+static int tm_cfpr_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
+{
+       u64 buf[33];
+       int i;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       /* copy to local buffer then write that out */
+       for (i = 0; i < 32 ; i++)
+               buf[i] = target->thread.TS_FPR(i);
+       buf[32] = target->thread.fp_state.fpscr;
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+}
+
+/**
+ * tm_cfpr_set - set CFPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy into.
+ * @ubuf:      User buffer to copy from.
+ *
+ * This function sets in transaction checkpointed FPR registers.
+ *
+ * When the transaction is active 'fp_state' holds the checkpointed
+ * FPR register values for the current transaction to fall back on
+ * if it aborts in between. This function sets these checkpointed
+ * FPR registers. The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     u64     fpr[32];
+ *     u64     fpscr;
+ *};
+ */
+static int tm_cfpr_set(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       const void *kbuf, const void __user *ubuf)
+{
+       u64 buf[33];
+       int i;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       /* copy to local buffer then write that out */
+       i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
+       if (i)
+               return i;
+       for (i = 0; i < 32 ; i++)
+               target->thread.TS_FPR(i) = buf[i];
+       target->thread.fp_state.fpscr = buf[32];
+       return 0;
+}
+
+/**
+ * tm_cvmx_active - get active number of registers in CVMX
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ *
+ * This function checks for the active number of available
+ * regisers in checkpointed VMX category.
+ */
+static int tm_cvmx_active(struct task_struct *target,
+                               const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return 0;
+
+       return regset->n;
+}
+
+/**
+ * tm_cvmx_get - get CMVX registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy from.
+ * @ubuf:      User buffer to copy into.
+ *
+ * This function gets in transaction checkpointed VMX registers.
+ *
+ * When the transaction is active 'vr_state' and 'vr_save' hold
+ * the checkpointed values for the current transaction to fall
+ * back on if it aborts in between. The userspace interface buffer
+ * layout is as follows.
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ *};
+ */
+static int tm_cvmx_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       /* Flush the state */
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                       &target->thread.vr_state, 0,
+                                       33 * sizeof(vector128));
+       if (!ret) {
+               /*
+                * Copy out only the low-order word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                               33 * sizeof(vector128), -1);
+       }
+
+       return ret;
+}
+
+/**
+ * tm_cvmx_set - set CMVX registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy into.
+ * @ubuf:      User buffer to copy from.
+ *
+ * This function sets in transaction checkpointed VMX registers.
+ *
+ * When the transaction is active 'vr_state' and 'vr_save' hold
+ * the checkpointed values for the current transaction to fall
+ * back on if it aborts in between. The userspace interface buffer
+ * layout is as follows.
+ *
+ * struct data {
+ *     vector128       vr[32];
+ *     vector128       vscr;
+ *     vector128       vrsave;
+ *};
+ */
+static int tm_cvmx_set(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       BUILD_BUG_ON(TVSO(vscr) != TVSO(vr[32]));
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                       &target->thread.vr_state, 0,
+                                       33 * sizeof(vector128));
+       if (!ret && count > 0) {
+               /*
+                * We use only the low-order word of vrsave.
+                */
+               union {
+                       elf_vrreg_t reg;
+                       u32 word;
+               } vrsave;
+               memset(&vrsave, 0, sizeof(vrsave));
+               vrsave.word = target->thread.vrsave;
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
+                                               33 * sizeof(vector128), -1);
+               if (!ret)
+                       target->thread.vrsave = vrsave.word;
+       }
+
+       return ret;
+}
+
+/**
+ * tm_cvsx_active - get active number of registers in CVSX
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ *
+ * This function checks for the active number of available
+ * regisers in transaction checkpointed VSX category.
+ */
+static int tm_cvsx_active(struct task_struct *target,
+                               const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return 0;
+
+       flush_vsx_to_thread(target);
+       return target->thread.used_vsr ? regset->n : 0;
+}
+
+/**
+ * tm_cvsx_get - get CVSX registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy from.
+ * @ubuf:      User buffer to copy into.
+ *
+ * This function gets in transaction checkpointed VSX registers.
+ *
+ * When the transaction is active 'fp_state' holds the checkpointed
+ * values for the current transaction to fall back on if it aborts
+ * in between. This function gets those checkpointed VSX registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     u64     vsx[32];
+ *};
+ */
+static int tm_cvsx_get(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       void *kbuf, void __user *ubuf)
+{
+       u64 buf[32];
+       int ret, i;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       /* Flush the state */
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+       flush_vsx_to_thread(target);
+
+       for (i = 0; i < 32 ; i++)
+               buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                 buf, 0, 32 * sizeof(double));
+
+       return ret;
+}
+
+/**
+ * tm_cvsx_set - set CFPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy into.
+ * @ubuf:      User buffer to copy from.
+ *
+ * This function sets in transaction checkpointed VSX registers.
+ *
+ * When the transaction is active 'fp_state' holds the checkpointed
+ * VSX register values for the current transaction to fall back on
+ * if it aborts in between. This function sets these checkpointed
+ * FPR registers. The userspace interface buffer layout is as follows.
+ *
+ * struct data {
+ *     u64     vsx[32];
+ *};
+ */
+static int tm_cvsx_set(struct task_struct *target,
+                       const struct user_regset *regset,
+                       unsigned int pos, unsigned int count,
+                       const void *kbuf, const void __user *ubuf)
+{
+       u64 buf[32];
+       int ret, i;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       /* Flush the state */
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+       flush_vsx_to_thread(target);
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                buf, 0, 32 * sizeof(double));
+       for (i = 0; i < 32 ; i++)
+               target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i];
+
+       return ret;
+}
+
+/**
+ * tm_spr_active - get active number of registers in TM SPR
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ *
+ * This function checks the active number of available
+ * regisers in the transactional memory SPR category.
+ */
+static int tm_spr_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       return regset->n;
+}
+
+/**
+ * tm_spr_get - get the TM related SPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy from.
+ * @ubuf:      User buffer to copy into.
+ *
+ * This function gets transactional memory related SPR registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct {
+ *     u64             tm_tfhar;
+ *     u64             tm_texasr;
+ *     u64             tm_tfiar;
+ * };
+ */
+static int tm_spr_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       /* Build tests */
+       BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
+       BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
+       BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs));
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       /* Flush the states */
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       /* TFHAR register */
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tfhar, 0, sizeof(u64));
+
+       /* TEXASR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_texasr, sizeof(u64),
+                               2 * sizeof(u64));
+
+       /* TFIAR register */
+       if (!ret)
+               ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tfiar,
+                               2 * sizeof(u64), 3 * sizeof(u64));
+       return ret;
+}
+
+/**
+ * tm_spr_set - set the TM related SPR registers
+ * @target:    The target task.
+ * @regset:    The user regset structure.
+ * @pos:       The buffer position.
+ * @count:     Number of bytes to copy.
+ * @kbuf:      Kernel buffer to copy into.
+ * @ubuf:      User buffer to copy from.
+ *
+ * This function sets transactional memory related SPR registers.
+ * The userspace interface buffer layout is as follows.
+ *
+ * struct {
+ *     u64             tm_tfhar;
+ *     u64             tm_texasr;
+ *     u64             tm_tfiar;
+ * };
+ */
+static int tm_spr_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       /* Build tests */
+       BUILD_BUG_ON(TSO(tm_tfhar) + sizeof(u64) != TSO(tm_texasr));
+       BUILD_BUG_ON(TSO(tm_texasr) + sizeof(u64) != TSO(tm_tfiar));
+       BUILD_BUG_ON(TSO(tm_tfiar) + sizeof(u64) != TSO(ckpt_regs));
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       /* Flush the states */
+       flush_fp_to_thread(target);
+       flush_altivec_to_thread(target);
+       flush_tmregs_to_thread(target);
+
+       /* TFHAR register */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tfhar, 0, sizeof(u64));
+
+       /* TEXASR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_texasr, sizeof(u64),
+                               2 * sizeof(u64));
+
+       /* TFIAR register */
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tfiar,
+                                2 * sizeof(u64), 3 * sizeof(u64));
+       return ret;
+}
+
+static int tm_tar_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               return regset->n;
+
+       return 0;
+}
+
+static int tm_tar_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tar, 0, sizeof(u64));
+       return ret;
+}
+
+static int tm_tar_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_tar, 0, sizeof(u64));
+       return ret;
+}
+
+static int tm_ppr_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               return regset->n;
+
+       return 0;
+}
+
+
+static int tm_ppr_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_ppr, 0, sizeof(u64));
+       return ret;
+}
+
+static int tm_ppr_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_ppr, 0, sizeof(u64));
+       return ret;
+}
+
+static int tm_dscr_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (MSR_TM_ACTIVE(target->thread.regs->msr))
+               return regset->n;
+
+       return 0;
+}
+
+static int tm_dscr_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_dscr, 0, sizeof(u64));
+       return ret;
+}
+
+static int tm_dscr_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return -ENODEV;
+
+       if (!MSR_TM_ACTIVE(target->thread.regs->msr))
+               return -ENODATA;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tm_dscr, 0, sizeof(u64));
+       return ret;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
+#ifdef CONFIG_PPC64
+static int ppr_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.ppr, 0, sizeof(u64));
+       return ret;
+}
+
+static int ppr_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.ppr, 0, sizeof(u64));
+       return ret;
+}
+
+static int dscr_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.dscr, 0, sizeof(u64));
+       return ret;
+}
+static int dscr_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.dscr, 0, sizeof(u64));
+       return ret;
+}
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+static int tar_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tar, 0, sizeof(u64));
+       return ret;
+}
+static int tar_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                               &target->thread.tar, 0, sizeof(u64));
+       return ret;
+}
+
+static int ebb_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       if (target->thread.used_ebb)
+               return regset->n;
+
+       return 0;
+}
+
+static int ebb_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       /* Build tests */
+       BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr));
+       BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr));
+
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       if (!target->thread.used_ebb)
+               return -ENODATA;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.ebbrr, 0, 3 * sizeof(unsigned long));
+}
+
+static int ebb_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret = 0;
+
+       /* Build tests */
+       BUILD_BUG_ON(TSO(ebbrr) + sizeof(unsigned long) != TSO(ebbhr));
+       BUILD_BUG_ON(TSO(ebbhr) + sizeof(unsigned long) != TSO(bescr));
+
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       if (target->thread.used_ebb)
+               return -ENODATA;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.ebbrr, 0, sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.ebbhr, sizeof(unsigned long),
+                       2 * sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.bescr,
+                       2 * sizeof(unsigned long), 3 * sizeof(unsigned long));
+
+       return ret;
+}
+static int pmu_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       return regset->n;
+}
+
+static int pmu_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       /* Build tests */
+       BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar));
+       BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier));
+       BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2));
+       BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0));
+
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.siar, 0,
+                       5 * sizeof(unsigned long));
+}
+
+static int pmu_set(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     const void *kbuf, const void __user *ubuf)
+{
+       int ret = 0;
+
+       /* Build tests */
+       BUILD_BUG_ON(TSO(siar) + sizeof(unsigned long) != TSO(sdar));
+       BUILD_BUG_ON(TSO(sdar) + sizeof(unsigned long) != TSO(sier));
+       BUILD_BUG_ON(TSO(sier) + sizeof(unsigned long) != TSO(mmcr2));
+       BUILD_BUG_ON(TSO(mmcr2) + sizeof(unsigned long) != TSO(mmcr0));
+
+       if (!cpu_has_feature(CPU_FTR_ARCH_207S))
+               return -ENODEV;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.siar, 0,
+                       sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.sdar, sizeof(unsigned long),
+                       2 * sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.sier, 2 * sizeof(unsigned long),
+                       3 * sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.mmcr2, 3 * sizeof(unsigned long),
+                       4 * sizeof(unsigned long));
+
+       if (!ret)
+               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                       &target->thread.mmcr0, 4 * sizeof(unsigned long),
+                       5 * sizeof(unsigned long));
+       return ret;
+}
+#endif
+/*
+ * These are our native regset flavors.
+ */
+enum powerpc_regset {
+       REGSET_GPR,
+       REGSET_FPR,
+#ifdef CONFIG_ALTIVEC
+       REGSET_VMX,
+#endif
+#ifdef CONFIG_VSX
+       REGSET_VSX,
+#endif
+#ifdef CONFIG_SPE
+       REGSET_SPE,
+#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       REGSET_TM_CGPR,         /* TM checkpointed GPR registers */
+       REGSET_TM_CFPR,         /* TM checkpointed FPR registers */
+       REGSET_TM_CVMX,         /* TM checkpointed VMX registers */
+       REGSET_TM_CVSX,         /* TM checkpointed VSX registers */
+       REGSET_TM_SPR,          /* TM specific SPR registers */
+       REGSET_TM_CTAR,         /* TM checkpointed TAR register */
+       REGSET_TM_CPPR,         /* TM checkpointed PPR register */
+       REGSET_TM_CDSCR,        /* TM checkpointed DSCR register */
+#endif
+#ifdef CONFIG_PPC64
+       REGSET_PPR,             /* PPR register */
+       REGSET_DSCR,            /* DSCR register */
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       REGSET_TAR,             /* TAR register */
+       REGSET_EBB,             /* EBB registers */
+       REGSET_PMR,             /* Performance Monitor Registers */
+#endif
+};
+
+static const struct user_regset native_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+               .size = sizeof(long), .align = sizeof(long),
+               .get = gpr_get, .set = gpr_set
+       },
+       [REGSET_FPR] = {
+               .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .get = fpr_get, .set = fpr_set
+       },
+#ifdef CONFIG_ALTIVEC
+       [REGSET_VMX] = {
+               .core_note_type = NT_PPC_VMX, .n = 34,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .active = vr_active, .get = vr_get, .set = vr_set
+       },
+#endif
+#ifdef CONFIG_VSX
+       [REGSET_VSX] = {
+               .core_note_type = NT_PPC_VSX, .n = 32,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = vsr_active, .get = vsr_get, .set = vsr_set
+       },
+#endif
+#ifdef CONFIG_SPE
+       [REGSET_SPE] = {
+               .core_note_type = NT_PPC_SPE, .n = 35,
+               .size = sizeof(u32), .align = sizeof(u32),
+               .active = evr_active, .get = evr_get, .set = evr_set
+       },
+#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       [REGSET_TM_CGPR] = {
+               .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
+               .size = sizeof(long), .align = sizeof(long),
+               .active = tm_cgpr_active, .get = tm_cgpr_get, .set = tm_cgpr_set
+       },
+       [REGSET_TM_CFPR] = {
+               .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set
+       },
+       [REGSET_TM_CVMX] = {
+               .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
+       },
+       [REGSET_TM_CVSX] = {
+               .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
+       },
+       [REGSET_TM_SPR] = {
+               .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set
+       },
+       [REGSET_TM_CTAR] = {
+               .core_note_type = NT_PPC_TM_CTAR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set
+       },
+       [REGSET_TM_CPPR] = {
+               .core_note_type = NT_PPC_TM_CPPR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set
+       },
+       [REGSET_TM_CDSCR] = {
+               .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set
+       },
+#endif
+#ifdef CONFIG_PPC64
+       [REGSET_PPR] = {
+               .core_note_type = NT_PPC_PPR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = ppr_get, .set = ppr_set
+       },
+       [REGSET_DSCR] = {
+               .core_note_type = NT_PPC_DSCR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = dscr_get, .set = dscr_set
+       },
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       [REGSET_TAR] = {
+               .core_note_type = NT_PPC_TAR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tar_get, .set = tar_set
+       },
+       [REGSET_EBB] = {
+               .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = ebb_active, .get = ebb_get, .set = ebb_set
+       },
+       [REGSET_PMR] = {
+               .core_note_type = NT_PPC_PMU, .n = ELF_NPMU,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = pmu_active, .get = pmu_get, .set = pmu_set
+       },
+#endif
+};
+
+static const struct user_regset_view user_ppc_native_view = {
+       .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
+       .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
+
+#ifdef CONFIG_PPC64
+#include <linux/compat.h>
+
+static int gpr32_get_common(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                           void *kbuf, void __user *ubuf, bool tm_active)
+{
+       const unsigned long *regs = &target->thread.regs->gpr[0];
+       const unsigned long *ckpt_regs;
+       compat_ulong_t *k = kbuf;
+       compat_ulong_t __user *u = ubuf;
+       compat_ulong_t reg;
+       int i;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       ckpt_regs = &target->thread.ckpt_regs.gpr[0];
+#endif
+       if (tm_active) {
+               regs = ckpt_regs;
+       } else {
+               if (target->thread.regs == NULL)
+                       return -EIO;
+
+               if (!FULL_REGS(target->thread.regs)) {
+                       /*
+                        * We have a partial register set.
+                        * Fill 14-31 with bogus values.
+                        */
+                       for (i = 14; i < 32; i++)
+                               target->thread.regs->gpr[i] = NV_REG_POISON;
+               }
+       }
+
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
+
+       if (kbuf)
+               for (; count > 0 && pos < PT_MSR; --count)
+                       *k++ = regs[pos++];
+       else
+               for (; count > 0 && pos < PT_MSR; --count)
+                       if (__put_user((compat_ulong_t) regs[pos++], u++))
+                               return -EFAULT;
+
+       if (count > 0 && pos == PT_MSR) {
+               reg = get_user_msr(target);
+               if (kbuf)
+                       *k++ = reg;
+               else if (__put_user(reg, u++))
+                       return -EFAULT;
+               ++pos;
+               --count;
+       }
+
+       if (kbuf)
+               for (; count > 0 && pos < PT_REGS_COUNT; --count)
+                       *k++ = regs[pos++];
+       else
+               for (; count > 0 && pos < PT_REGS_COUNT; --count)
+                       if (__put_user((compat_ulong_t) regs[pos++], u++))
+                               return -EFAULT;
+
+       kbuf = k;
+       ubuf = u;
+       pos *= sizeof(reg);
+       count *= sizeof(reg);
+       return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+                                       PT_REGS_COUNT * sizeof(reg), -1);
+}
+
+static int gpr32_set_common(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf, bool tm_active)
+{
+       unsigned long *regs = &target->thread.regs->gpr[0];
+       unsigned long *ckpt_regs;
+       const compat_ulong_t *k = kbuf;
+       const compat_ulong_t __user *u = ubuf;
+       compat_ulong_t reg;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       ckpt_regs = &target->thread.ckpt_regs.gpr[0];
+#endif
+
+       if (tm_active) {
+               regs = ckpt_regs;
+       } else {
+               regs = &target->thread.regs->gpr[0];
+
+               if (target->thread.regs == NULL)
+                       return -EIO;
+
+               CHECK_FULL_REGS(target->thread.regs);
+       }
+
+       pos /= sizeof(reg);
+       count /= sizeof(reg);
+
+       if (kbuf)
+               for (; count > 0 && pos < PT_MSR; --count)
                        regs[pos++] = *k++;
        else
                for (; count > 0 && pos < PT_MSR; --count) {
@@ -804,6 +2195,40 @@ static int gpr32_set(struct task_struct *target,
                                         (PT_TRAP + 1) * sizeof(reg), -1);
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static int tm_cgpr32_get(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    void *kbuf, void __user *ubuf)
+{
+       return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, 1);
+}
+
+static int tm_cgpr32_set(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf)
+{
+       return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 1);
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
+static int gpr32_get(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    void *kbuf, void __user *ubuf)
+{
+       return gpr32_get_common(target, regset, pos, count, kbuf, ubuf, 0);
+}
+
+static int gpr32_set(struct task_struct *target,
+                    const struct user_regset *regset,
+                    unsigned int pos, unsigned int count,
+                    const void *kbuf, const void __user *ubuf)
+{
+       return gpr32_set_common(target, regset, pos, count, kbuf, ubuf, 0);
+}
+
 /*
  * These are the regset flavors matching the CONFIG_PPC32 native set.
  */
@@ -832,6 +2257,73 @@ static const struct user_regset compat_regsets[] = {
                .active = evr_active, .get = evr_get, .set = evr_set
        },
 #endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       [REGSET_TM_CGPR] = {
+               .core_note_type = NT_PPC_TM_CGPR, .n = ELF_NGREG,
+               .size = sizeof(long), .align = sizeof(long),
+               .active = tm_cgpr_active,
+               .get = tm_cgpr32_get, .set = tm_cgpr32_set
+       },
+       [REGSET_TM_CFPR] = {
+               .core_note_type = NT_PPC_TM_CFPR, .n = ELF_NFPREG,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = tm_cfpr_active, .get = tm_cfpr_get, .set = tm_cfpr_set
+       },
+       [REGSET_TM_CVMX] = {
+               .core_note_type = NT_PPC_TM_CVMX, .n = ELF_NVMX,
+               .size = sizeof(vector128), .align = sizeof(vector128),
+               .active = tm_cvmx_active, .get = tm_cvmx_get, .set = tm_cvmx_set
+       },
+       [REGSET_TM_CVSX] = {
+               .core_note_type = NT_PPC_TM_CVSX, .n = ELF_NVSX,
+               .size = sizeof(double), .align = sizeof(double),
+               .active = tm_cvsx_active, .get = tm_cvsx_get, .set = tm_cvsx_set
+       },
+       [REGSET_TM_SPR] = {
+               .core_note_type = NT_PPC_TM_SPR, .n = ELF_NTMSPRREG,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_spr_active, .get = tm_spr_get, .set = tm_spr_set
+       },
+       [REGSET_TM_CTAR] = {
+               .core_note_type = NT_PPC_TM_CTAR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_tar_active, .get = tm_tar_get, .set = tm_tar_set
+       },
+       [REGSET_TM_CPPR] = {
+               .core_note_type = NT_PPC_TM_CPPR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_ppr_active, .get = tm_ppr_get, .set = tm_ppr_set
+       },
+       [REGSET_TM_CDSCR] = {
+               .core_note_type = NT_PPC_TM_CDSCR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = tm_dscr_active, .get = tm_dscr_get, .set = tm_dscr_set
+       },
+#endif
+#ifdef CONFIG_PPC64
+       [REGSET_PPR] = {
+               .core_note_type = NT_PPC_PPR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = ppr_get, .set = ppr_set
+       },
+       [REGSET_DSCR] = {
+               .core_note_type = NT_PPC_DSCR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = dscr_get, .set = dscr_set
+       },
+#endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       [REGSET_TAR] = {
+               .core_note_type = NT_PPC_TAR, .n = 1,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .get = tar_get, .set = tar_set
+       },
+       [REGSET_EBB] = {
+               .core_note_type = NT_PPC_EBB, .n = ELF_NEBB,
+               .size = sizeof(u64), .align = sizeof(u64),
+               .active = ebb_active, .get = ebb_get, .set = ebb_set
+       },
+#endif
 };
 
 static const struct user_regset_view user_ppc_compat_view = {
index 714b4ba..dba265c 100644 (file)
@@ -66,6 +66,7 @@
 #include <asm/hugetlb.h>
 #include <asm/livepatch.h>
 #include <asm/mmu_context.h>
+#include <asm/cpu_has_feature.h>
 
 #include "setup.h"
 
index 00f5775..c3e861d 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/serial.h>
 #include <asm/udbg.h>
 #include <asm/code-patching.h>
+#include <asm/cpu_has_feature.h>
 
 #define DBG(fmt...)
 
index d8216ae..eafb9a7 100644 (file)
@@ -227,8 +227,8 @@ static void __init configure_exceptions(void)
                        opal_configure_cores();
 
                /* Enable AIL if supported, and we are in hypervisor mode */
-               if (cpu_has_feature(CPU_FTR_HVMODE) &&
-                   cpu_has_feature(CPU_FTR_ARCH_207S)) {
+               if (early_cpu_has_feature(CPU_FTR_HVMODE) &&
+                   early_cpu_has_feature(CPU_FTR_ARCH_207S)) {
                        unsigned long lpcr = mfspr(SPRN_LPCR);
                        mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
                }
@@ -298,12 +298,12 @@ void __init early_setup(unsigned long dt_ptr)
         */
        configure_exceptions();
 
-       /* Initialize the hash table or TLB handling */
-       early_init_mmu();
-
        /* Apply all the dynamic patching */
        apply_feature_fixups();
 
+       /* Initialize the hash table or TLB handling */
+       early_init_mmu();
+
        /*
         * At this point, we can let interrupts switch to virtual mode
         * (the MMU has been setup), so adjust the MSR in the PACA to
index 5a1f015..25a3905 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/debug.h>
 #include <asm/kexec.h>
 #include <asm/asm-prototypes.h>
+#include <asm/cpu_has_feature.h>
 
 #ifdef DEBUG
 #include <asm/udbg.h>
index 4e7759c..3efbede 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/irq_work.h>
 #include <linux/clk-provider.h>
 #include <linux/suspend.h>
+#include <linux/rtc.h>
 #include <asm/trace.h>
 
 #include <asm/io.h>
@@ -1159,6 +1160,29 @@ void calibrate_delay(void)
        loops_per_jiffy = tb_ticks_per_jiffy;
 }
 
+#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
+static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
+{
+       ppc_md.get_rtc_time(tm);
+       return rtc_valid_tm(tm);
+}
+
+static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
+{
+       if (!ppc_md.set_rtc_time)
+               return -EOPNOTSUPP;
+
+       if (ppc_md.set_rtc_time(tm) < 0)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static const struct rtc_class_ops rtc_generic_ops = {
+       .read_time = rtc_generic_get_time,
+       .set_time = rtc_generic_set_time,
+};
+
 static int __init rtc_init(void)
 {
        struct platform_device *pdev;
@@ -1166,9 +1190,12 @@ static int __init rtc_init(void)
        if (!ppc_md.get_rtc_time)
                return -ENODEV;
 
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &rtc_generic_ops,
+                                            sizeof(rtc_generic_ops));
 
        return PTR_ERR_OR_ZERO(pdev);
 }
 
 device_initcall(rtc_init);
+#endif
index f7e2f2e..2cb5892 100644 (file)
@@ -61,6 +61,7 @@
 #include <asm/tm.h>
 #include <asm/debug.h>
 #include <asm/asm-prototypes.h>
+#include <asm/hmi.h>
 #include <sysdev/fsl_pci.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
@@ -308,9 +309,13 @@ long hmi_exception_realmode(struct pt_regs *regs)
 {
        __this_cpu_inc(irq_stat.hmi_exceptions);
 
+       wait_for_subcore_guest_exit();
+
        if (ppc_md.hmi_exception_early)
                ppc_md.hmi_exception_early(regs);
 
+       wait_for_tb_resync();
+
        return 0;
 }
 
index 8d7358f..b3813dd 100644 (file)
@@ -482,7 +482,7 @@ static void vio_cmo_balance(struct work_struct *work)
 
 static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
                                          dma_addr_t *dma_handle, gfp_t flag,
-                                         struct dma_attrs *attrs)
+                                         unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
        void *ret;
@@ -503,7 +503,7 @@ static void *vio_dma_iommu_alloc_coherent(struct device *dev, size_t size,
 
 static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
                                        void *vaddr, dma_addr_t dma_handle,
-                                       struct dma_attrs *attrs)
+                                       unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
 
@@ -515,7 +515,7 @@ static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
 static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
                                          unsigned long offset, size_t size,
                                          enum dma_data_direction direction,
-                                         struct dma_attrs *attrs)
+                                         unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
        struct iommu_table *tbl;
@@ -539,7 +539,7 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
 static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
                                     size_t size,
                                     enum dma_data_direction direction,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
        struct iommu_table *tbl;
@@ -552,7 +552,7 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
 
 static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                                 int nelems, enum dma_data_direction direction,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
        struct iommu_table *tbl;
@@ -588,7 +588,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 static void vio_dma_iommu_unmap_sg(struct device *dev,
                struct scatterlist *sglist, int nelems,
                enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
        struct iommu_table *tbl;
index eba0bea..1f9e552 100644 (file)
@@ -20,7 +20,7 @@ common-objs-y += powerpc.o emulate.o emulate_loadstore.o
 obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o
 obj-$(CONFIG_KVM_BOOK3S_HANDLER) += book3s_exports.o
 
-AFLAGS_booke_interrupts.o := -I$(obj)
+AFLAGS_booke_interrupts.o := -I$(objtree)/$(obj)
 
 kvm-e500-objs := \
        $(common-objs-y) \
index e20beae..2fd5580 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/switch_to.h>
 #include <asm/smp.h>
 #include <asm/dbell.h>
+#include <asm/hmi.h>
 #include <linux/gfp.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
@@ -2522,7 +2523,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
                list_for_each_entry(pvc, &core_info.vcs[sub], preempt_list)
                        spin_unlock(&pvc->lock);
 
-       kvm_guest_enter();
+       guest_enter();
 
        srcu_idx = srcu_read_lock(&vc->kvm->srcu);
 
@@ -2570,7 +2571,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
 
        /* make sure updates to secondary vcpu structs are visible now */
        smp_mb();
-       kvm_guest_exit();
+       guest_exit();
 
        for (sub = 0; sub < core_info.n_subcores; ++sub)
                list_for_each_entry_safe(pvc, vcnext, &core_info.vcs[sub],
@@ -3401,6 +3402,38 @@ static struct kvmppc_ops kvm_ops_hv = {
        .hcall_implemented = kvmppc_hcall_impl_hv,
 };
 
+static int kvm_init_subcore_bitmap(void)
+{
+       int i, j;
+       int nr_cores = cpu_nr_cores();
+       struct sibling_subcore_state *sibling_subcore_state;
+
+       for (i = 0; i < nr_cores; i++) {
+               int first_cpu = i * threads_per_core;
+               int node = cpu_to_node(first_cpu);
+
+               /* Ignore if it is already allocated. */
+               if (paca[first_cpu].sibling_subcore_state)
+                       continue;
+
+               sibling_subcore_state =
+                       kmalloc_node(sizeof(struct sibling_subcore_state),
+                                                       GFP_KERNEL, node);
+               if (!sibling_subcore_state)
+                       return -ENOMEM;
+
+               memset(sibling_subcore_state, 0,
+                               sizeof(struct sibling_subcore_state));
+
+               for (j = 0; j < threads_per_core; j++) {
+                       int cpu = first_cpu + j;
+
+                       paca[cpu].sibling_subcore_state = sibling_subcore_state;
+               }
+       }
+       return 0;
+}
+
 static int kvmppc_book3s_init_hv(void)
 {
        int r;
@@ -3411,6 +3444,10 @@ static int kvmppc_book3s_init_hv(void)
        if (r < 0)
                return -ENODEV;
 
+       r = kvm_init_subcore_bitmap();
+       if (r)
+               return r;
+
        kvm_ops_hv.owner = THIS_MODULE;
        kvmppc_hv_ops = &kvm_ops_hv;
 
index 93b5f5c..0fa70a9 100644 (file)
@@ -13,6 +13,9 @@
 #include <linux/kernel.h>
 #include <asm/opal.h>
 #include <asm/mce.h>
+#include <asm/machdep.h>
+#include <asm/cputhreads.h>
+#include <asm/hmi.h>
 
 /* SRR1 bits for machine check on POWER7 */
 #define SRR1_MC_LDSTERR                (1ul << (63-42))
@@ -140,3 +143,176 @@ long kvmppc_realmode_machine_check(struct kvm_vcpu *vcpu)
 {
        return kvmppc_realmode_mc_power7(vcpu);
 }
+
+/* Check if dynamic split is in force and return subcore size accordingly. */
+static inline int kvmppc_cur_subcore_size(void)
+{
+       if (local_paca->kvm_hstate.kvm_split_mode)
+               return local_paca->kvm_hstate.kvm_split_mode->subcore_size;
+
+       return threads_per_subcore;
+}
+
+void kvmppc_subcore_enter_guest(void)
+{
+       int thread_id, subcore_id;
+
+       thread_id = cpu_thread_in_core(local_paca->paca_index);
+       subcore_id = thread_id / kvmppc_cur_subcore_size();
+
+       local_paca->sibling_subcore_state->in_guest[subcore_id] = 1;
+}
+
+void kvmppc_subcore_exit_guest(void)
+{
+       int thread_id, subcore_id;
+
+       thread_id = cpu_thread_in_core(local_paca->paca_index);
+       subcore_id = thread_id / kvmppc_cur_subcore_size();
+
+       local_paca->sibling_subcore_state->in_guest[subcore_id] = 0;
+}
+
+static bool kvmppc_tb_resync_required(void)
+{
+       if (test_and_set_bit(CORE_TB_RESYNC_REQ_BIT,
+                               &local_paca->sibling_subcore_state->flags))
+               return false;
+
+       return true;
+}
+
+static void kvmppc_tb_resync_done(void)
+{
+       clear_bit(CORE_TB_RESYNC_REQ_BIT,
+                       &local_paca->sibling_subcore_state->flags);
+}
+
+/*
+ * kvmppc_realmode_hmi_handler() is called only by primary thread during
+ * guest exit path.
+ *
+ * There are multiple reasons why HMI could occur, one of them is
+ * Timebase (TB) error. If this HMI is due to TB error, then TB would
+ * have been in stopped state. The opal hmi handler Will fix it and
+ * restore the TB value with host timebase value. For HMI caused due
+ * to non-TB errors, opal hmi handler will not touch/restore TB register
+ * and hence there won't be any change in TB value.
+ *
+ * Since we are not sure about the cause of this HMI, we can't be sure
+ * about the content of TB register whether it holds guest or host timebase
+ * value. Hence the idea is to resync the TB on every HMI, so that we
+ * know about the exact state of the TB value. Resync TB call will
+ * restore TB to host timebase.
+ *
+ * Things to consider:
+ * - On TB error, HMI interrupt is reported on all the threads of the core
+ *   that has encountered TB error irrespective of split-core mode.
+ * - The very first thread on the core that get chance to fix TB error
+ *   would rsync the TB with local chipTOD value.
+ * - The resync TB is a core level action i.e. it will sync all the TBs
+ *   in that core independent of split-core mode. This means if we trigger
+ *   TB sync from a thread from one subcore, it would affect TB values of
+ *   sibling subcores of the same core.
+ *
+ * All threads need to co-ordinate before making opal hmi handler.
+ * All threads will use sibling_subcore_state->in_guest[] (shared by all
+ * threads in the core) in paca which holds information about whether
+ * sibling subcores are in Guest mode or host mode. The in_guest[] array
+ * is of size MAX_SUBCORE_PER_CORE=4, indexed using subcore id to set/unset
+ * subcore status. Only primary threads from each subcore is responsible
+ * to set/unset its designated array element while entering/exiting the
+ * guset.
+ *
+ * After invoking opal hmi handler call, one of the thread (of entire core)
+ * will need to resync the TB. Bit 63 from subcore state bitmap flags
+ * (sibling_subcore_state->flags) will be used to co-ordinate between
+ * primary threads to decide who takes up the responsibility.
+ *
+ * This is what we do:
+ * - Primary thread from each subcore tries to set resync required bit[63]
+ *   of paca->sibling_subcore_state->flags.
+ * - The first primary thread that is able to set the flag takes the
+ *   responsibility of TB resync. (Let us call it as thread leader)
+ * - All other threads which are in host will call
+ *   wait_for_subcore_guest_exit() and wait for in_guest[0-3] from
+ *   paca->sibling_subcore_state to get cleared.
+ * - All the primary thread will clear its subcore status from subcore
+ *   state in_guest[] array respectively.
+ * - Once all primary threads clear in_guest[0-3], all of them will invoke
+ *   opal hmi handler.
+ * - Now all threads will wait for TB resync to complete by invoking
+ *   wait_for_tb_resync() except the thread leader.
+ * - Thread leader will do a TB resync by invoking opal_resync_timebase()
+ *   call and the it will clear the resync required bit.
+ * - All other threads will now come out of resync wait loop and proceed
+ *   with individual execution.
+ * - On return of this function, primary thread will signal all
+ *   secondary threads to proceed.
+ * - All secondary threads will eventually call opal hmi handler on
+ *   their exit path.
+ */
+
+long kvmppc_realmode_hmi_handler(void)
+{
+       int ptid = local_paca->kvm_hstate.ptid;
+       bool resync_req;
+
+       /* This is only called on primary thread. */
+       BUG_ON(ptid != 0);
+       __this_cpu_inc(irq_stat.hmi_exceptions);
+
+       /*
+        * By now primary thread has already completed guest->host
+        * partition switch but haven't signaled secondaries yet.
+        * All the secondary threads on this subcore is waiting
+        * for primary thread to signal them to go ahead.
+        *
+        * For threads from subcore which isn't in guest, they all will
+        * wait until all other subcores on this core exit the guest.
+        *
+        * Now set the resync required bit. If you are the first to
+        * set this bit then kvmppc_tb_resync_required() function will
+        * return true. For rest all other subcores
+        * kvmppc_tb_resync_required() will return false.
+        *
+        * If resync_req == true, then this thread is responsible to
+        * initiate TB resync after hmi handler has completed.
+        * All other threads on this core will wait until this thread
+        * clears the resync required bit flag.
+        */
+       resync_req = kvmppc_tb_resync_required();
+
+       /* Reset the subcore status to indicate it has exited guest */
+       kvmppc_subcore_exit_guest();
+
+       /*
+        * Wait for other subcores on this core to exit the guest.
+        * All the primary threads and threads from subcore that are
+        * not in guest will wait here until all subcores are out
+        * of guest context.
+        */
+       wait_for_subcore_guest_exit();
+
+       /*
+        * At this point we are sure that primary threads from each
+        * subcore on this core have completed guest->host partition
+        * switch. Now it is safe to call HMI handler.
+        */
+       if (ppc_md.hmi_exception_early)
+               ppc_md.hmi_exception_early(NULL);
+
+       /*
+        * Check if this thread is responsible to resync TB.
+        * All other threads will wait until this thread completes the
+        * TB resync.
+        */
+       if (resync_req) {
+               opal_resync_timebase();
+               /* Reset TB resync req bit */
+               kvmppc_tb_resync_done();
+       } else {
+               wait_for_tb_resync();
+       }
+       return 0;
+}
index 86f0cae..9756555 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/kvm_book3s_asm.h>
 #include <asm/book3s/64/mmu-hash.h>
 #include <asm/tm.h>
+#include <asm/opal.h>
 
 #define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
 
@@ -373,6 +374,18 @@ kvm_secondary_got_guest:
        lwsync
        std     r0, HSTATE_KVM_VCORE(r13)
 
+       /*
+        * All secondaries exiting guest will fall through this path.
+        * Before proceeding, just check for HMI interrupt and
+        * invoke opal hmi handler. By now we are sure that the
+        * primary thread on this core/subcore has already made partition
+        * switch/TB resync and we are good to call opal hmi handler.
+        */
+       cmpwi   r12, BOOK3S_INTERRUPT_HMI
+       bne     kvm_no_guest
+
+       li      r3,0                    /* NULL argument */
+       bl      hmi_exception_realmode
 /*
  * At this point we have finished executing in the guest.
  * We need to wait for hwthread_req to become zero, since
@@ -427,6 +440,22 @@ kvm_no_guest:
  * whole-core mode, so we need to nap.
  */
 kvm_unsplit_nap:
+       /*
+        * When secondaries are napping in kvm_unsplit_nap() with
+        * hwthread_req = 1, HMI goes ignored even though subcores are
+        * already exited the guest. Hence HMI keeps waking up secondaries
+        * from nap in a loop and secondaries always go back to nap since
+        * no vcore is assigned to them. This makes impossible for primary
+        * thread to get hold of secondary threads resulting into a soft
+        * lockup in KVM path.
+        *
+        * Let us check if HMI is pending and handle it before we go to nap.
+        */
+       cmpwi   r12, BOOK3S_INTERRUPT_HMI
+       bne     55f
+       li      r3, 0                   /* NULL argument */
+       bl      hmi_exception_realmode
+55:
        /*
         * Ensure that secondary doesn't nap when it has
         * its vcore pointer set.
@@ -601,6 +630,11 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_DPDES, r8
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
+       /* Mark the subcore state as inside guest */
+       bl      kvmppc_subcore_enter_guest
+       nop
+       ld      r5, HSTATE_KVM_VCORE(r13)
+       ld      r4, HSTATE_KVM_VCPU(r13)
        li      r0,1
        stb     r0,VCORE_IN_GUEST(r5)   /* signal secondaries to continue */
 
@@ -655,112 +689,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-       b       skip_tm
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-
-       /* Turn on TM/FP/VSX/VMX so we can restore them. */
-       mfmsr   r5
-       li      r6, MSR_TM >> 32
-       sldi    r6, r6, 32
-       or      r5, r5, r6
-       ori     r5, r5, MSR_FP
-       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
-       mtmsrd  r5
-
-       /*
-        * The user may change these outside of a transaction, so they must
-        * always be context switched.
-        */
-       ld      r5, VCPU_TFHAR(r4)
-       ld      r6, VCPU_TFIAR(r4)
-       ld      r7, VCPU_TEXASR(r4)
-       mtspr   SPRN_TFHAR, r5
-       mtspr   SPRN_TFIAR, r6
-       mtspr   SPRN_TEXASR, r7
-
-       ld      r5, VCPU_MSR(r4)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-       beq     skip_tm /* TM not active in guest */
-
-       /* Make sure the failure summary is set, otherwise we'll program check
-        * when we trechkpt.  It's possible that this might have been not set
-        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
-        * host.
-        */
-       oris    r7, r7, (TEXASR_FS)@h
-       mtspr   SPRN_TEXASR, r7
-
-       /*
-        * We need to load up the checkpointed state for the guest.
-        * We need to do this early as it will blow away any GPRs, VSRs and
-        * some SPRs.
-        */
-
-       mr      r31, r4
-       addi    r3, r31, VCPU_FPRS_TM
-       bl      load_fp_state
-       addi    r3, r31, VCPU_VRS_TM
-       bl      load_vr_state
-       mr      r4, r31
-       lwz     r7, VCPU_VRSAVE_TM(r4)
-       mtspr   SPRN_VRSAVE, r7
-
-       ld      r5, VCPU_LR_TM(r4)
-       lwz     r6, VCPU_CR_TM(r4)
-       ld      r7, VCPU_CTR_TM(r4)
-       ld      r8, VCPU_AMR_TM(r4)
-       ld      r9, VCPU_TAR_TM(r4)
-       mtlr    r5
-       mtcr    r6
-       mtctr   r7
-       mtspr   SPRN_AMR, r8
-       mtspr   SPRN_TAR, r9
-
-       /*
-        * Load up PPR and DSCR values but don't put them in the actual SPRs
-        * till the last moment to avoid running with userspace PPR and DSCR for
-        * too long.
-        */
-       ld      r29, VCPU_DSCR_TM(r4)
-       ld      r30, VCPU_PPR_TM(r4)
-
-       std     r2, PACATMSCRATCH(r13) /* Save TOC */
-
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
-       li      r5, 0
-       mtmsrd  r5, 1
-
-       /* Load GPRs r0-r28 */
-       reg = 0
-       .rept   29
-       ld      reg, VCPU_GPRS_TM(reg)(r31)
-       reg = reg + 1
-       .endr
-
-       mtspr   SPRN_DSCR, r29
-       mtspr   SPRN_PPR, r30
-
-       /* Load final GPRs */
-       ld      29, VCPU_GPRS_TM(29)(r31)
-       ld      30, VCPU_GPRS_TM(30)(r31)
-       ld      31, VCPU_GPRS_TM(31)(r31)
-
-       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
-       TRECHKPT
-
-       /* Now let's get back the state we need. */
-       HMT_MEDIUM
-       GET_PACA(r13)
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-       ld      r4, HSTATE_KVM_VCPU(r13)
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATMSCRATCH(r13)
-
-       /* Set the MSR RI since we have our registers back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-skip_tm:
+       bl      kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
        /* Load guest PMU registers */
@@ -841,12 +771,6 @@ BEGIN_FTR_SECTION
        /* Skip next section on POWER7 */
        b       8f
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
        /* Load up POWER8-specific registers */
        ld      r5, VCPU_IAMR(r4)
        lwz     r6, VCPU_PSPB(r4)
@@ -1436,106 +1360,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-       b       2f
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-       /* Turn on TM. */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
-       ld      r5, VCPU_MSR(r9)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-       beq     1f      /* TM not active in guest. */
-
-       li      r3, TM_CAUSE_KVM_RESCHED
-
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
-       li      r5, 0
-       mtmsrd  r5, 1
-
-       /* All GPRs are volatile at this point. */
-       TRECLAIM(R3)
-
-       /* Temporarily store r13 and r9 so we have some regs to play with */
-       SET_SCRATCH0(r13)
-       GET_PACA(r13)
-       std     r9, PACATMSCRATCH(r13)
-       ld      r9, HSTATE_KVM_VCPU(r13)
-
-       /* Get a few more GPRs free. */
-       std     r29, VCPU_GPRS_TM(29)(r9)
-       std     r30, VCPU_GPRS_TM(30)(r9)
-       std     r31, VCPU_GPRS_TM(31)(r9)
-
-       /* Save away PPR and DSCR soon so don't run with user values. */
-       mfspr   r31, SPRN_PPR
-       HMT_MEDIUM
-       mfspr   r30, SPRN_DSCR
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-
-       /* Save all but r9, r13 & r29-r31 */
-       reg = 0
-       .rept   29
-       .if (reg != 9) && (reg != 13)
-       std     reg, VCPU_GPRS_TM(reg)(r9)
-       .endif
-       reg = reg + 1
-       .endr
-       /* ... now save r13 */
-       GET_SCRATCH0(r4)
-       std     r4, VCPU_GPRS_TM(13)(r9)
-       /* ... and save r9 */
-       ld      r4, PACATMSCRATCH(r13)
-       std     r4, VCPU_GPRS_TM(9)(r9)
-
-       /* Reload stack pointer and TOC. */
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATOC(r13)
-
-       /* Set MSR RI now we have r1 and r13 back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-
-       /* Save away checkpinted SPRs. */
-       std     r31, VCPU_PPR_TM(r9)
-       std     r30, VCPU_DSCR_TM(r9)
-       mflr    r5
-       mfcr    r6
-       mfctr   r7
-       mfspr   r8, SPRN_AMR
-       mfspr   r10, SPRN_TAR
-       std     r5, VCPU_LR_TM(r9)
-       stw     r6, VCPU_CR_TM(r9)
-       std     r7, VCPU_CTR_TM(r9)
-       std     r8, VCPU_AMR_TM(r9)
-       std     r10, VCPU_TAR_TM(r9)
-
-       /* Restore r12 as trap number. */
-       lwz     r12, VCPU_TRAP(r9)
-
-       /* Save FP/VSX. */
-       addi    r3, r9, VCPU_FPRS_TM
-       bl      store_fp_state
-       addi    r3, r9, VCPU_VRS_TM
-       bl      store_vr_state
-       mfspr   r6, SPRN_VRSAVE
-       stw     r6, VCPU_VRSAVE_TM(r9)
-1:
-       /*
-        * We need to save these SPRs after the treclaim so that the software
-        * error code is recorded correctly in the TEXASR.  Also the user may
-        * change these outside of a transaction, so they must always be
-        * context switched.
-        */
-       mfspr   r5, SPRN_TFHAR
-       mfspr   r6, SPRN_TFIAR
-       mfspr   r7, SPRN_TEXASR
-       std     r5, VCPU_TFHAR(r9)
-       std     r6, VCPU_TFIAR(r9)
-       std     r7, VCPU_TEXASR(r9)
-2:
+       bl      kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
        /* Increment yield count if they have a VPA */
@@ -1683,6 +1509,23 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_DPDES, r8
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
+       /* If HMI, call kvmppc_realmode_hmi_handler() */
+       cmpwi   r12, BOOK3S_INTERRUPT_HMI
+       bne     27f
+       bl      kvmppc_realmode_hmi_handler
+       nop
+       li      r12, BOOK3S_INTERRUPT_HMI
+       /*
+        * At this point kvmppc_realmode_hmi_handler would have resync-ed
+        * the TB. Hence it is not required to subtract guest timebase
+        * offset from timebase. So, skip it.
+        *
+        * Also, do not call kvmppc_subcore_exit_guest() because it has
+        * been invoked as part of kvmppc_realmode_hmi_handler().
+        */
+       b       30f
+
+27:
        /* Subtract timebase offset from timebase */
        ld      r8,VCORE_TB_OFFSET(r5)
        cmpdi   r8,0
@@ -1698,8 +1541,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        addis   r8,r8,0x100             /* if so, increment upper 40 bits */
        mtspr   SPRN_TBU40,r8
 
+17:    bl      kvmppc_subcore_exit_guest
+       nop
+30:    ld      r5,HSTATE_KVM_VCORE(r13)
+       ld      r4,VCORE_KVM(r5)        /* pointer to struct kvm */
+
        /* Reset PCR */
-17:    ld      r0, VCORE_PCR(r5)
+       ld      r0, VCORE_PCR(r5)
        cmpdi   r0, 0
        beq     18f
        li      r0, 0
@@ -2245,6 +2093,13 @@ _GLOBAL(kvmppc_h_cede)           /* r3 = vcpu pointer, r11 = msr, r13 = paca */
        /* save FP state */
        bl      kvmppc_save_fp
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+       ld      r9, HSTATE_KVM_VCPU(r13)
+       bl      kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
        /*
         * Set DEC to the smaller of DEC and HDEC, so that we wake
         * no later than the end of our timeslice (HDEC interrupts
@@ -2321,6 +2176,12 @@ kvm_end_cede:
        bl      kvmhv_accumulate_time
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+       bl      kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
        /* load up FP state */
        bl      kvmppc_load_fp
 
@@ -2461,6 +2322,8 @@ BEGIN_FTR_SECTION
        cmpwi   r6, 3                   /* hypervisor doorbell? */
        beq     3f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+       cmpwi   r6, 0xa                 /* Hypervisor maintenance ? */
+       beq     4f
        li      r3, 1                   /* anything else, return 1 */
 0:     blr
 
@@ -2482,6 +2345,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        li      r3, -1
        blr
 
+       /* Woken up due to Hypervisor maintenance interrupt */
+4:     li      r12, BOOK3S_INTERRUPT_HMI
+       li      r3, 1
+       blr
+
 /*
  * Determine what sort of external interrupt is pending (if any).
  * Returns:
@@ -2631,6 +2499,239 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        mr      r4,r31
        blr
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Save transactional state and TM-related registers.
+ * Called with r9 pointing to the vcpu struct.
+ * This can modify all checkpointed registers, but
+ * restores r1, r2 and r9 (vcpu pointer) before exit.
+ */
+kvmppc_save_tm:
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM. */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       mtmsrd  r8
+
+       ld      r5, VCPU_MSR(r9)
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beq     1f      /* TM not active in guest. */
+
+       std     r1, HSTATE_HOST_R1(r13)
+       li      r3, TM_CAUSE_KVM_RESCHED
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* All GPRs are volatile at this point. */
+       TRECLAIM(R3)
+
+       /* Temporarily store r13 and r9 so we have some regs to play with */
+       SET_SCRATCH0(r13)
+       GET_PACA(r13)
+       std     r9, PACATMSCRATCH(r13)
+       ld      r9, HSTATE_KVM_VCPU(r13)
+
+       /* Get a few more GPRs free. */
+       std     r29, VCPU_GPRS_TM(29)(r9)
+       std     r30, VCPU_GPRS_TM(30)(r9)
+       std     r31, VCPU_GPRS_TM(31)(r9)
+
+       /* Save away PPR and DSCR soon so don't run with user values. */
+       mfspr   r31, SPRN_PPR
+       HMT_MEDIUM
+       mfspr   r30, SPRN_DSCR
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+
+       /* Save all but r9, r13 & r29-r31 */
+       reg = 0
+       .rept   29
+       .if (reg != 9) && (reg != 13)
+       std     reg, VCPU_GPRS_TM(reg)(r9)
+       .endif
+       reg = reg + 1
+       .endr
+       /* ... now save r13 */
+       GET_SCRATCH0(r4)
+       std     r4, VCPU_GPRS_TM(13)(r9)
+       /* ... and save r9 */
+       ld      r4, PACATMSCRATCH(r13)
+       std     r4, VCPU_GPRS_TM(9)(r9)
+
+       /* Reload stack pointer and TOC. */
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATOC(r13)
+
+       /* Set MSR RI now we have r1 and r13 back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+
+       /* Save away checkpinted SPRs. */
+       std     r31, VCPU_PPR_TM(r9)
+       std     r30, VCPU_DSCR_TM(r9)
+       mflr    r5
+       mfcr    r6
+       mfctr   r7
+       mfspr   r8, SPRN_AMR
+       mfspr   r10, SPRN_TAR
+       std     r5, VCPU_LR_TM(r9)
+       stw     r6, VCPU_CR_TM(r9)
+       std     r7, VCPU_CTR_TM(r9)
+       std     r8, VCPU_AMR_TM(r9)
+       std     r10, VCPU_TAR_TM(r9)
+
+       /* Restore r12 as trap number. */
+       lwz     r12, VCPU_TRAP(r9)
+
+       /* Save FP/VSX. */
+       addi    r3, r9, VCPU_FPRS_TM
+       bl      store_fp_state
+       addi    r3, r9, VCPU_VRS_TM
+       bl      store_vr_state
+       mfspr   r6, SPRN_VRSAVE
+       stw     r6, VCPU_VRSAVE_TM(r9)
+1:
+       /*
+        * We need to save these SPRs after the treclaim so that the software
+        * error code is recorded correctly in the TEXASR.  Also the user may
+        * change these outside of a transaction, so they must always be
+        * context switched.
+        */
+       mfspr   r5, SPRN_TFHAR
+       mfspr   r6, SPRN_TFIAR
+       mfspr   r7, SPRN_TEXASR
+       std     r5, VCPU_TFHAR(r9)
+       std     r6, VCPU_TFIAR(r9)
+       std     r7, VCPU_TEXASR(r9)
+
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+
+/*
+ * Restore transactional state and TM-related registers.
+ * Called with r4 pointing to the vcpu struct.
+ * This potentially modifies all checkpointed registers.
+ * It restores r1, r2, r4 from the PACA.
+ */
+kvmppc_restore_tm:
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM/FP/VSX/VMX so we can restore them. */
+       mfmsr   r5
+       li      r6, MSR_TM >> 32
+       sldi    r6, r6, 32
+       or      r5, r5, r6
+       ori     r5, r5, MSR_FP
+       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
+       mtmsrd  r5
+
+       /*
+        * The user may change these outside of a transaction, so they must
+        * always be context switched.
+        */
+       ld      r5, VCPU_TFHAR(r4)
+       ld      r6, VCPU_TFIAR(r4)
+       ld      r7, VCPU_TEXASR(r4)
+       mtspr   SPRN_TFHAR, r5
+       mtspr   SPRN_TFIAR, r6
+       mtspr   SPRN_TEXASR, r7
+
+       ld      r5, VCPU_MSR(r4)
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beqlr           /* TM not active in guest */
+       std     r1, HSTATE_HOST_R1(r13)
+
+       /* Make sure the failure summary is set, otherwise we'll program check
+        * when we trechkpt.  It's possible that this might have been not set
+        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+        * host.
+        */
+       oris    r7, r7, (TEXASR_FS)@h
+       mtspr   SPRN_TEXASR, r7
+
+       /*
+        * We need to load up the checkpointed state for the guest.
+        * We need to do this early as it will blow away any GPRs, VSRs and
+        * some SPRs.
+        */
+
+       mr      r31, r4
+       addi    r3, r31, VCPU_FPRS_TM
+       bl      load_fp_state
+       addi    r3, r31, VCPU_VRS_TM
+       bl      load_vr_state
+       mr      r4, r31
+       lwz     r7, VCPU_VRSAVE_TM(r4)
+       mtspr   SPRN_VRSAVE, r7
+
+       ld      r5, VCPU_LR_TM(r4)
+       lwz     r6, VCPU_CR_TM(r4)
+       ld      r7, VCPU_CTR_TM(r4)
+       ld      r8, VCPU_AMR_TM(r4)
+       ld      r9, VCPU_TAR_TM(r4)
+       mtlr    r5
+       mtcr    r6
+       mtctr   r7
+       mtspr   SPRN_AMR, r8
+       mtspr   SPRN_TAR, r9
+
+       /*
+        * Load up PPR and DSCR values but don't put them in the actual SPRs
+        * till the last moment to avoid running with userspace PPR and DSCR for
+        * too long.
+        */
+       ld      r29, VCPU_DSCR_TM(r4)
+       ld      r30, VCPU_PPR_TM(r4)
+
+       std     r2, PACATMSCRATCH(r13) /* Save TOC */
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* Load GPRs r0-r28 */
+       reg = 0
+       .rept   29
+       ld      reg, VCPU_GPRS_TM(reg)(r31)
+       reg = reg + 1
+       .endr
+
+       mtspr   SPRN_DSCR, r29
+       mtspr   SPRN_PPR, r30
+
+       /* Load final GPRs */
+       ld      29, VCPU_GPRS_TM(29)(r31)
+       ld      30, VCPU_GPRS_TM(30)(r31)
+       ld      31, VCPU_GPRS_TM(31)(r31)
+
+       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
+       TRECHKPT
+
+       /* Now let's get back the state we need. */
+       HMT_MEDIUM
+       GET_PACA(r13)
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+       ld      r4, HSTATE_KVM_VCPU(r13)
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATMSCRATCH(r13)
+
+       /* Set the MSR RI since we have our registers back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+#endif
+
 /*
  * We come here if we get any exception or interrupt while we are
  * executing host real mode code while in guest MMU context.
index c4f7d6b..e76f79a 100644 (file)
@@ -914,7 +914,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* We get here with MSR.EE=1 */
 
        trace_kvm_exit(exit_nr, vcpu);
-       kvm_guest_exit();
+       guest_exit();
 
        switch (exit_nr) {
        case BOOK3S_INTERRUPT_INST_STORAGE:
@@ -1049,7 +1049,17 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
                int emul;
 
 program_interrupt:
-               flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
+               /*
+                * shadow_srr1 only contains valid flags if we came here via
+                * a program exception. The other exceptions (emulation assist,
+                * FP unavailable, etc.) do not provide flags in SRR1, so use
+                * an illegal-instruction exception when injecting a program
+                * interrupt into the guest.
+                */
+               if (exit_nr == BOOK3S_INTERRUPT_PROGRAM)
+                       flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
+               else
+                       flags = SRR1_PROGILL;
 
                emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst);
                if (emul != EMULATE_DONE) {
@@ -1531,7 +1541,7 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        kvmppc_clear_debug(vcpu);
 
-       /* No need for kvm_guest_exit. It's done in handle_exit.
+       /* No need for guest_exit. It's done in handle_exit.
           We also get here with interrupts enabled. */
 
        /* Make sure we save the guest FPU/Altivec/VSX state */
index 4afae69..02b4672 100644 (file)
@@ -776,7 +776,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
-       /* No need for kvm_guest_exit. It's done in handle_exit.
+       /* No need for guest_exit. It's done in handle_exit.
           We also get here with interrupts enabled. */
 
        /* Switch back to user space debug context */
@@ -1012,7 +1012,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        }
 
        trace_kvm_exit(exit_nr, vcpu);
-       __kvm_guest_exit();
+       guest_exit_irqoff();
 
        local_irq_enable();
 
index 5cc2e7a..b379146 100644 (file)
@@ -302,7 +302,6 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        advance = 0;
                        printk(KERN_ERR "Couldn't emulate instruction 0x%08x "
                               "(op %d xop %d)\n", inst, get_op(inst), get_xop(inst));
-                       kvmppc_core_queue_program(vcpu, 0);
                }
        }
 
index 6249cdc..ed38f81 100644 (file)
@@ -1823,7 +1823,8 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
        return 0;
 }
 
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
 {
        int r = -EINVAL;
index 02416fe..6ce40dd 100644 (file)
@@ -119,7 +119,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
                        continue;
                }
 
-               __kvm_guest_enter();
+               guest_enter_irqoff();
                return 1;
        }
 
@@ -588,6 +588,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = 1;
                break;
 #endif
+       case KVM_CAP_PPC_HTM:
+               r = cpu_has_feature(CPU_FTR_TM_COMP) &&
+                   is_kvmppc_hv_enabled(kvm);
+               break;
        default:
                r = 0;
                break;
index 60b0b3f..a58abe4 100644 (file)
@@ -6,7 +6,7 @@
 #include <asm/setup.h>
 
 
-void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
+void * __ref zalloc_maybe_bootmem(size_t size, gfp_t mask)
 {
        void *p;
 
index defb299..74145f0 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/jump_label.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
@@ -152,9 +153,18 @@ static void do_final_fixups(void)
 #endif
 }
 
-void apply_feature_fixups(void)
+static unsigned long __initdata saved_cpu_features;
+static unsigned int __initdata saved_mmu_features;
+#ifdef CONFIG_PPC64
+static unsigned long __initdata saved_firmware_features;
+#endif
+
+void __init apply_feature_fixups(void)
 {
-       struct cpu_spec *spec = *PTRRELOC(&cur_cpu_spec);
+       struct cpu_spec *spec = PTRRELOC(*PTRRELOC(&cur_cpu_spec));
+
+       *PTRRELOC(&saved_cpu_features) = spec->cpu_features;
+       *PTRRELOC(&saved_mmu_features) = spec->mmu_features;
 
        /*
         * Apply the CPU-specific and firmware specific fixups to kernel text
@@ -173,11 +183,36 @@ void apply_feature_fixups(void)
                         PTRRELOC(&__stop___lwsync_fixup));
 
 #ifdef CONFIG_PPC64
+       saved_firmware_features = powerpc_firmware_features;
        do_feature_fixups(powerpc_firmware_features,
                          &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 #endif
        do_final_fixups();
+
+       /*
+        * Initialise jump label. This causes all the cpu/mmu_has_feature()
+        * checks to take on their correct polarity based on the current set of
+        * CPU/MMU features.
+        */
+       jump_label_init();
+       cpu_feature_keys_init();
+       mmu_feature_keys_init();
+}
+
+static int __init check_features(void)
+{
+       WARN(saved_cpu_features != cur_cpu_spec->cpu_features,
+            "CPU features changed after feature patching!\n");
+       WARN(saved_mmu_features != cur_cpu_spec->mmu_features,
+            "MMU features changed after feature patching!\n");
+#ifdef CONFIG_PPC64
+       WARN(saved_firmware_features != powerpc_firmware_features,
+            "Firmware features changed after feature patching!\n");
+#endif
+
+       return 0;
 }
+late_initcall(check_features);
 
 #ifdef CONFIG_FTR_FIXUP_SELFTEST
 
index 88ce7d2..0e4e965 100644 (file)
@@ -72,8 +72,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
                /* clear out bits after (52) [0....52.....63] */
                va &= ~((1ul << (64 - 52)) - 1);
                va |= ssize << 8;
-               sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
-                       ((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
+               sllp = get_sllp_encoding(apsize);
                va |= sllp << 5;
                asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2)
                             : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206)
@@ -122,8 +121,7 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
                /* clear out bits after(52) [0....52.....63] */
                va &= ~((1ul << (64 - 52)) - 1);
                va |= ssize << 8;
-               sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
-                       ((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
+               sllp = get_sllp_encoding(apsize);
                va |= sllp << 5;
                asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)"
                             : : "r"(va) : "memory");
@@ -749,5 +747,5 @@ void __init hpte_init_native(void)
        mmu_hash_ops.hugepage_invalidate   = native_hugepage_invalidate;
 
        if (cpu_has_feature(CPU_FTR_ARCH_300))
-               ppc_md.register_process_table = native_register_proc_table;
+               register_process_table = native_register_proc_table;
 }
index b78b5d2..0821556 100644 (file)
@@ -363,11 +363,6 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node,
        return 0;
 }
 
-static void __init htab_init_seg_sizes(void)
-{
-       of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL);
-}
-
 static int __init get_idx_from_shift(unsigned int shift)
 {
        int idx = -1;
@@ -539,7 +534,7 @@ static bool might_have_hea(void)
 
 #endif /* #ifdef CONFIG_PPC_64K_PAGES */
 
-static void __init htab_init_page_sizes(void)
+static void __init htab_scan_page_sizes(void)
 {
        int rc;
 
@@ -554,17 +549,23 @@ static void __init htab_init_page_sizes(void)
         * Try to find the available page sizes in the device-tree
         */
        rc = of_scan_flat_dt(htab_dt_scan_page_sizes, NULL);
-       if (rc != 0)  /* Found */
-               goto found;
-
-       /*
-        * Not in the device-tree, let's fallback on known size
-        * list for 16M capable GP & GR
-        */
-       if (mmu_has_feature(MMU_FTR_16M_PAGE))
+       if (rc == 0 && early_mmu_has_feature(MMU_FTR_16M_PAGE)) {
+               /*
+                * Nothing in the device-tree, but the CPU supports 16M pages,
+                * so let's fallback on a known size list for 16M capable CPUs.
+                */
                memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
                       sizeof(mmu_psize_defaults_gp));
-found:
+       }
+
+#ifdef CONFIG_HUGETLB_PAGE
+       /* Reserve 16G huge page memory sections for huge pages */
+       of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL);
+#endif /* CONFIG_HUGETLB_PAGE */
+}
+
+static void __init htab_init_page_sizes(void)
+{
        if (!debug_pagealloc_enabled()) {
                /*
                 * Pick a size for the linear mapping. Currently, we only
@@ -630,11 +631,6 @@ found:
               ,mmu_psize_defs[mmu_vmemmap_psize].shift
 #endif
               );
-
-#ifdef CONFIG_HUGETLB_PAGE
-       /* Reserve 16G huge page memory sections for huge pages */
-       of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL);
-#endif /* CONFIG_HUGETLB_PAGE */
 }
 
 static int __init htab_dt_scan_pftsize(unsigned long node,
@@ -759,12 +755,6 @@ static void __init htab_initialize(void)
 
        DBG(" -> htab_initialize()\n");
 
-       /* Initialize segment sizes */
-       htab_init_seg_sizes();
-
-       /* Initialize page sizes */
-       htab_init_page_sizes();
-
        if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) {
                mmu_kernel_ssize = MMU_SEGSIZE_1T;
                mmu_highuser_ssize = MMU_SEGSIZE_1T;
@@ -885,8 +875,19 @@ static void __init htab_initialize(void)
 #undef KB
 #undef MB
 
+void __init hash__early_init_devtree(void)
+{
+       /* Initialize segment sizes */
+       of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL);
+
+       /* Initialize page sizes */
+       htab_scan_page_sizes();
+}
+
 void __init hash__early_init_mmu(void)
 {
+       htab_init_page_sizes();
+
        /*
         * initialize page table size
         */
index 1e11559..35254a6 100644 (file)
@@ -5,39 +5,34 @@
 #include <asm/cacheflush.h>
 #include <asm/machdep.h>
 #include <asm/mman.h>
+#include <asm/tlb.h>
 
 void radix__flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
-       unsigned long ap, shift;
+       int psize;
        struct hstate *hstate = hstate_file(vma->vm_file);
 
-       shift = huge_page_shift(hstate);
-       if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
-               ap = mmu_get_ap(MMU_PAGE_2M);
-       else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
-               ap = mmu_get_ap(MMU_PAGE_1G);
-       else {
-               WARN(1, "Wrong huge page shift\n");
-               return ;
-       }
-       radix___flush_tlb_page(vma->vm_mm, vmaddr, ap, 0);
+       psize = hstate_get_psize(hstate);
+       radix__flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
 }
 
 void radix__local_flush_hugetlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
-       unsigned long ap, shift;
+       int psize;
        struct hstate *hstate = hstate_file(vma->vm_file);
 
-       shift = huge_page_shift(hstate);
-       if (shift == mmu_psize_defs[MMU_PAGE_2M].shift)
-               ap = mmu_get_ap(MMU_PAGE_2M);
-       else if (shift == mmu_psize_defs[MMU_PAGE_1G].shift)
-               ap = mmu_get_ap(MMU_PAGE_1G);
-       else {
-               WARN(1, "Wrong huge page shift\n");
-               return ;
-       }
-       radix___local_flush_tlb_page(vma->vm_mm, vmaddr, ap, 0);
+       psize = hstate_get_psize(hstate);
+       radix__local_flush_tlb_page_psize(vma->vm_mm, vmaddr, psize);
+}
+
+void radix__flush_hugetlb_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                                  unsigned long end)
+{
+       int psize;
+       struct hstate *hstate = hstate_file(vma->vm_file);
+
+       psize = hstate_get_psize(hstate);
+       radix__flush_tlb_range_psize(vma->vm_mm, start, end, psize);
 }
 
 /*
index 33709bd..16ada1e 100644 (file)
@@ -411,3 +411,25 @@ struct page *realmode_pfn_to_page(unsigned long pfn)
 EXPORT_SYMBOL_GPL(realmode_pfn_to_page);
 
 #endif /* CONFIG_SPARSEMEM_VMEMMAP/CONFIG_FLATMEM */
+
+#ifdef CONFIG_PPC_STD_MMU_64
+static bool disable_radix;
+static int __init parse_disable_radix(char *p)
+{
+       disable_radix = true;
+       return 0;
+}
+early_param("disable_radix", parse_disable_radix);
+
+void __init mmu_early_init_devtree(void)
+{
+       /* Disable radix mode based on kernel command line. */
+       if (disable_radix)
+               cur_cpu_spec->mmu_features &= ~MMU_FTR_TYPE_RADIX;
+
+       if (early_radix_enabled())
+               radix__early_init_devtree();
+       else
+               hash__early_init_devtree();
+}
+#endif /* CONFIG_PPC_STD_MMU_64 */
index 6703187..3407930 100644 (file)
@@ -14,6 +14,9 @@
 #include "mmu_decl.h"
 #include <trace/events/thp.h>
 
+int (*register_process_table)(unsigned long base, unsigned long page_size,
+                             unsigned long tbl_size);
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 /*
  * This is called when relaxing access to a hugepage. It's also called in the page
@@ -33,7 +36,7 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
        changed = !pmd_same(*(pmdp), entry);
        if (changed) {
                __ptep_set_access_flags(pmdp_ptep(pmdp), pmd_pte(entry));
-               flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+               flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        }
        return changed;
 }
@@ -66,7 +69,7 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                     pmd_t *pmdp)
 {
        pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
-       flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+       flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        /*
         * This ensures that generic code that rely on IRQ disabling
         * to prevent a parallel THP split work as expected.
index 003ff48..af897d9 100644 (file)
@@ -171,7 +171,7 @@ redo:
         * of process table here. But our linear mapping also enable us to use
         * physical address here.
         */
-       ppc_md.register_process_table(__pa(process_tb), 0, PRTB_SIZE_SHIFT - 12);
+       register_process_table(__pa(process_tb), 0, PRTB_SIZE_SHIFT - 12);
        pr_info("Process table %p and radix root for kernel: %p\n", process_tb, init_mm.pgd);
 }
 
@@ -198,7 +198,7 @@ static void __init radix_init_partition_table(void)
 
 void __init radix_init_native(void)
 {
-       ppc_md.register_process_table = native_register_process_table;
+       register_process_table = native_register_process_table;
 }
 
 static int __init get_idx_from_shift(unsigned int shift)
@@ -264,7 +264,7 @@ static int __init radix_dt_scan_page_sizes(unsigned long node,
        return 1;
 }
 
-static void __init radix_init_page_sizes(void)
+void __init radix__early_init_devtree(void)
 {
        int rc;
 
@@ -343,7 +343,6 @@ void __init radix__early_init_mmu(void)
        __pte_frag_nr = H_PTE_FRAG_NR;
        __pte_frag_size_shift = H_PTE_FRAG_SIZE_SHIFT;
 
-       radix_init_page_sizes();
        if (!firmware_has_feature(FW_FEATURE_LPAR)) {
                radix_init_native();
                lpcr = mfspr(SPRN_LPCR);
index 88a3075..0b6fb24 100644 (file)
@@ -225,7 +225,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
                if (!is_vm_hugetlb_page(vma))
                        assert_pte_locked(vma->vm_mm, address);
                __ptep_set_access_flags(ptep, entry);
-               flush_tlb_page_nohash(vma, address);
+               flush_tlb_page(vma, address);
        }
        return changed;
 }
index 7f922f5..0ae0572 100644 (file)
@@ -79,7 +79,7 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 #endif
 }
 
-__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+__ref pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
        pte_t *pte;
 
index e1f2270..48df05e 100644 (file)
@@ -140,10 +140,11 @@ void radix__local_flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr)
 }
 EXPORT_SYMBOL(radix__local_flush_tlb_pwc);
 
-void radix___local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
-                           unsigned long ap, int nid)
+void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
+                                      int psize)
 {
        unsigned long pid;
+       unsigned long ap = mmu_get_ap(psize);
 
        preempt_disable();
        pid = mm ? mm->context.id : 0;
@@ -159,18 +160,12 @@ void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmadd
        if (vma && is_vm_hugetlb_page(vma))
                return __local_flush_hugetlb_page(vma, vmaddr);
 #endif
-       radix___local_flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
-                              mmu_get_ap(mmu_virtual_psize), 0);
+       radix__local_flush_tlb_page_psize(vma ? vma->vm_mm : NULL, vmaddr,
+                                         mmu_virtual_psize);
 }
 EXPORT_SYMBOL(radix__local_flush_tlb_page);
 
 #ifdef CONFIG_SMP
-static int mm_is_core_local(struct mm_struct *mm)
-{
-       return cpumask_subset(mm_cpumask(mm),
-                             topology_sibling_cpumask(smp_processor_id()));
-}
-
 void radix__flush_tlb_mm(struct mm_struct *mm)
 {
        unsigned long pid;
@@ -221,10 +216,11 @@ no_context:
 }
 EXPORT_SYMBOL(radix__flush_tlb_pwc);
 
-void radix___flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
-                      unsigned long ap, int nid)
+void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
+                                int psize)
 {
        unsigned long pid;
+       unsigned long ap = mmu_get_ap(psize);
 
        preempt_disable();
        pid = mm ? mm->context.id : 0;
@@ -250,8 +246,8 @@ void radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
        if (vma && is_vm_hugetlb_page(vma))
                return flush_hugetlb_page(vma, vmaddr);
 #endif
-       radix___flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
-                        mmu_get_ap(mmu_virtual_psize), 0);
+       radix__flush_tlb_page_psize(vma ? vma->vm_mm : NULL, vmaddr,
+                                   mmu_virtual_psize);
 }
 EXPORT_SYMBOL(radix__flush_tlb_page);
 
@@ -299,8 +295,65 @@ static int radix_get_mmu_psize(int page_size)
 
 void radix__tlb_flush(struct mmu_gather *tlb)
 {
+       int psize = 0;
        struct mm_struct *mm = tlb->mm;
-       radix__flush_tlb_mm(mm);
+       int page_size = tlb->page_size;
+
+       psize = radix_get_mmu_psize(page_size);
+       /*
+        * if page size is not something we understand, do a full mm flush
+        */
+       if (psize != -1 && !tlb->fullmm && !tlb->need_flush_all)
+               radix__flush_tlb_range_psize(mm, tlb->start, tlb->end, psize);
+       else
+               radix__flush_tlb_mm(mm);
+}
+
+#define TLB_FLUSH_ALL -1UL
+/*
+ * Number of pages above which we will do a bcast tlbie. Just a
+ * number at this point copied from x86
+ */
+static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
+
+void radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start,
+                                 unsigned long end, int psize)
+{
+       unsigned long pid;
+       unsigned long addr;
+       int local = mm_is_core_local(mm);
+       unsigned long ap = mmu_get_ap(psize);
+       int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
+       unsigned long page_size = 1UL << mmu_psize_defs[psize].shift;
+
+
+       preempt_disable();
+       pid = mm ? mm->context.id : 0;
+       if (unlikely(pid == MMU_NO_CONTEXT))
+               goto err_out;
+
+       if (end == TLB_FLUSH_ALL ||
+           (end - start) > tlb_single_page_flush_ceiling * page_size) {
+               if (local)
+                       _tlbiel_pid(pid, RIC_FLUSH_TLB);
+               else
+                       _tlbie_pid(pid, RIC_FLUSH_TLB);
+               goto err_out;
+       }
+       for (addr = start; addr < end; addr += page_size) {
+
+               if (local)
+                       _tlbiel_va(addr, pid, ap, RIC_FLUSH_TLB);
+               else {
+                       if (lock_tlbie)
+                               raw_spin_lock(&native_tlbie_lock);
+                       _tlbie_va(addr, pid, ap, RIC_FLUSH_TLB);
+                       if (lock_tlbie)
+                               raw_spin_unlock(&native_tlbie_lock);
+               }
+       }
+err_out:
+       preempt_enable();
 }
 
 void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
@@ -340,3 +393,10 @@ void radix__flush_tlb_lpid(unsigned long lpid)
        asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 EXPORT_SYMBOL(radix__flush_tlb_lpid);
+
+void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
+                               unsigned long start, unsigned long end)
+{
+       radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M);
+}
+EXPORT_SYMBOL(radix__flush_pmd_tlb_range);
index 558e30c..702d768 100644 (file)
@@ -48,17 +48,6 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
 }
 EXPORT_SYMBOL(flush_hash_entry);
 
-/*
- * Called by ptep_set_access_flags, must flush on CPUs for which the
- * DSI handler can't just "fixup" the TLB on a write fault
- */
-void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr)
-{
-       if (Hash != 0)
-               return;
-       _tlbie(addr);
-}
-
 /*
  * Called at the end of a mmu_gather operation to make sure the
  * TLB flush is completely done.
index f466848..050badc 100644 (file)
@@ -215,12 +215,6 @@ EXPORT_SYMBOL(local_flush_tlb_page);
 
 static DEFINE_RAW_SPINLOCK(tlbivax_lock);
 
-static int mm_is_core_local(struct mm_struct *mm)
-{
-       return cpumask_subset(mm_cpumask(mm),
-                             topology_sibling_cpumask(smp_processor_id()));
-}
-
 struct tlb_flush_param {
        unsigned long addr;
        unsigned int pid;
index cda6fcb..6447dc1 100644 (file)
@@ -34,15 +34,15 @@ EVENT(PM_L1_ICACHE_MISS,                    0x200fd)
 /* Instruction Demand sectors wriittent into IL1 */
 EVENT(PM_L1_DEMAND_WRITE,                      0x0408c)
 /* Instruction prefetch written into IL1 */
-EVENT(PM_IC_PREF_WRITE,                                0x0408e)
+EVENT(PM_IC_PREF_WRITE,                                0x0488c)
 /* The data cache was reloaded from local core's L3 due to a demand load */
 EVENT(PM_DATA_FROM_L3,                         0x4c042)
 /* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
 EVENT(PM_DATA_FROM_L3MISS,                     0x300fe)
 /* All successful D-side store dispatches for this thread */
-EVENT(PM_L2_ST,                                        0x16081)
+EVENT(PM_L2_ST,                                        0x16880)
 /* All successful D-side store dispatches for this thread that were L2 Miss */
-EVENT(PM_L2_ST_MISS,                           0x26081)
+EVENT(PM_L2_ST_MISS,                           0x26880)
 /* Total HW L3 prefetches(Load+store) */
 EVENT(PM_L3_PREF_ALL,                          0x4e052)
 /* Data PTEG reload */
index 3663f71..fbdae83 100644 (file)
@@ -321,6 +321,17 @@ config OF_RTC
          Uses information from the OF or flattened device tree to instantiate
          platform devices for direct mapped RTC chips like the DS1742 or DS1743.
 
+config GEN_RTC
+       bool "Use the platform RTC operations from user space"
+       select RTC_CLASS
+       select RTC_DRV_GENERIC
+       help
+         This option provides backwards compatibility with the old gen_rtc.ko
+         module that was traditionally used for old PowerPC machines.
+         Platforms should migrate to enabling the RTC_DRV_GENERIC by hand
+         replacing their get_rtc_time/set_rtc_time callbacks with
+         a proper RTC device driver.
+
 config SIMPLE_GPIO
        bool "Support for simple, memory-mapped GPIO controllers"
        depends on PPC
index 9027d7c..f7d1a49 100644 (file)
@@ -166,7 +166,7 @@ static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte,
 
 static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
                unsigned long uaddr, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int i;
        unsigned long *io_pte, base_pte;
@@ -193,7 +193,7 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
        base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
                CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask);
 #endif
-       if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
+       if (unlikely(attrs & DMA_ATTR_WEAK_ORDERING))
                base_pte &= ~CBE_IOPTE_SO_RW;
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
@@ -526,7 +526,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
 
        __set_bit(0, window->table.it_map);
        tce_build_cell(&window->table, window->table.it_offset, 1,
-                      (unsigned long)iommu->pad_page, DMA_TO_DEVICE, NULL);
+                      (unsigned long)iommu->pad_page, DMA_TO_DEVICE, 0);
 
        return window;
 }
@@ -572,7 +572,7 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
 
 static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
                                      dma_addr_t *dma_handle, gfp_t flag,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        if (iommu_fixed_is_weak)
                return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
@@ -586,7 +586,7 @@ static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
 
 static void dma_fixed_free_coherent(struct device *dev, size_t size,
                                    void *vaddr, dma_addr_t dma_handle,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        if (iommu_fixed_is_weak)
                iommu_free_coherent(cell_get_iommu_table(dev), size, vaddr,
@@ -598,9 +598,9 @@ static void dma_fixed_free_coherent(struct device *dev, size_t size,
 static dma_addr_t dma_fixed_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction direction,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
-       if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
+       if (iommu_fixed_is_weak == (attrs & DMA_ATTR_WEAK_ORDERING))
                return dma_direct_ops.map_page(dev, page, offset, size,
                                               direction, attrs);
        else
@@ -611,9 +611,9 @@ static dma_addr_t dma_fixed_map_page(struct device *dev, struct page *page,
 
 static void dma_fixed_unmap_page(struct device *dev, dma_addr_t dma_addr,
                                 size_t size, enum dma_data_direction direction,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
-       if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
+       if (iommu_fixed_is_weak == (attrs & DMA_ATTR_WEAK_ORDERING))
                dma_direct_ops.unmap_page(dev, dma_addr, size, direction,
                                          attrs);
        else
@@ -623,9 +623,9 @@ static void dma_fixed_unmap_page(struct device *dev, dma_addr_t dma_addr,
 
 static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
                           int nents, enum dma_data_direction direction,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
-       if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
+       if (iommu_fixed_is_weak == (attrs & DMA_ATTR_WEAK_ORDERING))
                return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs);
        else
                return ppc_iommu_map_sg(dev, cell_get_iommu_table(dev), sg,
@@ -635,9 +635,9 @@ static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
 
 static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
                               int nents, enum dma_data_direction direction,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
-       if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
+       if (iommu_fixed_is_weak == (attrs & DMA_ATTR_WEAK_ORDERING))
                dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs);
        else
                ppc_iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents,
@@ -1162,7 +1162,7 @@ static int __init setup_iommu_fixed(char *str)
        pciep = of_find_node_by_type(NULL, "pcie-endpoint");
 
        if (strcmp(str, "weak") == 0 || (pciep && strcmp(str, "strong") != 0))
-               iommu_fixed_is_weak = 1;
+               iommu_fixed_is_weak = DMA_ATTR_WEAK_ORDERING;
 
        of_node_put(pciep);
 
index d17e98b..e7d0750 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/pgtable.h>
 #include <asm/reg.h>
 #include <asm/cell-regs.h>
+#include <asm/cpu_has_feature.h>
 
 #include "pervasive.h"
 
index 43dd3fb..309d9cc 100644 (file)
@@ -88,7 +88,7 @@ static int iommu_table_iobmap_inited;
 static int iobmap_build(struct iommu_table *tbl, long index,
                         long npages, unsigned long uaddr,
                         enum dma_data_direction direction,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        u32 *ip;
        u32 rpn;
index 3de4a7c..6b4e9d1 100644 (file)
@@ -353,12 +353,12 @@ static int pmac_late_init(void)
 machine_late_initcall(powermac, pmac_late_init);
 
 /*
- * This is __init_refok because we check for "initializing" before
+ * This is __ref because we check for "initializing" before
  * touching any of the __init sensitive things and "initializing"
  * will be false after __init time. This can't be __init because it
  * can be called whenever a disk is first accessed.
  */
-void __init_refok note_bootable_part(dev_t dev, int part, int goodness)
+void __ref note_bootable_part(dev_t dev, int part, int goodness)
 {
        char *p;
 
index 4383a5f..00e1a01 100644 (file)
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(pnv_pci_get_npu_dev);
 
 static void *dma_npu_alloc(struct device *dev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flag,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        NPU_DMA_OP_UNSUPPORTED();
        return NULL;
@@ -81,7 +81,7 @@ static void *dma_npu_alloc(struct device *dev, size_t size,
 
 static void dma_npu_free(struct device *dev, size_t size,
                         void *vaddr, dma_addr_t dma_handle,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        NPU_DMA_OP_UNSUPPORTED();
 }
@@ -89,7 +89,7 @@ static void dma_npu_free(struct device *dev, size_t size,
 static dma_addr_t dma_npu_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction direction,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        NPU_DMA_OP_UNSUPPORTED();
        return 0;
@@ -97,7 +97,7 @@ static dma_addr_t dma_npu_map_page(struct device *dev, struct page *page,
 
 static int dma_npu_map_sg(struct device *dev, struct scatterlist *sglist,
                          int nelems, enum dma_data_direction direction,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        NPU_DMA_OP_UNSUPPORTED();
        return 0;
index cf928bb..3d29d40 100644 (file)
@@ -64,7 +64,6 @@ END_FTR_SECTION(0, 1);                                                \
        OPAL_BRANCH(opal_tracepoint_entry) \
        mfcr    r12;                    \
        stw     r12,8(r1);              \
-       std     r1,PACAR1(r13);         \
        li      r11,0;                  \
        mfmsr   r12;                    \
        ori     r11,r11,MSR_EE;         \
@@ -127,7 +126,6 @@ opal_tracepoint_entry:
        mfcr    r12
        std     r11,16(r1)
        stw     r12,8(r1)
-       std     r1,PACAR1(r13)
        li      r11,0
        mfmsr   r12
        ori     r11,r11,MSR_EE
index 891fc4a..6b95283 100644 (file)
@@ -1806,7 +1806,7 @@ static void pnv_pci_p7ioc_tce_invalidate(struct iommu_table *tbl,
 static int pnv_ioda1_tce_build(struct iommu_table *tbl, long index,
                long npages, unsigned long uaddr,
                enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
                        attrs);
@@ -1950,7 +1950,7 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
 static int pnv_ioda2_tce_build(struct iommu_table *tbl, long index,
                long npages, unsigned long uaddr,
                enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
                        attrs);
index 6701dd5..a21d831 100644 (file)
@@ -704,7 +704,7 @@ static __be64 *pnv_tce(struct iommu_table *tbl, long idx)
 
 int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
                unsigned long uaddr, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        u64 proto_tce = iommu_direction_to_tce_perm(direction);
        u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
index d088d4f..e64df78 100644 (file)
@@ -181,7 +181,7 @@ struct pnv_phb {
 extern struct pci_ops pnv_pci_ops;
 extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
                unsigned long uaddr, enum dma_data_direction direction,
-               struct dma_attrs *attrs);
+               unsigned long attrs);
 extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages);
 extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
                unsigned long *hpa, enum dma_data_direction *direction);
index 3f175e8..57caaf1 100644 (file)
@@ -189,7 +189,7 @@ fail_malloc:
        return result;
 }
 
-static int __init_refok ps3_setup_uhc_device(
+static int __ref ps3_setup_uhc_device(
        const struct ps3_repository_device *repo, enum ps3_match_id match_id,
        enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type)
 {
index 5606fe3..8af1c15 100644 (file)
@@ -516,7 +516,7 @@ core_initcall(ps3_system_bus_init);
  */
 static void * ps3_alloc_coherent(struct device *_dev, size_t size,
                                 dma_addr_t *dma_handle, gfp_t flag,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        int result;
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -553,7 +553,7 @@ clean_none:
 }
 
 static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
-                             dma_addr_t dma_handle, struct dma_attrs *attrs)
+                             dma_addr_t dma_handle, unsigned long attrs)
 {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
 
@@ -569,7 +569,7 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
 
 static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
        unsigned long offset, size_t size, enum dma_data_direction direction,
-       struct dma_attrs *attrs)
+       unsigned long attrs)
 {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
        int result;
@@ -592,7 +592,7 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
 static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
                                    unsigned long offset, size_t size,
                                    enum dma_data_direction direction,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
        int result;
@@ -626,7 +626,7 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
 }
 
 static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
-       size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
+       size_t size, enum dma_data_direction direction, unsigned long attrs)
 {
        struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
        int result;
@@ -640,7 +640,7 @@ static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
 }
 
 static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl,
-       int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+       int nents, enum dma_data_direction direction, unsigned long attrs)
 {
 #if defined(CONFIG_PS3_DYNAMIC_DMA)
        BUG_ON("do");
@@ -670,14 +670,14 @@ static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sgl,
 static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg,
                           int nents,
                           enum dma_data_direction direction,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        BUG();
        return 0;
 }
 
 static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
-       int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+       int nents, enum dma_data_direction direction, unsigned long attrs)
 {
 #if defined(CONFIG_PS3_DYNAMIC_DMA)
        BUG_ON("do");
@@ -686,7 +686,7 @@ static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
 
 static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg,
                            int nents, enum dma_data_direction direction,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        BUG();
 }
index 791c614..11b45b5 100644 (file)
@@ -20,9 +20,9 @@
 
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
 
 #include <asm/firmware.h>
-#include <asm/rtc.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
 
index 770a753..0024e45 100644 (file)
@@ -123,7 +123,7 @@ static void iommu_pseries_free_group(struct iommu_table_group *table_group,
 static int tce_build_pSeries(struct iommu_table *tbl, long index,
                              long npages, unsigned long uaddr,
                              enum dma_data_direction direction,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        u64 proto_tce;
        __be64 *tcep, *tces;
@@ -173,7 +173,7 @@ static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
 static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
                                long npages, unsigned long uaddr,
                                enum dma_data_direction direction,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        u64 rc = 0;
        u64 proto_tce, tce;
@@ -216,7 +216,7 @@ static DEFINE_PER_CPU(__be64 *, tce_page);
 static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
                                     long npages, unsigned long uaddr,
                                     enum dma_data_direction direction,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        u64 rc = 0;
        u64 proto_tce;
index 26904f4..3573d54 100644 (file)
@@ -185,7 +185,7 @@ static void dart_flush(struct iommu_table *tbl)
 static int dart_build(struct iommu_table *tbl, long index,
                       long npages, unsigned long uaddr,
                       enum dma_data_direction direction,
-                      struct dma_attrs *attrs)
+                      unsigned long attrs)
 {
        unsigned int *dp, *orig_dp;
        unsigned int rpn;
index f5bf38b..68e7c0d 100644 (file)
@@ -289,7 +289,7 @@ static void fsl_rio_inbound_mem_init(struct rio_priv *priv)
 }
 
 int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
-       u64 rstart, u32 size, u32 flags)
+       u64 rstart, u64 size, u32 flags)
 {
        struct rio_priv *priv = mport->priv;
        u32 base_size;
@@ -298,7 +298,7 @@ int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
        u32 riwar;
        int i;
 
-       if ((size & (size - 1)) != 0)
+       if ((size & (size - 1)) != 0 || size > 0x400000000ULL)
                return -EINVAL;
 
        base_size_log = ilog2(size);
@@ -491,6 +491,7 @@ int fsl_rio_setup(struct platform_device *dev)
        rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0);
        if (!rmu_node) {
                dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n");
+               rc = -ENOENT;
                goto err_rmu;
        }
        rc = of_address_to_resource(rmu_node, 0, &rmu_regs);
@@ -643,19 +644,11 @@ int fsl_rio_setup(struct platform_device *dev)
                port->ops = ops;
                port->priv = priv;
                port->phys_efptr = 0x100;
+               port->phys_rmap = 1;
                priv->regs_win = rio_regs_win;
 
-               /* Probe the master port phy type */
                ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20);
-               port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL;
-               if (port->phy_type == RIO_PHY_PARALLEL) {
-                       dev_err(&dev->dev, "RIO: Parallel PHY type, unsupported port type!\n");
-                       release_resource(&port->iores);
-                       kfree(priv);
-                       kfree(port);
-                       continue;
-               }
-               dev_info(&dev->dev, "RapidIO PHY type: Serial\n");
+
                /* Checking the port training status */
                if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) {
                        dev_err(&dev->dev, "Port %d is not ready. "
@@ -705,11 +698,9 @@ int fsl_rio_setup(struct platform_device *dev)
                        ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET :
                        RIO_INB_ATMU_REGS_PORT2_OFFSET));
 
-
-               /* Set to receive any dist ID for serial RapidIO controller. */
-               if (port->phy_type == RIO_PHY_SERIAL)
-                       out_be32((priv->regs_win
-                               + RIO_ISR_AACR + i*0x80), RIO_ISR_AACR_AA);
+               /* Set to receive packets with any dest ID */
+               out_be32((priv->regs_win + RIO_ISR_AACR + i*0x80),
+                        RIO_ISR_AACR_AA);
 
                /* Configure maintenance transaction window */
                out_be32(&priv->maint_atmu_regs->rowbar,
index ed5234e..5ebd3f0 100644 (file)
@@ -112,7 +112,7 @@ int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp)
        return 0;
 }
 
-int __init_refok msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
+int __ref msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
                     struct device_node *of_node)
 {
        int size;
index 89098f3..ee98917 100644 (file)
@@ -20,6 +20,7 @@ along with this file; see the file COPYING.  If not, write to the Free
 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <asm/cputable.h>
+#include <asm/cpu_has_feature.h>
 #include "nonstdio.h"
 #include "ansidecl.h"
 #include "ppc.h"
index 9e607bf..e751fe2 100644 (file)
@@ -123,6 +123,7 @@ config S390
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_EARLY_PFN_TO_NID
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_JUMP_LABEL
        select CPU_NO_EFFICIENT_FFS if !HAVE_MARCH_Z9_109_FEATURES
        select HAVE_ARCH_SECCOMP_FILTER
@@ -871,4 +872,17 @@ config S390_GUEST
          Select this option if you want to run the kernel as a guest under
          the KVM hypervisor.
 
+config S390_GUEST_OLD_TRANSPORT
+       def_bool y
+       prompt "Guest support for old s390 virtio transport (DEPRECATED)"
+       depends on S390_GUEST
+       help
+         Enable this option to add support for the old s390-virtio
+         transport (i.e. virtio devices NOT based on virtio-ccw). This
+         type of virtio devices is only available on the experimental
+         kuli userspace or with old (< 2.6) qemu. If you are running
+         with a modern version of qemu (which supports virtio-ccw since
+         1.4 and uses it by default since version 2.4), you probably won't
+         need this.
+
 endmenu
index 13723c3..33ba697 100644 (file)
@@ -33,10 +33,10 @@ quiet_cmd_sizes = GEN $@
 $(obj)/sizes.h: vmlinux
        $(call if_changed,sizes)
 
-AFLAGS_head.o += -I$(obj)
+AFLAGS_head.o += -I$(objtree)/$(obj)
 $(obj)/head.o: $(obj)/sizes.h
 
-CFLAGS_misc.o += -I$(obj)
+CFLAGS_misc.o += -I$(objtree)/$(obj)
 $(obj)/misc.o: $(obj)/sizes.h
 
 OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
index 67d43a0..28f03ca 100644 (file)
 #include <asm/ebcdic.h>
 #include "hypfs.h"
 
-#define LPAR_NAME_LEN 8                /* lpar name len in diag 204 data */
-#define CPU_NAME_LEN 16                /* type name len of cpus in diag224 name table */
 #define TMP_SIZE 64            /* size of temporary buffers */
 
 #define DBFS_D204_HDR_VERSION  0
 
-/* diag 204 subcodes */
-enum diag204_sc {
-       SUBC_STIB4 = 4,
-       SUBC_RSI = 5,
-       SUBC_STIB6 = 6,
-       SUBC_STIB7 = 7
-};
-
-/* The two available diag 204 data formats */
-enum diag204_format {
-       INFO_SIMPLE = 0,
-       INFO_EXT = 0x00010000
-};
-
-/* bit is set in flags, when physical cpu info is included in diag 204 data */
-#define LPAR_PHYS_FLG  0x80
-
 static char *diag224_cpu_names;                        /* diag 224 name table */
 static enum diag204_sc diag204_store_sc;       /* used subcode for store */
 static enum diag204_format diag204_info_type;  /* used diag 204 data format */
@@ -53,7 +34,7 @@ static int diag204_buf_pages;         /* number of pages for diag204 data */
 static struct dentry *dbfs_d204_file;
 
 /*
- * DIAG 204 data structures and member access functions.
+ * DIAG 204 member access functions.
  *
  * Since we have two different diag 204 data formats for old and new s390
  * machines, we do not access the structs directly, but use getter functions for
@@ -62,304 +43,173 @@ static struct dentry *dbfs_d204_file;
 
 /* Time information block */
 
-struct info_blk_hdr {
-       __u8  npar;
-       __u8  flags;
-       __u16 tslice;
-       __u16 phys_cpus;
-       __u16 this_part;
-       __u64 curtod;
-} __attribute__ ((packed));
-
-struct x_info_blk_hdr {
-       __u8  npar;
-       __u8  flags;
-       __u16 tslice;
-       __u16 phys_cpus;
-       __u16 this_part;
-       __u64 curtod1;
-       __u64 curtod2;
-       char reserved[40];
-} __attribute__ ((packed));
-
 static inline int info_blk_hdr__size(enum diag204_format type)
 {
-       if (type == INFO_SIMPLE)
-               return sizeof(struct info_blk_hdr);
-       else /* INFO_EXT */
-               return sizeof(struct x_info_blk_hdr);
+       if (type == DIAG204_INFO_SIMPLE)
+               return sizeof(struct diag204_info_blk_hdr);
+       else /* DIAG204_INFO_EXT */
+               return sizeof(struct diag204_x_info_blk_hdr);
 }
 
 static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct info_blk_hdr *)hdr)->npar;
-       else /* INFO_EXT */
-               return ((struct x_info_blk_hdr *)hdr)->npar;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_info_blk_hdr *)hdr)->npar;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
 }
 
 static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct info_blk_hdr *)hdr)->flags;
-       else /* INFO_EXT */
-               return ((struct x_info_blk_hdr *)hdr)->flags;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_info_blk_hdr *)hdr)->flags;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
 }
 
 static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct info_blk_hdr *)hdr)->phys_cpus;
-       else /* INFO_EXT */
-               return ((struct x_info_blk_hdr *)hdr)->phys_cpus;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
 }
 
 /* Partition header */
 
-struct part_hdr {
-       __u8 pn;
-       __u8 cpus;
-       char reserved[6];
-       char part_name[LPAR_NAME_LEN];
-} __attribute__ ((packed));
-
-struct x_part_hdr {
-       __u8  pn;
-       __u8  cpus;
-       __u8  rcpus;
-       __u8  pflag;
-       __u32 mlu;
-       char  part_name[LPAR_NAME_LEN];
-       char  lpc_name[8];
-       char  os_name[8];
-       __u64 online_cs;
-       __u64 online_es;
-       __u8  upid;
-       char  reserved1[3];
-       __u32 group_mlu;
-       char  group_name[8];
-       char  reserved2[32];
-} __attribute__ ((packed));
-
 static inline int part_hdr__size(enum diag204_format type)
 {
-       if (type == INFO_SIMPLE)
-               return sizeof(struct part_hdr);
-       else /* INFO_EXT */
-               return sizeof(struct x_part_hdr);
+       if (type == DIAG204_INFO_SIMPLE)
+               return sizeof(struct diag204_part_hdr);
+       else /* DIAG204_INFO_EXT */
+               return sizeof(struct diag204_x_part_hdr);
 }
 
 static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct part_hdr *)hdr)->cpus;
-       else /* INFO_EXT */
-               return ((struct x_part_hdr *)hdr)->rcpus;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_part_hdr *)hdr)->cpus;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_part_hdr *)hdr)->rcpus;
 }
 
 static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
                                       char *name)
 {
-       if (type == INFO_SIMPLE)
-               memcpy(name, ((struct part_hdr *)hdr)->part_name,
-                      LPAR_NAME_LEN);
-       else /* INFO_EXT */
-               memcpy(name, ((struct x_part_hdr *)hdr)->part_name,
-                      LPAR_NAME_LEN);
-       EBCASC(name, LPAR_NAME_LEN);
-       name[LPAR_NAME_LEN] = 0;
+       if (type == DIAG204_INFO_SIMPLE)
+               memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
+                      DIAG204_LPAR_NAME_LEN);
+       else /* DIAG204_INFO_EXT */
+               memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
+                      DIAG204_LPAR_NAME_LEN);
+       EBCASC(name, DIAG204_LPAR_NAME_LEN);
+       name[DIAG204_LPAR_NAME_LEN] = 0;
        strim(name);
 }
 
-struct cpu_info {
-       __u16 cpu_addr;
-       char  reserved1[2];
-       __u8  ctidx;
-       __u8  cflag;
-       __u16 weight;
-       __u64 acc_time;
-       __u64 lp_time;
-} __attribute__ ((packed));
-
-struct x_cpu_info {
-       __u16 cpu_addr;
-       char  reserved1[2];
-       __u8  ctidx;
-       __u8  cflag;
-       __u16 weight;
-       __u64 acc_time;
-       __u64 lp_time;
-       __u16 min_weight;
-       __u16 cur_weight;
-       __u16 max_weight;
-       char  reseved2[2];
-       __u64 online_time;
-       __u64 wait_time;
-       __u32 pma_weight;
-       __u32 polar_weight;
-       char  reserved3[40];
-} __attribute__ ((packed));
-
 /* CPU info block */
 
 static inline int cpu_info__size(enum diag204_format type)
 {
-       if (type == INFO_SIMPLE)
-               return sizeof(struct cpu_info);
-       else /* INFO_EXT */
-               return sizeof(struct x_cpu_info);
+       if (type == DIAG204_INFO_SIMPLE)
+               return sizeof(struct diag204_cpu_info);
+       else /* DIAG204_INFO_EXT */
+               return sizeof(struct diag204_x_cpu_info);
 }
 
 static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct cpu_info *)hdr)->ctidx;
-       else /* INFO_EXT */
-               return ((struct x_cpu_info *)hdr)->ctidx;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_cpu_info *)hdr)->ctidx;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_cpu_info *)hdr)->ctidx;
 }
 
 static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct cpu_info *)hdr)->cpu_addr;
-       else /* INFO_EXT */
-               return ((struct x_cpu_info *)hdr)->cpu_addr;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_cpu_info *)hdr)->cpu_addr;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
 }
 
 static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct cpu_info *)hdr)->acc_time;
-       else /* INFO_EXT */
-               return ((struct x_cpu_info *)hdr)->acc_time;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_cpu_info *)hdr)->acc_time;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_cpu_info *)hdr)->acc_time;
 }
 
 static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct cpu_info *)hdr)->lp_time;
-       else /* INFO_EXT */
-               return ((struct x_cpu_info *)hdr)->lp_time;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_cpu_info *)hdr)->lp_time;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_cpu_info *)hdr)->lp_time;
 }
 
 static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
+       if (type == DIAG204_INFO_SIMPLE)
                return 0;       /* online_time not available in simple info */
-       else /* INFO_EXT */
-               return ((struct x_cpu_info *)hdr)->online_time;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_cpu_info *)hdr)->online_time;
 }
 
 /* Physical header */
 
-struct phys_hdr {
-       char reserved1[1];
-       __u8 cpus;
-       char reserved2[6];
-       char mgm_name[8];
-} __attribute__ ((packed));
-
-struct x_phys_hdr {
-       char reserved1[1];
-       __u8 cpus;
-       char reserved2[6];
-       char mgm_name[8];
-       char reserved3[80];
-} __attribute__ ((packed));
-
 static inline int phys_hdr__size(enum diag204_format type)
 {
-       if (type == INFO_SIMPLE)
-               return sizeof(struct phys_hdr);
-       else /* INFO_EXT */
-               return sizeof(struct x_phys_hdr);
+       if (type == DIAG204_INFO_SIMPLE)
+               return sizeof(struct diag204_phys_hdr);
+       else /* DIAG204_INFO_EXT */
+               return sizeof(struct diag204_x_phys_hdr);
 }
 
 static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct phys_hdr *)hdr)->cpus;
-       else /* INFO_EXT */
-               return ((struct x_phys_hdr *)hdr)->cpus;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_phys_hdr *)hdr)->cpus;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_phys_hdr *)hdr)->cpus;
 }
 
 /* Physical CPU info block */
 
-struct phys_cpu {
-       __u16 cpu_addr;
-       char  reserved1[2];
-       __u8  ctidx;
-       char  reserved2[3];
-       __u64 mgm_time;
-       char  reserved3[8];
-} __attribute__ ((packed));
-
-struct x_phys_cpu {
-       __u16 cpu_addr;
-       char  reserved1[2];
-       __u8  ctidx;
-       char  reserved2[3];
-       __u64 mgm_time;
-       char  reserved3[80];
-} __attribute__ ((packed));
-
 static inline int phys_cpu__size(enum diag204_format type)
 {
-       if (type == INFO_SIMPLE)
-               return sizeof(struct phys_cpu);
-       else /* INFO_EXT */
-               return sizeof(struct x_phys_cpu);
+       if (type == DIAG204_INFO_SIMPLE)
+               return sizeof(struct diag204_phys_cpu);
+       else /* DIAG204_INFO_EXT */
+               return sizeof(struct diag204_x_phys_cpu);
 }
 
 static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct phys_cpu *)hdr)->cpu_addr;
-       else /* INFO_EXT */
-               return ((struct x_phys_cpu *)hdr)->cpu_addr;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
 }
 
 static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct phys_cpu *)hdr)->mgm_time;
-       else /* INFO_EXT */
-               return ((struct x_phys_cpu *)hdr)->mgm_time;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_phys_cpu *)hdr)->mgm_time;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
 }
 
 static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
 {
-       if (type == INFO_SIMPLE)
-               return ((struct phys_cpu *)hdr)->ctidx;
-       else /* INFO_EXT */
-               return ((struct x_phys_cpu *)hdr)->ctidx;
+       if (type == DIAG204_INFO_SIMPLE)
+               return ((struct diag204_phys_cpu *)hdr)->ctidx;
+       else /* DIAG204_INFO_EXT */
+               return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
 }
 
 /* Diagnose 204 functions */
-
-static inline int __diag204(unsigned long *subcode, unsigned long size, void *addr)
-{
-       register unsigned long _subcode asm("0") = *subcode;
-       register unsigned long _size asm("1") = size;
-
-       asm volatile(
-               "       diag    %2,%0,0x204\n"
-               "0:     nopr    %%r7\n"
-               EX_TABLE(0b,0b)
-               : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
-       *subcode = _subcode;
-       return _size;
-}
-
-static int diag204(unsigned long subcode, unsigned long size, void *addr)
-{
-       diag_stat_inc(DIAG_STAT_X204);
-       size = __diag204(&subcode, size, addr);
-       if (subcode)
-               return -1;
-       return size;
-}
-
 /*
  * For the old diag subcode 4 with simple data format we have to use real
  * memory. If we use subcode 6 or 7 with extended data format, we can (and
@@ -411,12 +261,12 @@ static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
                *pages = diag204_buf_pages;
                return diag204_buf;
        }
-       if (fmt == INFO_SIMPLE) {
+       if (fmt == DIAG204_INFO_SIMPLE) {
                *pages = 1;
                return diag204_alloc_rbuf();
-       } else {/* INFO_EXT */
-               *pages = diag204((unsigned long)SUBC_RSI |
-                                (unsigned long)INFO_EXT, 0, NULL);
+       } else {/* DIAG204_INFO_EXT */
+               *pages = diag204((unsigned long)DIAG204_SUBC_RSI |
+                                (unsigned long)DIAG204_INFO_EXT, 0, NULL);
                if (*pages <= 0)
                        return ERR_PTR(-ENOSYS);
                else
@@ -443,18 +293,18 @@ static int diag204_probe(void)
        void *buf;
        int pages, rc;
 
-       buf = diag204_get_buffer(INFO_EXT, &pages);
+       buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
        if (!IS_ERR(buf)) {
-               if (diag204((unsigned long)SUBC_STIB7 |
-                           (unsigned long)INFO_EXT, pages, buf) >= 0) {
-                       diag204_store_sc = SUBC_STIB7;
-                       diag204_info_type = INFO_EXT;
+               if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
+                           (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
+                       diag204_store_sc = DIAG204_SUBC_STIB7;
+                       diag204_info_type = DIAG204_INFO_EXT;
                        goto out;
                }
-               if (diag204((unsigned long)SUBC_STIB6 |
-                           (unsigned long)INFO_EXT, pages, buf) >= 0) {
-                       diag204_store_sc = SUBC_STIB6;
-                       diag204_info_type = INFO_EXT;
+               if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
+                           (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
+                       diag204_store_sc = DIAG204_SUBC_STIB6;
+                       diag204_info_type = DIAG204_INFO_EXT;
                        goto out;
                }
                diag204_free_buffer();
@@ -462,15 +312,15 @@ static int diag204_probe(void)
 
        /* subcodes 6 and 7 failed, now try subcode 4 */
 
-       buf = diag204_get_buffer(INFO_SIMPLE, &pages);
+       buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
        if (IS_ERR(buf)) {
                rc = PTR_ERR(buf);
                goto fail_alloc;
        }
-       if (diag204((unsigned long)SUBC_STIB4 |
-                   (unsigned long)INFO_SIMPLE, pages, buf) >= 0) {
-               diag204_store_sc = SUBC_STIB4;
-               diag204_info_type = INFO_SIMPLE;
+       if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
+                   (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
+               diag204_store_sc = DIAG204_SUBC_STIB4;
+               diag204_info_type = DIAG204_INFO_SIMPLE;
                goto out;
        } else {
                rc = -ENOSYS;
@@ -510,20 +360,6 @@ out:
 
 /* Diagnose 224 functions */
 
-static int diag224(void *ptr)
-{
-       int rc = -EOPNOTSUPP;
-
-       diag_stat_inc(DIAG_STAT_X224);
-       asm volatile(
-               "       diag    %1,%2,0x224\n"
-               "0:     lhi     %0,0x0\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (rc) :"d" (0), "d" (ptr) : "memory");
-       return rc;
-}
-
 static int diag224_get_name_table(void)
 {
        /* memory must be below 2GB */
@@ -545,9 +381,9 @@ static void diag224_delete_name_table(void)
 
 static int diag224_idx2name(int index, char *name)
 {
-       memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN),
-               CPU_NAME_LEN);
-       name[CPU_NAME_LEN] = 0;
+       memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
+              DIAG204_CPU_NAME_LEN);
+       name[DIAG204_CPU_NAME_LEN] = 0;
        strim(name);
        return 0;
 }
@@ -603,7 +439,7 @@ __init int hypfs_diag_init(void)
                pr_err("The hardware system does not support hypfs\n");
                return -ENODATA;
        }
-       if (diag204_info_type == INFO_EXT) {
+       if (diag204_info_type == DIAG204_INFO_EXT) {
                rc = hypfs_dbfs_create_file(&dbfs_file_d204);
                if (rc)
                        return rc;
@@ -651,7 +487,7 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
                              cpu_info__lp_time(diag204_info_type, cpu_info));
        if (IS_ERR(rc))
                return PTR_ERR(rc);
-       if (diag204_info_type == INFO_EXT) {
+       if (diag204_info_type == DIAG204_INFO_EXT) {
                rc = hypfs_create_u64(cpu_dir, "onlinetime",
                                      cpu_info__online_time(diag204_info_type,
                                                            cpu_info));
@@ -667,12 +503,12 @@ static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
 {
        struct dentry *cpus_dir;
        struct dentry *lpar_dir;
-       char lpar_name[LPAR_NAME_LEN + 1];
+       char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
        void *cpu_info;
        int i;
 
        part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
-       lpar_name[LPAR_NAME_LEN] = 0;
+       lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
        lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
        if (IS_ERR(lpar_dir))
                return lpar_dir;
@@ -755,7 +591,8 @@ int hypfs_diag_create_files(struct dentry *root)
                        goto err_out;
                }
        }
-       if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) {
+       if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
+           DIAG204_LPAR_PHYS_FLG) {
                ptr = hypfs_create_phys_files(root, part_hdr);
                if (IS_ERR(ptr)) {
                        rc = PTR_ERR(ptr);
index 1a82cf2..d28621d 100644 (file)
@@ -20,6 +20,9 @@
 #define CPACF_KMC              0xb92f          /* MSA  */
 #define CPACF_KIMD             0xb93e          /* MSA  */
 #define CPACF_KLMD             0xb93f          /* MSA  */
+#define CPACF_PCKMO            0xb928          /* MSA3 */
+#define CPACF_KMF              0xb92a          /* MSA4 */
+#define CPACF_KMO              0xb92b          /* MSA4 */
 #define CPACF_PCC              0xb92c          /* MSA4 */
 #define CPACF_KMCTR            0xb92d          /* MSA4 */
 #define CPACF_PPNO             0xb93c          /* MSA5 */
@@ -136,6 +139,7 @@ static inline void __cpacf_query(unsigned int opcode, unsigned char *status)
        register unsigned long r1 asm("1") = (unsigned long) status;
 
        asm volatile(
+               "       spm 0\n" /* pckmo doesn't change the cc */
                /* Parameter registers are ignored, but may not be 0 */
                "0:     .insn   rrf,%[opc] << 16,2,2,2,0\n"
                "       brc     1,0b\n" /* handle partial completion */
@@ -157,6 +161,12 @@ static inline int cpacf_query(unsigned int opcode, unsigned int func)
                if (!test_facility(17)) /* check for MSA */
                        return 0;
                break;
+       case CPACF_PCKMO:
+               if (!test_facility(76)) /* check for MSA3 */
+                       return 0;
+               break;
+       case CPACF_KMF:
+       case CPACF_KMO:
        case CPACF_PCC:
        case CPACF_KMCTR:
                if (!test_facility(77)) /* check for MSA4 */
index 86cae09..8acf482 100644 (file)
@@ -78,4 +78,153 @@ struct diag210 {
 
 extern int diag210(struct diag210 *addr);
 
+/* bit is set in flags, when physical cpu info is included in diag 204 data */
+#define DIAG204_LPAR_PHYS_FLG 0x80
+#define DIAG204_LPAR_NAME_LEN 8                /* lpar name len in diag 204 data */
+#define DIAG204_CPU_NAME_LEN 16                /* type name len of cpus in diag224 name table */
+
+/* diag 204 subcodes */
+enum diag204_sc {
+       DIAG204_SUBC_STIB4 = 4,
+       DIAG204_SUBC_RSI = 5,
+       DIAG204_SUBC_STIB6 = 6,
+       DIAG204_SUBC_STIB7 = 7
+};
+
+/* The two available diag 204 data formats */
+enum diag204_format {
+       DIAG204_INFO_SIMPLE = 0,
+       DIAG204_INFO_EXT = 0x00010000
+};
+
+enum diag204_cpu_flags {
+       DIAG204_CPU_ONLINE = 0x20,
+       DIAG204_CPU_CAPPED = 0x40,
+};
+
+struct diag204_info_blk_hdr {
+       __u8  npar;
+       __u8  flags;
+       __u16 tslice;
+       __u16 phys_cpus;
+       __u16 this_part;
+       __u64 curtod;
+} __packed;
+
+struct diag204_x_info_blk_hdr {
+       __u8  npar;
+       __u8  flags;
+       __u16 tslice;
+       __u16 phys_cpus;
+       __u16 this_part;
+       __u64 curtod1;
+       __u64 curtod2;
+       char reserved[40];
+} __packed;
+
+struct diag204_part_hdr {
+       __u8 pn;
+       __u8 cpus;
+       char reserved[6];
+       char part_name[DIAG204_LPAR_NAME_LEN];
+} __packed;
+
+struct diag204_x_part_hdr {
+       __u8  pn;
+       __u8  cpus;
+       __u8  rcpus;
+       __u8  pflag;
+       __u32 mlu;
+       char  part_name[DIAG204_LPAR_NAME_LEN];
+       char  lpc_name[8];
+       char  os_name[8];
+       __u64 online_cs;
+       __u64 online_es;
+       __u8  upid;
+       __u8  reserved:3;
+       __u8  mtid:5;
+       char  reserved1[2];
+       __u32 group_mlu;
+       char  group_name[8];
+       char  hardware_group_name[8];
+       char  reserved2[24];
+} __packed;
+
+struct diag204_cpu_info {
+       __u16 cpu_addr;
+       char  reserved1[2];
+       __u8  ctidx;
+       __u8  cflag;
+       __u16 weight;
+       __u64 acc_time;
+       __u64 lp_time;
+} __packed;
+
+struct diag204_x_cpu_info {
+       __u16 cpu_addr;
+       char  reserved1[2];
+       __u8  ctidx;
+       __u8  cflag;
+       __u16 weight;
+       __u64 acc_time;
+       __u64 lp_time;
+       __u16 min_weight;
+       __u16 cur_weight;
+       __u16 max_weight;
+       char  reseved2[2];
+       __u64 online_time;
+       __u64 wait_time;
+       __u32 pma_weight;
+       __u32 polar_weight;
+       __u32 cpu_type_cap;
+       __u32 group_cpu_type_cap;
+       char  reserved3[32];
+} __packed;
+
+struct diag204_phys_hdr {
+       char reserved1[1];
+       __u8 cpus;
+       char reserved2[6];
+       char mgm_name[8];
+} __packed;
+
+struct diag204_x_phys_hdr {
+       char reserved1[1];
+       __u8 cpus;
+       char reserved2[6];
+       char mgm_name[8];
+       char reserved3[80];
+} __packed;
+
+struct diag204_phys_cpu {
+       __u16 cpu_addr;
+       char  reserved1[2];
+       __u8  ctidx;
+       char  reserved2[3];
+       __u64 mgm_time;
+       char  reserved3[8];
+} __packed;
+
+struct diag204_x_phys_cpu {
+       __u16 cpu_addr;
+       char  reserved1[2];
+       __u8  ctidx;
+       char  reserved2[1];
+       __u16 weight;
+       __u64 mgm_time;
+       char  reserved3[80];
+} __packed;
+
+struct diag204_x_part_block {
+       struct diag204_x_part_hdr hdr;
+       struct diag204_x_cpu_info cpus[];
+} __packed;
+
+struct diag204_x_phys_block {
+       struct diag204_x_phys_hdr hdr;
+       struct diag204_x_phys_cpu cpus[];
+} __packed;
+
+int diag204(unsigned long subcode, unsigned long size, void *addr);
+int diag224(void *ptr);
 #endif /* _ASM_S390_DIAG_H */
index 3249b74..ffaba07 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-debug.h>
 #include <linux/io.h>
 
index d054c1b..741ddba 100644 (file)
 
 /**
  * struct gmap_struct - guest address space
+ * @list: list head for the mm->context gmap list
  * @crst_list: list of all crst tables used in the guest address space
  * @mm: pointer to the parent mm_struct
  * @guest_to_host: radix tree with guest to host address translation
  * @host_to_guest: radix tree with pointer to segment table entries
  * @guest_table_lock: spinlock to protect all entries in the guest page table
+ * @ref_count: reference counter for the gmap structure
  * @table: pointer to the page directory
  * @asce: address space control element for gmap page table
  * @pfault_enabled: defines if pfaults are applicable for the guest
+ * @host_to_rmap: radix tree with gmap_rmap lists
+ * @children: list of shadow gmap structures
+ * @pt_list: list of all page tables used in the shadow guest address space
+ * @shadow_lock: spinlock to protect the shadow gmap list
+ * @parent: pointer to the parent gmap for shadow guest address spaces
+ * @orig_asce: ASCE for which the shadow page table has been created
+ * @edat_level: edat level to be used for the shadow translation
+ * @removed: flag to indicate if a shadow guest address space has been removed
+ * @initialized: flag to indicate if a shadow guest address space can be used
  */
 struct gmap {
        struct list_head list;
@@ -26,26 +37,64 @@ struct gmap {
        struct radix_tree_root guest_to_host;
        struct radix_tree_root host_to_guest;
        spinlock_t guest_table_lock;
+       atomic_t ref_count;
        unsigned long *table;
        unsigned long asce;
        unsigned long asce_end;
        void *private;
        bool pfault_enabled;
+       /* Additional data for shadow guest address spaces */
+       struct radix_tree_root host_to_rmap;
+       struct list_head children;
+       struct list_head pt_list;
+       spinlock_t shadow_lock;
+       struct gmap *parent;
+       unsigned long orig_asce;
+       int edat_level;
+       bool removed;
+       bool initialized;
 };
 
+/**
+ * struct gmap_rmap - reverse mapping for shadow page table entries
+ * @next: pointer to next rmap in the list
+ * @raddr: virtual rmap address in the shadow guest address space
+ */
+struct gmap_rmap {
+       struct gmap_rmap *next;
+       unsigned long raddr;
+};
+
+#define gmap_for_each_rmap(pos, head) \
+       for (pos = (head); pos; pos = pos->next)
+
+#define gmap_for_each_rmap_safe(pos, n, head) \
+       for (pos = (head); n = pos ? pos->next : NULL, pos; pos = n)
+
 /**
  * struct gmap_notifier - notify function block for page invalidation
  * @notifier_call: address of callback function
  */
 struct gmap_notifier {
        struct list_head list;
-       void (*notifier_call)(struct gmap *gmap, unsigned long gaddr);
+       struct rcu_head rcu;
+       void (*notifier_call)(struct gmap *gmap, unsigned long start,
+                             unsigned long end);
 };
 
-struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit);
-void gmap_free(struct gmap *gmap);
+static inline int gmap_is_shadow(struct gmap *gmap)
+{
+       return !!gmap->parent;
+}
+
+struct gmap *gmap_create(struct mm_struct *mm, unsigned long limit);
+void gmap_remove(struct gmap *gmap);
+struct gmap *gmap_get(struct gmap *gmap);
+void gmap_put(struct gmap *gmap);
+
 void gmap_enable(struct gmap *gmap);
 void gmap_disable(struct gmap *gmap);
+struct gmap *gmap_get_enabled(void);
 int gmap_map_segment(struct gmap *gmap, unsigned long from,
                     unsigned long to, unsigned long len);
 int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
@@ -57,8 +106,29 @@ void gmap_discard(struct gmap *, unsigned long from, unsigned long to);
 void __gmap_zap(struct gmap *, unsigned long gaddr);
 void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr);
 
-void gmap_register_ipte_notifier(struct gmap_notifier *);
-void gmap_unregister_ipte_notifier(struct gmap_notifier *);
-int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
+int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val);
+
+struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
+                        int edat_level);
+int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level);
+int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
+                   int fake);
+int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
+                   int fake);
+int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
+                   int fake);
+int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
+                   int fake);
+int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
+                          unsigned long *pgt, int *dat_protection, int *fake);
+int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);
+
+void gmap_register_pte_notifier(struct gmap_notifier *);
+void gmap_unregister_pte_notifier(struct gmap_notifier *);
+void gmap_pte_notify(struct mm_struct *, unsigned long addr, pte_t *,
+                    unsigned long bits);
+
+int gmap_mprotect_notify(struct gmap *, unsigned long start,
+                        unsigned long len, int prot);
 
 #endif /* _ASM_S390_GMAP_H */
index ac82e8e..8e5daf7 100644 (file)
@@ -43,6 +43,7 @@
 /* s390-specific vcpu->requests bit members */
 #define KVM_REQ_ENABLE_IBS         8
 #define KVM_REQ_DISABLE_IBS        9
+#define KVM_REQ_ICPT_OPEREXC       10
 
 #define SIGP_CTRL_C            0x80
 #define SIGP_CTRL_SCN_MASK     0x3f
@@ -145,7 +146,7 @@ struct kvm_s390_sie_block {
        __u64   cputm;                  /* 0x0028 */
        __u64   ckc;                    /* 0x0030 */
        __u64   epoch;                  /* 0x0038 */
-       __u8    reserved40[4];          /* 0x0040 */
+       __u32   svcc;                   /* 0x0040 */
 #define LCTL_CR0       0x8000
 #define LCTL_CR6       0x0200
 #define LCTL_CR9       0x0040
@@ -154,6 +155,7 @@ struct kvm_s390_sie_block {
 #define LCTL_CR14      0x0002
        __u16   lctl;                   /* 0x0044 */
        __s16   icpua;                  /* 0x0046 */
+#define ICTL_OPEREXC   0x80000000
 #define ICTL_PINT      0x20000000
 #define ICTL_LPSW      0x00400000
 #define ICTL_STCTL     0x00040000
@@ -166,6 +168,9 @@ struct kvm_s390_sie_block {
 #define ICPT_INST      0x04
 #define ICPT_PROGI     0x08
 #define ICPT_INSTPROGI 0x0C
+#define ICPT_EXTINT    0x14
+#define ICPT_VALIDITY  0x20
+#define ICPT_STOP      0x28
 #define ICPT_OPEREXC   0x2C
 #define ICPT_PARTEXEC  0x38
 #define ICPT_IOINST    0x40
@@ -185,7 +190,9 @@ struct kvm_s390_sie_block {
        __u32   scaol;                  /* 0x0064 */
        __u8    reserved68[4];          /* 0x0068 */
        __u32   todpr;                  /* 0x006c */
-       __u8    reserved70[32];         /* 0x0070 */
+       __u8    reserved70[16];         /* 0x0070 */
+       __u64   mso;                    /* 0x0080 */
+       __u64   msl;                    /* 0x0088 */
        psw_t   gpsw;                   /* 0x0090 */
        __u64   gg14;                   /* 0x00a0 */
        __u64   gg15;                   /* 0x00a8 */
@@ -223,7 +230,7 @@ struct kvm_s390_sie_block {
        __u8    reserved1e6[2];         /* 0x01e6 */
        __u64   itdba;                  /* 0x01e8 */
        __u64   riccbd;                 /* 0x01f0 */
-       __u8    reserved1f8[8];         /* 0x01f8 */
+       __u64   gvrd;                   /* 0x01f8 */
 } __attribute__((packed));
 
 struct kvm_s390_itdb {
@@ -256,6 +263,7 @@ struct kvm_vcpu_stat {
        u32 instruction_stctg;
        u32 exit_program_interruption;
        u32 exit_instr_and_program;
+       u32 exit_operation_exception;
        u32 deliver_external_call;
        u32 deliver_emergency_signal;
        u32 deliver_service_signal;
@@ -278,7 +286,9 @@ struct kvm_vcpu_stat {
        u32 instruction_stsi;
        u32 instruction_stfl;
        u32 instruction_tprot;
+       u32 instruction_sie;
        u32 instruction_essa;
+       u32 instruction_sthyi;
        u32 instruction_sigp_sense;
        u32 instruction_sigp_sense_running;
        u32 instruction_sigp_external_call;
@@ -541,12 +551,16 @@ struct kvm_guestdbg_info_arch {
 
 struct kvm_vcpu_arch {
        struct kvm_s390_sie_block *sie_block;
+       /* if vsie is active, currently executed shadow sie control block */
+       struct kvm_s390_sie_block *vsie_block;
        unsigned int      host_acrs[NUM_ACRS];
        struct fpu        host_fpregs;
        struct kvm_s390_local_interrupt local_int;
        struct hrtimer    ckc_timer;
        struct kvm_s390_pgm_info pgm;
        struct gmap *gmap;
+       /* backup location for the currently enabled gmap when scheduled out */
+       struct gmap *enabled_gmap;
        struct kvm_guestdbg_info_arch guestdbg;
        unsigned long pfault_token;
        unsigned long pfault_select;
@@ -631,6 +645,14 @@ struct sie_page2 {
        u8 reserved900[0x1000 - 0x900];                 /* 0x0900 */
 } __packed;
 
+struct kvm_s390_vsie {
+       struct mutex mutex;
+       struct radix_tree_root addr_to_page;
+       int page_count;
+       int next;
+       struct page *pages[KVM_MAX_VCPUS];
+};
+
 struct kvm_arch{
        void *sca;
        int use_esca;
@@ -646,15 +668,20 @@ struct kvm_arch{
        int user_cpu_state_ctrl;
        int user_sigp;
        int user_stsi;
+       int user_instr0;
        struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
        wait_queue_head_t ipte_wq;
        int ipte_lock_count;
        struct mutex ipte_mutex;
+       struct ratelimit_state sthyi_limit;
        spinlock_t start_stop_lock;
        struct sie_page2 *sie_page2;
        struct kvm_s390_cpu_model model;
        struct kvm_s390_crypto crypto;
+       struct kvm_s390_vsie vsie;
        u64 epoch;
+       /* subset of available cpu features enabled by user space */
+       DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
 };
 
 #define KVM_HVA_ERR_BAD                (-1UL)
index 1822643..6d39329 100644 (file)
@@ -8,8 +8,9 @@ typedef struct {
        cpumask_t cpu_attach_mask;
        atomic_t flush_count;
        unsigned int flush_mm;
-       spinlock_t list_lock;
+       spinlock_t pgtable_lock;
        struct list_head pgtable_list;
+       spinlock_t gmap_lock;
        struct list_head gmap_list;
        unsigned long asce;
        unsigned long asce_limit;
@@ -22,9 +23,11 @@ typedef struct {
        unsigned int use_skey:1;
 } mm_context_t;
 
-#define INIT_MM_CONTEXT(name)                                                \
-       .context.list_lock    = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
-       .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),    \
+#define INIT_MM_CONTEXT(name)                                             \
+       .context.pgtable_lock =                                            \
+                       __SPIN_LOCK_UNLOCKED(name.context.pgtable_lock),   \
+       .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
+       .context.gmap_lock = __SPIN_LOCK_UNLOCKED(name.context.gmap_lock), \
        .context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),
 
 static inline int tprot(unsigned long addr)
index f77c638..c6a088c 100644 (file)
@@ -15,8 +15,9 @@
 static inline int init_new_context(struct task_struct *tsk,
                                   struct mm_struct *mm)
 {
-       spin_lock_init(&mm->context.list_lock);
+       spin_lock_init(&mm->context.pgtable_lock);
        INIT_LIST_HEAD(&mm->context.pgtable_list);
+       spin_lock_init(&mm->context.gmap_lock);
        INIT_LIST_HEAD(&mm->context.gmap_list);
        cpumask_clear(&mm->context.cpu_attach_mask);
        atomic_set(&mm->context.flush_count, 0);
index b2146c4..69b8a41 100644 (file)
@@ -111,13 +111,14 @@ static inline unsigned char page_get_storage_key(unsigned long addr)
 
 static inline int page_reset_referenced(unsigned long addr)
 {
-       unsigned int ipm;
+       int cc;
 
        asm volatile(
                "       rrbe    0,%1\n"
                "       ipm     %0\n"
-               : "=d" (ipm) : "a" (addr) : "cc");
-       return !!(ipm & 0x20000000);
+               "       srl     %0,28\n"
+               : "=d" (cc) : "a" (addr) : "cc");
+       return cc;
 }
 
 /* Bits int the storage key */
@@ -148,6 +149,8 @@ static inline int devmem_is_allowed(unsigned long pfn)
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn)       __va((pfn) << PAGE_SHIFT)
+#define page_to_virt(page)     pfn_to_virt(page_to_pfn(page))
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
index da34cb6..f4eb984 100644 (file)
@@ -19,8 +19,10 @@ unsigned long *crst_table_alloc(struct mm_struct *);
 void crst_table_free(struct mm_struct *, unsigned long *);
 
 unsigned long *page_table_alloc(struct mm_struct *);
+struct page *page_table_alloc_pgste(struct mm_struct *mm);
 void page_table_free(struct mm_struct *, unsigned long *);
 void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
+void page_table_free_pgste(struct page *page);
 extern int page_table_allocate_pgste;
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
index 48d383a..72c7f60 100644 (file)
@@ -277,6 +277,7 @@ static inline int is_module_addr(void *addr)
 /* Bits in the region table entry */
 #define _REGION_ENTRY_ORIGIN   ~0xfffUL/* region/segment table origin      */
 #define _REGION_ENTRY_PROTECT  0x200   /* region protection bit            */
+#define _REGION_ENTRY_OFFSET   0xc0    /* region table offset              */
 #define _REGION_ENTRY_INVALID  0x20    /* invalid region table entry       */
 #define _REGION_ENTRY_TYPE_MASK        0x0c    /* region/segment table type mask   */
 #define _REGION_ENTRY_TYPE_R1  0x0c    /* region first table type          */
@@ -364,6 +365,7 @@ static inline int is_module_addr(void *addr)
 #define PGSTE_GC_BIT   0x0002000000000000UL
 #define PGSTE_UC_BIT   0x0000800000000000UL    /* user dirty (migration) */
 #define PGSTE_IN_BIT   0x0000400000000000UL    /* IPTE notify bit */
+#define PGSTE_VSIE_BIT 0x0000200000000000UL    /* ref'd in a shadow table */
 
 /* Guest Page State used for virtualization */
 #define _PGSTE_GPS_ZERO                0x0000000080000000UL
@@ -1002,15 +1004,26 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
 void ptep_set_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t entry);
 void ptep_set_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
-void ptep_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+void ptep_notify(struct mm_struct *mm, unsigned long addr,
+                pte_t *ptep, unsigned long bits);
+int ptep_force_prot(struct mm_struct *mm, unsigned long gaddr,
+                   pte_t *ptep, int prot, unsigned long bit);
 void ptep_zap_unused(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep , int reset);
 void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr,
+                   pte_t *sptep, pte_t *tptep, pte_t pte);
+void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep);
 
 bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long address);
 int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
                          unsigned char key, bool nq);
-unsigned char get_guest_storage_key(struct mm_struct *mm, unsigned long addr);
+int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                              unsigned char key, unsigned char *oldkey,
+                              bool nq, bool mr, bool mc);
+int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr);
+int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                         unsigned char *key);
 
 /*
  * Certain architectures need to do special things when PTEs
index 0952920..0332317 100644 (file)
@@ -112,6 +112,8 @@ struct thread_struct {
         unsigned long ksp;              /* kernel stack pointer             */
        mm_segment_t mm_segment;
        unsigned long gmap_addr;        /* address of last gmap fault. */
+       unsigned int gmap_write_flag;   /* gmap fault write indication */
+       unsigned int gmap_int_code;     /* int code of last gmap fault */
        unsigned int gmap_pfault;       /* signal of a pending guest pfault */
        struct per_regs per_user;       /* User specified PER registers */
        struct per_event per_event;     /* Cause of the last PER trap */
index e4f6f73..2ad9c20 100644 (file)
@@ -32,12 +32,19 @@ struct sclp_core_entry {
        u8 reserved0;
        u8 : 4;
        u8 sief2 : 1;
-       u8 : 3;
-       u8 : 3;
+       u8 skey : 1;
+       u8 : 2;
+       u8 : 2;
+       u8 gpere : 1;
        u8 siif : 1;
        u8 sigpif : 1;
        u8 : 3;
-       u8 reserved2[10];
+       u8 reserved2[3];
+       u8 : 2;
+       u8 ib : 1;
+       u8 cei : 1;
+       u8 : 4;
+       u8 reserved3[6];
        u8 type;
        u8 reserved1;
 } __attribute__((packed));
@@ -59,6 +66,15 @@ struct sclp_info {
        unsigned char has_hvs : 1;
        unsigned char has_esca : 1;
        unsigned char has_sief2 : 1;
+       unsigned char has_64bscao : 1;
+       unsigned char has_gpere : 1;
+       unsigned char has_cmma : 1;
+       unsigned char has_gsls : 1;
+       unsigned char has_ib : 1;
+       unsigned char has_cei : 1;
+       unsigned char has_pfmfi : 1;
+       unsigned char has_ibs : 1;
+       unsigned char has_skey : 1;
        unsigned int ibc;
        unsigned int mtid;
        unsigned int mtid_cp;
@@ -101,5 +117,6 @@ int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
 void sclp_early_detect(void);
 void _sclp_print_early(const char *);
+void sclp_ocf_cpc_name_copy(char *dst);
 
 #endif /* _ASM_S390_SCLP_H */
index 3b8e99e..a2ffec4 100644 (file)
@@ -93,6 +93,47 @@ struct kvm_s390_vm_cpu_machine {
        __u64 fac_list[256];
 };
 
+#define KVM_S390_VM_CPU_PROCESSOR_FEAT 2
+#define KVM_S390_VM_CPU_MACHINE_FEAT   3
+
+#define KVM_S390_VM_CPU_FEAT_NR_BITS   1024
+#define KVM_S390_VM_CPU_FEAT_ESOP      0
+#define KVM_S390_VM_CPU_FEAT_SIEF2     1
+#define KVM_S390_VM_CPU_FEAT_64BSCAO   2
+#define KVM_S390_VM_CPU_FEAT_SIIF      3
+#define KVM_S390_VM_CPU_FEAT_GPERE     4
+#define KVM_S390_VM_CPU_FEAT_GSLS      5
+#define KVM_S390_VM_CPU_FEAT_IB                6
+#define KVM_S390_VM_CPU_FEAT_CEI       7
+#define KVM_S390_VM_CPU_FEAT_IBS       8
+#define KVM_S390_VM_CPU_FEAT_SKEY      9
+#define KVM_S390_VM_CPU_FEAT_CMMA      10
+#define KVM_S390_VM_CPU_FEAT_PFMFI     11
+#define KVM_S390_VM_CPU_FEAT_SIGPIF    12
+struct kvm_s390_vm_cpu_feat {
+       __u64 feat[16];
+};
+
+#define KVM_S390_VM_CPU_PROCESSOR_SUBFUNC      4
+#define KVM_S390_VM_CPU_MACHINE_SUBFUNC                5
+/* for "test bit" instructions MSB 0 bit ordering, for "query" raw blocks */
+struct kvm_s390_vm_cpu_subfunc {
+       __u8 plo[32];           /* always */
+       __u8 ptff[16];          /* with TOD-clock steering */
+       __u8 kmac[16];          /* with MSA */
+       __u8 kmc[16];           /* with MSA */
+       __u8 km[16];            /* with MSA */
+       __u8 kimd[16];          /* with MSA */
+       __u8 klmd[16];          /* with MSA */
+       __u8 pckmo[16];         /* with MSA3 */
+       __u8 kmctr[16];         /* with MSA4 */
+       __u8 kmf[16];           /* with MSA4 */
+       __u8 kmo[16];           /* with MSA4 */
+       __u8 pcc[16];           /* with MSA4 */
+       __u8 ppno[16];          /* with MSA5 */
+       __u8 reserved[1824];
+};
+
 /* kvm attributes for crypto */
 #define KVM_S390_VM_CRYPTO_ENABLE_AES_KW       0
 #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW       1
index 8fb5d4a..3ac6343 100644 (file)
        exit_code_ipa0(0xB2, 0x4c, "TAR"),      \
        exit_code_ipa0(0xB2, 0x50, "CSP"),      \
        exit_code_ipa0(0xB2, 0x54, "MVPG"),     \
+       exit_code_ipa0(0xB2, 0x56, "STHYI"),    \
        exit_code_ipa0(0xB2, 0x58, "BSG"),      \
        exit_code_ipa0(0xB2, 0x5a, "BSA"),      \
        exit_code_ipa0(0xB2, 0x5f, "CHSC"),     \
index 48b37b8..a97354c 100644 (file)
@@ -162,6 +162,30 @@ int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
 }
 EXPORT_SYMBOL(diag14);
 
+static inline int __diag204(unsigned long *subcode, unsigned long size, void *addr)
+{
+       register unsigned long _subcode asm("0") = *subcode;
+       register unsigned long _size asm("1") = size;
+
+       asm volatile(
+               "       diag    %2,%0,0x204\n"
+               "0:     nopr    %%r7\n"
+               EX_TABLE(0b,0b)
+               : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
+       *subcode = _subcode;
+       return _size;
+}
+
+int diag204(unsigned long subcode, unsigned long size, void *addr)
+{
+       diag_stat_inc(DIAG_STAT_X204);
+       size = __diag204(&subcode, size, addr);
+       if (subcode)
+               return -1;
+       return size;
+}
+EXPORT_SYMBOL(diag204);
+
 /*
  * Diagnose 210: Get information about a virtual device
  */
@@ -196,3 +220,18 @@ int diag210(struct diag210 *addr)
        return ccode;
 }
 EXPORT_SYMBOL(diag210);
+
+int diag224(void *ptr)
+{
+       int rc = -EOPNOTSUPP;
+
+       diag_stat_inc(DIAG_STAT_X224);
+       asm volatile(
+               "       diag    %1,%2,0x224\n"
+               "0:     lhi     %0,0x0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) :"d" (0), "d" (ptr) : "memory");
+       return rc;
+}
+EXPORT_SYMBOL(diag224);
index d42fa38..09a9e6d 100644 (file)
@@ -12,6 +12,6 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o  $(KVM)/async_pf.o $(KVM)/irqch
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
-kvm-objs += diag.o gaccess.o guestdbg.o
+kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o
 
 obj-$(CONFIG_KVM) += kvm.o
index 1ea4095..ce865bd 100644 (file)
@@ -212,6 +212,11 @@ static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu)
            (vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY))
                return -EOPNOTSUPP;
 
+       VCPU_EVENT(vcpu, 4, "diag 0x500 schid 0x%8.8x queue 0x%x cookie 0x%llx",
+                           (u32) vcpu->run->s.regs.gprs[2],
+                           (u32) vcpu->run->s.regs.gprs[3],
+                           vcpu->run->s.regs.gprs[4]);
+
        /*
         * The layout is as follows:
         * - gpr 2 contains the subchannel id (passed as addr)
index 66938d2..5420020 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/vmalloc.h>
 #include <linux/err.h>
 #include <asm/pgtable.h>
+#include <asm/gmap.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include <asm/switch_to.h>
@@ -476,18 +477,73 @@ enum {
        FSI_FETCH   = 2  /* Exception was due to fetch operation */
 };
 
-static int get_vcpu_asce(struct kvm_vcpu *vcpu, union asce *asce,
-                        ar_t ar, enum gacc_mode mode)
+enum prot_type {
+       PROT_TYPE_LA   = 0,
+       PROT_TYPE_KEYC = 1,
+       PROT_TYPE_ALC  = 2,
+       PROT_TYPE_DAT  = 3,
+};
+
+static int trans_exc(struct kvm_vcpu *vcpu, int code, unsigned long gva,
+                    ar_t ar, enum gacc_mode mode, enum prot_type prot)
 {
-       int rc;
-       struct psw_bits psw = psw_bits(vcpu->arch.sie_block->gpsw);
        struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
-       struct trans_exc_code_bits *tec_bits;
+       struct trans_exc_code_bits *tec;
 
        memset(pgm, 0, sizeof(*pgm));
-       tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
-       tec_bits->fsi = mode == GACC_STORE ? FSI_STORE : FSI_FETCH;
-       tec_bits->as = psw.as;
+       pgm->code = code;
+       tec = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
+
+       switch (code) {
+       case PGM_ASCE_TYPE:
+       case PGM_PAGE_TRANSLATION:
+       case PGM_REGION_FIRST_TRANS:
+       case PGM_REGION_SECOND_TRANS:
+       case PGM_REGION_THIRD_TRANS:
+       case PGM_SEGMENT_TRANSLATION:
+               /*
+                * op_access_id only applies to MOVE_PAGE -> set bit 61
+                * exc_access_id has to be set to 0 for some instructions. Both
+                * cases have to be handled by the caller. We can always store
+                * exc_access_id, as it is undefined for non-ar cases.
+                */
+               tec->addr = gva >> PAGE_SHIFT;
+               tec->fsi = mode == GACC_STORE ? FSI_STORE : FSI_FETCH;
+               tec->as = psw_bits(vcpu->arch.sie_block->gpsw).as;
+               /* FALL THROUGH */
+       case PGM_ALEN_TRANSLATION:
+       case PGM_ALE_SEQUENCE:
+       case PGM_ASTE_VALIDITY:
+       case PGM_ASTE_SEQUENCE:
+       case PGM_EXTENDED_AUTHORITY:
+               pgm->exc_access_id = ar;
+               break;
+       case PGM_PROTECTION:
+               switch (prot) {
+               case PROT_TYPE_ALC:
+                       tec->b60 = 1;
+                       /* FALL THROUGH */
+               case PROT_TYPE_DAT:
+                       tec->b61 = 1;
+                       tec->addr = gva >> PAGE_SHIFT;
+                       tec->fsi = mode == GACC_STORE ? FSI_STORE : FSI_FETCH;
+                       tec->as = psw_bits(vcpu->arch.sie_block->gpsw).as;
+                       /* exc_access_id is undefined for most cases */
+                       pgm->exc_access_id = ar;
+                       break;
+               default: /* LA and KEYC set b61 to 0, other params undefined */
+                       break;
+               }
+               break;
+       }
+       return code;
+}
+
+static int get_vcpu_asce(struct kvm_vcpu *vcpu, union asce *asce,
+                        unsigned long ga, ar_t ar, enum gacc_mode mode)
+{
+       int rc;
+       struct psw_bits psw = psw_bits(vcpu->arch.sie_block->gpsw);
 
        if (!psw.t) {
                asce->val = 0;
@@ -510,21 +566,8 @@ static int get_vcpu_asce(struct kvm_vcpu *vcpu, union asce *asce,
                return 0;
        case PSW_AS_ACCREG:
                rc = ar_translation(vcpu, asce, ar, mode);
-               switch (rc) {
-               case PGM_ALEN_TRANSLATION:
-               case PGM_ALE_SEQUENCE:
-               case PGM_ASTE_VALIDITY:
-               case PGM_ASTE_SEQUENCE:
-               case PGM_EXTENDED_AUTHORITY:
-                       vcpu->arch.pgm.exc_access_id = ar;
-                       break;
-               case PGM_PROTECTION:
-                       tec_bits->b60 = 1;
-                       tec_bits->b61 = 1;
-                       break;
-               }
                if (rc > 0)
-                       pgm->code = rc;
+                       return trans_exc(vcpu, rc, ga, ar, mode, PROT_TYPE_ALC);
                return rc;
        }
        return 0;
@@ -729,40 +772,31 @@ static int low_address_protection_enabled(struct kvm_vcpu *vcpu,
        return 1;
 }
 
-static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga,
+static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar,
                            unsigned long *pages, unsigned long nr_pages,
                            const union asce asce, enum gacc_mode mode)
 {
-       struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
        psw_t *psw = &vcpu->arch.sie_block->gpsw;
-       struct trans_exc_code_bits *tec_bits;
-       int lap_enabled, rc;
+       int lap_enabled, rc = 0;
 
-       tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
        lap_enabled = low_address_protection_enabled(vcpu, asce);
        while (nr_pages) {
                ga = kvm_s390_logical_to_effective(vcpu, ga);
-               tec_bits->addr = ga >> PAGE_SHIFT;
-               if (mode == GACC_STORE && lap_enabled && is_low_address(ga)) {
-                       pgm->code = PGM_PROTECTION;
-                       return pgm->code;
-               }
+               if (mode == GACC_STORE && lap_enabled && is_low_address(ga))
+                       return trans_exc(vcpu, PGM_PROTECTION, ga, ar, mode,
+                                        PROT_TYPE_LA);
                ga &= PAGE_MASK;
                if (psw_bits(*psw).t) {
                        rc = guest_translate(vcpu, ga, pages, asce, mode);
                        if (rc < 0)
                                return rc;
-                       if (rc == PGM_PROTECTION)
-                               tec_bits->b61 = 1;
-                       if (rc)
-                               pgm->code = rc;
                } else {
                        *pages = kvm_s390_real_to_abs(vcpu, ga);
                        if (kvm_is_error_gpa(vcpu->kvm, *pages))
-                               pgm->code = PGM_ADDRESSING;
+                               rc = PGM_ADDRESSING;
                }
-               if (pgm->code)
-                       return pgm->code;
+               if (rc)
+                       return trans_exc(vcpu, rc, ga, ar, mode, PROT_TYPE_DAT);
                ga += PAGE_SIZE;
                pages++;
                nr_pages--;
@@ -783,7 +817,8 @@ int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar, void *data,
 
        if (!len)
                return 0;
-       rc = get_vcpu_asce(vcpu, &asce, ar, mode);
+       ga = kvm_s390_logical_to_effective(vcpu, ga);
+       rc = get_vcpu_asce(vcpu, &asce, ga, ar, mode);
        if (rc)
                return rc;
        nr_pages = (((ga & ~PAGE_MASK) + len - 1) >> PAGE_SHIFT) + 1;
@@ -795,7 +830,7 @@ int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, ar_t ar, void *data,
        need_ipte_lock = psw_bits(*psw).t && !asce.r;
        if (need_ipte_lock)
                ipte_lock(vcpu);
-       rc = guest_page_range(vcpu, ga, pages, nr_pages, asce, mode);
+       rc = guest_page_range(vcpu, ga, ar, pages, nr_pages, asce, mode);
        for (idx = 0; idx < nr_pages && !rc; idx++) {
                gpa = *(pages + idx) + (ga & ~PAGE_MASK);
                _len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len);
@@ -846,37 +881,28 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
 int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar,
                            unsigned long *gpa, enum gacc_mode mode)
 {
-       struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
        psw_t *psw = &vcpu->arch.sie_block->gpsw;
-       struct trans_exc_code_bits *tec;
        union asce asce;
        int rc;
 
        gva = kvm_s390_logical_to_effective(vcpu, gva);
-       tec = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
-       rc = get_vcpu_asce(vcpu, &asce, ar, mode);
-       tec->addr = gva >> PAGE_SHIFT;
+       rc = get_vcpu_asce(vcpu, &asce, gva, ar, mode);
        if (rc)
                return rc;
        if (is_low_address(gva) && low_address_protection_enabled(vcpu, asce)) {
-               if (mode == GACC_STORE) {
-                       rc = pgm->code = PGM_PROTECTION;
-                       return rc;
-               }
+               if (mode == GACC_STORE)
+                       return trans_exc(vcpu, PGM_PROTECTION, gva, 0,
+                                        mode, PROT_TYPE_LA);
        }
 
        if (psw_bits(*psw).t && !asce.r) {      /* Use DAT? */
                rc = guest_translate(vcpu, gva, gpa, asce, mode);
-               if (rc > 0) {
-                       if (rc == PGM_PROTECTION)
-                               tec->b61 = 1;
-                       pgm->code = rc;
-               }
+               if (rc > 0)
+                       return trans_exc(vcpu, rc, gva, 0, mode, PROT_TYPE_DAT);
        } else {
-               rc = 0;
                *gpa = kvm_s390_real_to_abs(vcpu, gva);
                if (kvm_is_error_gpa(vcpu->kvm, *gpa))
-                       rc = pgm->code = PGM_ADDRESSING;
+                       return trans_exc(vcpu, rc, gva, PGM_ADDRESSING, mode, 0);
        }
 
        return rc;
@@ -915,20 +941,247 @@ int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, ar_t ar,
  */
 int kvm_s390_check_low_addr_prot_real(struct kvm_vcpu *vcpu, unsigned long gra)
 {
-       struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
-       psw_t *psw = &vcpu->arch.sie_block->gpsw;
-       struct trans_exc_code_bits *tec_bits;
        union ctlreg0 ctlreg0 = {.val = vcpu->arch.sie_block->gcr[0]};
 
        if (!ctlreg0.lap || !is_low_address(gra))
                return 0;
+       return trans_exc(vcpu, PGM_PROTECTION, gra, 0, GACC_STORE, PROT_TYPE_LA);
+}
 
-       memset(pgm, 0, sizeof(*pgm));
-       tec_bits = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
-       tec_bits->fsi = FSI_STORE;
-       tec_bits->as = psw_bits(*psw).as;
-       tec_bits->addr = gra >> PAGE_SHIFT;
-       pgm->code = PGM_PROTECTION;
+/**
+ * kvm_s390_shadow_tables - walk the guest page table and create shadow tables
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @pgt: pointer to the page table address result
+ * @fake: pgt references contiguous guest memory block, not a pgtable
+ */
+static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
+                                 unsigned long *pgt, int *dat_protection,
+                                 int *fake)
+{
+       struct gmap *parent;
+       union asce asce;
+       union vaddress vaddr;
+       unsigned long ptr;
+       int rc;
+
+       *fake = 0;
+       *dat_protection = 0;
+       parent = sg->parent;
+       vaddr.addr = saddr;
+       asce.val = sg->orig_asce;
+       ptr = asce.origin * 4096;
+       if (asce.r) {
+               *fake = 1;
+               asce.dt = ASCE_TYPE_REGION1;
+       }
+       switch (asce.dt) {
+       case ASCE_TYPE_REGION1:
+               if (vaddr.rfx01 > asce.tl && !asce.r)
+                       return PGM_REGION_FIRST_TRANS;
+               break;
+       case ASCE_TYPE_REGION2:
+               if (vaddr.rfx)
+                       return PGM_ASCE_TYPE;
+               if (vaddr.rsx01 > asce.tl)
+                       return PGM_REGION_SECOND_TRANS;
+               break;
+       case ASCE_TYPE_REGION3:
+               if (vaddr.rfx || vaddr.rsx)
+                       return PGM_ASCE_TYPE;
+               if (vaddr.rtx01 > asce.tl)
+                       return PGM_REGION_THIRD_TRANS;
+               break;
+       case ASCE_TYPE_SEGMENT:
+               if (vaddr.rfx || vaddr.rsx || vaddr.rtx)
+                       return PGM_ASCE_TYPE;
+               if (vaddr.sx01 > asce.tl)
+                       return PGM_SEGMENT_TRANSLATION;
+               break;
+       }
+
+       switch (asce.dt) {
+       case ASCE_TYPE_REGION1: {
+               union region1_table_entry rfte;
 
-       return pgm->code;
+               if (*fake) {
+                       /* offset in 16EB guest memory block */
+                       ptr = ptr + ((unsigned long) vaddr.rsx << 53UL);
+                       rfte.val = ptr;
+                       goto shadow_r2t;
+               }
+               rc = gmap_read_table(parent, ptr + vaddr.rfx * 8, &rfte.val);
+               if (rc)
+                       return rc;
+               if (rfte.i)
+                       return PGM_REGION_FIRST_TRANS;
+               if (rfte.tt != TABLE_TYPE_REGION1)
+                       return PGM_TRANSLATION_SPEC;
+               if (vaddr.rsx01 < rfte.tf || vaddr.rsx01 > rfte.tl)
+                       return PGM_REGION_SECOND_TRANS;
+               if (sg->edat_level >= 1)
+                       *dat_protection |= rfte.p;
+               ptr = rfte.rto << 12UL;
+shadow_r2t:
+               rc = gmap_shadow_r2t(sg, saddr, rfte.val, *fake);
+               if (rc)
+                       return rc;
+               /* fallthrough */
+       }
+       case ASCE_TYPE_REGION2: {
+               union region2_table_entry rste;
+
+               if (*fake) {
+                       /* offset in 8PB guest memory block */
+                       ptr = ptr + ((unsigned long) vaddr.rtx << 42UL);
+                       rste.val = ptr;
+                       goto shadow_r3t;
+               }
+               rc = gmap_read_table(parent, ptr + vaddr.rsx * 8, &rste.val);
+               if (rc)
+                       return rc;
+               if (rste.i)
+                       return PGM_REGION_SECOND_TRANS;
+               if (rste.tt != TABLE_TYPE_REGION2)
+                       return PGM_TRANSLATION_SPEC;
+               if (vaddr.rtx01 < rste.tf || vaddr.rtx01 > rste.tl)
+                       return PGM_REGION_THIRD_TRANS;
+               if (sg->edat_level >= 1)
+                       *dat_protection |= rste.p;
+               ptr = rste.rto << 12UL;
+shadow_r3t:
+               rste.p |= *dat_protection;
+               rc = gmap_shadow_r3t(sg, saddr, rste.val, *fake);
+               if (rc)
+                       return rc;
+               /* fallthrough */
+       }
+       case ASCE_TYPE_REGION3: {
+               union region3_table_entry rtte;
+
+               if (*fake) {
+                       /* offset in 4TB guest memory block */
+                       ptr = ptr + ((unsigned long) vaddr.sx << 31UL);
+                       rtte.val = ptr;
+                       goto shadow_sgt;
+               }
+               rc = gmap_read_table(parent, ptr + vaddr.rtx * 8, &rtte.val);
+               if (rc)
+                       return rc;
+               if (rtte.i)
+                       return PGM_REGION_THIRD_TRANS;
+               if (rtte.tt != TABLE_TYPE_REGION3)
+                       return PGM_TRANSLATION_SPEC;
+               if (rtte.cr && asce.p && sg->edat_level >= 2)
+                       return PGM_TRANSLATION_SPEC;
+               if (rtte.fc && sg->edat_level >= 2) {
+                       *dat_protection |= rtte.fc0.p;
+                       *fake = 1;
+                       ptr = rtte.fc1.rfaa << 31UL;
+                       rtte.val = ptr;
+                       goto shadow_sgt;
+               }
+               if (vaddr.sx01 < rtte.fc0.tf || vaddr.sx01 > rtte.fc0.tl)
+                       return PGM_SEGMENT_TRANSLATION;
+               if (sg->edat_level >= 1)
+                       *dat_protection |= rtte.fc0.p;
+               ptr = rtte.fc0.sto << 12UL;
+shadow_sgt:
+               rtte.fc0.p |= *dat_protection;
+               rc = gmap_shadow_sgt(sg, saddr, rtte.val, *fake);
+               if (rc)
+                       return rc;
+               /* fallthrough */
+       }
+       case ASCE_TYPE_SEGMENT: {
+               union segment_table_entry ste;
+
+               if (*fake) {
+                       /* offset in 2G guest memory block */
+                       ptr = ptr + ((unsigned long) vaddr.sx << 20UL);
+                       ste.val = ptr;
+                       goto shadow_pgt;
+               }
+               rc = gmap_read_table(parent, ptr + vaddr.sx * 8, &ste.val);
+               if (rc)
+                       return rc;
+               if (ste.i)
+                       return PGM_SEGMENT_TRANSLATION;
+               if (ste.tt != TABLE_TYPE_SEGMENT)
+                       return PGM_TRANSLATION_SPEC;
+               if (ste.cs && asce.p)
+                       return PGM_TRANSLATION_SPEC;
+               *dat_protection |= ste.fc0.p;
+               if (ste.fc && sg->edat_level >= 1) {
+                       *fake = 1;
+                       ptr = ste.fc1.sfaa << 20UL;
+                       ste.val = ptr;
+                       goto shadow_pgt;
+               }
+               ptr = ste.fc0.pto << 11UL;
+shadow_pgt:
+               ste.fc0.p |= *dat_protection;
+               rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake);
+               if (rc)
+                       return rc;
+       }
+       }
+       /* Return the parent address of the page table */
+       *pgt = ptr;
+       return 0;
+}
+
+/**
+ * kvm_s390_shadow_fault - handle fault on a shadow page table
+ * @vcpu: virtual cpu
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ *
+ * Returns: - 0 if the shadow fault was successfully resolved
+ *         - > 0 (pgm exception code) on exceptions while faulting
+ *         - -EAGAIN if the caller can retry immediately
+ *         - -EFAULT when accessing invalid guest addresses
+ *         - -ENOMEM if out of memory
+ */
+int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
+                         unsigned long saddr)
+{
+       union vaddress vaddr;
+       union page_table_entry pte;
+       unsigned long pgt;
+       int dat_protection, fake;
+       int rc;
+
+       down_read(&sg->mm->mmap_sem);
+       /*
+        * We don't want any guest-2 tables to change - so the parent
+        * tables/pointers we read stay valid - unshadowing is however
+        * always possible - only guest_table_lock protects us.
+        */
+       ipte_lock(vcpu);
+
+       rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
+       if (rc)
+               rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection,
+                                           &fake);
+
+       vaddr.addr = saddr;
+       if (fake) {
+               /* offset in 1MB guest memory block */
+               pte.val = pgt + ((unsigned long) vaddr.px << 12UL);
+               goto shadow_page;
+       }
+       if (!rc)
+               rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val);
+       if (!rc && pte.i)
+               rc = PGM_PAGE_TRANSLATION;
+       if (!rc && (pte.z || (pte.co && sg->edat_level < 1)))
+               rc = PGM_TRANSLATION_SPEC;
+shadow_page:
+       pte.p |= dat_protection;
+       if (!rc)
+               rc = gmap_shadow_page(sg, saddr, __pte(pte.val));
+       ipte_unlock(vcpu);
+       up_read(&sg->mm->mmap_sem);
+       return rc;
 }
index df0a79d..8756569 100644 (file)
@@ -361,4 +361,7 @@ void ipte_unlock(struct kvm_vcpu *vcpu);
 int ipte_lock_held(struct kvm_vcpu *vcpu);
 int kvm_s390_check_low_addr_prot_real(struct kvm_vcpu *vcpu, unsigned long gra);
 
+int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *shadow,
+                         unsigned long saddr);
+
 #endif /* __KVM_S390_GACCESS_H */
index e8c6843..31a0533 100644 (file)
@@ -439,6 +439,23 @@ exit_required:
 #define guest_per_enabled(vcpu) \
                             (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER)
 
+int kvm_s390_handle_per_ifetch_icpt(struct kvm_vcpu *vcpu)
+{
+       const u8 ilen = kvm_s390_get_ilen(vcpu);
+       struct kvm_s390_pgm_info pgm_info = {
+               .code = PGM_PER,
+               .per_code = PER_EVENT_IFETCH >> 24,
+               .per_address = __rewind_psw(vcpu->arch.sie_block->gpsw, ilen),
+       };
+
+       /*
+        * The PSW points to the next instruction, therefore the intercepted
+        * instruction generated a PER i-fetch event. PER address therefore
+        * points at the previous PSW address (could be an EXECUTE function).
+        */
+       return kvm_s390_inject_prog_irq(vcpu, &pgm_info);
+}
+
 static void filter_guest_per_event(struct kvm_vcpu *vcpu)
 {
        u32 perc = vcpu->arch.sie_block->perc << 24;
@@ -465,7 +482,7 @@ static void filter_guest_per_event(struct kvm_vcpu *vcpu)
                guest_perc &= ~PER_EVENT_IFETCH;
 
        /* All other PER events will be given to the guest */
-       /* TODO: Check alterated address/address space */
+       /* TODO: Check altered address/address space */
 
        vcpu->arch.sie_block->perc = guest_perc >> 24;
 
index 2521571..dfd0ca2 100644 (file)
@@ -351,8 +351,26 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
        return -EOPNOTSUPP;
 }
 
+static int handle_operexc(struct kvm_vcpu *vcpu)
+{
+       vcpu->stat.exit_operation_exception++;
+       trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa,
+                                     vcpu->arch.sie_block->ipb);
+
+       if (vcpu->arch.sie_block->ipa == 0xb256 &&
+           test_kvm_facility(vcpu->kvm, 74))
+               return handle_sthyi(vcpu);
+
+       if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
+               return -EOPNOTSUPP;
+
+       return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+}
+
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
 {
+       int rc, per_rc = 0;
+
        if (kvm_is_ucontrol(vcpu->kvm))
                return -EOPNOTSUPP;
 
@@ -361,7 +379,8 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
        case 0x18:
                return handle_noop(vcpu);
        case 0x04:
-               return handle_instruction(vcpu);
+               rc = handle_instruction(vcpu);
+               break;
        case 0x08:
                return handle_prog(vcpu);
        case 0x14:
@@ -372,9 +391,19 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
                return handle_validity(vcpu);
        case 0x28:
                return handle_stop(vcpu);
+       case 0x2c:
+               rc = handle_operexc(vcpu);
+               break;
        case 0x38:
-               return handle_partial_execution(vcpu);
+               rc = handle_partial_execution(vcpu);
+               break;
        default:
                return -EOPNOTSUPP;
        }
+
+       /* process PER, also if the instrution is processed in user space */
+       if (vcpu->arch.sie_block->icptstatus & 0x02 &&
+           (!rc || rc == -EOPNOTSUPP))
+               per_rc = kvm_s390_handle_per_ifetch_icpt(vcpu);
+       return per_rc ? per_rc : rc;
 }
index 5a80af7..24524c0 100644 (file)
@@ -28,9 +28,6 @@
 #include "gaccess.h"
 #include "trace-s390.h"
 
-#define IOINT_SCHID_MASK 0x0000ffff
-#define IOINT_SSID_MASK 0x00030000
-#define IOINT_CSSID_MASK 0x03fc0000
 #define PFAULT_INIT 0x0600
 #define PFAULT_DONE 0x0680
 #define VIRTIO_PARAM 0x0d00
@@ -821,7 +818,14 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
                                        struct kvm_s390_interrupt_info,
                                        list);
        if (inti) {
-               VCPU_EVENT(vcpu, 4, "deliver: I/O 0x%llx", inti->type);
+               if (inti->type & KVM_S390_INT_IO_AI_MASK)
+                       VCPU_EVENT(vcpu, 4, "%s", "deliver: I/O (AI)");
+               else
+                       VCPU_EVENT(vcpu, 4, "deliver: I/O %x ss %x schid %04x",
+                       inti->io.subchannel_id >> 8,
+                       inti->io.subchannel_id >> 1 & 0x3,
+                       inti->io.subchannel_nr);
+
                vcpu->stat.deliver_io_int++;
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
                                inti->type,
@@ -991,6 +995,11 @@ void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
                swake_up(&vcpu->wq);
                vcpu->stat.halt_wakeup++;
        }
+       /*
+        * The VCPU might not be sleeping but is executing the VSIE. Let's
+        * kick it, so it leaves the SIE to process the request.
+        */
+       kvm_s390_vsie_kick(vcpu);
 }
 
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
@@ -1415,6 +1424,13 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
        }
        fi->counters[FIRQ_CNTR_IO] += 1;
 
+       if (inti->type & KVM_S390_INT_IO_AI_MASK)
+               VM_EVENT(kvm, 4, "%s", "inject: I/O (AI)");
+       else
+               VM_EVENT(kvm, 4, "inject: I/O %x ss %x schid %04x",
+                       inti->io.subchannel_id >> 8,
+                       inti->io.subchannel_id >> 1 & 0x3,
+                       inti->io.subchannel_nr);
        isc = int_word_to_isc(inti->io.io_int_word);
        list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc];
        list_add_tail(&inti->list, list);
@@ -1531,13 +1547,6 @@ int kvm_s390_inject_vm(struct kvm *kvm,
                inti->mchk.mcic = s390int->parm64;
                break;
        case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-               if (inti->type & KVM_S390_INT_IO_AI_MASK)
-                       VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
-               else
-                       VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
-                                s390int->type & IOINT_CSSID_MASK,
-                                s390int->type & IOINT_SSID_MASK,
-                                s390int->type & IOINT_SCHID_MASK);
                inti->io.subchannel_id = s390int->parm >> 16;
                inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
                inti->io.io_int_parm = s390int->parm64 >> 32;
@@ -2237,7 +2246,8 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
        return ret;
 }
 
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
 {
        int ret;
index 6f5c344..3f3ae48 100644 (file)
 #include <linux/init.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/mman.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/vmalloc.h>
+#include <linux/bitmap.h>
 #include <asm/asm-offsets.h>
 #include <asm/lowcore.h>
 #include <asm/stp.h>
@@ -35,6 +37,8 @@
 #include <asm/switch_to.h>
 #include <asm/isc.h>
 #include <asm/sclp.h>
+#include <asm/cpacf.h>
+#include <asm/timex.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 
@@ -64,6 +68,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "exit_pei", VCPU_STAT(exit_pei) },
        { "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
        { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
+       { "exit_operation_exception", VCPU_STAT(exit_operation_exception) },
        { "halt_successful_poll", VCPU_STAT(halt_successful_poll) },
        { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) },
        { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) },
@@ -94,6 +99,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_stsi", VCPU_STAT(instruction_stsi) },
        { "instruction_stfl", VCPU_STAT(instruction_stfl) },
        { "instruction_tprot", VCPU_STAT(instruction_tprot) },
+       { "instruction_sthyi", VCPU_STAT(instruction_sthyi) },
+       { "instruction_sie", VCPU_STAT(instruction_sie) },
        { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
        { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
        { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
@@ -119,6 +126,11 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
+/* allow nested virtualization in KVM (if enabled by user space) */
+static int nested;
+module_param(nested, int, S_IRUGO);
+MODULE_PARM_DESC(nested, "Nested virtualization support");
+
 /* upper facilities limit for kvm */
 unsigned long kvm_s390_fac_list_mask[16] = {
        0xffe6000000000000UL,
@@ -131,7 +143,13 @@ unsigned long kvm_s390_fac_list_mask_size(void)
        return ARRAY_SIZE(kvm_s390_fac_list_mask);
 }
 
+/* available cpu features supported by kvm */
+static DECLARE_BITMAP(kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
+/* available subfunctions indicated via query / "test bit" */
+static struct kvm_s390_vm_cpu_subfunc kvm_s390_available_subfunc;
+
 static struct gmap_notifier gmap_notifier;
+static struct gmap_notifier vsie_gmap_notifier;
 debug_info_t *kvm_s390_dbf;
 
 /* Section: not file related */
@@ -141,7 +159,8 @@ int kvm_arch_hardware_enable(void)
        return 0;
 }
 
-static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
+                             unsigned long end);
 
 /*
  * This callback is executed during stop_machine(). All CPUs are therefore
@@ -163,6 +182,8 @@ static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val,
                        vcpu->arch.sie_block->epoch -= *delta;
                        if (vcpu->arch.cputm_enabled)
                                vcpu->arch.cputm_start += *delta;
+                       if (vcpu->arch.vsie_block)
+                               vcpu->arch.vsie_block->epoch -= *delta;
                }
        }
        return NOTIFY_OK;
@@ -175,7 +196,9 @@ static struct notifier_block kvm_clock_notifier = {
 int kvm_arch_hardware_setup(void)
 {
        gmap_notifier.notifier_call = kvm_gmap_notifier;
-       gmap_register_ipte_notifier(&gmap_notifier);
+       gmap_register_pte_notifier(&gmap_notifier);
+       vsie_gmap_notifier.notifier_call = kvm_s390_vsie_gmap_notifier;
+       gmap_register_pte_notifier(&vsie_gmap_notifier);
        atomic_notifier_chain_register(&s390_epoch_delta_notifier,
                                       &kvm_clock_notifier);
        return 0;
@@ -183,11 +206,109 @@ int kvm_arch_hardware_setup(void)
 
 void kvm_arch_hardware_unsetup(void)
 {
-       gmap_unregister_ipte_notifier(&gmap_notifier);
+       gmap_unregister_pte_notifier(&gmap_notifier);
+       gmap_unregister_pte_notifier(&vsie_gmap_notifier);
        atomic_notifier_chain_unregister(&s390_epoch_delta_notifier,
                                         &kvm_clock_notifier);
 }
 
+static void allow_cpu_feat(unsigned long nr)
+{
+       set_bit_inv(nr, kvm_s390_available_cpu_feat);
+}
+
+static inline int plo_test_bit(unsigned char nr)
+{
+       register unsigned long r0 asm("0") = (unsigned long) nr | 0x100;
+       int cc = 3; /* subfunction not available */
+
+       asm volatile(
+               /* Parameter registers are ignored for "test bit" */
+               "       plo     0,0,0,0(0)\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
+               : "=d" (cc)
+               : "d" (r0)
+               : "cc");
+       return cc == 0;
+}
+
+static void kvm_s390_cpu_feat_init(void)
+{
+       int i;
+
+       for (i = 0; i < 256; ++i) {
+               if (plo_test_bit(i))
+                       kvm_s390_available_subfunc.plo[i >> 3] |= 0x80 >> (i & 7);
+       }
+
+       if (test_facility(28)) /* TOD-clock steering */
+               ptff(kvm_s390_available_subfunc.ptff,
+                    sizeof(kvm_s390_available_subfunc.ptff),
+                    PTFF_QAF);
+
+       if (test_facility(17)) { /* MSA */
+               __cpacf_query(CPACF_KMAC, kvm_s390_available_subfunc.kmac);
+               __cpacf_query(CPACF_KMC, kvm_s390_available_subfunc.kmc);
+               __cpacf_query(CPACF_KM, kvm_s390_available_subfunc.km);
+               __cpacf_query(CPACF_KIMD, kvm_s390_available_subfunc.kimd);
+               __cpacf_query(CPACF_KLMD, kvm_s390_available_subfunc.klmd);
+       }
+       if (test_facility(76)) /* MSA3 */
+               __cpacf_query(CPACF_PCKMO, kvm_s390_available_subfunc.pckmo);
+       if (test_facility(77)) { /* MSA4 */
+               __cpacf_query(CPACF_KMCTR, kvm_s390_available_subfunc.kmctr);
+               __cpacf_query(CPACF_KMF, kvm_s390_available_subfunc.kmf);
+               __cpacf_query(CPACF_KMO, kvm_s390_available_subfunc.kmo);
+               __cpacf_query(CPACF_PCC, kvm_s390_available_subfunc.pcc);
+       }
+       if (test_facility(57)) /* MSA5 */
+               __cpacf_query(CPACF_PPNO, kvm_s390_available_subfunc.ppno);
+
+       if (MACHINE_HAS_ESOP)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ESOP);
+       /*
+        * We need SIE support, ESOP (PROT_READ protection for gmap_shadow),
+        * 64bit SCAO (SCA passthrough) and IDTE (for gmap_shadow unshadowing).
+        */
+       if (!sclp.has_sief2 || !MACHINE_HAS_ESOP || !sclp.has_64bscao ||
+           !test_facility(3) || !nested)
+               return;
+       allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
+       if (sclp.has_64bscao)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
+       if (sclp.has_siif)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
+       if (sclp.has_gpere)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GPERE);
+       if (sclp.has_gsls)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GSLS);
+       if (sclp.has_ib)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IB);
+       if (sclp.has_cei)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_CEI);
+       if (sclp.has_ibs)
+               allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IBS);
+       /*
+        * KVM_S390_VM_CPU_FEAT_SKEY: Wrong shadow of PTE.I bits will make
+        * all skey handling functions read/set the skey from the PGSTE
+        * instead of the real storage key.
+        *
+        * KVM_S390_VM_CPU_FEAT_CMMA: Wrong shadow of PTE.I bits will make
+        * pages being detected as preserved although they are resident.
+        *
+        * KVM_S390_VM_CPU_FEAT_PFMFI: Wrong shadow of PTE.I bits will
+        * have the same effect as for KVM_S390_VM_CPU_FEAT_SKEY.
+        *
+        * For KVM_S390_VM_CPU_FEAT_SKEY, KVM_S390_VM_CPU_FEAT_CMMA and
+        * KVM_S390_VM_CPU_FEAT_PFMFI, all PTE.I and PGSTE bits have to be
+        * correctly shadowed. We can do that for the PGSTE but not for PTE.I.
+        *
+        * KVM_S390_VM_CPU_FEAT_SIGPIF: Wrong SCB addresses in the SCA. We
+        * cannot easily shadow the SCA because of the ipte lock.
+        */
+}
+
 int kvm_arch_init(void *opaque)
 {
        kvm_s390_dbf = debug_register("kvm-trace", 32, 1, 7 * sizeof(long));
@@ -199,6 +320,8 @@ int kvm_arch_init(void *opaque)
                return -ENOMEM;
        }
 
+       kvm_s390_cpu_feat_init();
+
        /* Register floating interrupt controller interface. */
        return kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
 }
@@ -244,6 +367,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_S390_USER_STSI:
        case KVM_CAP_S390_SKEYS:
        case KVM_CAP_S390_IRQ_STATE:
+       case KVM_CAP_S390_USER_INSTR0:
                r = 1;
                break;
        case KVM_CAP_S390_MEM_OP:
@@ -251,8 +375,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                break;
        case KVM_CAP_NR_VCPUS:
        case KVM_CAP_MAX_VCPUS:
-               r = sclp.has_esca ? KVM_S390_ESCA_CPU_SLOTS
-                                 : KVM_S390_BSCA_CPU_SLOTS;
+               r = KVM_S390_BSCA_CPU_SLOTS;
+               if (sclp.has_esca && sclp.has_64bscao)
+                       r = KVM_S390_ESCA_CPU_SLOTS;
                break;
        case KVM_CAP_NR_MEMSLOTS:
                r = KVM_USER_MEM_SLOTS;
@@ -335,6 +460,16 @@ out:
        return r;
 }
 
+static void icpt_operexc_on_all_vcpus(struct kvm *kvm)
+{
+       unsigned int i;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               kvm_s390_sync_request(KVM_REQ_ICPT_OPEREXC, vcpu);
+       }
+}
+
 static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
 {
        int r;
@@ -355,7 +490,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                break;
        case KVM_CAP_S390_VECTOR_REGISTERS:
                mutex_lock(&kvm->lock);
-               if (atomic_read(&kvm->online_vcpus)) {
+               if (kvm->created_vcpus) {
                        r = -EBUSY;
                } else if (MACHINE_HAS_VX) {
                        set_kvm_facility(kvm->arch.model.fac_mask, 129);
@@ -370,7 +505,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
        case KVM_CAP_S390_RI:
                r = -EINVAL;
                mutex_lock(&kvm->lock);
-               if (atomic_read(&kvm->online_vcpus)) {
+               if (kvm->created_vcpus) {
                        r = -EBUSY;
                } else if (test_facility(64)) {
                        set_kvm_facility(kvm->arch.model.fac_mask, 64);
@@ -386,6 +521,12 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                kvm->arch.user_stsi = 1;
                r = 0;
                break;
+       case KVM_CAP_S390_USER_INSTR0:
+               VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_INSTR0");
+               kvm->arch.user_instr0 = 1;
+               icpt_operexc_on_all_vcpus(kvm);
+               r = 0;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -418,21 +559,23 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
        unsigned int idx;
        switch (attr->attr) {
        case KVM_S390_VM_MEM_ENABLE_CMMA:
-               /* enable CMMA only for z10 and later (EDAT_1) */
-               ret = -EINVAL;
-               if (!MACHINE_IS_LPAR || !MACHINE_HAS_EDAT1)
+               ret = -ENXIO;
+               if (!sclp.has_cmma)
                        break;
 
                ret = -EBUSY;
                VM_EVENT(kvm, 3, "%s", "ENABLE: CMMA support");
                mutex_lock(&kvm->lock);
-               if (atomic_read(&kvm->online_vcpus) == 0) {
+               if (!kvm->created_vcpus) {
                        kvm->arch.use_cmma = 1;
                        ret = 0;
                }
                mutex_unlock(&kvm->lock);
                break;
        case KVM_S390_VM_MEM_CLR_CMMA:
+               ret = -ENXIO;
+               if (!sclp.has_cmma)
+                       break;
                ret = -EINVAL;
                if (!kvm->arch.use_cmma)
                        break;
@@ -461,20 +604,20 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
                if (!new_limit)
                        return -EINVAL;
 
-               /* gmap_alloc takes last usable address */
+               /* gmap_create takes last usable address */
                if (new_limit != KVM_S390_NO_MEM_LIMIT)
                        new_limit -= 1;
 
                ret = -EBUSY;
                mutex_lock(&kvm->lock);
-               if (atomic_read(&kvm->online_vcpus) == 0) {
-                       /* gmap_alloc will round the limit up */
-                       struct gmap *new = gmap_alloc(current->mm, new_limit);
+               if (!kvm->created_vcpus) {
+                       /* gmap_create will round the limit up */
+                       struct gmap *new = gmap_create(current->mm, new_limit);
 
                        if (!new) {
                                ret = -ENOMEM;
                        } else {
-                               gmap_free(kvm->arch.gmap);
+                               gmap_remove(kvm->arch.gmap);
                                new->private = kvm;
                                kvm->arch.gmap = new;
                                ret = 0;
@@ -644,7 +787,7 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
        int ret = 0;
 
        mutex_lock(&kvm->lock);
-       if (atomic_read(&kvm->online_vcpus)) {
+       if (kvm->created_vcpus) {
                ret = -EBUSY;
                goto out;
        }
@@ -676,6 +819,39 @@ out:
        return ret;
 }
 
+static int kvm_s390_set_processor_feat(struct kvm *kvm,
+                                      struct kvm_device_attr *attr)
+{
+       struct kvm_s390_vm_cpu_feat data;
+       int ret = -EBUSY;
+
+       if (copy_from_user(&data, (void __user *)attr->addr, sizeof(data)))
+               return -EFAULT;
+       if (!bitmap_subset((unsigned long *) data.feat,
+                          kvm_s390_available_cpu_feat,
+                          KVM_S390_VM_CPU_FEAT_NR_BITS))
+               return -EINVAL;
+
+       mutex_lock(&kvm->lock);
+       if (!atomic_read(&kvm->online_vcpus)) {
+               bitmap_copy(kvm->arch.cpu_feat, (unsigned long *) data.feat,
+                           KVM_S390_VM_CPU_FEAT_NR_BITS);
+               ret = 0;
+       }
+       mutex_unlock(&kvm->lock);
+       return ret;
+}
+
+static int kvm_s390_set_processor_subfunc(struct kvm *kvm,
+                                         struct kvm_device_attr *attr)
+{
+       /*
+        * Once supported by kernel + hw, we have to store the subfunctions
+        * in kvm->arch and remember that user space configured them.
+        */
+       return -ENXIO;
+}
+
 static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
 {
        int ret = -ENXIO;
@@ -684,6 +860,12 @@ static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
        case KVM_S390_VM_CPU_PROCESSOR:
                ret = kvm_s390_set_processor(kvm, attr);
                break;
+       case KVM_S390_VM_CPU_PROCESSOR_FEAT:
+               ret = kvm_s390_set_processor_feat(kvm, attr);
+               break;
+       case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
+               ret = kvm_s390_set_processor_subfunc(kvm, attr);
+               break;
        }
        return ret;
 }
@@ -732,6 +914,50 @@ out:
        return ret;
 }
 
+static int kvm_s390_get_processor_feat(struct kvm *kvm,
+                                      struct kvm_device_attr *attr)
+{
+       struct kvm_s390_vm_cpu_feat data;
+
+       bitmap_copy((unsigned long *) data.feat, kvm->arch.cpu_feat,
+                   KVM_S390_VM_CPU_FEAT_NR_BITS);
+       if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
+               return -EFAULT;
+       return 0;
+}
+
+static int kvm_s390_get_machine_feat(struct kvm *kvm,
+                                    struct kvm_device_attr *attr)
+{
+       struct kvm_s390_vm_cpu_feat data;
+
+       bitmap_copy((unsigned long *) data.feat,
+                   kvm_s390_available_cpu_feat,
+                   KVM_S390_VM_CPU_FEAT_NR_BITS);
+       if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
+               return -EFAULT;
+       return 0;
+}
+
+static int kvm_s390_get_processor_subfunc(struct kvm *kvm,
+                                         struct kvm_device_attr *attr)
+{
+       /*
+        * Once we can actually configure subfunctions (kernel + hw support),
+        * we have to check if they were already set by user space, if so copy
+        * them from kvm->arch.
+        */
+       return -ENXIO;
+}
+
+static int kvm_s390_get_machine_subfunc(struct kvm *kvm,
+                                       struct kvm_device_attr *attr)
+{
+       if (copy_to_user((void __user *)attr->addr, &kvm_s390_available_subfunc,
+           sizeof(struct kvm_s390_vm_cpu_subfunc)))
+               return -EFAULT;
+       return 0;
+}
 static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
 {
        int ret = -ENXIO;
@@ -743,6 +969,18 @@ static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
        case KVM_S390_VM_CPU_MACHINE:
                ret = kvm_s390_get_machine(kvm, attr);
                break;
+       case KVM_S390_VM_CPU_PROCESSOR_FEAT:
+               ret = kvm_s390_get_processor_feat(kvm, attr);
+               break;
+       case KVM_S390_VM_CPU_MACHINE_FEAT:
+               ret = kvm_s390_get_machine_feat(kvm, attr);
+               break;
+       case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
+               ret = kvm_s390_get_processor_subfunc(kvm, attr);
+               break;
+       case KVM_S390_VM_CPU_MACHINE_SUBFUNC:
+               ret = kvm_s390_get_machine_subfunc(kvm, attr);
+               break;
        }
        return ret;
 }
@@ -803,6 +1041,8 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
                switch (attr->attr) {
                case KVM_S390_VM_MEM_ENABLE_CMMA:
                case KVM_S390_VM_MEM_CLR_CMMA:
+                       ret = sclp.has_cmma ? 0 : -ENXIO;
+                       break;
                case KVM_S390_VM_MEM_LIMIT_SIZE:
                        ret = 0;
                        break;
@@ -826,8 +1066,13 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
                switch (attr->attr) {
                case KVM_S390_VM_CPU_PROCESSOR:
                case KVM_S390_VM_CPU_MACHINE:
+               case KVM_S390_VM_CPU_PROCESSOR_FEAT:
+               case KVM_S390_VM_CPU_MACHINE_FEAT:
+               case KVM_S390_VM_CPU_MACHINE_SUBFUNC:
                        ret = 0;
                        break;
+               /* configuring subfunctions is not supported yet */
+               case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
                default:
                        ret = -ENXIO;
                        break;
@@ -858,7 +1103,6 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
 {
        uint8_t *keys;
        uint64_t hva;
-       unsigned long curkey;
        int i, r = 0;
 
        if (args->flags != 0)
@@ -879,26 +1123,27 @@ static long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
        if (!keys)
                return -ENOMEM;
 
+       down_read(&current->mm->mmap_sem);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
                        r = -EFAULT;
-                       goto out;
+                       break;
                }
 
-               curkey = get_guest_storage_key(current->mm, hva);
-               if (IS_ERR_VALUE(curkey)) {
-                       r = curkey;
-                       goto out;
-               }
-               keys[i] = curkey;
+               r = get_guest_storage_key(current->mm, hva, &keys[i]);
+               if (r)
+                       break;
+       }
+       up_read(&current->mm->mmap_sem);
+
+       if (!r) {
+               r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
+                                sizeof(uint8_t) * args->count);
+               if (r)
+                       r = -EFAULT;
        }
 
-       r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
-                        sizeof(uint8_t) * args->count);
-       if (r)
-               r = -EFAULT;
-out:
        kvfree(keys);
        return r;
 }
@@ -935,24 +1180,25 @@ static long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
        if (r)
                goto out;
 
+       down_read(&current->mm->mmap_sem);
        for (i = 0; i < args->count; i++) {
                hva = gfn_to_hva(kvm, args->start_gfn + i);
                if (kvm_is_error_hva(hva)) {
                        r = -EFAULT;
-                       goto out;
+                       break;
                }
 
                /* Lowest order bit is reserved */
                if (keys[i] & 0x01) {
                        r = -EINVAL;
-                       goto out;
+                       break;
                }
 
-               r = set_guest_storage_key(current->mm, hva,
-                                         (unsigned long)keys[i], 0);
+               r = set_guest_storage_key(current->mm, hva, keys[i], 0);
                if (r)
-                       goto out;
+                       break;
        }
+       up_read(&current->mm->mmap_sem);
 out:
        kvfree(keys);
        return r;
@@ -1129,6 +1375,7 @@ static void sca_dispose(struct kvm *kvm)
 
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
+       gfp_t alloc_flags = GFP_KERNEL;
        int i, rc;
        char debug_name[16];
        static unsigned long sca_offset;
@@ -1150,9 +1397,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        rc = -ENOMEM;
 
+       ratelimit_state_init(&kvm->arch.sthyi_limit, 5 * HZ, 500);
+
        kvm->arch.use_esca = 0; /* start with basic SCA */
+       if (!sclp.has_64bscao)
+               alloc_flags |= GFP_DMA;
        rwlock_init(&kvm->arch.sca_lock);
-       kvm->arch.sca = (struct bsca_block *) get_zeroed_page(GFP_KERNEL);
+       kvm->arch.sca = (struct bsca_block *) get_zeroed_page(alloc_flags);
        if (!kvm->arch.sca)
                goto out_err;
        spin_lock(&kvm_lock);
@@ -1189,6 +1440,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        memcpy(kvm->arch.model.fac_list, kvm->arch.model.fac_mask,
               S390_ARCH_FAC_LIST_SIZE_BYTE);
 
+       set_kvm_facility(kvm->arch.model.fac_mask, 74);
+       set_kvm_facility(kvm->arch.model.fac_list, 74);
+
        kvm->arch.model.cpuid = kvm_s390_get_initial_cpuid();
        kvm->arch.model.ibc = sclp.ibc & 0x0fff;
 
@@ -1212,7 +1466,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
                else
                        kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE,
                                                    sclp.hamax + 1);
-               kvm->arch.gmap = gmap_alloc(current->mm, kvm->arch.mem_limit - 1);
+               kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1);
                if (!kvm->arch.gmap)
                        goto out_err;
                kvm->arch.gmap->private = kvm;
@@ -1224,6 +1478,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
        kvm->arch.epoch = 0;
 
        spin_lock_init(&kvm->arch.start_stop_lock);
+       kvm_s390_vsie_init(kvm);
        KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid);
 
        return 0;
@@ -1245,7 +1500,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
                sca_del_vcpu(vcpu);
 
        if (kvm_is_ucontrol(vcpu->kvm))
-               gmap_free(vcpu->arch.gmap);
+               gmap_remove(vcpu->arch.gmap);
 
        if (vcpu->kvm->arch.use_cmma)
                kvm_s390_vcpu_unsetup_cmma(vcpu);
@@ -1278,16 +1533,17 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        debug_unregister(kvm->arch.dbf);
        free_page((unsigned long)kvm->arch.sie_page2);
        if (!kvm_is_ucontrol(kvm))
-               gmap_free(kvm->arch.gmap);
+               gmap_remove(kvm->arch.gmap);
        kvm_s390_destroy_adapters(kvm);
        kvm_s390_clear_float_irqs(kvm);
+       kvm_s390_vsie_destroy(kvm);
        KVM_EVENT(3, "vm 0x%pK destroyed", kvm);
 }
 
 /* Section: vcpu related */
 static int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.gmap = gmap_alloc(current->mm, -1UL);
+       vcpu->arch.gmap = gmap_create(current->mm, -1UL);
        if (!vcpu->arch.gmap)
                return -ENOMEM;
        vcpu->arch.gmap->private = vcpu->kvm;
@@ -1396,7 +1652,7 @@ static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
 
        if (id < KVM_S390_BSCA_CPU_SLOTS)
                return true;
-       if (!sclp.has_esca)
+       if (!sclp.has_esca || !sclp.has_64bscao)
                return false;
 
        mutex_lock(&kvm->lock);
@@ -1537,7 +1793,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
        save_access_regs(vcpu->arch.host_acrs);
        restore_access_regs(vcpu->run->s.regs.acrs);
-       gmap_enable(vcpu->arch.gmap);
+       gmap_enable(vcpu->arch.enabled_gmap);
        atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
        if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu))
                __start_cpu_timer_accounting(vcpu);
@@ -1550,7 +1806,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu))
                __stop_cpu_timer_accounting(vcpu);
        atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
-       gmap_disable(vcpu->arch.gmap);
+       vcpu->arch.enabled_gmap = gmap_get_enabled();
+       gmap_disable(vcpu->arch.enabled_gmap);
 
        /* Save guest register state */
        save_fpu_regs();
@@ -1599,7 +1856,10 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
                vcpu->arch.gmap = vcpu->kvm->arch.gmap;
                sca_add_vcpu(vcpu);
        }
-
+       if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0)
+               vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
+       /* make vcpu_load load the right gmap on the first trigger */
+       vcpu->arch.enabled_gmap = vcpu->arch.gmap;
 }
 
 static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
@@ -1658,15 +1918,21 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 
        kvm_s390_vcpu_setup_model(vcpu);
 
-       vcpu->arch.sie_block->ecb = 0x02;
+       /* pgste_set_pte has special handling for !MACHINE_HAS_ESOP */
+       if (MACHINE_HAS_ESOP)
+               vcpu->arch.sie_block->ecb |= 0x02;
        if (test_kvm_facility(vcpu->kvm, 9))
                vcpu->arch.sie_block->ecb |= 0x04;
-       if (test_kvm_facility(vcpu->kvm, 50) && test_kvm_facility(vcpu->kvm, 73))
+       if (test_kvm_facility(vcpu->kvm, 73))
                vcpu->arch.sie_block->ecb |= 0x10;
 
-       if (test_kvm_facility(vcpu->kvm, 8))
+       if (test_kvm_facility(vcpu->kvm, 8) && sclp.has_pfmfi)
                vcpu->arch.sie_block->ecb2 |= 0x08;
-       vcpu->arch.sie_block->eca   = 0xC1002000U;
+       vcpu->arch.sie_block->eca = 0x1002000U;
+       if (sclp.has_cei)
+               vcpu->arch.sie_block->eca |= 0x80000000U;
+       if (sclp.has_ib)
+               vcpu->arch.sie_block->eca |= 0x40000000U;
        if (sclp.has_siif)
                vcpu->arch.sie_block->eca |= 1;
        if (sclp.has_sigpif)
@@ -1716,6 +1982,10 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        vcpu->arch.sie_block = &sie_page->sie_block;
        vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
 
+       /* the real guest size will always be smaller than msl */
+       vcpu->arch.sie_block->mso = 0;
+       vcpu->arch.sie_block->msl = sclp.hamax;
+
        vcpu->arch.sie_block->icpua = id;
        spin_lock_init(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
@@ -1784,16 +2054,25 @@ void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu)
        kvm_s390_vcpu_request(vcpu);
 }
 
-static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
+                             unsigned long end)
 {
-       int i;
        struct kvm *kvm = gmap->private;
        struct kvm_vcpu *vcpu;
+       unsigned long prefix;
+       int i;
 
+       if (gmap_is_shadow(gmap))
+               return;
+       if (start >= 1UL << 31)
+               /* We are only interested in prefix pages */
+               return;
        kvm_for_each_vcpu(i, vcpu, kvm) {
                /* match against both prefix pages */
-               if (kvm_s390_get_prefix(vcpu) == (address & ~0x1000UL)) {
-                       VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
+               prefix = kvm_s390_get_prefix(vcpu);
+               if (prefix <= end && start <= prefix + 2*PAGE_SIZE - 1) {
+                       VCPU_EVENT(vcpu, 2, "gmap notifier for %lx-%lx",
+                                  start, end);
                        kvm_s390_sync_request(KVM_REQ_MMU_RELOAD, vcpu);
                }
        }
@@ -2002,6 +2281,8 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 
        if (dbg->control & ~VALID_GUESTDBG_FLAGS)
                return -EINVAL;
+       if (!sclp.has_gpere)
+               return -EINVAL;
 
        if (dbg->control & KVM_GUESTDBG_ENABLE) {
                vcpu->guest_debug = dbg->control;
@@ -2070,16 +2351,16 @@ retry:
                return 0;
        /*
         * We use MMU_RELOAD just to re-arm the ipte notifier for the
-        * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
+        * guest prefix page. gmap_mprotect_notify will wait on the ptl lock.
         * This ensures that the ipte instruction for this request has
         * already finished. We might race against a second unmapper that
         * wants to set the blocking bit. Lets just retry the request loop.
         */
        if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) {
                int rc;
-               rc = gmap_ipte_notify(vcpu->arch.gmap,
-                                     kvm_s390_get_prefix(vcpu),
-                                     PAGE_SIZE * 2);
+               rc = gmap_mprotect_notify(vcpu->arch.gmap,
+                                         kvm_s390_get_prefix(vcpu),
+                                         PAGE_SIZE * 2, PROT_WRITE);
                if (rc)
                        return rc;
                goto retry;
@@ -2108,6 +2389,11 @@ retry:
                goto retry;
        }
 
+       if (kvm_check_request(KVM_REQ_ICPT_OPEREXC, vcpu)) {
+               vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
+               goto retry;
+       }
+
        /* nothing to do, just clear the request */
        clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
 
@@ -2362,14 +2648,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
                 * guest_enter and guest_exit should be no uaccess.
                 */
                local_irq_disable();
-               __kvm_guest_enter();
+               guest_enter_irqoff();
                __disable_cpu_timer_accounting(vcpu);
                local_irq_enable();
                exit_reason = sie64a(vcpu->arch.sie_block,
                                     vcpu->run->s.regs.gprs);
                local_irq_disable();
                __enable_cpu_timer_accounting(vcpu);
-               __kvm_guest_exit();
+               guest_exit_irqoff();
                local_irq_enable();
                vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
 
@@ -2598,6 +2884,8 @@ static void __disable_ibs_on_all_vcpus(struct kvm *kvm)
 
 static void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu)
 {
+       if (!sclp.has_ibs)
+               return;
        kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu);
        kvm_s390_sync_request(KVM_REQ_ENABLE_IBS, vcpu);
 }
index 8621ab0..b843286 100644 (file)
@@ -56,7 +56,7 @@ static inline int is_vcpu_stopped(struct kvm_vcpu *vcpu)
 
 static inline int is_vcpu_idle(struct kvm_vcpu *vcpu)
 {
-       return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_WAIT;
+       return test_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
 }
 
 static inline int kvm_is_ucontrol(struct kvm *kvm)
@@ -175,6 +175,12 @@ static inline int set_kvm_facility(u64 *fac_list, unsigned long nr)
        return 0;
 }
 
+static inline int test_kvm_cpu_feat(struct kvm *kvm, unsigned long nr)
+{
+       WARN_ON_ONCE(nr >= KVM_S390_VM_CPU_FEAT_NR_BITS);
+       return test_bit_inv(nr, kvm->arch.cpu_feat);
+}
+
 /* are cpu states controlled by user space */
 static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm)
 {
@@ -232,6 +238,8 @@ static inline void kvm_s390_forward_psw(struct kvm_vcpu *vcpu, int ilen)
 }
 static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
 {
+       /* don't inject PER events if we re-execute the instruction */
+       vcpu->arch.sie_block->icptstatus &= ~0x02;
        kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu));
 }
 
@@ -246,10 +254,21 @@ int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_eb(struct kvm_vcpu *vcpu);
 
+/* implemented in vsie.c */
+int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu);
+void kvm_s390_vsie_kick(struct kvm_vcpu *vcpu);
+void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start,
+                                unsigned long end);
+void kvm_s390_vsie_init(struct kvm *kvm);
+void kvm_s390_vsie_destroy(struct kvm *kvm);
+
 /* implemented in sigp.c */
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
 
+/* implemented in sthyi.c */
+int handle_sthyi(struct kvm_vcpu *vcpu);
+
 /* implemented in kvm-s390.c */
 void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
 long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
@@ -360,6 +379,7 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu,
                            struct kvm_guest_debug *dbg);
 void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu);
 void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_per_ifetch_icpt(struct kvm_vcpu *vcpu);
 void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu);
 
 /* support for Basic/Extended SCA handling */
index 95916fa..4616038 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/ptrace.h>
 #include <asm/compat.h>
+#include <asm/sclp.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
 #include "trace.h"
@@ -152,30 +153,166 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
 static int __skey_check_enable(struct kvm_vcpu *vcpu)
 {
        int rc = 0;
+
+       trace_kvm_s390_skey_related_inst(vcpu);
        if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)))
                return rc;
 
        rc = s390_enable_skey();
-       VCPU_EVENT(vcpu, 3, "%s", "enabling storage keys for guest");
-       trace_kvm_s390_skey_related_inst(vcpu);
-       vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
+       VCPU_EVENT(vcpu, 3, "enabling storage keys for guest: %d", rc);
+       if (!rc)
+               vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
        return rc;
 }
 
-
-static int handle_skey(struct kvm_vcpu *vcpu)
+static int try_handle_skey(struct kvm_vcpu *vcpu)
 {
-       int rc = __skey_check_enable(vcpu);
+       int rc;
 
+       vcpu->stat.instruction_storage_key++;
+       rc = __skey_check_enable(vcpu);
        if (rc)
                return rc;
-       vcpu->stat.instruction_storage_key++;
-
+       if (sclp.has_skey) {
+               /* with storage-key facility, SIE interprets it for us */
+               kvm_s390_retry_instr(vcpu);
+               VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
+               return -EAGAIN;
+       }
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+       return 0;
+}
 
-       kvm_s390_retry_instr(vcpu);
-       VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
+static int handle_iske(struct kvm_vcpu *vcpu)
+{
+       unsigned long addr;
+       unsigned char key;
+       int reg1, reg2;
+       int rc;
+
+       rc = try_handle_skey(vcpu);
+       if (rc)
+               return rc != -EAGAIN ? rc : 0;
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+
+       addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
+       addr = kvm_s390_logical_to_effective(vcpu, addr);
+       addr = kvm_s390_real_to_abs(vcpu, addr);
+       addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr));
+       if (kvm_is_error_hva(addr))
+               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+       down_read(&current->mm->mmap_sem);
+       rc = get_guest_storage_key(current->mm, addr, &key);
+       up_read(&current->mm->mmap_sem);
+       if (rc)
+               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+       vcpu->run->s.regs.gprs[reg1] &= ~0xff;
+       vcpu->run->s.regs.gprs[reg1] |= key;
+       return 0;
+}
+
+static int handle_rrbe(struct kvm_vcpu *vcpu)
+{
+       unsigned long addr;
+       int reg1, reg2;
+       int rc;
+
+       rc = try_handle_skey(vcpu);
+       if (rc)
+               return rc != -EAGAIN ? rc : 0;
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+
+       addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
+       addr = kvm_s390_logical_to_effective(vcpu, addr);
+       addr = kvm_s390_real_to_abs(vcpu, addr);
+       addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr));
+       if (kvm_is_error_hva(addr))
+               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+       down_read(&current->mm->mmap_sem);
+       rc = reset_guest_reference_bit(current->mm, addr);
+       up_read(&current->mm->mmap_sem);
+       if (rc < 0)
+               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+       kvm_s390_set_psw_cc(vcpu, rc);
+       return 0;
+}
+
+#define SSKE_NQ 0x8
+#define SSKE_MR 0x4
+#define SSKE_MC 0x2
+#define SSKE_MB 0x1
+static int handle_sske(struct kvm_vcpu *vcpu)
+{
+       unsigned char m3 = vcpu->arch.sie_block->ipb >> 28;
+       unsigned long start, end;
+       unsigned char key, oldkey;
+       int reg1, reg2;
+       int rc;
+
+       rc = try_handle_skey(vcpu);
+       if (rc)
+               return rc != -EAGAIN ? rc : 0;
+
+       if (!test_kvm_facility(vcpu->kvm, 8))
+               m3 &= ~SSKE_MB;
+       if (!test_kvm_facility(vcpu->kvm, 10))
+               m3 &= ~(SSKE_MC | SSKE_MR);
+       if (!test_kvm_facility(vcpu->kvm, 14))
+               m3 &= ~SSKE_NQ;
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+
+       key = vcpu->run->s.regs.gprs[reg1] & 0xfe;
+       start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
+       start = kvm_s390_logical_to_effective(vcpu, start);
+       if (m3 & SSKE_MB) {
+               /* start already designates an absolute address */
+               end = (start + (1UL << 20)) & ~((1UL << 20) - 1);
+       } else {
+               start = kvm_s390_real_to_abs(vcpu, start);
+               end = start + PAGE_SIZE;
+       }
+
+       while (start != end) {
+               unsigned long addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
+
+               if (kvm_is_error_hva(addr))
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+               down_read(&current->mm->mmap_sem);
+               rc = cond_set_guest_storage_key(current->mm, addr, key, &oldkey,
+                                               m3 & SSKE_NQ, m3 & SSKE_MR,
+                                               m3 & SSKE_MC);
+               up_read(&current->mm->mmap_sem);
+               if (rc < 0)
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               start += PAGE_SIZE;
+       };
+
+       if (m3 & (SSKE_MC | SSKE_MR)) {
+               if (m3 & SSKE_MB) {
+                       /* skey in reg1 is unpredictable */
+                       kvm_s390_set_psw_cc(vcpu, 3);
+               } else {
+                       kvm_s390_set_psw_cc(vcpu, rc);
+                       vcpu->run->s.regs.gprs[reg1] &= ~0xff00UL;
+                       vcpu->run->s.regs.gprs[reg1] |= (u64) oldkey << 8;
+               }
+       }
+       if (m3 & SSKE_MB) {
+               if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_AMODE_64BIT)
+                       vcpu->run->s.regs.gprs[reg2] &= ~PAGE_MASK;
+               else
+                       vcpu->run->s.regs.gprs[reg2] &= ~0xfffff000UL;
+               end = kvm_s390_logical_to_effective(vcpu, end);
+               vcpu->run->s.regs.gprs[reg2] |= end;
+       }
        return 0;
 }
 
@@ -582,10 +719,11 @@ static const intercept_handler_t b2_handlers[256] = {
        [0x10] = handle_set_prefix,
        [0x11] = handle_store_prefix,
        [0x12] = handle_store_cpu_address,
+       [0x14] = kvm_s390_handle_vsie,
        [0x21] = handle_ipte_interlock,
-       [0x29] = handle_skey,
-       [0x2a] = handle_skey,
-       [0x2b] = handle_skey,
+       [0x29] = handle_iske,
+       [0x2a] = handle_rrbe,
+       [0x2b] = handle_sske,
        [0x2c] = handle_test_block,
        [0x30] = handle_io_inst,
        [0x31] = handle_io_inst,
@@ -654,8 +792,10 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
 
 static int handle_pfmf(struct kvm_vcpu *vcpu)
 {
+       bool mr = false, mc = false, nq;
        int reg1, reg2;
        unsigned long start, end;
+       unsigned char key;
 
        vcpu->stat.instruction_pfmf++;
 
@@ -675,15 +815,27 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
            !test_kvm_facility(vcpu->kvm, 14))
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
-       /* No support for conditional-SSKE */
-       if (vcpu->run->s.regs.gprs[reg1] & (PFMF_MR | PFMF_MC))
-               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+       /* Only provide conditional-SSKE support if enabled for the guest */
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK &&
+           test_kvm_facility(vcpu->kvm, 10)) {
+               mr = vcpu->run->s.regs.gprs[reg1] & PFMF_MR;
+               mc = vcpu->run->s.regs.gprs[reg1] & PFMF_MC;
+       }
 
+       nq = vcpu->run->s.regs.gprs[reg1] & PFMF_NQ;
+       key = vcpu->run->s.regs.gprs[reg1] & PFMF_KEY;
        start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
        start = kvm_s390_logical_to_effective(vcpu, start);
 
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
+               if (kvm_s390_check_low_addr_prot_real(vcpu, start))
+                       return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
+       }
+
        switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
        case 0x00000000:
+               /* only 4k frames specify a real address */
+               start = kvm_s390_real_to_abs(vcpu, start);
                end = (start + (1UL << 12)) & ~((1UL << 12) - 1);
                break;
        case 0x00001000:
@@ -701,20 +853,11 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
        }
 
-       if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
-               if (kvm_s390_check_low_addr_prot_real(vcpu, start))
-                       return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
-       }
-
-       while (start < end) {
-               unsigned long useraddr, abs_addr;
+       while (start != end) {
+               unsigned long useraddr;
 
                /* Translate guest address to host address */
-               if ((vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) == 0)
-                       abs_addr = kvm_s390_real_to_abs(vcpu, start);
-               else
-                       abs_addr = start;
-               useraddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(abs_addr));
+               useraddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
                if (kvm_is_error_hva(useraddr))
                        return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 
@@ -728,16 +871,25 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
 
                        if (rc)
                                return rc;
-                       if (set_guest_storage_key(current->mm, useraddr,
-                                       vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
-                                       vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
+                       down_read(&current->mm->mmap_sem);
+                       rc = cond_set_guest_storage_key(current->mm, useraddr,
+                                                       key, NULL, nq, mr, mc);
+                       up_read(&current->mm->mmap_sem);
+                       if (rc < 0)
                                return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
                }
 
                start += PAGE_SIZE;
        }
-       if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC)
-               vcpu->run->s.regs.gprs[reg2] = end;
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
+               if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_AMODE_64BIT) {
+                       vcpu->run->s.regs.gprs[reg2] = end;
+               } else {
+                       vcpu->run->s.regs.gprs[reg2] &= ~0xffffffffUL;
+                       end = kvm_s390_logical_to_effective(vcpu, end);
+                       vcpu->run->s.regs.gprs[reg2] |= end;
+               }
+       }
        return 0;
 }
 
@@ -1033,7 +1185,15 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static int handle_ptff(struct kvm_vcpu *vcpu)
+{
+       /* we don't emulate any control instructions yet */
+       kvm_s390_set_psw_cc(vcpu, 3);
+       return 0;
+}
+
 static const intercept_handler_t x01_handlers[256] = {
+       [0x04] = handle_ptff,
        [0x07] = handle_sckpf,
 };
 
index 28ea0ca..1a252f5 100644 (file)
@@ -77,18 +77,18 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
        const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
        u16 p_asn, s_asn;
        psw_t *psw;
-       u32 flags;
+       bool idle;
 
-       flags = atomic_read(&dst_vcpu->arch.sie_block->cpuflags);
+       idle = is_vcpu_idle(vcpu);
        psw = &dst_vcpu->arch.sie_block->gpsw;
        p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff;  /* Primary ASN */
        s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff;  /* Secondary ASN */
 
        /* Inject the emergency signal? */
-       if (!(flags & CPUSTAT_STOPPED)
+       if (!is_vcpu_stopped(vcpu)
            || (psw->mask & psw_int_mask) != psw_int_mask
-           || ((flags & CPUSTAT_WAIT) && psw->addr != 0)
-           || (!(flags & CPUSTAT_WAIT) && (asn == p_asn || asn == s_asn))) {
+           || (idle && psw->addr != 0)
+           || (!idle && (asn == p_asn || asn == s_asn))) {
                return __inject_sigp_emergency(vcpu, dst_vcpu);
        } else {
                *reg &= 0xffffffff00000000UL;
diff --git a/arch/s390/kvm/sthyi.c b/arch/s390/kvm/sthyi.c
new file mode 100644 (file)
index 0000000..bd98b7d
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * store hypervisor information instruction emulation functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Copyright IBM Corp. 2016
+ * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com>
+ */
+#include <linux/kvm_host.h>
+#include <linux/errno.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/ratelimit.h>
+
+#include <asm/kvm_host.h>
+#include <asm/asm-offsets.h>
+#include <asm/sclp.h>
+#include <asm/diag.h>
+#include <asm/sysinfo.h>
+#include <asm/ebcdic.h>
+
+#include "kvm-s390.h"
+#include "gaccess.h"
+#include "trace.h"
+
+#define DED_WEIGHT 0xffff
+/*
+ * CP and IFL as EBCDIC strings, SP/0x40 determines the end of string
+ * as they are justified with spaces.
+ */
+#define CP  0xc3d7404040404040UL
+#define IFL 0xc9c6d34040404040UL
+
+enum hdr_flags {
+       HDR_NOT_LPAR   = 0x10,
+       HDR_STACK_INCM = 0x20,
+       HDR_STSI_UNAV  = 0x40,
+       HDR_PERF_UNAV  = 0x80,
+};
+
+enum mac_validity {
+       MAC_NAME_VLD = 0x20,
+       MAC_ID_VLD   = 0x40,
+       MAC_CNT_VLD  = 0x80,
+};
+
+enum par_flag {
+       PAR_MT_EN = 0x80,
+};
+
+enum par_validity {
+       PAR_GRP_VLD  = 0x08,
+       PAR_ID_VLD   = 0x10,
+       PAR_ABS_VLD  = 0x20,
+       PAR_WGHT_VLD = 0x40,
+       PAR_PCNT_VLD  = 0x80,
+};
+
+struct hdr_sctn {
+       u8 infhflg1;
+       u8 infhflg2; /* reserved */
+       u8 infhval1; /* reserved */
+       u8 infhval2; /* reserved */
+       u8 reserved[3];
+       u8 infhygct;
+       u16 infhtotl;
+       u16 infhdln;
+       u16 infmoff;
+       u16 infmlen;
+       u16 infpoff;
+       u16 infplen;
+       u16 infhoff1;
+       u16 infhlen1;
+       u16 infgoff1;
+       u16 infglen1;
+       u16 infhoff2;
+       u16 infhlen2;
+       u16 infgoff2;
+       u16 infglen2;
+       u16 infhoff3;
+       u16 infhlen3;
+       u16 infgoff3;
+       u16 infglen3;
+       u8 reserved2[4];
+} __packed;
+
+struct mac_sctn {
+       u8 infmflg1; /* reserved */
+       u8 infmflg2; /* reserved */
+       u8 infmval1;
+       u8 infmval2; /* reserved */
+       u16 infmscps;
+       u16 infmdcps;
+       u16 infmsifl;
+       u16 infmdifl;
+       char infmname[8];
+       char infmtype[4];
+       char infmmanu[16];
+       char infmseq[16];
+       char infmpman[4];
+       u8 reserved[4];
+} __packed;
+
+struct par_sctn {
+       u8 infpflg1;
+       u8 infpflg2; /* reserved */
+       u8 infpval1;
+       u8 infpval2; /* reserved */
+       u16 infppnum;
+       u16 infpscps;
+       u16 infpdcps;
+       u16 infpsifl;
+       u16 infpdifl;
+       u16 reserved;
+       char infppnam[8];
+       u32 infpwbcp;
+       u32 infpabcp;
+       u32 infpwbif;
+       u32 infpabif;
+       char infplgnm[8];
+       u32 infplgcp;
+       u32 infplgif;
+} __packed;
+
+struct sthyi_sctns {
+       struct hdr_sctn hdr;
+       struct mac_sctn mac;
+       struct par_sctn par;
+} __packed;
+
+struct cpu_inf {
+       u64 lpar_cap;
+       u64 lpar_grp_cap;
+       u64 lpar_weight;
+       u64 all_weight;
+       int cpu_num_ded;
+       int cpu_num_shd;
+};
+
+struct lpar_cpu_inf {
+       struct cpu_inf cp;
+       struct cpu_inf ifl;
+};
+
+static inline u64 cpu_id(u8 ctidx, void *diag224_buf)
+{
+       return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN));
+}
+
+/*
+ * Scales the cpu capping from the lpar range to the one expected in
+ * sthyi data.
+ *
+ * diag204 reports a cap in hundredths of processor units.
+ * z/VM's range for one core is 0 - 0x10000.
+ */
+static u32 scale_cap(u32 in)
+{
+       return (0x10000 * in) / 100;
+}
+
+static void fill_hdr(struct sthyi_sctns *sctns)
+{
+       sctns->hdr.infhdln = sizeof(sctns->hdr);
+       sctns->hdr.infmoff = sizeof(sctns->hdr);
+       sctns->hdr.infmlen = sizeof(sctns->mac);
+       sctns->hdr.infplen = sizeof(sctns->par);
+       sctns->hdr.infpoff = sctns->hdr.infhdln + sctns->hdr.infmlen;
+       sctns->hdr.infhtotl = sctns->hdr.infpoff + sctns->hdr.infplen;
+}
+
+static void fill_stsi_mac(struct sthyi_sctns *sctns,
+                         struct sysinfo_1_1_1 *sysinfo)
+{
+       if (stsi(sysinfo, 1, 1, 1))
+               return;
+
+       sclp_ocf_cpc_name_copy(sctns->mac.infmname);
+
+       memcpy(sctns->mac.infmtype, sysinfo->type, sizeof(sctns->mac.infmtype));
+       memcpy(sctns->mac.infmmanu, sysinfo->manufacturer, sizeof(sctns->mac.infmmanu));
+       memcpy(sctns->mac.infmpman, sysinfo->plant, sizeof(sctns->mac.infmpman));
+       memcpy(sctns->mac.infmseq, sysinfo->sequence, sizeof(sctns->mac.infmseq));
+
+       sctns->mac.infmval1 |= MAC_ID_VLD | MAC_NAME_VLD;
+}
+
+static void fill_stsi_par(struct sthyi_sctns *sctns,
+                         struct sysinfo_2_2_2 *sysinfo)
+{
+       if (stsi(sysinfo, 2, 2, 2))
+               return;
+
+       sctns->par.infppnum = sysinfo->lpar_number;
+       memcpy(sctns->par.infppnam, sysinfo->name, sizeof(sctns->par.infppnam));
+
+       sctns->par.infpval1 |= PAR_ID_VLD;
+}
+
+static void fill_stsi(struct sthyi_sctns *sctns)
+{
+       void *sysinfo;
+
+       /* Errors are handled through the validity bits in the response. */
+       sysinfo = (void *)__get_free_page(GFP_KERNEL);
+       if (!sysinfo)
+               return;
+
+       fill_stsi_mac(sctns, sysinfo);
+       fill_stsi_par(sctns, sysinfo);
+
+       free_pages((unsigned long)sysinfo, 0);
+}
+
+static void fill_diag_mac(struct sthyi_sctns *sctns,
+                         struct diag204_x_phys_block *block,
+                         void *diag224_buf)
+{
+       int i;
+
+       for (i = 0; i < block->hdr.cpus; i++) {
+               switch (cpu_id(block->cpus[i].ctidx, diag224_buf)) {
+               case CP:
+                       if (block->cpus[i].weight == DED_WEIGHT)
+                               sctns->mac.infmdcps++;
+                       else
+                               sctns->mac.infmscps++;
+                       break;
+               case IFL:
+                       if (block->cpus[i].weight == DED_WEIGHT)
+                               sctns->mac.infmdifl++;
+                       else
+                               sctns->mac.infmsifl++;
+                       break;
+               }
+       }
+       sctns->mac.infmval1 |= MAC_CNT_VLD;
+}
+
+/* Returns a pointer to the the next partition block. */
+static struct diag204_x_part_block *lpar_cpu_inf(struct lpar_cpu_inf *part_inf,
+                                                bool this_lpar,
+                                                void *diag224_buf,
+                                                struct diag204_x_part_block *block)
+{
+       int i, capped = 0, weight_cp = 0, weight_ifl = 0;
+       struct cpu_inf *cpu_inf;
+
+       for (i = 0; i < block->hdr.rcpus; i++) {
+               if (!(block->cpus[i].cflag & DIAG204_CPU_ONLINE))
+                       continue;
+
+               switch (cpu_id(block->cpus[i].ctidx, diag224_buf)) {
+               case CP:
+                       cpu_inf = &part_inf->cp;
+                       if (block->cpus[i].cur_weight < DED_WEIGHT)
+                               weight_cp |= block->cpus[i].cur_weight;
+                       break;
+               case IFL:
+                       cpu_inf = &part_inf->ifl;
+                       if (block->cpus[i].cur_weight < DED_WEIGHT)
+                               weight_ifl |= block->cpus[i].cur_weight;
+                       break;
+               default:
+                       continue;
+               }
+
+               if (!this_lpar)
+                       continue;
+
+               capped |= block->cpus[i].cflag & DIAG204_CPU_CAPPED;
+               cpu_inf->lpar_cap |= block->cpus[i].cpu_type_cap;
+               cpu_inf->lpar_grp_cap |= block->cpus[i].group_cpu_type_cap;
+
+               if (block->cpus[i].weight == DED_WEIGHT)
+                       cpu_inf->cpu_num_ded += 1;
+               else
+                       cpu_inf->cpu_num_shd += 1;
+       }
+
+       if (this_lpar && capped) {
+               part_inf->cp.lpar_weight = weight_cp;
+               part_inf->ifl.lpar_weight = weight_ifl;
+       }
+       part_inf->cp.all_weight += weight_cp;
+       part_inf->ifl.all_weight += weight_ifl;
+       return (struct diag204_x_part_block *)&block->cpus[i];
+}
+
+static void fill_diag(struct sthyi_sctns *sctns)
+{
+       int i, r, pages;
+       bool this_lpar;
+       void *diag204_buf;
+       void *diag224_buf = NULL;
+       struct diag204_x_info_blk_hdr *ti_hdr;
+       struct diag204_x_part_block *part_block;
+       struct diag204_x_phys_block *phys_block;
+       struct lpar_cpu_inf lpar_inf = {};
+
+       /* Errors are handled through the validity bits in the response. */
+       pages = diag204((unsigned long)DIAG204_SUBC_RSI |
+                       (unsigned long)DIAG204_INFO_EXT, 0, NULL);
+       if (pages <= 0)
+               return;
+
+       diag204_buf = vmalloc(PAGE_SIZE * pages);
+       if (!diag204_buf)
+               return;
+
+       r = diag204((unsigned long)DIAG204_SUBC_STIB7 |
+                   (unsigned long)DIAG204_INFO_EXT, pages, diag204_buf);
+       if (r < 0)
+               goto out;
+
+       diag224_buf = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+       if (!diag224_buf || diag224(diag224_buf))
+               goto out;
+
+       ti_hdr = diag204_buf;
+       part_block = diag204_buf + sizeof(*ti_hdr);
+
+       for (i = 0; i < ti_hdr->npar; i++) {
+               /*
+                * For the calling lpar we also need to get the cpu
+                * caps and weights. The time information block header
+                * specifies the offset to the partition block of the
+                * caller lpar, so we know when we process its data.
+                */
+               this_lpar = (void *)part_block - diag204_buf == ti_hdr->this_part;
+               part_block = lpar_cpu_inf(&lpar_inf, this_lpar, diag224_buf,
+                                         part_block);
+       }
+
+       phys_block = (struct diag204_x_phys_block *)part_block;
+       part_block = diag204_buf + ti_hdr->this_part;
+       if (part_block->hdr.mtid)
+               sctns->par.infpflg1 = PAR_MT_EN;
+
+       sctns->par.infpval1 |= PAR_GRP_VLD;
+       sctns->par.infplgcp = scale_cap(lpar_inf.cp.lpar_grp_cap);
+       sctns->par.infplgif = scale_cap(lpar_inf.ifl.lpar_grp_cap);
+       memcpy(sctns->par.infplgnm, part_block->hdr.hardware_group_name,
+              sizeof(sctns->par.infplgnm));
+
+       sctns->par.infpscps = lpar_inf.cp.cpu_num_shd;
+       sctns->par.infpdcps = lpar_inf.cp.cpu_num_ded;
+       sctns->par.infpsifl = lpar_inf.ifl.cpu_num_shd;
+       sctns->par.infpdifl = lpar_inf.ifl.cpu_num_ded;
+       sctns->par.infpval1 |= PAR_PCNT_VLD;
+
+       sctns->par.infpabcp = scale_cap(lpar_inf.cp.lpar_cap);
+       sctns->par.infpabif = scale_cap(lpar_inf.ifl.lpar_cap);
+       sctns->par.infpval1 |= PAR_ABS_VLD;
+
+       /*
+        * Everything below needs global performance data to be
+        * meaningful.
+        */
+       if (!(ti_hdr->flags & DIAG204_LPAR_PHYS_FLG)) {
+               sctns->hdr.infhflg1 |= HDR_PERF_UNAV;
+               goto out;
+       }
+
+       fill_diag_mac(sctns, phys_block, diag224_buf);
+
+       if (lpar_inf.cp.lpar_weight) {
+               sctns->par.infpwbcp = sctns->mac.infmscps * 0x10000 *
+                       lpar_inf.cp.lpar_weight / lpar_inf.cp.all_weight;
+       }
+
+       if (lpar_inf.ifl.lpar_weight) {
+               sctns->par.infpwbif = sctns->mac.infmsifl * 0x10000 *
+                       lpar_inf.ifl.lpar_weight / lpar_inf.ifl.all_weight;
+       }
+       sctns->par.infpval1 |= PAR_WGHT_VLD;
+
+out:
+       kfree(diag224_buf);
+       vfree(diag204_buf);
+}
+
+static int sthyi(u64 vaddr)
+{
+       register u64 code asm("0") = 0;
+       register u64 addr asm("2") = vaddr;
+       int cc;
+
+       asm volatile(
+               ".insn   rre,0xB2560000,%[code],%[addr]\n"
+               "ipm     %[cc]\n"
+               "srl     %[cc],28\n"
+               : [cc] "=d" (cc)
+               : [code] "d" (code), [addr] "a" (addr)
+               : "memory", "cc");
+       return cc;
+}
+
+int handle_sthyi(struct kvm_vcpu *vcpu)
+{
+       int reg1, reg2, r = 0;
+       u64 code, addr, cc = 0;
+       struct sthyi_sctns *sctns = NULL;
+
+       /*
+        * STHYI requires extensive locking in the higher hypervisors
+        * and is very computational/memory expensive. Therefore we
+        * ratelimit the executions per VM.
+        */
+       if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) {
+               kvm_s390_retry_instr(vcpu);
+               return 0;
+       }
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+       code = vcpu->run->s.regs.gprs[reg1];
+       addr = vcpu->run->s.regs.gprs[reg2];
+
+       vcpu->stat.instruction_sthyi++;
+       VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
+       trace_kvm_s390_handle_sthyi(vcpu, code, addr);
+
+       if (reg1 == reg2 || reg1 & 1 || reg2 & 1 || addr & ~PAGE_MASK)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       if (code & 0xffff) {
+               cc = 3;
+               goto out;
+       }
+
+       /*
+        * If the page has not yet been faulted in, we want to do that
+        * now and not after all the expensive calculations.
+        */
+       r = write_guest(vcpu, addr, reg2, &cc, 1);
+       if (r)
+               return kvm_s390_inject_prog_cond(vcpu, r);
+
+       sctns = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!sctns)
+               return -ENOMEM;
+
+       /*
+        * If we are a guest, we don't want to emulate an emulated
+        * instruction. We ask the hypervisor to provide the data.
+        */
+       if (test_facility(74)) {
+               cc = sthyi((u64)sctns);
+               goto out;
+       }
+
+       fill_hdr(sctns);
+       fill_stsi(sctns);
+       fill_diag(sctns);
+
+out:
+       if (!cc) {
+               r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
+               if (r) {
+                       free_page((unsigned long)sctns);
+                       return kvm_s390_inject_prog_cond(vcpu, r);
+               }
+       }
+
+       free_page((unsigned long)sctns);
+       vcpu->run->s.regs.gprs[reg2 + 1] = cc ? 4 : 0;
+       kvm_s390_set_psw_cc(vcpu, cc);
+       return r;
+}
index 916834d..4fc9d4e 100644 (file)
@@ -41,7 +41,7 @@ TRACE_EVENT(kvm_s390_skey_related_inst,
            TP_fast_assign(
                    VCPU_ASSIGN_COMMON
                    ),
-           VCPU_TP_PRINTK("%s", "first instruction related to skeys on vcpu")
+           VCPU_TP_PRINTK("%s", "storage key related instruction")
        );
 
 TRACE_EVENT(kvm_s390_major_guest_pfault,
@@ -185,8 +185,10 @@ TRACE_EVENT(kvm_s390_intercept_prog,
                    __entry->code = code;
                    ),
 
-           VCPU_TP_PRINTK("intercepted program interruption %04x",
-                          __entry->code)
+           VCPU_TP_PRINTK("intercepted program interruption %04x (%s)",
+                          __entry->code,
+                          __print_symbolic(__entry->code,
+                                           icpt_prog_codes))
        );
 
 /*
@@ -412,6 +414,47 @@ TRACE_EVENT(kvm_s390_handle_stsi,
                           __entry->addr)
        );
 
+TRACE_EVENT(kvm_s390_handle_operexc,
+           TP_PROTO(VCPU_PROTO_COMMON, __u16 ipa, __u32 ipb),
+           TP_ARGS(VCPU_ARGS_COMMON, ipa, ipb),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u64, instruction)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->instruction = ((__u64)ipa << 48) |
+                   ((__u64)ipb << 16);
+                   ),
+
+           VCPU_TP_PRINTK("operation exception on instruction %016llx (%s)",
+                          __entry->instruction,
+                          __print_symbolic(icpt_insn_decoder(__entry->instruction),
+                                           icpt_insn_codes))
+       );
+
+TRACE_EVENT(kvm_s390_handle_sthyi,
+           TP_PROTO(VCPU_PROTO_COMMON, u64 code, u64 addr),
+           TP_ARGS(VCPU_ARGS_COMMON, code, addr),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(u64, code)
+                   __field(u64, addr)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->code = code;
+                   __entry->addr = addr;
+                   ),
+
+           VCPU_TP_PRINTK("STHYI fc: %llu addr: %016llx",
+                          __entry->code, __entry->addr)
+       );
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
new file mode 100644 (file)
index 0000000..c106488
--- /dev/null
@@ -0,0 +1,1091 @@
+/*
+ * kvm nested virtualization support for s390x
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
+ */
+#include <linux/vmalloc.h>
+#include <linux/kvm_host.h>
+#include <linux/bug.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+#include <asm/gmap.h>
+#include <asm/mmu_context.h>
+#include <asm/sclp.h>
+#include <asm/nmi.h>
+#include <asm/dis.h>
+#include "kvm-s390.h"
+#include "gaccess.h"
+
+struct vsie_page {
+       struct kvm_s390_sie_block scb_s;        /* 0x0000 */
+       /* the pinned originial scb */
+       struct kvm_s390_sie_block *scb_o;       /* 0x0200 */
+       /* the shadow gmap in use by the vsie_page */
+       struct gmap *gmap;                      /* 0x0208 */
+       /* address of the last reported fault to guest2 */
+       unsigned long fault_addr;               /* 0x0210 */
+       __u8 reserved[0x0700 - 0x0218];         /* 0x0218 */
+       struct kvm_s390_crypto_cb crycb;        /* 0x0700 */
+       __u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE]; /* 0x0800 */
+} __packed;
+
+/* trigger a validity icpt for the given scb */
+static int set_validity_icpt(struct kvm_s390_sie_block *scb,
+                            __u16 reason_code)
+{
+       scb->ipa = 0x1000;
+       scb->ipb = ((__u32) reason_code) << 16;
+       scb->icptcode = ICPT_VALIDITY;
+       return 1;
+}
+
+/* mark the prefix as unmapped, this will block the VSIE */
+static void prefix_unmapped(struct vsie_page *vsie_page)
+{
+       atomic_or(PROG_REQUEST, &vsie_page->scb_s.prog20);
+}
+
+/* mark the prefix as unmapped and wait until the VSIE has been left */
+static void prefix_unmapped_sync(struct vsie_page *vsie_page)
+{
+       prefix_unmapped(vsie_page);
+       if (vsie_page->scb_s.prog0c & PROG_IN_SIE)
+               atomic_or(CPUSTAT_STOP_INT, &vsie_page->scb_s.cpuflags);
+       while (vsie_page->scb_s.prog0c & PROG_IN_SIE)
+               cpu_relax();
+}
+
+/* mark the prefix as mapped, this will allow the VSIE to run */
+static void prefix_mapped(struct vsie_page *vsie_page)
+{
+       atomic_andnot(PROG_REQUEST, &vsie_page->scb_s.prog20);
+}
+
+/* test if the prefix is mapped into the gmap shadow */
+static int prefix_is_mapped(struct vsie_page *vsie_page)
+{
+       return !(atomic_read(&vsie_page->scb_s.prog20) & PROG_REQUEST);
+}
+
+/* copy the updated intervention request bits into the shadow scb */
+static void update_intervention_requests(struct vsie_page *vsie_page)
+{
+       const int bits = CPUSTAT_STOP_INT | CPUSTAT_IO_INT | CPUSTAT_EXT_INT;
+       int cpuflags;
+
+       cpuflags = atomic_read(&vsie_page->scb_o->cpuflags);
+       atomic_andnot(bits, &vsie_page->scb_s.cpuflags);
+       atomic_or(cpuflags & bits, &vsie_page->scb_s.cpuflags);
+}
+
+/* shadow (filter and validate) the cpuflags  */
+static int prepare_cpuflags(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       int newflags, cpuflags = atomic_read(&scb_o->cpuflags);
+
+       /* we don't allow ESA/390 guests */
+       if (!(cpuflags & CPUSTAT_ZARCH))
+               return set_validity_icpt(scb_s, 0x0001U);
+
+       if (cpuflags & (CPUSTAT_RRF | CPUSTAT_MCDS))
+               return set_validity_icpt(scb_s, 0x0001U);
+       else if (cpuflags & (CPUSTAT_SLSV | CPUSTAT_SLSR))
+               return set_validity_icpt(scb_s, 0x0007U);
+
+       /* intervention requests will be set later */
+       newflags = CPUSTAT_ZARCH;
+       if (cpuflags & CPUSTAT_GED && test_kvm_facility(vcpu->kvm, 8))
+               newflags |= CPUSTAT_GED;
+       if (cpuflags & CPUSTAT_GED2 && test_kvm_facility(vcpu->kvm, 78)) {
+               if (cpuflags & CPUSTAT_GED)
+                       return set_validity_icpt(scb_s, 0x0001U);
+               newflags |= CPUSTAT_GED2;
+       }
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_GPERE))
+               newflags |= cpuflags & CPUSTAT_P;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_GSLS))
+               newflags |= cpuflags & CPUSTAT_SM;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_IBS))
+               newflags |= cpuflags & CPUSTAT_IBS;
+
+       atomic_set(&scb_s->cpuflags, newflags);
+       return 0;
+}
+
+/*
+ * Create a shadow copy of the crycb block and setup key wrapping, if
+ * requested for guest 3 and enabled for guest 2.
+ *
+ * We only accept format-1 (no AP in g2), but convert it into format-2
+ * There is nothing to do for format-0.
+ *
+ * Returns: - 0 if shadowed or nothing to do
+ *          - > 0 if control has to be given to guest 2
+ */
+static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       u32 crycb_addr = scb_o->crycbd & 0x7ffffff8U;
+       unsigned long *b1, *b2;
+       u8 ecb3_flags;
+
+       scb_s->crycbd = 0;
+       if (!(scb_o->crycbd & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1))
+               return 0;
+       /* format-1 is supported with message-security-assist extension 3 */
+       if (!test_kvm_facility(vcpu->kvm, 76))
+               return 0;
+       /* we may only allow it if enabled for guest 2 */
+       ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 &
+                    (ECB3_AES | ECB3_DEA);
+       if (!ecb3_flags)
+               return 0;
+
+       if ((crycb_addr & PAGE_MASK) != ((crycb_addr + 128) & PAGE_MASK))
+               return set_validity_icpt(scb_s, 0x003CU);
+       else if (!crycb_addr)
+               return set_validity_icpt(scb_s, 0x0039U);
+
+       /* copy only the wrapping keys */
+       if (read_guest_real(vcpu, crycb_addr + 72, &vsie_page->crycb, 56))
+               return set_validity_icpt(scb_s, 0x0035U);
+
+       scb_s->ecb3 |= ecb3_flags;
+       scb_s->crycbd = ((__u32)(__u64) &vsie_page->crycb) | CRYCB_FORMAT1 |
+                       CRYCB_FORMAT2;
+
+       /* xor both blocks in one run */
+       b1 = (unsigned long *) vsie_page->crycb.dea_wrapping_key_mask;
+       b2 = (unsigned long *)
+                           vcpu->kvm->arch.crypto.crycb->dea_wrapping_key_mask;
+       /* as 56%8 == 0, bitmap_xor won't overwrite any data */
+       bitmap_xor(b1, b1, b2, BITS_PER_BYTE * 56);
+       return 0;
+}
+
+/* shadow (round up/down) the ibc to avoid validity icpt */
+static void prepare_ibc(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       __u64 min_ibc = (sclp.ibc >> 16) & 0x0fffU;
+
+       scb_s->ibc = 0;
+       /* ibc installed in g2 and requested for g3 */
+       if (vcpu->kvm->arch.model.ibc && (scb_o->ibc & 0x0fffU)) {
+               scb_s->ibc = scb_o->ibc & 0x0fffU;
+               /* takte care of the minimum ibc level of the machine */
+               if (scb_s->ibc < min_ibc)
+                       scb_s->ibc = min_ibc;
+               /* take care of the maximum ibc level set for the guest */
+               if (scb_s->ibc > vcpu->kvm->arch.model.ibc)
+                       scb_s->ibc = vcpu->kvm->arch.model.ibc;
+       }
+}
+
+/* unshadow the scb, copying parameters back to the real scb */
+static void unshadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+
+       /* interception */
+       scb_o->icptcode = scb_s->icptcode;
+       scb_o->icptstatus = scb_s->icptstatus;
+       scb_o->ipa = scb_s->ipa;
+       scb_o->ipb = scb_s->ipb;
+       scb_o->gbea = scb_s->gbea;
+
+       /* timer */
+       scb_o->cputm = scb_s->cputm;
+       scb_o->ckc = scb_s->ckc;
+       scb_o->todpr = scb_s->todpr;
+
+       /* guest state */
+       scb_o->gpsw = scb_s->gpsw;
+       scb_o->gg14 = scb_s->gg14;
+       scb_o->gg15 = scb_s->gg15;
+       memcpy(scb_o->gcr, scb_s->gcr, 128);
+       scb_o->pp = scb_s->pp;
+
+       /* interrupt intercept */
+       switch (scb_s->icptcode) {
+       case ICPT_PROGI:
+       case ICPT_INSTPROGI:
+       case ICPT_EXTINT:
+               memcpy((void *)((u64)scb_o + 0xc0),
+                      (void *)((u64)scb_s + 0xc0), 0xf0 - 0xc0);
+               break;
+       case ICPT_PARTEXEC:
+               /* MVPG only */
+               memcpy((void *)((u64)scb_o + 0xc0),
+                      (void *)((u64)scb_s + 0xc0), 0xd0 - 0xc0);
+               break;
+       }
+
+       if (scb_s->ihcpu != 0xffffU)
+               scb_o->ihcpu = scb_s->ihcpu;
+}
+
+/*
+ * Setup the shadow scb by copying and checking the relevant parts of the g2
+ * provided scb.
+ *
+ * Returns: - 0 if the scb has been shadowed
+ *          - > 0 if control has to be given to guest 2
+ */
+static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       bool had_tx = scb_s->ecb & 0x10U;
+       unsigned long new_mso = 0;
+       int rc;
+
+       /* make sure we don't have any leftovers when reusing the scb */
+       scb_s->icptcode = 0;
+       scb_s->eca = 0;
+       scb_s->ecb = 0;
+       scb_s->ecb2 = 0;
+       scb_s->ecb3 = 0;
+       scb_s->ecd = 0;
+       scb_s->fac = 0;
+
+       rc = prepare_cpuflags(vcpu, vsie_page);
+       if (rc)
+               goto out;
+
+       /* timer */
+       scb_s->cputm = scb_o->cputm;
+       scb_s->ckc = scb_o->ckc;
+       scb_s->todpr = scb_o->todpr;
+       scb_s->epoch = scb_o->epoch;
+
+       /* guest state */
+       scb_s->gpsw = scb_o->gpsw;
+       scb_s->gg14 = scb_o->gg14;
+       scb_s->gg15 = scb_o->gg15;
+       memcpy(scb_s->gcr, scb_o->gcr, 128);
+       scb_s->pp = scb_o->pp;
+
+       /* interception / execution handling */
+       scb_s->gbea = scb_o->gbea;
+       scb_s->lctl = scb_o->lctl;
+       scb_s->svcc = scb_o->svcc;
+       scb_s->ictl = scb_o->ictl;
+       /*
+        * SKEY handling functions can't deal with false setting of PTE invalid
+        * bits. Therefore we cannot provide interpretation and would later
+        * have to provide own emulation handlers.
+        */
+       scb_s->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
+       scb_s->icpua = scb_o->icpua;
+
+       if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM))
+               new_mso = scb_o->mso & 0xfffffffffff00000UL;
+       /* if the hva of the prefix changes, we have to remap the prefix */
+       if (scb_s->mso != new_mso || scb_s->prefix != scb_o->prefix)
+               prefix_unmapped(vsie_page);
+        /* SIE will do mso/msl validity and exception checks for us */
+       scb_s->msl = scb_o->msl & 0xfffffffffff00000UL;
+       scb_s->mso = new_mso;
+       scb_s->prefix = scb_o->prefix;
+
+       /* We have to definetly flush the tlb if this scb never ran */
+       if (scb_s->ihcpu != 0xffffU)
+               scb_s->ihcpu = scb_o->ihcpu;
+
+       /* MVPG and Protection Exception Interpretation are always available */
+       scb_s->eca |= scb_o->eca & 0x01002000U;
+       /* Host-protection-interruption introduced with ESOP */
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP))
+               scb_s->ecb |= scb_o->ecb & 0x02U;
+       /* transactional execution */
+       if (test_kvm_facility(vcpu->kvm, 73)) {
+               /* remap the prefix is tx is toggled on */
+               if ((scb_o->ecb & 0x10U) && !had_tx)
+                       prefix_unmapped(vsie_page);
+               scb_s->ecb |= scb_o->ecb & 0x10U;
+       }
+       /* SIMD */
+       if (test_kvm_facility(vcpu->kvm, 129)) {
+               scb_s->eca |= scb_o->eca & 0x00020000U;
+               scb_s->ecd |= scb_o->ecd & 0x20000000U;
+       }
+       /* Run-time-Instrumentation */
+       if (test_kvm_facility(vcpu->kvm, 64))
+               scb_s->ecb3 |= scb_o->ecb3 & 0x01U;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIIF))
+               scb_s->eca |= scb_o->eca & 0x00000001U;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_IB))
+               scb_s->eca |= scb_o->eca & 0x40000000U;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_CEI))
+               scb_s->eca |= scb_o->eca & 0x80000000U;
+
+       prepare_ibc(vcpu, vsie_page);
+       rc = shadow_crycb(vcpu, vsie_page);
+out:
+       if (rc)
+               unshadow_scb(vcpu, vsie_page);
+       return rc;
+}
+
+void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start,
+                                unsigned long end)
+{
+       struct kvm *kvm = gmap->private;
+       struct vsie_page *cur;
+       unsigned long prefix;
+       struct page *page;
+       int i;
+
+       if (!gmap_is_shadow(gmap))
+               return;
+       if (start >= 1UL << 31)
+               /* We are only interested in prefix pages */
+               return;
+
+       /*
+        * Only new shadow blocks are added to the list during runtime,
+        * therefore we can safely reference them all the time.
+        */
+       for (i = 0; i < kvm->arch.vsie.page_count; i++) {
+               page = READ_ONCE(kvm->arch.vsie.pages[i]);
+               if (!page)
+                       continue;
+               cur = page_to_virt(page);
+               if (READ_ONCE(cur->gmap) != gmap)
+                       continue;
+               prefix = cur->scb_s.prefix << GUEST_PREFIX_SHIFT;
+               /* with mso/msl, the prefix lies at an offset */
+               prefix += cur->scb_s.mso;
+               if (prefix <= end && start <= prefix + 2 * PAGE_SIZE - 1)
+                       prefix_unmapped_sync(cur);
+       }
+}
+
+/*
+ * Map the first prefix page and if tx is enabled also the second prefix page.
+ *
+ * The prefix will be protected, a gmap notifier will inform about unmaps.
+ * The shadow scb must not be executed until the prefix is remapped, this is
+ * guaranteed by properly handling PROG_REQUEST.
+ *
+ * Returns: - 0 on if successfully mapped or already mapped
+ *          - > 0 if control has to be given to guest 2
+ *          - -EAGAIN if the caller can retry immediately
+ *          - -ENOMEM if out of memory
+ */
+static int map_prefix(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       u64 prefix = scb_s->prefix << GUEST_PREFIX_SHIFT;
+       int rc;
+
+       if (prefix_is_mapped(vsie_page))
+               return 0;
+
+       /* mark it as mapped so we can catch any concurrent unmappers */
+       prefix_mapped(vsie_page);
+
+       /* with mso/msl, the prefix lies at offset *mso* */
+       prefix += scb_s->mso;
+
+       rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap, prefix);
+       if (!rc && (scb_s->ecb & 0x10U))
+               rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
+                                          prefix + PAGE_SIZE);
+       /*
+        * We don't have to mprotect, we will be called for all unshadows.
+        * SIE will detect if protection applies and trigger a validity.
+        */
+       if (rc)
+               prefix_unmapped(vsie_page);
+       if (rc > 0 || rc == -EFAULT)
+               rc = set_validity_icpt(scb_s, 0x0037U);
+       return rc;
+}
+
+/*
+ * Pin the guest page given by gpa and set hpa to the pinned host address.
+ * Will always be pinned writable.
+ *
+ * Returns: - 0 on success
+ *          - -EINVAL if the gpa is not valid guest storage
+ *          - -ENOMEM if out of memory
+ */
+static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
+{
+       struct page *page;
+       hva_t hva;
+       int rc;
+
+       hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
+       if (kvm_is_error_hva(hva))
+               return -EINVAL;
+       rc = get_user_pages_fast(hva, 1, 1, &page);
+       if (rc < 0)
+               return rc;
+       else if (rc != 1)
+               return -ENOMEM;
+       *hpa = (hpa_t) page_to_virt(page) + (gpa & ~PAGE_MASK);
+       return 0;
+}
+
+/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
+static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
+{
+       struct page *page;
+
+       page = virt_to_page(hpa);
+       set_page_dirty_lock(page);
+       put_page(page);
+       /* mark the page always as dirty for migration */
+       mark_page_dirty(kvm, gpa_to_gfn(gpa));
+}
+
+/* unpin all blocks previously pinned by pin_blocks(), marking them dirty */
+static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       hpa_t hpa;
+       gpa_t gpa;
+
+       hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
+       if (hpa) {
+               gpa = scb_o->scaol & ~0xfUL;
+               if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
+                       gpa |= (u64) scb_o->scaoh << 32;
+               unpin_guest_page(vcpu->kvm, gpa, hpa);
+               scb_s->scaol = 0;
+               scb_s->scaoh = 0;
+       }
+
+       hpa = scb_s->itdba;
+       if (hpa) {
+               gpa = scb_o->itdba & ~0xffUL;
+               unpin_guest_page(vcpu->kvm, gpa, hpa);
+               scb_s->itdba = 0;
+       }
+
+       hpa = scb_s->gvrd;
+       if (hpa) {
+               gpa = scb_o->gvrd & ~0x1ffUL;
+               unpin_guest_page(vcpu->kvm, gpa, hpa);
+               scb_s->gvrd = 0;
+       }
+
+       hpa = scb_s->riccbd;
+       if (hpa) {
+               gpa = scb_o->riccbd & ~0x3fUL;
+               unpin_guest_page(vcpu->kvm, gpa, hpa);
+               scb_s->riccbd = 0;
+       }
+}
+
+/*
+ * Instead of shadowing some blocks, we can simply forward them because the
+ * addresses in the scb are 64 bit long.
+ *
+ * This works as long as the data lies in one page. If blocks ever exceed one
+ * page, we have to fall back to shadowing.
+ *
+ * As we reuse the sca, the vcpu pointers contained in it are invalid. We must
+ * therefore not enable any facilities that access these pointers (e.g. SIGPIF).
+ *
+ * Returns: - 0 if all blocks were pinned.
+ *          - > 0 if control has to be given to guest 2
+ *          - -ENOMEM if out of memory
+ */
+static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       hpa_t hpa;
+       gpa_t gpa;
+       int rc = 0;
+
+       gpa = scb_o->scaol & ~0xfUL;
+       if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
+               gpa |= (u64) scb_o->scaoh << 32;
+       if (gpa) {
+               if (!(gpa & ~0x1fffUL))
+                       rc = set_validity_icpt(scb_s, 0x0038U);
+               else if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
+                       rc = set_validity_icpt(scb_s, 0x0011U);
+               else if ((gpa & PAGE_MASK) !=
+                        ((gpa + sizeof(struct bsca_block) - 1) & PAGE_MASK))
+                       rc = set_validity_icpt(scb_s, 0x003bU);
+               if (!rc) {
+                       rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+                       if (rc == -EINVAL)
+                               rc = set_validity_icpt(scb_s, 0x0034U);
+               }
+               if (rc)
+                       goto unpin;
+               scb_s->scaoh = (u32)((u64)hpa >> 32);
+               scb_s->scaol = (u32)(u64)hpa;
+       }
+
+       gpa = scb_o->itdba & ~0xffUL;
+       if (gpa && (scb_s->ecb & 0x10U)) {
+               if (!(gpa & ~0x1fffU)) {
+                       rc = set_validity_icpt(scb_s, 0x0080U);
+                       goto unpin;
+               }
+               /* 256 bytes cannot cross page boundaries */
+               rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+               if (rc == -EINVAL)
+                       rc = set_validity_icpt(scb_s, 0x0080U);
+               if (rc)
+                       goto unpin;
+               scb_s->itdba = hpa;
+       }
+
+       gpa = scb_o->gvrd & ~0x1ffUL;
+       if (gpa && (scb_s->eca & 0x00020000U) &&
+           !(scb_s->ecd & 0x20000000U)) {
+               if (!(gpa & ~0x1fffUL)) {
+                       rc = set_validity_icpt(scb_s, 0x1310U);
+                       goto unpin;
+               }
+               /*
+                * 512 bytes vector registers cannot cross page boundaries
+                * if this block gets bigger, we have to shadow it.
+                */
+               rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+               if (rc == -EINVAL)
+                       rc = set_validity_icpt(scb_s, 0x1310U);
+               if (rc)
+                       goto unpin;
+               scb_s->gvrd = hpa;
+       }
+
+       gpa = scb_o->riccbd & ~0x3fUL;
+       if (gpa && (scb_s->ecb3 & 0x01U)) {
+               if (!(gpa & ~0x1fffUL)) {
+                       rc = set_validity_icpt(scb_s, 0x0043U);
+                       goto unpin;
+               }
+               /* 64 bytes cannot cross page boundaries */
+               rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+               if (rc == -EINVAL)
+                       rc = set_validity_icpt(scb_s, 0x0043U);
+               /* Validity 0x0044 will be checked by SIE */
+               if (rc)
+                       goto unpin;
+               scb_s->gvrd = hpa;
+       }
+       return 0;
+unpin:
+       unpin_blocks(vcpu, vsie_page);
+       return rc;
+}
+
+/* unpin the scb provided by guest 2, marking it as dirty */
+static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
+                     gpa_t gpa)
+{
+       hpa_t hpa = (hpa_t) vsie_page->scb_o;
+
+       if (hpa)
+               unpin_guest_page(vcpu->kvm, gpa, hpa);
+       vsie_page->scb_o = NULL;
+}
+
+/*
+ * Pin the scb at gpa provided by guest 2 at vsie_page->scb_o.
+ *
+ * Returns: - 0 if the scb was pinned.
+ *          - > 0 if control has to be given to guest 2
+ *          - -ENOMEM if out of memory
+ */
+static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
+                  gpa_t gpa)
+{
+       hpa_t hpa;
+       int rc;
+
+       rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+       if (rc == -EINVAL) {
+               rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               if (!rc)
+                       rc = 1;
+       }
+       if (!rc)
+               vsie_page->scb_o = (struct kvm_s390_sie_block *) hpa;
+       return rc;
+}
+
+/*
+ * Inject a fault into guest 2.
+ *
+ * Returns: - > 0 if control has to be given to guest 2
+ *            < 0 if an error occurred during injection.
+ */
+static int inject_fault(struct kvm_vcpu *vcpu, __u16 code, __u64 vaddr,
+                       bool write_flag)
+{
+       struct kvm_s390_pgm_info pgm = {
+               .code = code,
+               .trans_exc_code =
+                       /* 0-51: virtual address */
+                       (vaddr & 0xfffffffffffff000UL) |
+                       /* 52-53: store / fetch */
+                       (((unsigned int) !write_flag) + 1) << 10,
+                       /* 62-63: asce id (alway primary == 0) */
+               .exc_access_id = 0, /* always primary */
+               .op_access_id = 0, /* not MVPG */
+       };
+       int rc;
+
+       if (code == PGM_PROTECTION)
+               pgm.trans_exc_code |= 0x4UL;
+
+       rc = kvm_s390_inject_prog_irq(vcpu, &pgm);
+       return rc ? rc : 1;
+}
+
+/*
+ * Handle a fault during vsie execution on a gmap shadow.
+ *
+ * Returns: - 0 if the fault was resolved
+ *          - > 0 if control has to be given to guest 2
+ *          - < 0 if an error occurred
+ */
+static int handle_fault(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       int rc;
+
+       if (current->thread.gmap_int_code == PGM_PROTECTION)
+               /* we can directly forward all protection exceptions */
+               return inject_fault(vcpu, PGM_PROTECTION,
+                                   current->thread.gmap_addr, 1);
+
+       rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
+                                  current->thread.gmap_addr);
+       if (rc > 0) {
+               rc = inject_fault(vcpu, rc,
+                                 current->thread.gmap_addr,
+                                 current->thread.gmap_write_flag);
+               if (rc >= 0)
+                       vsie_page->fault_addr = current->thread.gmap_addr;
+       }
+       return rc;
+}
+
+/*
+ * Retry the previous fault that required guest 2 intervention. This avoids
+ * one superfluous SIE re-entry and direct exit.
+ *
+ * Will ignore any errors. The next SIE fault will do proper fault handling.
+ */
+static void handle_last_fault(struct kvm_vcpu *vcpu,
+                             struct vsie_page *vsie_page)
+{
+       if (vsie_page->fault_addr)
+               kvm_s390_shadow_fault(vcpu, vsie_page->gmap,
+                                     vsie_page->fault_addr);
+       vsie_page->fault_addr = 0;
+}
+
+static inline void clear_vsie_icpt(struct vsie_page *vsie_page)
+{
+       vsie_page->scb_s.icptcode = 0;
+}
+
+/* rewind the psw and clear the vsie icpt, so we can retry execution */
+static void retry_vsie_icpt(struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       int ilen = insn_length(scb_s->ipa >> 8);
+
+       /* take care of EXECUTE instructions */
+       if (scb_s->icptstatus & 1) {
+               ilen = (scb_s->icptstatus >> 4) & 0x6;
+               if (!ilen)
+                       ilen = 4;
+       }
+       scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, ilen);
+       clear_vsie_icpt(vsie_page);
+}
+
+/*
+ * Try to shadow + enable the guest 2 provided facility list.
+ * Retry instruction execution if enabled for and provided by guest 2.
+ *
+ * Returns: - 0 if handled (retry or guest 2 icpt)
+ *          - > 0 if control has to be given to guest 2
+ */
+static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       __u32 fac = vsie_page->scb_o->fac & 0x7ffffff8U;
+
+       if (fac && test_kvm_facility(vcpu->kvm, 7)) {
+               retry_vsie_icpt(vsie_page);
+               if (read_guest_real(vcpu, fac, &vsie_page->fac,
+                                   sizeof(vsie_page->fac)))
+                       return set_validity_icpt(scb_s, 0x1090U);
+               scb_s->fac = (__u32)(__u64) &vsie_page->fac;
+       }
+       return 0;
+}
+
+/*
+ * Run the vsie on a shadow scb and a shadow gmap, without any further
+ * sanity checks, handling SIE faults.
+ *
+ * Returns: - 0 everything went fine
+ *          - > 0 if control has to be given to guest 2
+ *          - < 0 if an error occurred
+ */
+static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       int rc;
+
+       handle_last_fault(vcpu, vsie_page);
+
+       if (need_resched())
+               schedule();
+       if (test_cpu_flag(CIF_MCCK_PENDING))
+               s390_handle_mcck();
+
+       srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+       local_irq_disable();
+       guest_enter_irqoff();
+       local_irq_enable();
+
+       rc = sie64a(scb_s, vcpu->run->s.regs.gprs);
+
+       local_irq_disable();
+       guest_exit_irqoff();
+       local_irq_enable();
+       vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+
+       if (rc > 0)
+               rc = 0; /* we could still have an icpt */
+       else if (rc == -EFAULT)
+               return handle_fault(vcpu, vsie_page);
+
+       switch (scb_s->icptcode) {
+       case ICPT_INST:
+               if (scb_s->ipa == 0xb2b0)
+                       rc = handle_stfle(vcpu, vsie_page);
+               break;
+       case ICPT_STOP:
+               /* stop not requested by g2 - must have been a kick */
+               if (!(atomic_read(&scb_o->cpuflags) & CPUSTAT_STOP_INT))
+                       clear_vsie_icpt(vsie_page);
+               break;
+       case ICPT_VALIDITY:
+               if ((scb_s->ipa & 0xf000) != 0xf000)
+                       scb_s->ipa += 0x1000;
+               break;
+       }
+       return rc;
+}
+
+static void release_gmap_shadow(struct vsie_page *vsie_page)
+{
+       if (vsie_page->gmap)
+               gmap_put(vsie_page->gmap);
+       WRITE_ONCE(vsie_page->gmap, NULL);
+       prefix_unmapped(vsie_page);
+}
+
+static int acquire_gmap_shadow(struct kvm_vcpu *vcpu,
+                              struct vsie_page *vsie_page)
+{
+       unsigned long asce;
+       union ctlreg0 cr0;
+       struct gmap *gmap;
+       int edat;
+
+       asce = vcpu->arch.sie_block->gcr[1];
+       cr0.val = vcpu->arch.sie_block->gcr[0];
+       edat = cr0.edat && test_kvm_facility(vcpu->kvm, 8);
+       edat += edat && test_kvm_facility(vcpu->kvm, 78);
+
+       /*
+        * ASCE or EDAT could have changed since last icpt, or the gmap
+        * we're holding has been unshadowed. If the gmap is still valid,
+        * we can safely reuse it.
+        */
+       if (vsie_page->gmap && gmap_shadow_valid(vsie_page->gmap, asce, edat))
+               return 0;
+
+       /* release the old shadow - if any, and mark the prefix as unmapped */
+       release_gmap_shadow(vsie_page);
+       gmap = gmap_shadow(vcpu->arch.gmap, asce, edat);
+       if (IS_ERR(gmap))
+               return PTR_ERR(gmap);
+       gmap->private = vcpu->kvm;
+       WRITE_ONCE(vsie_page->gmap, gmap);
+       return 0;
+}
+
+/*
+ * Register the shadow scb at the VCPU, e.g. for kicking out of vsie.
+ */
+static void register_shadow_scb(struct kvm_vcpu *vcpu,
+                               struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+
+       WRITE_ONCE(vcpu->arch.vsie_block, &vsie_page->scb_s);
+       /*
+        * External calls have to lead to a kick of the vcpu and
+        * therefore the vsie -> Simulate Wait state.
+        */
+       atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+       /*
+        * We have to adjust the g3 epoch by the g2 epoch. The epoch will
+        * automatically be adjusted on tod clock changes via kvm_sync_clock.
+        */
+       preempt_disable();
+       scb_s->epoch += vcpu->kvm->arch.epoch;
+       preempt_enable();
+}
+
+/*
+ * Unregister a shadow scb from a VCPU.
+ */
+static void unregister_shadow_scb(struct kvm_vcpu *vcpu)
+{
+       atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+       WRITE_ONCE(vcpu->arch.vsie_block, NULL);
+}
+
+/*
+ * Run the vsie on a shadowed scb, managing the gmap shadow, handling
+ * prefix pages and faults.
+ *
+ * Returns: - 0 if no errors occurred
+ *          - > 0 if control has to be given to guest 2
+ *          - -ENOMEM if out of memory
+ */
+static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
+{
+       struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+       int rc = 0;
+
+       while (1) {
+               rc = acquire_gmap_shadow(vcpu, vsie_page);
+               if (!rc)
+                       rc = map_prefix(vcpu, vsie_page);
+               if (!rc) {
+                       gmap_enable(vsie_page->gmap);
+                       update_intervention_requests(vsie_page);
+                       rc = do_vsie_run(vcpu, vsie_page);
+                       gmap_enable(vcpu->arch.gmap);
+               }
+               atomic_andnot(PROG_BLOCK_SIE, &scb_s->prog20);
+
+               if (rc == -EAGAIN)
+                       rc = 0;
+               if (rc || scb_s->icptcode || signal_pending(current) ||
+                   kvm_s390_vcpu_has_irq(vcpu, 0))
+                       break;
+       };
+
+       if (rc == -EFAULT) {
+               /*
+                * Addressing exceptions are always presentes as intercepts.
+                * As addressing exceptions are suppressing and our guest 3 PSW
+                * points at the responsible instruction, we have to
+                * forward the PSW and set the ilc. If we can't read guest 3
+                * instruction, we can use an arbitrary ilc. Let's always use
+                * ilen = 4 for now, so we can avoid reading in guest 3 virtual
+                * memory. (we could also fake the shadow so the hardware
+                * handles it).
+                */
+               scb_s->icptcode = ICPT_PROGI;
+               scb_s->iprcc = PGM_ADDRESSING;
+               scb_s->pgmilc = 4;
+               scb_s->gpsw.addr = __rewind_psw(scb_s->gpsw, 4);
+       }
+       return rc;
+}
+
+/*
+ * Get or create a vsie page for a scb address.
+ *
+ * Returns: - address of a vsie page (cached or new one)
+ *          - NULL if the same scb address is already used by another VCPU
+ *          - ERR_PTR(-ENOMEM) if out of memory
+ */
+static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
+{
+       struct vsie_page *vsie_page;
+       struct page *page;
+       int nr_vcpus;
+
+       rcu_read_lock();
+       page = radix_tree_lookup(&kvm->arch.vsie.addr_to_page, addr >> 9);
+       rcu_read_unlock();
+       if (page) {
+               if (page_ref_inc_return(page) == 2)
+                       return page_to_virt(page);
+               page_ref_dec(page);
+       }
+
+       /*
+        * We want at least #online_vcpus shadows, so every VCPU can execute
+        * the VSIE in parallel.
+        */
+       nr_vcpus = atomic_read(&kvm->online_vcpus);
+
+       mutex_lock(&kvm->arch.vsie.mutex);
+       if (kvm->arch.vsie.page_count < nr_vcpus) {
+               page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA);
+               if (!page) {
+                       mutex_unlock(&kvm->arch.vsie.mutex);
+                       return ERR_PTR(-ENOMEM);
+               }
+               page_ref_inc(page);
+               kvm->arch.vsie.pages[kvm->arch.vsie.page_count] = page;
+               kvm->arch.vsie.page_count++;
+       } else {
+               /* reuse an existing entry that belongs to nobody */
+               while (true) {
+                       page = kvm->arch.vsie.pages[kvm->arch.vsie.next];
+                       if (page_ref_inc_return(page) == 2)
+                               break;
+                       page_ref_dec(page);
+                       kvm->arch.vsie.next++;
+                       kvm->arch.vsie.next %= nr_vcpus;
+               }
+               radix_tree_delete(&kvm->arch.vsie.addr_to_page, page->index >> 9);
+       }
+       page->index = addr;
+       /* double use of the same address */
+       if (radix_tree_insert(&kvm->arch.vsie.addr_to_page, addr >> 9, page)) {
+               page_ref_dec(page);
+               mutex_unlock(&kvm->arch.vsie.mutex);
+               return NULL;
+       }
+       mutex_unlock(&kvm->arch.vsie.mutex);
+
+       vsie_page = page_to_virt(page);
+       memset(&vsie_page->scb_s, 0, sizeof(struct kvm_s390_sie_block));
+       release_gmap_shadow(vsie_page);
+       vsie_page->fault_addr = 0;
+       vsie_page->scb_s.ihcpu = 0xffffU;
+       return vsie_page;
+}
+
+/* put a vsie page acquired via get_vsie_page */
+static void put_vsie_page(struct kvm *kvm, struct vsie_page *vsie_page)
+{
+       struct page *page = pfn_to_page(__pa(vsie_page) >> PAGE_SHIFT);
+
+       page_ref_dec(page);
+}
+
+int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
+{
+       struct vsie_page *vsie_page;
+       unsigned long scb_addr;
+       int rc;
+
+       vcpu->stat.instruction_sie++;
+       if (!test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIEF2))
+               return -EOPNOTSUPP;
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       BUILD_BUG_ON(sizeof(struct vsie_page) != 4096);
+       scb_addr = kvm_s390_get_base_disp_s(vcpu, NULL);
+
+       /* 512 byte alignment */
+       if (unlikely(scb_addr & 0x1ffUL))
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0))
+               return 0;
+
+       vsie_page = get_vsie_page(vcpu->kvm, scb_addr);
+       if (IS_ERR(vsie_page))
+               return PTR_ERR(vsie_page);
+       else if (!vsie_page)
+               /* double use of sie control block - simply do nothing */
+               return 0;
+
+       rc = pin_scb(vcpu, vsie_page, scb_addr);
+       if (rc)
+               goto out_put;
+       rc = shadow_scb(vcpu, vsie_page);
+       if (rc)
+               goto out_unpin_scb;
+       rc = pin_blocks(vcpu, vsie_page);
+       if (rc)
+               goto out_unshadow;
+       register_shadow_scb(vcpu, vsie_page);
+       rc = vsie_run(vcpu, vsie_page);
+       unregister_shadow_scb(vcpu);
+       unpin_blocks(vcpu, vsie_page);
+out_unshadow:
+       unshadow_scb(vcpu, vsie_page);
+out_unpin_scb:
+       unpin_scb(vcpu, vsie_page, scb_addr);
+out_put:
+       put_vsie_page(vcpu->kvm, vsie_page);
+
+       return rc < 0 ? rc : 0;
+}
+
+/* Init the vsie data structures. To be called when a vm is initialized. */
+void kvm_s390_vsie_init(struct kvm *kvm)
+{
+       mutex_init(&kvm->arch.vsie.mutex);
+       INIT_RADIX_TREE(&kvm->arch.vsie.addr_to_page, GFP_KERNEL);
+}
+
+/* Destroy the vsie data structures. To be called when a vm is destroyed. */
+void kvm_s390_vsie_destroy(struct kvm *kvm)
+{
+       struct vsie_page *vsie_page;
+       struct page *page;
+       int i;
+
+       mutex_lock(&kvm->arch.vsie.mutex);
+       for (i = 0; i < kvm->arch.vsie.page_count; i++) {
+               page = kvm->arch.vsie.pages[i];
+               kvm->arch.vsie.pages[i] = NULL;
+               vsie_page = page_to_virt(page);
+               release_gmap_shadow(vsie_page);
+               /* free the radix tree entry */
+               radix_tree_delete(&kvm->arch.vsie.addr_to_page, page->index >> 9);
+               __free_page(page);
+       }
+       kvm->arch.vsie.page_count = 0;
+       mutex_unlock(&kvm->arch.vsie.mutex);
+}
+
+void kvm_s390_vsie_kick(struct kvm_vcpu *vcpu)
+{
+       struct kvm_s390_sie_block *scb = READ_ONCE(vcpu->arch.vsie_block);
+
+       /*
+        * Even if the VCPU lets go of the shadow sie block reference, it is
+        * still valid in the cache. So we can safely kick it.
+        */
+       if (scb) {
+               atomic_or(PROG_BLOCK_SIE, &scb->prog20);
+               if (scb->prog0c & PROG_IN_SIE)
+                       atomic_or(CPUSTAT_STOP_INT, &scb->cpuflags);
+       }
+}
index d965961..f481fcd 100644 (file)
@@ -104,6 +104,7 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
 
 unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
+       check_object_size(to, n, false);
        if (static_branch_likely(&have_mvcos))
                return copy_from_user_mvcos(to, from, n);
        return copy_from_user_mvcp(to, from, n);
@@ -177,6 +178,7 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
 
 unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
+       check_object_size(from, n, true);
        if (static_branch_likely(&have_mvcos))
                return copy_to_user_mvcos(to, from, n);
        return copy_to_user_mvcs(to, from, n);
index 25783dc..a58bca6 100644 (file)
@@ -418,6 +418,8 @@ static inline int do_exception(struct pt_regs *regs, int access)
                (struct gmap *) S390_lowcore.gmap : NULL;
        if (gmap) {
                current->thread.gmap_addr = address;
+               current->thread.gmap_write_flag = !!(flags & FAULT_FLAG_WRITE);
+               current->thread.gmap_int_code = regs->int_code & 0xffff;
                address = __gmap_translate(gmap, address);
                if (address == -EFAULT) {
                        fault = VM_FAULT_BADMAP;
index 063c721..2ce6bb3 100644 (file)
 #include <asm/gmap.h>
 #include <asm/tlb.h>
 
+#define GMAP_SHADOW_FAKE_TABLE 1ULL
+
 /**
- * gmap_alloc - allocate a guest address space
+ * gmap_alloc - allocate and initialize a guest address space
  * @mm: pointer to the parent mm_struct
  * @limit: maximum address of the gmap address space
  *
  * Returns a guest address space structure.
  */
-struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit)
+static struct gmap *gmap_alloc(unsigned long limit)
 {
        struct gmap *gmap;
        struct page *page;
@@ -55,10 +57,14 @@ struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit)
        if (!gmap)
                goto out;
        INIT_LIST_HEAD(&gmap->crst_list);
+       INIT_LIST_HEAD(&gmap->children);
+       INIT_LIST_HEAD(&gmap->pt_list);
        INIT_RADIX_TREE(&gmap->guest_to_host, GFP_KERNEL);
        INIT_RADIX_TREE(&gmap->host_to_guest, GFP_ATOMIC);
+       INIT_RADIX_TREE(&gmap->host_to_rmap, GFP_ATOMIC);
        spin_lock_init(&gmap->guest_table_lock);
-       gmap->mm = mm;
+       spin_lock_init(&gmap->shadow_lock);
+       atomic_set(&gmap->ref_count, 1);
        page = alloc_pages(GFP_KERNEL, 2);
        if (!page)
                goto out_free;
@@ -70,9 +76,6 @@ struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit)
        gmap->asce = atype | _ASCE_TABLE_LENGTH |
                _ASCE_USER_BITS | __pa(table);
        gmap->asce_end = limit;
-       down_write(&mm->mmap_sem);
-       list_add(&gmap->list, &mm->context.gmap_list);
-       up_write(&mm->mmap_sem);
        return gmap;
 
 out_free:
@@ -80,7 +83,28 @@ out_free:
 out:
        return NULL;
 }
-EXPORT_SYMBOL_GPL(gmap_alloc);
+
+/**
+ * gmap_create - create a guest address space
+ * @mm: pointer to the parent mm_struct
+ * @limit: maximum size of the gmap address space
+ *
+ * Returns a guest address space structure.
+ */
+struct gmap *gmap_create(struct mm_struct *mm, unsigned long limit)
+{
+       struct gmap *gmap;
+
+       gmap = gmap_alloc(limit);
+       if (!gmap)
+               return NULL;
+       gmap->mm = mm;
+       spin_lock(&mm->context.gmap_lock);
+       list_add_rcu(&gmap->list, &mm->context.gmap_list);
+       spin_unlock(&mm->context.gmap_lock);
+       return gmap;
+}
+EXPORT_SYMBOL_GPL(gmap_create);
 
 static void gmap_flush_tlb(struct gmap *gmap)
 {
@@ -114,31 +138,117 @@ static void gmap_radix_tree_free(struct radix_tree_root *root)
        } while (nr > 0);
 }
 
+static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)
+{
+       struct gmap_rmap *rmap, *rnext, *head;
+       struct radix_tree_iter iter;
+       unsigned long indices[16];
+       unsigned long index;
+       void **slot;
+       int i, nr;
+
+       /* A radix tree is freed by deleting all of its entries */
+       index = 0;
+       do {
+               nr = 0;
+               radix_tree_for_each_slot(slot, root, &iter, index) {
+                       indices[nr] = iter.index;
+                       if (++nr == 16)
+                               break;
+               }
+               for (i = 0; i < nr; i++) {
+                       index = indices[i];
+                       head = radix_tree_delete(root, index);
+                       gmap_for_each_rmap_safe(rmap, rnext, head)
+                               kfree(rmap);
+               }
+       } while (nr > 0);
+}
+
 /**
  * gmap_free - free a guest address space
  * @gmap: pointer to the guest address space structure
+ *
+ * No locks required. There are no references to this gmap anymore.
  */
-void gmap_free(struct gmap *gmap)
+static void gmap_free(struct gmap *gmap)
 {
        struct page *page, *next;
 
-       /* Flush tlb. */
-       if (MACHINE_HAS_IDTE)
-               __tlb_flush_idte(gmap->asce);
-       else
-               __tlb_flush_global();
-
+       /* Flush tlb of all gmaps (if not already done for shadows) */
+       if (!(gmap_is_shadow(gmap) && gmap->removed))
+               gmap_flush_tlb(gmap);
        /* Free all segment & region tables. */
        list_for_each_entry_safe(page, next, &gmap->crst_list, lru)
                __free_pages(page, 2);
        gmap_radix_tree_free(&gmap->guest_to_host);
        gmap_radix_tree_free(&gmap->host_to_guest);
-       down_write(&gmap->mm->mmap_sem);
-       list_del(&gmap->list);
-       up_write(&gmap->mm->mmap_sem);
+
+       /* Free additional data for a shadow gmap */
+       if (gmap_is_shadow(gmap)) {
+               /* Free all page tables. */
+               list_for_each_entry_safe(page, next, &gmap->pt_list, lru)
+                       page_table_free_pgste(page);
+               gmap_rmap_radix_tree_free(&gmap->host_to_rmap);
+               /* Release reference to the parent */
+               gmap_put(gmap->parent);
+       }
+
        kfree(gmap);
 }
-EXPORT_SYMBOL_GPL(gmap_free);
+
+/**
+ * gmap_get - increase reference counter for guest address space
+ * @gmap: pointer to the guest address space structure
+ *
+ * Returns the gmap pointer
+ */
+struct gmap *gmap_get(struct gmap *gmap)
+{
+       atomic_inc(&gmap->ref_count);
+       return gmap;
+}
+EXPORT_SYMBOL_GPL(gmap_get);
+
+/**
+ * gmap_put - decrease reference counter for guest address space
+ * @gmap: pointer to the guest address space structure
+ *
+ * If the reference counter reaches zero the guest address space is freed.
+ */
+void gmap_put(struct gmap *gmap)
+{
+       if (atomic_dec_return(&gmap->ref_count) == 0)
+               gmap_free(gmap);
+}
+EXPORT_SYMBOL_GPL(gmap_put);
+
+/**
+ * gmap_remove - remove a guest address space but do not free it yet
+ * @gmap: pointer to the guest address space structure
+ */
+void gmap_remove(struct gmap *gmap)
+{
+       struct gmap *sg, *next;
+
+       /* Remove all shadow gmaps linked to this gmap */
+       if (!list_empty(&gmap->children)) {
+               spin_lock(&gmap->shadow_lock);
+               list_for_each_entry_safe(sg, next, &gmap->children, list) {
+                       list_del(&sg->list);
+                       gmap_put(sg);
+               }
+               spin_unlock(&gmap->shadow_lock);
+       }
+       /* Remove gmap from the pre-mm list */
+       spin_lock(&gmap->mm->context.gmap_lock);
+       list_del_rcu(&gmap->list);
+       spin_unlock(&gmap->mm->context.gmap_lock);
+       synchronize_rcu();
+       /* Put reference */
+       gmap_put(gmap);
+}
+EXPORT_SYMBOL_GPL(gmap_remove);
 
 /**
  * gmap_enable - switch primary space to the guest address space
@@ -160,6 +270,17 @@ void gmap_disable(struct gmap *gmap)
 }
 EXPORT_SYMBOL_GPL(gmap_disable);
 
+/**
+ * gmap_get_enabled - get a pointer to the currently enabled gmap
+ *
+ * Returns a pointer to the currently enabled gmap. 0 if none is enabled.
+ */
+struct gmap *gmap_get_enabled(void)
+{
+       return (struct gmap *) S390_lowcore.gmap;
+}
+EXPORT_SYMBOL_GPL(gmap_get_enabled);
+
 /*
  * gmap_alloc_table is assumed to be called with mmap_sem held
  */
@@ -175,7 +296,7 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
                return -ENOMEM;
        new = (unsigned long *) page_to_phys(page);
        crst_table_init(new, init);
-       spin_lock(&gmap->mm->page_table_lock);
+       spin_lock(&gmap->guest_table_lock);
        if (*table & _REGION_ENTRY_INVALID) {
                list_add(&page->lru, &gmap->crst_list);
                *table = (unsigned long) new | _REGION_ENTRY_LENGTH |
@@ -183,7 +304,7 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
                page->index = gaddr;
                page = NULL;
        }
-       spin_unlock(&gmap->mm->page_table_lock);
+       spin_unlock(&gmap->guest_table_lock);
        if (page)
                __free_pages(page, 2);
        return 0;
@@ -219,6 +340,7 @@ static int __gmap_unlink_by_vmaddr(struct gmap *gmap, unsigned long vmaddr)
        unsigned long *entry;
        int flush = 0;
 
+       BUG_ON(gmap_is_shadow(gmap));
        spin_lock(&gmap->guest_table_lock);
        entry = radix_tree_delete(&gmap->host_to_guest, vmaddr >> PMD_SHIFT);
        if (entry) {
@@ -258,6 +380,7 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
        unsigned long off;
        int flush;
 
+       BUG_ON(gmap_is_shadow(gmap));
        if ((to | len) & (PMD_SIZE - 1))
                return -EINVAL;
        if (len == 0 || to + len < to)
@@ -289,6 +412,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
        unsigned long off;
        int flush;
 
+       BUG_ON(gmap_is_shadow(gmap));
        if ((from | to | len) & (PMD_SIZE - 1))
                return -EINVAL;
        if (len == 0 || from + len < from || to + len < to ||
@@ -326,6 +450,8 @@ EXPORT_SYMBOL_GPL(gmap_map_segment);
  * This function does not establish potentially missing page table entries.
  * The mmap_sem of the mm that belongs to the address space must be held
  * when this function gets called.
+ *
+ * Note: Can also be called for shadow gmaps.
  */
 unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr)
 {
@@ -333,6 +459,7 @@ unsigned long __gmap_translate(struct gmap *gmap, unsigned long gaddr)
 
        vmaddr = (unsigned long)
                radix_tree_lookup(&gmap->guest_to_host, gaddr >> PMD_SHIFT);
+       /* Note: guest_to_host is empty for a shadow gmap */
        return vmaddr ? (vmaddr | (gaddr & ~PMD_MASK)) : -EFAULT;
 }
 EXPORT_SYMBOL_GPL(__gmap_translate);
@@ -369,11 +496,13 @@ void gmap_unlink(struct mm_struct *mm, unsigned long *table,
        struct gmap *gmap;
        int flush;
 
-       list_for_each_entry(gmap, &mm->context.gmap_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
                flush = __gmap_unlink_by_vmaddr(gmap, vmaddr);
                if (flush)
                        gmap_flush_tlb(gmap);
        }
+       rcu_read_unlock();
 }
 
 /**
@@ -397,6 +526,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr)
        pmd_t *pmd;
        int rc;
 
+       BUG_ON(gmap_is_shadow(gmap));
        /* Create higher level tables in the gmap page table */
        table = gmap->table;
        if ((gmap->asce & _ASCE_TYPE_MASK) >= _ASCE_TYPE_REGION1) {
@@ -552,116 +682,1412 @@ static LIST_HEAD(gmap_notifier_list);
 static DEFINE_SPINLOCK(gmap_notifier_lock);
 
 /**
- * gmap_register_ipte_notifier - register a pte invalidation callback
+ * gmap_register_pte_notifier - register a pte invalidation callback
  * @nb: pointer to the gmap notifier block
  */
-void gmap_register_ipte_notifier(struct gmap_notifier *nb)
+void gmap_register_pte_notifier(struct gmap_notifier *nb)
 {
        spin_lock(&gmap_notifier_lock);
-       list_add(&nb->list, &gmap_notifier_list);
+       list_add_rcu(&nb->list, &gmap_notifier_list);
        spin_unlock(&gmap_notifier_lock);
 }
-EXPORT_SYMBOL_GPL(gmap_register_ipte_notifier);
+EXPORT_SYMBOL_GPL(gmap_register_pte_notifier);
 
 /**
- * gmap_unregister_ipte_notifier - remove a pte invalidation callback
+ * gmap_unregister_pte_notifier - remove a pte invalidation callback
  * @nb: pointer to the gmap notifier block
  */
-void gmap_unregister_ipte_notifier(struct gmap_notifier *nb)
+void gmap_unregister_pte_notifier(struct gmap_notifier *nb)
 {
        spin_lock(&gmap_notifier_lock);
-       list_del_init(&nb->list);
+       list_del_rcu(&nb->list);
        spin_unlock(&gmap_notifier_lock);
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(gmap_unregister_pte_notifier);
+
+/**
+ * gmap_call_notifier - call all registered invalidation callbacks
+ * @gmap: pointer to guest mapping meta data structure
+ * @start: start virtual address in the guest address space
+ * @end: end virtual address in the guest address space
+ */
+static void gmap_call_notifier(struct gmap *gmap, unsigned long start,
+                              unsigned long end)
+{
+       struct gmap_notifier *nb;
+
+       list_for_each_entry(nb, &gmap_notifier_list, list)
+               nb->notifier_call(gmap, start, end);
+}
+
+/**
+ * gmap_table_walk - walk the gmap page tables
+ * @gmap: pointer to guest mapping meta data structure
+ * @gaddr: virtual address in the guest address space
+ * @level: page table level to stop at
+ *
+ * Returns a table entry pointer for the given guest address and @level
+ * @level=0 : returns a pointer to a page table table entry (or NULL)
+ * @level=1 : returns a pointer to a segment table entry (or NULL)
+ * @level=2 : returns a pointer to a region-3 table entry (or NULL)
+ * @level=3 : returns a pointer to a region-2 table entry (or NULL)
+ * @level=4 : returns a pointer to a region-1 table entry (or NULL)
+ *
+ * Returns NULL if the gmap page tables could not be walked to the
+ * requested level.
+ *
+ * Note: Can also be called for shadow gmaps.
+ */
+static inline unsigned long *gmap_table_walk(struct gmap *gmap,
+                                            unsigned long gaddr, int level)
+{
+       unsigned long *table;
+
+       if ((gmap->asce & _ASCE_TYPE_MASK) + 4 < (level * 4))
+               return NULL;
+       if (gmap_is_shadow(gmap) && gmap->removed)
+               return NULL;
+       if (gaddr & (-1UL << (31 + ((gmap->asce & _ASCE_TYPE_MASK) >> 2)*11)))
+               return NULL;
+       table = gmap->table;
+       switch (gmap->asce & _ASCE_TYPE_MASK) {
+       case _ASCE_TYPE_REGION1:
+               table += (gaddr >> 53) & 0x7ff;
+               if (level == 4)
+                       break;
+               if (*table & _REGION_ENTRY_INVALID)
+                       return NULL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+               /* Fallthrough */
+       case _ASCE_TYPE_REGION2:
+               table += (gaddr >> 42) & 0x7ff;
+               if (level == 3)
+                       break;
+               if (*table & _REGION_ENTRY_INVALID)
+                       return NULL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+               /* Fallthrough */
+       case _ASCE_TYPE_REGION3:
+               table += (gaddr >> 31) & 0x7ff;
+               if (level == 2)
+                       break;
+               if (*table & _REGION_ENTRY_INVALID)
+                       return NULL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+               /* Fallthrough */
+       case _ASCE_TYPE_SEGMENT:
+               table += (gaddr >> 20) & 0x7ff;
+               if (level == 1)
+                       break;
+               if (*table & _REGION_ENTRY_INVALID)
+                       return NULL;
+               table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
+               table += (gaddr >> 12) & 0xff;
+       }
+       return table;
+}
+
+/**
+ * gmap_pte_op_walk - walk the gmap page table, get the page table lock
+ *                   and return the pte pointer
+ * @gmap: pointer to guest mapping meta data structure
+ * @gaddr: virtual address in the guest address space
+ * @ptl: pointer to the spinlock pointer
+ *
+ * Returns a pointer to the locked pte for a guest address, or NULL
+ *
+ * Note: Can also be called for shadow gmaps.
+ */
+static pte_t *gmap_pte_op_walk(struct gmap *gmap, unsigned long gaddr,
+                              spinlock_t **ptl)
+{
+       unsigned long *table;
+
+       if (gmap_is_shadow(gmap))
+               spin_lock(&gmap->guest_table_lock);
+       /* Walk the gmap page table, lock and get pte pointer */
+       table = gmap_table_walk(gmap, gaddr, 1); /* get segment pointer */
+       if (!table || *table & _SEGMENT_ENTRY_INVALID) {
+               if (gmap_is_shadow(gmap))
+                       spin_unlock(&gmap->guest_table_lock);
+               return NULL;
+       }
+       if (gmap_is_shadow(gmap)) {
+               *ptl = &gmap->guest_table_lock;
+               return pte_offset_map((pmd_t *) table, gaddr);
+       }
+       return pte_alloc_map_lock(gmap->mm, (pmd_t *) table, gaddr, ptl);
+}
+
+/**
+ * gmap_pte_op_fixup - force a page in and connect the gmap page table
+ * @gmap: pointer to guest mapping meta data structure
+ * @gaddr: virtual address in the guest address space
+ * @vmaddr: address in the host process address space
+ * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
+ *
+ * Returns 0 if the caller can retry __gmap_translate (might fail again),
+ * -ENOMEM if out of memory and -EFAULT if anything goes wrong while fixing
+ * up or connecting the gmap page table.
+ */
+static int gmap_pte_op_fixup(struct gmap *gmap, unsigned long gaddr,
+                            unsigned long vmaddr, int prot)
+{
+       struct mm_struct *mm = gmap->mm;
+       unsigned int fault_flags;
+       bool unlocked = false;
+
+       BUG_ON(gmap_is_shadow(gmap));
+       fault_flags = (prot == PROT_WRITE) ? FAULT_FLAG_WRITE : 0;
+       if (fixup_user_fault(current, mm, vmaddr, fault_flags, &unlocked))
+               return -EFAULT;
+       if (unlocked)
+               /* lost mmap_sem, caller has to retry __gmap_translate */
+               return 0;
+       /* Connect the page tables */
+       return __gmap_link(gmap, gaddr, vmaddr);
 }
-EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier);
 
 /**
- * gmap_ipte_notify - mark a range of ptes for invalidation notification
+ * gmap_pte_op_end - release the page table lock
+ * @ptl: pointer to the spinlock pointer
+ */
+static void gmap_pte_op_end(spinlock_t *ptl)
+{
+       spin_unlock(ptl);
+}
+
+/*
+ * gmap_protect_range - remove access rights to memory and set pgste bits
  * @gmap: pointer to guest mapping meta data structure
  * @gaddr: virtual address in the guest address space
  * @len: size of area
+ * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
+ * @bits: pgste notification bits to set
  *
- * Returns 0 if for each page in the given range a gmap mapping exists and
- * the invalidation notification could be set. If the gmap mapping is missing
- * for one or more pages -EFAULT is returned. If no memory could be allocated
- * -ENOMEM is returned. This function establishes missing page table entries.
+ * Returns 0 if successfully protected, -ENOMEM if out of memory and
+ * -EFAULT if gaddr is invalid (or mapping for shadows is missing).
+ *
+ * Called with sg->mm->mmap_sem in read.
+ *
+ * Note: Can also be called for shadow gmaps.
  */
-int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len)
+static int gmap_protect_range(struct gmap *gmap, unsigned long gaddr,
+                             unsigned long len, int prot, unsigned long bits)
 {
-       unsigned long addr;
+       unsigned long vmaddr;
        spinlock_t *ptl;
        pte_t *ptep;
-       bool unlocked;
-       int rc = 0;
+       int rc;
+
+       while (len) {
+               rc = -EAGAIN;
+               ptep = gmap_pte_op_walk(gmap, gaddr, &ptl);
+               if (ptep) {
+                       rc = ptep_force_prot(gmap->mm, gaddr, ptep, prot, bits);
+                       gmap_pte_op_end(ptl);
+               }
+               if (rc) {
+                       vmaddr = __gmap_translate(gmap, gaddr);
+                       if (IS_ERR_VALUE(vmaddr))
+                               return vmaddr;
+                       rc = gmap_pte_op_fixup(gmap, gaddr, vmaddr, prot);
+                       if (rc)
+                               return rc;
+                       continue;
+               }
+               gaddr += PAGE_SIZE;
+               len -= PAGE_SIZE;
+       }
+       return 0;
+}
+
+/**
+ * gmap_mprotect_notify - change access rights for a range of ptes and
+ *                        call the notifier if any pte changes again
+ * @gmap: pointer to guest mapping meta data structure
+ * @gaddr: virtual address in the guest address space
+ * @len: size of area
+ * @prot: indicates access rights: PROT_NONE, PROT_READ or PROT_WRITE
+ *
+ * Returns 0 if for each page in the given range a gmap mapping exists,
+ * the new access rights could be set and the notifier could be armed.
+ * If the gmap mapping is missing for one or more pages -EFAULT is
+ * returned. If no memory could be allocated -ENOMEM is returned.
+ * This function establishes missing page table entries.
+ */
+int gmap_mprotect_notify(struct gmap *gmap, unsigned long gaddr,
+                        unsigned long len, int prot)
+{
+       int rc;
 
-       if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK))
+       if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK) || gmap_is_shadow(gmap))
+               return -EINVAL;
+       if (!MACHINE_HAS_ESOP && prot == PROT_READ)
                return -EINVAL;
        down_read(&gmap->mm->mmap_sem);
-       while (len) {
-               unlocked = false;
-               /* Convert gmap address and connect the page tables */
-               addr = __gmap_translate(gmap, gaddr);
-               if (IS_ERR_VALUE(addr)) {
-                       rc = addr;
-                       break;
+       rc = gmap_protect_range(gmap, gaddr, len, prot, PGSTE_IN_BIT);
+       up_read(&gmap->mm->mmap_sem);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_mprotect_notify);
+
+/**
+ * gmap_read_table - get an unsigned long value from a guest page table using
+ *                   absolute addressing, without marking the page referenced.
+ * @gmap: pointer to guest mapping meta data structure
+ * @gaddr: virtual address in the guest address space
+ * @val: pointer to the unsigned long value to return
+ *
+ * Returns 0 if the value was read, -ENOMEM if out of memory and -EFAULT
+ * if reading using the virtual address failed.
+ *
+ * Called with gmap->mm->mmap_sem in read.
+ */
+int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val)
+{
+       unsigned long address, vmaddr;
+       spinlock_t *ptl;
+       pte_t *ptep, pte;
+       int rc;
+
+       while (1) {
+               rc = -EAGAIN;
+               ptep = gmap_pte_op_walk(gmap, gaddr, &ptl);
+               if (ptep) {
+                       pte = *ptep;
+                       if (pte_present(pte) && (pte_val(pte) & _PAGE_READ)) {
+                               address = pte_val(pte) & PAGE_MASK;
+                               address += gaddr & ~PAGE_MASK;
+                               *val = *(unsigned long *) address;
+                               pte_val(*ptep) |= _PAGE_YOUNG;
+                               /* Do *NOT* clear the _PAGE_INVALID bit! */
+                               rc = 0;
+                       }
+                       gmap_pte_op_end(ptl);
                }
-               /* Get the page mapped */
-               if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE,
-                                    &unlocked)) {
-                       rc = -EFAULT;
+               if (!rc)
+                       break;
+               vmaddr = __gmap_translate(gmap, gaddr);
+               if (IS_ERR_VALUE(vmaddr)) {
+                       rc = vmaddr;
                        break;
                }
-               /* While trying to map mmap_sem got unlocked. Let us retry */
-               if (unlocked)
-                       continue;
-               rc = __gmap_link(gmap, gaddr, addr);
+               rc = gmap_pte_op_fixup(gmap, gaddr, vmaddr, PROT_READ);
                if (rc)
                        break;
-               /* Walk the process page table, lock and get pte pointer */
-               ptep = get_locked_pte(gmap->mm, addr, &ptl);
-               VM_BUG_ON(!ptep);
-               /* Set notification bit in the pgste of the pte */
-               if ((pte_val(*ptep) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) {
-                       ptep_set_notify(gmap->mm, addr, ptep);
-                       gaddr += PAGE_SIZE;
-                       len -= PAGE_SIZE;
-               }
-               pte_unmap_unlock(ptep, ptl);
        }
-       up_read(&gmap->mm->mmap_sem);
        return rc;
 }
-EXPORT_SYMBOL_GPL(gmap_ipte_notify);
+EXPORT_SYMBOL_GPL(gmap_read_table);
 
 /**
- * ptep_notify - call all invalidation callbacks for a specific pte.
- * @mm: pointer to the process mm_struct
- * @addr: virtual address in the process address space
- * @pte: pointer to the page table entry
+ * gmap_insert_rmap - add a rmap to the host_to_rmap radix tree
+ * @sg: pointer to the shadow guest address space structure
+ * @vmaddr: vm address associated with the rmap
+ * @rmap: pointer to the rmap structure
  *
- * This function is assumed to be called with the page table lock held
- * for the pte to notify.
+ * Called with the sg->guest_table_lock
  */
-void ptep_notify(struct mm_struct *mm, unsigned long vmaddr, pte_t *pte)
+static inline void gmap_insert_rmap(struct gmap *sg, unsigned long vmaddr,
+                                   struct gmap_rmap *rmap)
 {
-       unsigned long offset, gaddr;
-       unsigned long *table;
-       struct gmap_notifier *nb;
-       struct gmap *gmap;
+       void **slot;
 
-       offset = ((unsigned long) pte) & (255 * sizeof(pte_t));
-       offset = offset * (4096 / sizeof(pte_t));
-       spin_lock(&gmap_notifier_lock);
-       list_for_each_entry(gmap, &mm->context.gmap_list, list) {
-               table = radix_tree_lookup(&gmap->host_to_guest,
-                                         vmaddr >> PMD_SHIFT);
-               if (!table)
+       BUG_ON(!gmap_is_shadow(sg));
+       slot = radix_tree_lookup_slot(&sg->host_to_rmap, vmaddr >> PAGE_SHIFT);
+       if (slot) {
+               rmap->next = radix_tree_deref_slot_protected(slot,
+                                                       &sg->guest_table_lock);
+               radix_tree_replace_slot(slot, rmap);
+       } else {
+               rmap->next = NULL;
+               radix_tree_insert(&sg->host_to_rmap, vmaddr >> PAGE_SHIFT,
+                                 rmap);
+       }
+}
+
+/**
+ * gmap_protect_rmap - modify access rights to memory and create an rmap
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow gmap
+ * @paddr: address in the parent guest address space
+ * @len: length of the memory area to protect
+ * @prot: indicates access rights: none, read-only or read-write
+ *
+ * Returns 0 if successfully protected and the rmap was created, -ENOMEM
+ * if out of memory and -EFAULT if paddr is invalid.
+ */
+static int gmap_protect_rmap(struct gmap *sg, unsigned long raddr,
+                            unsigned long paddr, unsigned long len, int prot)
+{
+       struct gmap *parent;
+       struct gmap_rmap *rmap;
+       unsigned long vmaddr;
+       spinlock_t *ptl;
+       pte_t *ptep;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       parent = sg->parent;
+       while (len) {
+               vmaddr = __gmap_translate(parent, paddr);
+               if (IS_ERR_VALUE(vmaddr))
+                       return vmaddr;
+               rmap = kzalloc(sizeof(*rmap), GFP_KERNEL);
+               if (!rmap)
+                       return -ENOMEM;
+               rmap->raddr = raddr;
+               rc = radix_tree_preload(GFP_KERNEL);
+               if (rc) {
+                       kfree(rmap);
+                       return rc;
+               }
+               rc = -EAGAIN;
+               ptep = gmap_pte_op_walk(parent, paddr, &ptl);
+               if (ptep) {
+                       spin_lock(&sg->guest_table_lock);
+                       rc = ptep_force_prot(parent->mm, paddr, ptep, prot,
+                                            PGSTE_VSIE_BIT);
+                       if (!rc)
+                               gmap_insert_rmap(sg, vmaddr, rmap);
+                       spin_unlock(&sg->guest_table_lock);
+                       gmap_pte_op_end(ptl);
+               }
+               radix_tree_preload_end();
+               if (rc) {
+                       kfree(rmap);
+                       rc = gmap_pte_op_fixup(parent, paddr, vmaddr, prot);
+                       if (rc)
+                               return rc;
                        continue;
-               gaddr = __gmap_segment_gaddr(table) + offset;
-               list_for_each_entry(nb, &gmap_notifier_list, list)
-                       nb->notifier_call(gmap, gaddr);
+               }
+               paddr += PAGE_SIZE;
+               len -= PAGE_SIZE;
        }
-       spin_unlock(&gmap_notifier_lock);
+       return 0;
+}
+
+#define _SHADOW_RMAP_MASK      0x7
+#define _SHADOW_RMAP_REGION1   0x5
+#define _SHADOW_RMAP_REGION2   0x4
+#define _SHADOW_RMAP_REGION3   0x3
+#define _SHADOW_RMAP_SEGMENT   0x2
+#define _SHADOW_RMAP_PGTABLE   0x1
+
+/**
+ * gmap_idte_one - invalidate a single region or segment table entry
+ * @asce: region or segment table *origin* + table-type bits
+ * @vaddr: virtual address to identify the table entry to flush
+ *
+ * The invalid bit of a single region or segment table entry is set
+ * and the associated TLB entries depending on the entry are flushed.
+ * The table-type of the @asce identifies the portion of the @vaddr
+ * that is used as the invalidation index.
+ */
+static inline void gmap_idte_one(unsigned long asce, unsigned long vaddr)
+{
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,%0,%1,0,0"
+               : : "a" (asce), "a" (vaddr) : "cc", "memory");
+}
+
+/**
+ * gmap_unshadow_page - remove a page from a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void gmap_unshadow_page(struct gmap *sg, unsigned long raddr)
+{
+       unsigned long *table;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       table = gmap_table_walk(sg, raddr, 0); /* get page table pointer */
+       if (!table || *table & _PAGE_INVALID)
+               return;
+       gmap_call_notifier(sg, raddr, raddr + (1UL << 12) - 1);
+       ptep_unshadow_pte(sg->mm, raddr, (pte_t *) table);
+}
+
+/**
+ * __gmap_unshadow_pgt - remove all entries from a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ * @pgt: pointer to the start of a shadow page table
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void __gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr,
+                               unsigned long *pgt)
+{
+       int i;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       for (i = 0; i < 256; i++, raddr += 1UL << 12)
+               pgt[i] = _PAGE_INVALID;
+}
+
+/**
+ * gmap_unshadow_pgt - remove a shadow page table from a segment entry
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: address in the shadow guest address space
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr)
+{
+       unsigned long sto, *ste, *pgt;
+       struct page *page;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       ste = gmap_table_walk(sg, raddr, 1); /* get segment pointer */
+       if (!ste || !(*ste & _SEGMENT_ENTRY_ORIGIN))
+               return;
+       gmap_call_notifier(sg, raddr, raddr + (1UL << 20) - 1);
+       sto = (unsigned long) (ste - ((raddr >> 20) & 0x7ff));
+       gmap_idte_one(sto | _ASCE_TYPE_SEGMENT, raddr);
+       pgt = (unsigned long *)(*ste & _SEGMENT_ENTRY_ORIGIN);
+       *ste = _SEGMENT_ENTRY_EMPTY;
+       __gmap_unshadow_pgt(sg, raddr, pgt);
+       /* Free page table */
+       page = pfn_to_page(__pa(pgt) >> PAGE_SHIFT);
+       list_del(&page->lru);
+       page_table_free_pgste(page);
+}
+
+/**
+ * __gmap_unshadow_sgt - remove all entries from a shadow segment table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ * @sgt: pointer to the start of a shadow segment table
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void __gmap_unshadow_sgt(struct gmap *sg, unsigned long raddr,
+                               unsigned long *sgt)
+{
+       unsigned long asce, *pgt;
+       struct page *page;
+       int i;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       asce = (unsigned long) sgt | _ASCE_TYPE_SEGMENT;
+       for (i = 0; i < 2048; i++, raddr += 1UL << 20) {
+               if (!(sgt[i] & _SEGMENT_ENTRY_ORIGIN))
+                       continue;
+               pgt = (unsigned long *)(sgt[i] & _REGION_ENTRY_ORIGIN);
+               sgt[i] = _SEGMENT_ENTRY_EMPTY;
+               __gmap_unshadow_pgt(sg, raddr, pgt);
+               /* Free page table */
+               page = pfn_to_page(__pa(pgt) >> PAGE_SHIFT);
+               list_del(&page->lru);
+               page_table_free_pgste(page);
+       }
+}
+
+/**
+ * gmap_unshadow_sgt - remove a shadow segment table from a region-3 entry
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ *
+ * Called with the shadow->guest_table_lock
+ */
+static void gmap_unshadow_sgt(struct gmap *sg, unsigned long raddr)
+{
+       unsigned long r3o, *r3e, *sgt;
+       struct page *page;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       r3e = gmap_table_walk(sg, raddr, 2); /* get region-3 pointer */
+       if (!r3e || !(*r3e & _REGION_ENTRY_ORIGIN))
+               return;
+       gmap_call_notifier(sg, raddr, raddr + (1UL << 31) - 1);
+       r3o = (unsigned long) (r3e - ((raddr >> 31) & 0x7ff));
+       gmap_idte_one(r3o | _ASCE_TYPE_REGION3, raddr);
+       sgt = (unsigned long *)(*r3e & _REGION_ENTRY_ORIGIN);
+       *r3e = _REGION3_ENTRY_EMPTY;
+       __gmap_unshadow_sgt(sg, raddr, sgt);
+       /* Free segment table */
+       page = pfn_to_page(__pa(sgt) >> PAGE_SHIFT);
+       list_del(&page->lru);
+       __free_pages(page, 2);
+}
+
+/**
+ * __gmap_unshadow_r3t - remove all entries from a shadow region-3 table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: address in the shadow guest address space
+ * @r3t: pointer to the start of a shadow region-3 table
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void __gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr,
+                               unsigned long *r3t)
+{
+       unsigned long asce, *sgt;
+       struct page *page;
+       int i;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       asce = (unsigned long) r3t | _ASCE_TYPE_REGION3;
+       for (i = 0; i < 2048; i++, raddr += 1UL << 31) {
+               if (!(r3t[i] & _REGION_ENTRY_ORIGIN))
+                       continue;
+               sgt = (unsigned long *)(r3t[i] & _REGION_ENTRY_ORIGIN);
+               r3t[i] = _REGION3_ENTRY_EMPTY;
+               __gmap_unshadow_sgt(sg, raddr, sgt);
+               /* Free segment table */
+               page = pfn_to_page(__pa(sgt) >> PAGE_SHIFT);
+               list_del(&page->lru);
+               __free_pages(page, 2);
+       }
+}
+
+/**
+ * gmap_unshadow_r3t - remove a shadow region-3 table from a region-2 entry
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr)
+{
+       unsigned long r2o, *r2e, *r3t;
+       struct page *page;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       r2e = gmap_table_walk(sg, raddr, 3); /* get region-2 pointer */
+       if (!r2e || !(*r2e & _REGION_ENTRY_ORIGIN))
+               return;
+       gmap_call_notifier(sg, raddr, raddr + (1UL << 42) - 1);
+       r2o = (unsigned long) (r2e - ((raddr >> 42) & 0x7ff));
+       gmap_idte_one(r2o | _ASCE_TYPE_REGION2, raddr);
+       r3t = (unsigned long *)(*r2e & _REGION_ENTRY_ORIGIN);
+       *r2e = _REGION2_ENTRY_EMPTY;
+       __gmap_unshadow_r3t(sg, raddr, r3t);
+       /* Free region 3 table */
+       page = pfn_to_page(__pa(r3t) >> PAGE_SHIFT);
+       list_del(&page->lru);
+       __free_pages(page, 2);
+}
+
+/**
+ * __gmap_unshadow_r2t - remove all entries from a shadow region-2 table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ * @r2t: pointer to the start of a shadow region-2 table
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void __gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr,
+                               unsigned long *r2t)
+{
+       unsigned long asce, *r3t;
+       struct page *page;
+       int i;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       asce = (unsigned long) r2t | _ASCE_TYPE_REGION2;
+       for (i = 0; i < 2048; i++, raddr += 1UL << 42) {
+               if (!(r2t[i] & _REGION_ENTRY_ORIGIN))
+                       continue;
+               r3t = (unsigned long *)(r2t[i] & _REGION_ENTRY_ORIGIN);
+               r2t[i] = _REGION2_ENTRY_EMPTY;
+               __gmap_unshadow_r3t(sg, raddr, r3t);
+               /* Free region 3 table */
+               page = pfn_to_page(__pa(r3t) >> PAGE_SHIFT);
+               list_del(&page->lru);
+               __free_pages(page, 2);
+       }
+}
+
+/**
+ * gmap_unshadow_r2t - remove a shadow region-2 table from a region-1 entry
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ *
+ * Called with the sg->guest_table_lock
+ */
+static void gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr)
+{
+       unsigned long r1o, *r1e, *r2t;
+       struct page *page;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       r1e = gmap_table_walk(sg, raddr, 4); /* get region-1 pointer */
+       if (!r1e || !(*r1e & _REGION_ENTRY_ORIGIN))
+               return;
+       gmap_call_notifier(sg, raddr, raddr + (1UL << 53) - 1);
+       r1o = (unsigned long) (r1e - ((raddr >> 53) & 0x7ff));
+       gmap_idte_one(r1o | _ASCE_TYPE_REGION1, raddr);
+       r2t = (unsigned long *)(*r1e & _REGION_ENTRY_ORIGIN);
+       *r1e = _REGION1_ENTRY_EMPTY;
+       __gmap_unshadow_r2t(sg, raddr, r2t);
+       /* Free region 2 table */
+       page = pfn_to_page(__pa(r2t) >> PAGE_SHIFT);
+       list_del(&page->lru);
+       __free_pages(page, 2);
+}
+
+/**
+ * __gmap_unshadow_r1t - remove all entries from a shadow region-1 table
+ * @sg: pointer to the shadow guest address space structure
+ * @raddr: rmap address in the shadow guest address space
+ * @r1t: pointer to the start of a shadow region-1 table
+ *
+ * Called with the shadow->guest_table_lock
+ */
+static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,
+                               unsigned long *r1t)
+{
+       unsigned long asce, *r2t;
+       struct page *page;
+       int i;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       asce = (unsigned long) r1t | _ASCE_TYPE_REGION1;
+       for (i = 0; i < 2048; i++, raddr += 1UL << 53) {
+               if (!(r1t[i] & _REGION_ENTRY_ORIGIN))
+                       continue;
+               r2t = (unsigned long *)(r1t[i] & _REGION_ENTRY_ORIGIN);
+               __gmap_unshadow_r2t(sg, raddr, r2t);
+               /* Clear entry and flush translation r1t -> r2t */
+               gmap_idte_one(asce, raddr);
+               r1t[i] = _REGION1_ENTRY_EMPTY;
+               /* Free region 2 table */
+               page = pfn_to_page(__pa(r2t) >> PAGE_SHIFT);
+               list_del(&page->lru);
+               __free_pages(page, 2);
+       }
+}
+
+/**
+ * gmap_unshadow - remove a shadow page table completely
+ * @sg: pointer to the shadow guest address space structure
+ *
+ * Called with sg->guest_table_lock
+ */
+static void gmap_unshadow(struct gmap *sg)
+{
+       unsigned long *table;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       if (sg->removed)
+               return;
+       sg->removed = 1;
+       gmap_call_notifier(sg, 0, -1UL);
+       gmap_flush_tlb(sg);
+       table = (unsigned long *)(sg->asce & _ASCE_ORIGIN);
+       switch (sg->asce & _ASCE_TYPE_MASK) {
+       case _ASCE_TYPE_REGION1:
+               __gmap_unshadow_r1t(sg, 0, table);
+               break;
+       case _ASCE_TYPE_REGION2:
+               __gmap_unshadow_r2t(sg, 0, table);
+               break;
+       case _ASCE_TYPE_REGION3:
+               __gmap_unshadow_r3t(sg, 0, table);
+               break;
+       case _ASCE_TYPE_SEGMENT:
+               __gmap_unshadow_sgt(sg, 0, table);
+               break;
+       }
+}
+
+/**
+ * gmap_find_shadow - find a specific asce in the list of shadow tables
+ * @parent: pointer to the parent gmap
+ * @asce: ASCE for which the shadow table is created
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * Returns the pointer to a gmap if a shadow table with the given asce is
+ * already available, ERR_PTR(-EAGAIN) if another one is just being created,
+ * otherwise NULL
+ */
+static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce,
+                                    int edat_level)
+{
+       struct gmap *sg;
+
+       list_for_each_entry(sg, &parent->children, list) {
+               if (sg->orig_asce != asce || sg->edat_level != edat_level ||
+                   sg->removed)
+                       continue;
+               if (!sg->initialized)
+                       return ERR_PTR(-EAGAIN);
+               atomic_inc(&sg->ref_count);
+               return sg;
+       }
+       return NULL;
+}
+
+/**
+ * gmap_shadow_valid - check if a shadow guest address space matches the
+ *                     given properties and is still valid
+ * @sg: pointer to the shadow guest address space structure
+ * @asce: ASCE for which the shadow table is requested
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * Returns 1 if the gmap shadow is still valid and matches the given
+ * properties, the caller can continue using it. Returns 0 otherwise, the
+ * caller has to request a new shadow gmap in this case.
+ *
+ */
+int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level)
+{
+       if (sg->removed)
+               return 0;
+       return sg->orig_asce == asce && sg->edat_level == edat_level;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_valid);
+
+/**
+ * gmap_shadow - create/find a shadow guest address space
+ * @parent: pointer to the parent gmap
+ * @asce: ASCE for which the shadow table is created
+ * @edat_level: edat level to be used for the shadow translation
+ *
+ * The pages of the top level page table referred by the asce parameter
+ * will be set to read-only and marked in the PGSTEs of the kvm process.
+ * The shadow table will be removed automatically on any change to the
+ * PTE mapping for the source table.
+ *
+ * Returns a guest address space structure, ERR_PTR(-ENOMEM) if out of memory,
+ * ERR_PTR(-EAGAIN) if the caller has to retry and ERR_PTR(-EFAULT) if the
+ * parent gmap table could not be protected.
+ */
+struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
+                        int edat_level)
+{
+       struct gmap *sg, *new;
+       unsigned long limit;
+       int rc;
+
+       BUG_ON(gmap_is_shadow(parent));
+       spin_lock(&parent->shadow_lock);
+       sg = gmap_find_shadow(parent, asce, edat_level);
+       spin_unlock(&parent->shadow_lock);
+       if (sg)
+               return sg;
+       /* Create a new shadow gmap */
+       limit = -1UL >> (33 - (((asce & _ASCE_TYPE_MASK) >> 2) * 11));
+       if (asce & _ASCE_REAL_SPACE)
+               limit = -1UL;
+       new = gmap_alloc(limit);
+       if (!new)
+               return ERR_PTR(-ENOMEM);
+       new->mm = parent->mm;
+       new->parent = gmap_get(parent);
+       new->orig_asce = asce;
+       new->edat_level = edat_level;
+       new->initialized = false;
+       spin_lock(&parent->shadow_lock);
+       /* Recheck if another CPU created the same shadow */
+       sg = gmap_find_shadow(parent, asce, edat_level);
+       if (sg) {
+               spin_unlock(&parent->shadow_lock);
+               gmap_free(new);
+               return sg;
+       }
+       if (asce & _ASCE_REAL_SPACE) {
+               /* only allow one real-space gmap shadow */
+               list_for_each_entry(sg, &parent->children, list) {
+                       if (sg->orig_asce & _ASCE_REAL_SPACE) {
+                               spin_lock(&sg->guest_table_lock);
+                               gmap_unshadow(sg);
+                               spin_unlock(&sg->guest_table_lock);
+                               list_del(&sg->list);
+                               gmap_put(sg);
+                               break;
+                       }
+               }
+       }
+       atomic_set(&new->ref_count, 2);
+       list_add(&new->list, &parent->children);
+       if (asce & _ASCE_REAL_SPACE) {
+               /* nothing to protect, return right away */
+               new->initialized = true;
+               spin_unlock(&parent->shadow_lock);
+               return new;
+       }
+       spin_unlock(&parent->shadow_lock);
+       /* protect after insertion, so it will get properly invalidated */
+       down_read(&parent->mm->mmap_sem);
+       rc = gmap_protect_range(parent, asce & _ASCE_ORIGIN,
+                               ((asce & _ASCE_TABLE_LENGTH) + 1) * 4096,
+                               PROT_READ, PGSTE_VSIE_BIT);
+       up_read(&parent->mm->mmap_sem);
+       spin_lock(&parent->shadow_lock);
+       new->initialized = true;
+       if (rc) {
+               list_del(&new->list);
+               gmap_free(new);
+               new = ERR_PTR(rc);
+       }
+       spin_unlock(&parent->shadow_lock);
+       return new;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow);
+
+/**
+ * gmap_shadow_r2t - create an empty shadow region 2 table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @r2t: parent gmap address of the region 2 table to get shadowed
+ * @fake: r2t references contiguous guest memory block, not a r2t
+ *
+ * The r2t parameter specifies the address of the source table. The
+ * four pages of the source table are made read-only in the parent gmap
+ * address space. A write to the source table area @r2t will automatically
+ * remove the shadow r2 table and all of its decendents.
+ *
+ * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
+ * shadow table structure is incomplete, -ENOMEM if out of memory and
+ * -EFAULT if an address in the parent gmap could not be resolved.
+ *
+ * Called with sg->mm->mmap_sem in read.
+ */
+int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
+                   int fake)
+{
+       unsigned long raddr, origin, offset, len;
+       unsigned long *s_r2t, *table;
+       struct page *page;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       /* Allocate a shadow region second table */
+       page = alloc_pages(GFP_KERNEL, 2);
+       if (!page)
+               return -ENOMEM;
+       page->index = r2t & _REGION_ENTRY_ORIGIN;
+       if (fake)
+               page->index |= GMAP_SHADOW_FAKE_TABLE;
+       s_r2t = (unsigned long *) page_to_phys(page);
+       /* Install shadow region second table */
+       spin_lock(&sg->guest_table_lock);
+       table = gmap_table_walk(sg, saddr, 4); /* get region-1 pointer */
+       if (!table) {
+               rc = -EAGAIN;           /* Race with unshadow */
+               goto out_free;
+       }
+       if (!(*table & _REGION_ENTRY_INVALID)) {
+               rc = 0;                 /* Already established */
+               goto out_free;
+       } else if (*table & _REGION_ENTRY_ORIGIN) {
+               rc = -EAGAIN;           /* Race with shadow */
+               goto out_free;
+       }
+       crst_table_init(s_r2t, _REGION2_ENTRY_EMPTY);
+       /* mark as invalid as long as the parent table is not protected */
+       *table = (unsigned long) s_r2t | _REGION_ENTRY_LENGTH |
+                _REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= (r2t & _REGION_ENTRY_PROTECT);
+       list_add(&page->lru, &sg->crst_list);
+       if (fake) {
+               /* nothing to protect for fake tables */
+               *table &= ~_REGION_ENTRY_INVALID;
+               spin_unlock(&sg->guest_table_lock);
+               return 0;
+       }
+       spin_unlock(&sg->guest_table_lock);
+       /* Make r2t read-only in parent gmap page table */
+       raddr = (saddr & 0xffe0000000000000UL) | _SHADOW_RMAP_REGION1;
+       origin = r2t & _REGION_ENTRY_ORIGIN;
+       offset = ((r2t & _REGION_ENTRY_OFFSET) >> 6) * 4096;
+       len = ((r2t & _REGION_ENTRY_LENGTH) + 1) * 4096 - offset;
+       rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ);
+       spin_lock(&sg->guest_table_lock);
+       if (!rc) {
+               table = gmap_table_walk(sg, saddr, 4);
+               if (!table || (*table & _REGION_ENTRY_ORIGIN) !=
+                             (unsigned long) s_r2t)
+                       rc = -EAGAIN;           /* Race with unshadow */
+               else
+                       *table &= ~_REGION_ENTRY_INVALID;
+       } else {
+               gmap_unshadow_r2t(sg, raddr);
+       }
+       spin_unlock(&sg->guest_table_lock);
+       return rc;
+out_free:
+       spin_unlock(&sg->guest_table_lock);
+       __free_pages(page, 2);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_r2t);
+
+/**
+ * gmap_shadow_r3t - create a shadow region 3 table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @r3t: parent gmap address of the region 3 table to get shadowed
+ * @fake: r3t references contiguous guest memory block, not a r3t
+ *
+ * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
+ * shadow table structure is incomplete, -ENOMEM if out of memory and
+ * -EFAULT if an address in the parent gmap could not be resolved.
+ *
+ * Called with sg->mm->mmap_sem in read.
+ */
+int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
+                   int fake)
+{
+       unsigned long raddr, origin, offset, len;
+       unsigned long *s_r3t, *table;
+       struct page *page;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       /* Allocate a shadow region second table */
+       page = alloc_pages(GFP_KERNEL, 2);
+       if (!page)
+               return -ENOMEM;
+       page->index = r3t & _REGION_ENTRY_ORIGIN;
+       if (fake)
+               page->index |= GMAP_SHADOW_FAKE_TABLE;
+       s_r3t = (unsigned long *) page_to_phys(page);
+       /* Install shadow region second table */
+       spin_lock(&sg->guest_table_lock);
+       table = gmap_table_walk(sg, saddr, 3); /* get region-2 pointer */
+       if (!table) {
+               rc = -EAGAIN;           /* Race with unshadow */
+               goto out_free;
+       }
+       if (!(*table & _REGION_ENTRY_INVALID)) {
+               rc = 0;                 /* Already established */
+               goto out_free;
+       } else if (*table & _REGION_ENTRY_ORIGIN) {
+               rc = -EAGAIN;           /* Race with shadow */
+       }
+       crst_table_init(s_r3t, _REGION3_ENTRY_EMPTY);
+       /* mark as invalid as long as the parent table is not protected */
+       *table = (unsigned long) s_r3t | _REGION_ENTRY_LENGTH |
+                _REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= (r3t & _REGION_ENTRY_PROTECT);
+       list_add(&page->lru, &sg->crst_list);
+       if (fake) {
+               /* nothing to protect for fake tables */
+               *table &= ~_REGION_ENTRY_INVALID;
+               spin_unlock(&sg->guest_table_lock);
+               return 0;
+       }
+       spin_unlock(&sg->guest_table_lock);
+       /* Make r3t read-only in parent gmap page table */
+       raddr = (saddr & 0xfffffc0000000000UL) | _SHADOW_RMAP_REGION2;
+       origin = r3t & _REGION_ENTRY_ORIGIN;
+       offset = ((r3t & _REGION_ENTRY_OFFSET) >> 6) * 4096;
+       len = ((r3t & _REGION_ENTRY_LENGTH) + 1) * 4096 - offset;
+       rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ);
+       spin_lock(&sg->guest_table_lock);
+       if (!rc) {
+               table = gmap_table_walk(sg, saddr, 3);
+               if (!table || (*table & _REGION_ENTRY_ORIGIN) !=
+                             (unsigned long) s_r3t)
+                       rc = -EAGAIN;           /* Race with unshadow */
+               else
+                       *table &= ~_REGION_ENTRY_INVALID;
+       } else {
+               gmap_unshadow_r3t(sg, raddr);
+       }
+       spin_unlock(&sg->guest_table_lock);
+       return rc;
+out_free:
+       spin_unlock(&sg->guest_table_lock);
+       __free_pages(page, 2);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_r3t);
+
+/**
+ * gmap_shadow_sgt - create a shadow segment table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @sgt: parent gmap address of the segment table to get shadowed
+ * @fake: sgt references contiguous guest memory block, not a sgt
+ *
+ * Returns: 0 if successfully shadowed or already shadowed, -EAGAIN if the
+ * shadow table structure is incomplete, -ENOMEM if out of memory and
+ * -EFAULT if an address in the parent gmap could not be resolved.
+ *
+ * Called with sg->mm->mmap_sem in read.
+ */
+int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
+                   int fake)
+{
+       unsigned long raddr, origin, offset, len;
+       unsigned long *s_sgt, *table;
+       struct page *page;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg) || (sgt & _REGION3_ENTRY_LARGE));
+       /* Allocate a shadow segment table */
+       page = alloc_pages(GFP_KERNEL, 2);
+       if (!page)
+               return -ENOMEM;
+       page->index = sgt & _REGION_ENTRY_ORIGIN;
+       if (fake)
+               page->index |= GMAP_SHADOW_FAKE_TABLE;
+       s_sgt = (unsigned long *) page_to_phys(page);
+       /* Install shadow region second table */
+       spin_lock(&sg->guest_table_lock);
+       table = gmap_table_walk(sg, saddr, 2); /* get region-3 pointer */
+       if (!table) {
+               rc = -EAGAIN;           /* Race with unshadow */
+               goto out_free;
+       }
+       if (!(*table & _REGION_ENTRY_INVALID)) {
+               rc = 0;                 /* Already established */
+               goto out_free;
+       } else if (*table & _REGION_ENTRY_ORIGIN) {
+               rc = -EAGAIN;           /* Race with shadow */
+               goto out_free;
+       }
+       crst_table_init(s_sgt, _SEGMENT_ENTRY_EMPTY);
+       /* mark as invalid as long as the parent table is not protected */
+       *table = (unsigned long) s_sgt | _REGION_ENTRY_LENGTH |
+                _REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID;
+       if (sg->edat_level >= 1)
+               *table |= sgt & _REGION_ENTRY_PROTECT;
+       list_add(&page->lru, &sg->crst_list);
+       if (fake) {
+               /* nothing to protect for fake tables */
+               *table &= ~_REGION_ENTRY_INVALID;
+               spin_unlock(&sg->guest_table_lock);
+               return 0;
+       }
+       spin_unlock(&sg->guest_table_lock);
+       /* Make sgt read-only in parent gmap page table */
+       raddr = (saddr & 0xffffffff80000000UL) | _SHADOW_RMAP_REGION3;
+       origin = sgt & _REGION_ENTRY_ORIGIN;
+       offset = ((sgt & _REGION_ENTRY_OFFSET) >> 6) * 4096;
+       len = ((sgt & _REGION_ENTRY_LENGTH) + 1) * 4096 - offset;
+       rc = gmap_protect_rmap(sg, raddr, origin + offset, len, PROT_READ);
+       spin_lock(&sg->guest_table_lock);
+       if (!rc) {
+               table = gmap_table_walk(sg, saddr, 2);
+               if (!table || (*table & _REGION_ENTRY_ORIGIN) !=
+                             (unsigned long) s_sgt)
+                       rc = -EAGAIN;           /* Race with unshadow */
+               else
+                       *table &= ~_REGION_ENTRY_INVALID;
+       } else {
+               gmap_unshadow_sgt(sg, raddr);
+       }
+       spin_unlock(&sg->guest_table_lock);
+       return rc;
+out_free:
+       spin_unlock(&sg->guest_table_lock);
+       __free_pages(page, 2);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
+
+/**
+ * gmap_shadow_lookup_pgtable - find a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: the address in the shadow aguest address space
+ * @pgt: parent gmap address of the page table to get shadowed
+ * @dat_protection: if the pgtable is marked as protected by dat
+ * @fake: pgt references contiguous guest memory block, not a pgtable
+ *
+ * Returns 0 if the shadow page table was found and -EAGAIN if the page
+ * table was not found.
+ *
+ * Called with sg->mm->mmap_sem in read.
+ */
+int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
+                          unsigned long *pgt, int *dat_protection,
+                          int *fake)
+{
+       unsigned long *table;
+       struct page *page;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       spin_lock(&sg->guest_table_lock);
+       table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
+       if (table && !(*table & _SEGMENT_ENTRY_INVALID)) {
+               /* Shadow page tables are full pages (pte+pgste) */
+               page = pfn_to_page(*table >> PAGE_SHIFT);
+               *pgt = page->index & ~GMAP_SHADOW_FAKE_TABLE;
+               *dat_protection = !!(*table & _SEGMENT_ENTRY_PROTECT);
+               *fake = !!(page->index & GMAP_SHADOW_FAKE_TABLE);
+               rc = 0;
+       } else  {
+               rc = -EAGAIN;
+       }
+       spin_unlock(&sg->guest_table_lock);
+       return rc;
+
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_pgt_lookup);
+
+/**
+ * gmap_shadow_pgt - instantiate a shadow page table
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @pgt: parent gmap address of the page table to get shadowed
+ * @fake: pgt references contiguous guest memory block, not a pgtable
+ *
+ * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
+ * shadow table structure is incomplete, -ENOMEM if out of memory,
+ * -EFAULT if an address in the parent gmap could not be resolved and
+ *
+ * Called with gmap->mm->mmap_sem in read
+ */
+int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
+                   int fake)
+{
+       unsigned long raddr, origin;
+       unsigned long *s_pgt, *table;
+       struct page *page;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg) || (pgt & _SEGMENT_ENTRY_LARGE));
+       /* Allocate a shadow page table */
+       page = page_table_alloc_pgste(sg->mm);
+       if (!page)
+               return -ENOMEM;
+       page->index = pgt & _SEGMENT_ENTRY_ORIGIN;
+       if (fake)
+               page->index |= GMAP_SHADOW_FAKE_TABLE;
+       s_pgt = (unsigned long *) page_to_phys(page);
+       /* Install shadow page table */
+       spin_lock(&sg->guest_table_lock);
+       table = gmap_table_walk(sg, saddr, 1); /* get segment pointer */
+       if (!table) {
+               rc = -EAGAIN;           /* Race with unshadow */
+               goto out_free;
+       }
+       if (!(*table & _SEGMENT_ENTRY_INVALID)) {
+               rc = 0;                 /* Already established */
+               goto out_free;
+       } else if (*table & _SEGMENT_ENTRY_ORIGIN) {
+               rc = -EAGAIN;           /* Race with shadow */
+               goto out_free;
+       }
+       /* mark as invalid as long as the parent table is not protected */
+       *table = (unsigned long) s_pgt | _SEGMENT_ENTRY |
+                (pgt & _SEGMENT_ENTRY_PROTECT) | _SEGMENT_ENTRY_INVALID;
+       list_add(&page->lru, &sg->pt_list);
+       if (fake) {
+               /* nothing to protect for fake tables */
+               *table &= ~_SEGMENT_ENTRY_INVALID;
+               spin_unlock(&sg->guest_table_lock);
+               return 0;
+       }
+       spin_unlock(&sg->guest_table_lock);
+       /* Make pgt read-only in parent gmap page table (not the pgste) */
+       raddr = (saddr & 0xfffffffffff00000UL) | _SHADOW_RMAP_SEGMENT;
+       origin = pgt & _SEGMENT_ENTRY_ORIGIN & PAGE_MASK;
+       rc = gmap_protect_rmap(sg, raddr, origin, PAGE_SIZE, PROT_READ);
+       spin_lock(&sg->guest_table_lock);
+       if (!rc) {
+               table = gmap_table_walk(sg, saddr, 1);
+               if (!table || (*table & _SEGMENT_ENTRY_ORIGIN) !=
+                             (unsigned long) s_pgt)
+                       rc = -EAGAIN;           /* Race with unshadow */
+               else
+                       *table &= ~_SEGMENT_ENTRY_INVALID;
+       } else {
+               gmap_unshadow_pgt(sg, raddr);
+       }
+       spin_unlock(&sg->guest_table_lock);
+       return rc;
+out_free:
+       spin_unlock(&sg->guest_table_lock);
+       page_table_free_pgste(page);
+       return rc;
+
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_pgt);
+
+/**
+ * gmap_shadow_page - create a shadow page mapping
+ * @sg: pointer to the shadow guest address space structure
+ * @saddr: faulting address in the shadow gmap
+ * @pte: pte in parent gmap address space to get shadowed
+ *
+ * Returns 0 if successfully shadowed or already shadowed, -EAGAIN if the
+ * shadow table structure is incomplete, -ENOMEM if out of memory and
+ * -EFAULT if an address in the parent gmap could not be resolved.
+ *
+ * Called with sg->mm->mmap_sem in read.
+ */
+int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte)
+{
+       struct gmap *parent;
+       struct gmap_rmap *rmap;
+       unsigned long vmaddr, paddr;
+       spinlock_t *ptl;
+       pte_t *sptep, *tptep;
+       int prot;
+       int rc;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       parent = sg->parent;
+       prot = (pte_val(pte) & _PAGE_PROTECT) ? PROT_READ : PROT_WRITE;
+
+       rmap = kzalloc(sizeof(*rmap), GFP_KERNEL);
+       if (!rmap)
+               return -ENOMEM;
+       rmap->raddr = (saddr & PAGE_MASK) | _SHADOW_RMAP_PGTABLE;
+
+       while (1) {
+               paddr = pte_val(pte) & PAGE_MASK;
+               vmaddr = __gmap_translate(parent, paddr);
+               if (IS_ERR_VALUE(vmaddr)) {
+                       rc = vmaddr;
+                       break;
+               }
+               rc = radix_tree_preload(GFP_KERNEL);
+               if (rc)
+                       break;
+               rc = -EAGAIN;
+               sptep = gmap_pte_op_walk(parent, paddr, &ptl);
+               if (sptep) {
+                       spin_lock(&sg->guest_table_lock);
+                       /* Get page table pointer */
+                       tptep = (pte_t *) gmap_table_walk(sg, saddr, 0);
+                       if (!tptep) {
+                               spin_unlock(&sg->guest_table_lock);
+                               gmap_pte_op_end(ptl);
+                               radix_tree_preload_end();
+                               break;
+                       }
+                       rc = ptep_shadow_pte(sg->mm, saddr, sptep, tptep, pte);
+                       if (rc > 0) {
+                               /* Success and a new mapping */
+                               gmap_insert_rmap(sg, vmaddr, rmap);
+                               rmap = NULL;
+                               rc = 0;
+                       }
+                       gmap_pte_op_end(ptl);
+                       spin_unlock(&sg->guest_table_lock);
+               }
+               radix_tree_preload_end();
+               if (!rc)
+                       break;
+               rc = gmap_pte_op_fixup(parent, paddr, vmaddr, prot);
+               if (rc)
+                       break;
+       }
+       kfree(rmap);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_shadow_page);
+
+/**
+ * gmap_shadow_notify - handle notifications for shadow gmap
+ *
+ * Called with sg->parent->shadow_lock.
+ */
+static void gmap_shadow_notify(struct gmap *sg, unsigned long vmaddr,
+                              unsigned long offset, pte_t *pte)
+{
+       struct gmap_rmap *rmap, *rnext, *head;
+       unsigned long gaddr, start, end, bits, raddr;
+       unsigned long *table;
+
+       BUG_ON(!gmap_is_shadow(sg));
+       spin_lock(&sg->parent->guest_table_lock);
+       table = radix_tree_lookup(&sg->parent->host_to_guest,
+                                 vmaddr >> PMD_SHIFT);
+       gaddr = table ? __gmap_segment_gaddr(table) + offset : 0;
+       spin_unlock(&sg->parent->guest_table_lock);
+       if (!table)
+               return;
+
+       spin_lock(&sg->guest_table_lock);
+       if (sg->removed) {
+               spin_unlock(&sg->guest_table_lock);
+               return;
+       }
+       /* Check for top level table */
+       start = sg->orig_asce & _ASCE_ORIGIN;
+       end = start + ((sg->orig_asce & _ASCE_TABLE_LENGTH) + 1) * 4096;
+       if (!(sg->orig_asce & _ASCE_REAL_SPACE) && gaddr >= start &&
+           gaddr < end) {
+               /* The complete shadow table has to go */
+               gmap_unshadow(sg);
+               spin_unlock(&sg->guest_table_lock);
+               list_del(&sg->list);
+               gmap_put(sg);
+               return;
+       }
+       /* Remove the page table tree from on specific entry */
+       head = radix_tree_delete(&sg->host_to_rmap, vmaddr >> 12);
+       gmap_for_each_rmap_safe(rmap, rnext, head) {
+               bits = rmap->raddr & _SHADOW_RMAP_MASK;
+               raddr = rmap->raddr ^ bits;
+               switch (bits) {
+               case _SHADOW_RMAP_REGION1:
+                       gmap_unshadow_r2t(sg, raddr);
+                       break;
+               case _SHADOW_RMAP_REGION2:
+                       gmap_unshadow_r3t(sg, raddr);
+                       break;
+               case _SHADOW_RMAP_REGION3:
+                       gmap_unshadow_sgt(sg, raddr);
+                       break;
+               case _SHADOW_RMAP_SEGMENT:
+                       gmap_unshadow_pgt(sg, raddr);
+                       break;
+               case _SHADOW_RMAP_PGTABLE:
+                       gmap_unshadow_page(sg, raddr);
+                       break;
+               }
+               kfree(rmap);
+       }
+       spin_unlock(&sg->guest_table_lock);
+}
+
+/**
+ * ptep_notify - call all invalidation callbacks for a specific pte.
+ * @mm: pointer to the process mm_struct
+ * @addr: virtual address in the process address space
+ * @pte: pointer to the page table entry
+ * @bits: bits from the pgste that caused the notify call
+ *
+ * This function is assumed to be called with the page table lock held
+ * for the pte to notify.
+ */
+void ptep_notify(struct mm_struct *mm, unsigned long vmaddr,
+                pte_t *pte, unsigned long bits)
+{
+       unsigned long offset, gaddr;
+       unsigned long *table;
+       struct gmap *gmap, *sg, *next;
+
+       offset = ((unsigned long) pte) & (255 * sizeof(pte_t));
+       offset = offset * (4096 / sizeof(pte_t));
+       rcu_read_lock();
+       list_for_each_entry_rcu(gmap, &mm->context.gmap_list, list) {
+               if (!list_empty(&gmap->children) && (bits & PGSTE_VSIE_BIT)) {
+                       spin_lock(&gmap->shadow_lock);
+                       list_for_each_entry_safe(sg, next,
+                                                &gmap->children, list)
+                               gmap_shadow_notify(sg, vmaddr, offset, pte);
+                       spin_unlock(&gmap->shadow_lock);
+               }
+               if (!(bits & PGSTE_IN_BIT))
+                       continue;
+               spin_lock(&gmap->guest_table_lock);
+               table = radix_tree_lookup(&gmap->host_to_guest,
+                                         vmaddr >> PMD_SHIFT);
+               if (table)
+                       gaddr = __gmap_segment_gaddr(table) + offset;
+               spin_unlock(&gmap->guest_table_lock);
+               if (table)
+                       gmap_call_notifier(gmap, gaddr, gaddr + PAGE_SIZE - 1);
+       }
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ptep_notify);
 
index e2565d2..995f785 100644 (file)
@@ -137,6 +137,29 @@ static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)
        return new;
 }
 
+#ifdef CONFIG_PGSTE
+
+struct page *page_table_alloc_pgste(struct mm_struct *mm)
+{
+       struct page *page;
+       unsigned long *table;
+
+       page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
+       if (page) {
+               table = (unsigned long *) page_to_phys(page);
+               clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
+               clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
+       }
+       return page;
+}
+
+void page_table_free_pgste(struct page *page)
+{
+       __free_page(page);
+}
+
+#endif /* CONFIG_PGSTE */
+
 /*
  * page table entry allocation/free routines.
  */
@@ -149,7 +172,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        /* Try to get a fragment of a 4K page as a 2K page table */
        if (!mm_alloc_pgste(mm)) {
                table = NULL;
-               spin_lock_bh(&mm->context.list_lock);
+               spin_lock_bh(&mm->context.pgtable_lock);
                if (!list_empty(&mm->context.pgtable_list)) {
                        page = list_first_entry(&mm->context.pgtable_list,
                                                struct page, lru);
@@ -164,7 +187,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
                                list_del(&page->lru);
                        }
                }
-               spin_unlock_bh(&mm->context.list_lock);
+               spin_unlock_bh(&mm->context.pgtable_lock);
                if (table)
                        return table;
        }
@@ -187,9 +210,9 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
                /* Return the first 2K fragment of the page */
                atomic_set(&page->_mapcount, 1);
                clear_table(table, _PAGE_INVALID, PAGE_SIZE);
-               spin_lock_bh(&mm->context.list_lock);
+               spin_lock_bh(&mm->context.pgtable_lock);
                list_add(&page->lru, &mm->context.pgtable_list);
-               spin_unlock_bh(&mm->context.list_lock);
+               spin_unlock_bh(&mm->context.pgtable_lock);
        }
        return table;
 }
@@ -203,13 +226,13 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        if (!mm_alloc_pgste(mm)) {
                /* Free 2K page table fragment of a 4K page */
                bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
-               spin_lock_bh(&mm->context.list_lock);
+               spin_lock_bh(&mm->context.pgtable_lock);
                mask = atomic_xor_bits(&page->_mapcount, 1U << bit);
                if (mask & 3)
                        list_add(&page->lru, &mm->context.pgtable_list);
                else
                        list_del(&page->lru);
-               spin_unlock_bh(&mm->context.list_lock);
+               spin_unlock_bh(&mm->context.pgtable_lock);
                if (mask != 0)
                        return;
        }
@@ -235,13 +258,13 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table,
                return;
        }
        bit = (__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t));
-       spin_lock_bh(&mm->context.list_lock);
+       spin_lock_bh(&mm->context.pgtable_lock);
        mask = atomic_xor_bits(&page->_mapcount, 0x11U << bit);
        if (mask & 3)
                list_add_tail(&page->lru, &mm->context.pgtable_list);
        else
                list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
+       spin_unlock_bh(&mm->context.pgtable_lock);
        table = (unsigned long *) (__pa(table) | (1U << bit));
        tlb_remove_table(tlb, table);
 }
index b98d1a1..5f09201 100644 (file)
@@ -174,14 +174,17 @@ static inline pgste_t pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
        return pgste;
 }
 
-static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
-                                       unsigned long addr,
-                                       pte_t *ptep, pgste_t pgste)
+static inline pgste_t pgste_pte_notify(struct mm_struct *mm,
+                                      unsigned long addr,
+                                      pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       if (pgste_val(pgste) & PGSTE_IN_BIT) {
-               pgste_val(pgste) &= ~PGSTE_IN_BIT;
-               ptep_notify(mm, addr, ptep);
+       unsigned long bits;
+
+       bits = pgste_val(pgste) & (PGSTE_IN_BIT | PGSTE_VSIE_BIT);
+       if (bits) {
+               pgste_val(pgste) ^= bits;
+               ptep_notify(mm, addr, ptep, bits);
        }
 #endif
        return pgste;
@@ -194,7 +197,7 @@ static inline pgste_t ptep_xchg_start(struct mm_struct *mm,
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               pgste = pgste_ipte_notify(mm, addr, ptep, pgste);
+               pgste = pgste_pte_notify(mm, addr, ptep, pgste);
        }
        return pgste;
 }
@@ -459,6 +462,90 @@ void ptep_set_notify(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
        preempt_enable();
 }
 
+/**
+ * ptep_force_prot - change access rights of a locked pte
+ * @mm: pointer to the process mm_struct
+ * @addr: virtual address in the guest address space
+ * @ptep: pointer to the page table entry
+ * @prot: indicates guest access rights: PROT_NONE, PROT_READ or PROT_WRITE
+ * @bit: pgste bit to set (e.g. for notification)
+ *
+ * Returns 0 if the access rights were changed and -EAGAIN if the current
+ * and requested access rights are incompatible.
+ */
+int ptep_force_prot(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, int prot, unsigned long bit)
+{
+       pte_t entry;
+       pgste_t pgste;
+       int pte_i, pte_p;
+
+       pgste = pgste_get_lock(ptep);
+       entry = *ptep;
+       /* Check pte entry after all locks have been acquired */
+       pte_i = pte_val(entry) & _PAGE_INVALID;
+       pte_p = pte_val(entry) & _PAGE_PROTECT;
+       if ((pte_i && (prot != PROT_NONE)) ||
+           (pte_p && (prot & PROT_WRITE))) {
+               pgste_set_unlock(ptep, pgste);
+               return -EAGAIN;
+       }
+       /* Change access rights and set pgste bit */
+       if (prot == PROT_NONE && !pte_i) {
+               ptep_flush_direct(mm, addr, ptep);
+               pgste = pgste_update_all(entry, pgste, mm);
+               pte_val(entry) |= _PAGE_INVALID;
+       }
+       if (prot == PROT_READ && !pte_p) {
+               ptep_flush_direct(mm, addr, ptep);
+               pte_val(entry) &= ~_PAGE_INVALID;
+               pte_val(entry) |= _PAGE_PROTECT;
+       }
+       pgste_val(pgste) |= bit;
+       pgste = pgste_set_pte(ptep, pgste, entry);
+       pgste_set_unlock(ptep, pgste);
+       return 0;
+}
+
+int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr,
+                   pte_t *sptep, pte_t *tptep, pte_t pte)
+{
+       pgste_t spgste, tpgste;
+       pte_t spte, tpte;
+       int rc = -EAGAIN;
+
+       if (!(pte_val(*tptep) & _PAGE_INVALID))
+               return 0;       /* already shadowed */
+       spgste = pgste_get_lock(sptep);
+       spte = *sptep;
+       if (!(pte_val(spte) & _PAGE_INVALID) &&
+           !((pte_val(spte) & _PAGE_PROTECT) &&
+             !(pte_val(pte) & _PAGE_PROTECT))) {
+               pgste_val(spgste) |= PGSTE_VSIE_BIT;
+               tpgste = pgste_get_lock(tptep);
+               pte_val(tpte) = (pte_val(spte) & PAGE_MASK) |
+                               (pte_val(pte) & _PAGE_PROTECT);
+               /* don't touch the storage key - it belongs to parent pgste */
+               tpgste = pgste_set_pte(tptep, tpgste, tpte);
+               pgste_set_unlock(tptep, tpgste);
+               rc = 1;
+       }
+       pgste_set_unlock(sptep, spgste);
+       return rc;
+}
+
+void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep)
+{
+       pgste_t pgste;
+
+       pgste = pgste_get_lock(ptep);
+       /* notifier is called by the caller */
+       ptep_flush_direct(mm, saddr, ptep);
+       /* don't touch the storage key - it belongs to parent pgste */
+       pgste = pgste_set_pte(ptep, pgste, __pte(_PAGE_INVALID));
+       pgste_set_unlock(ptep, pgste);
+}
+
 static void ptep_zap_swap_entry(struct mm_struct *mm, swp_entry_t entry)
 {
        if (!non_swap_entry(entry))
@@ -532,7 +619,7 @@ bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr)
        pgste_val(pgste) &= ~PGSTE_UC_BIT;
        pte = *ptep;
        if (dirty && (pte_val(pte) & _PAGE_PRESENT)) {
-               pgste = pgste_ipte_notify(mm, addr, ptep, pgste);
+               pgste = pgste_pte_notify(mm, addr, ptep, pgste);
                __ptep_ipte(addr, ptep);
                if (MACHINE_HAS_ESOP || !(pte_val(pte) & _PAGE_WRITE))
                        pte_val(pte) |= _PAGE_PROTECT;
@@ -555,12 +642,9 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
        pgste_t old, new;
        pte_t *ptep;
 
-       down_read(&mm->mmap_sem);
        ptep = get_locked_pte(mm, addr, &ptl);
-       if (unlikely(!ptep)) {
-               up_read(&mm->mmap_sem);
+       if (unlikely(!ptep))
                return -EFAULT;
-       }
 
        new = old = pgste_get_lock(ptep);
        pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
@@ -587,45 +671,100 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
 
        pgste_set_unlock(ptep, new);
        pte_unmap_unlock(ptep, ptl);
-       up_read(&mm->mmap_sem);
        return 0;
 }
 EXPORT_SYMBOL(set_guest_storage_key);
 
-unsigned char get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
+/**
+ * Conditionally set a guest storage key (handling csske).
+ * oldkey will be updated when either mr or mc is set and a pointer is given.
+ *
+ * Returns 0 if a guests storage key update wasn't necessary, 1 if the guest
+ * storage key was updated and -EFAULT on access errors.
+ */
+int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                              unsigned char key, unsigned char *oldkey,
+                              bool nq, bool mr, bool mc)
+{
+       unsigned char tmp, mask = _PAGE_ACC_BITS | _PAGE_FP_BIT;
+       int rc;
+
+       /* we can drop the pgste lock between getting and setting the key */
+       if (mr | mc) {
+               rc = get_guest_storage_key(current->mm, addr, &tmp);
+               if (rc)
+                       return rc;
+               if (oldkey)
+                       *oldkey = tmp;
+               if (!mr)
+                       mask |= _PAGE_REFERENCED;
+               if (!mc)
+                       mask |= _PAGE_CHANGED;
+               if (!((tmp ^ key) & mask))
+                       return 0;
+       }
+       rc = set_guest_storage_key(current->mm, addr, key, nq);
+       return rc < 0 ? rc : 1;
+}
+EXPORT_SYMBOL(cond_set_guest_storage_key);
+
+/**
+ * Reset a guest reference bit (rrbe), returning the reference and changed bit.
+ *
+ * Returns < 0 in case of error, otherwise the cc to be reported to the guest.
+ */
+int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr)
 {
-       unsigned char key;
        spinlock_t *ptl;
-       pgste_t pgste;
+       pgste_t old, new;
        pte_t *ptep;
+       int cc = 0;
 
-       down_read(&mm->mmap_sem);
        ptep = get_locked_pte(mm, addr, &ptl);
-       if (unlikely(!ptep)) {
-               up_read(&mm->mmap_sem);
+       if (unlikely(!ptep))
                return -EFAULT;
-       }
-       pgste = pgste_get_lock(ptep);
 
-       if (pte_val(*ptep) & _PAGE_INVALID) {
-               key  = (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56;
-               key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56;
-               key |= (pgste_val(pgste) & PGSTE_GR_BIT) >> 48;
-               key |= (pgste_val(pgste) & PGSTE_GC_BIT) >> 48;
-       } else {
-               key = page_get_storage_key(pte_val(*ptep) & PAGE_MASK);
+       new = old = pgste_get_lock(ptep);
+       /* Reset guest reference bit only */
+       pgste_val(new) &= ~PGSTE_GR_BIT;
 
-               /* Reflect guest's logical view, not physical */
-               if (pgste_val(pgste) & PGSTE_GR_BIT)
-                       key |= _PAGE_REFERENCED;
-               if (pgste_val(pgste) & PGSTE_GC_BIT)
-                       key |= _PAGE_CHANGED;
+       if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+               cc = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
+               /* Merge real referenced bit into host-set */
+               pgste_val(new) |= ((unsigned long) cc << 53) & PGSTE_HR_BIT;
        }
+       /* Reflect guest's logical view, not physical */
+       cc |= (pgste_val(old) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 49;
+       /* Changing the guest storage key is considered a change of the page */
+       if ((pgste_val(new) ^ pgste_val(old)) & PGSTE_GR_BIT)
+               pgste_val(new) |= PGSTE_UC_BIT;
+
+       pgste_set_unlock(ptep, new);
+       pte_unmap_unlock(ptep, ptl);
+       return 0;
+}
+EXPORT_SYMBOL(reset_guest_reference_bit);
+
+int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                         unsigned char *key)
+{
+       spinlock_t *ptl;
+       pgste_t pgste;
+       pte_t *ptep;
 
+       ptep = get_locked_pte(mm, addr, &ptl);
+       if (unlikely(!ptep))
+               return -EFAULT;
+
+       pgste = pgste_get_lock(ptep);
+       *key = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56;
+       if (!(pte_val(*ptep) & _PAGE_INVALID))
+               *key = page_get_storage_key(pte_val(*ptep) & PAGE_MASK);
+       /* Reflect guest's logical view, not physical */
+       *key |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48;
        pgste_set_unlock(ptep, pgste);
        pte_unmap_unlock(ptep, ptl);
-       up_read(&mm->mmap_sem);
-       return key;
+       return 0;
 }
 EXPORT_SYMBOL(get_guest_storage_key);
 #endif
index 070f1ae..7297fce 100644 (file)
@@ -286,7 +286,7 @@ static inline void zpci_err_dma(unsigned long rc, unsigned long addr)
 static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction direction,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long nr_pages, iommu_page_index;
@@ -332,7 +332,7 @@ out_err:
 
 static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
                                 size_t size, enum dma_data_direction direction,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long iommu_page_index;
@@ -355,7 +355,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
 
 static void *s390_dma_alloc(struct device *dev, size_t size,
                            dma_addr_t *dma_handle, gfp_t flag,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        struct page *page;
@@ -370,7 +370,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
        pa = page_to_phys(page);
        memset((void *) pa, 0, size);
 
-       map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, NULL);
+       map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, 0);
        if (dma_mapping_error(dev, map)) {
                free_pages(pa, get_order(size));
                return NULL;
@@ -384,19 +384,19 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
 
 static void s390_dma_free(struct device *dev, size_t size,
                          void *pa, dma_addr_t dma_handle,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
 
        size = PAGE_ALIGN(size);
        atomic64_sub(size / PAGE_SIZE, &zdev->allocated_pages);
-       s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
+       s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, 0);
        free_pages((unsigned long) pa, get_order(size));
 }
 
 static int s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
                           int nr_elements, enum dma_data_direction dir,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        int mapped_elements = 0;
        struct scatterlist *s;
@@ -405,7 +405,7 @@ static int s390_dma_map_sg(struct device *dev, struct scatterlist *sg,
        for_each_sg(sg, s, nr_elements, i) {
                struct page *page = sg_page(s);
                s->dma_address = s390_dma_map_pages(dev, page, s->offset,
-                                                   s->length, dir, NULL);
+                                                   s->length, dir, 0);
                if (!dma_mapping_error(dev, s->dma_address)) {
                        s->dma_length = s->length;
                        mapped_elements++;
@@ -419,7 +419,7 @@ unmap:
        for_each_sg(sg, s, mapped_elements, i) {
                if (s->dma_address)
                        s390_dma_unmap_pages(dev, s->dma_address, s->dma_length,
-                                            dir, NULL);
+                                            dir, 0);
                s->dma_address = 0;
                s->dma_length = 0;
        }
@@ -429,13 +429,14 @@ unmap:
 
 static void s390_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
                              int nr_elements, enum dma_data_direction dir,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
 
        for_each_sg(sg, s, nr_elements, i) {
-               s390_dma_unmap_pages(dev, s->dma_address, s->dma_length, dir, NULL);
+               s390_dma_unmap_pages(dev, s->dma_address, s->dma_length, dir,
+                                    0);
                s->dma_address = 0;
                s->dma_length = 0;
        }
index 9fbce49..444c26c 100644 (file)
@@ -91,7 +91,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void __init_refok free_initmem(void)
+void __ref free_initmem(void)
 {
        free_initmem_default(POISON_FREE_INITMEM);
 }
index 0d5f3a9..ee08695 100644 (file)
@@ -38,6 +38,7 @@ config SUPERH
        select GENERIC_IDLE_POLL_SETUP
        select GENERIC_CLOCKEVENTS
        select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
+       select GENERIC_SCHED_CLOCK
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
@@ -45,6 +46,7 @@ config SUPERH
        select OLD_SIGSUSPEND
        select OLD_SIGACTION
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_FUTEX_CMPXCHG if FUTEX
        select HAVE_NMI
        help
          The SuperH is a RISC processor targeted for use in embedded systems
@@ -184,6 +186,12 @@ config CPU_SH2A
        select CPU_SH2
        select UNCACHED_MAPPING
 
+config CPU_J2
+       bool
+       select CPU_SH2
+       select OF
+       select OF_EARLY_FLATTREE
+
 config CPU_SH3
        bool
        select CPU_HAS_INTEVT
@@ -250,6 +258,12 @@ config CPU_SUBTYPE_SH7619
        select CPU_SH2
        select SYS_SUPPORTS_SH_CMT
 
+config CPU_SUBTYPE_J2
+       bool "Support J2 processor"
+       select CPU_J2
+       select SYS_SUPPORTS_SMP
+       select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+
 # SH-2A Processor Support
 
 config CPU_SUBTYPE_SH7201
@@ -739,6 +753,26 @@ endmenu
 
 menu "Boot options"
 
+config USE_BUILTIN_DTB
+       bool "Use builtin DTB"
+       default n
+       depends on SH_DEVICE_TREE
+       help
+         Link a device tree blob for particular hardware into the kernel,
+         suppressing use of the DTB pointer provided by the bootloader.
+         This option should only be used with legacy bootloaders that are
+         not capable of providing a DTB to the kernel, or for experimental
+         hardware without stable device tree bindings.
+
+config BUILTIN_DTB_SOURCE
+       string "Source file for builtin DTB"
+       default ""
+       depends on USE_BUILTIN_DTB
+       help
+         Base name (without suffix, relative to arch/sh/boot/dts) for the
+         a DTS file that will be used to produce the DTB linked into the
+         kernel.
+
 config ZERO_PAGE_OFFSET
        hex
        default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \
index bf5b3f5..0047666 100644 (file)
@@ -31,6 +31,7 @@ isa-y                                 := $(isa-y)-up
 endif
 
 cflags-$(CONFIG_CPU_SH2)               := $(call cc-option,-m2,)
+cflags-$(CONFIG_CPU_J2)                        := $(call cc-option,-mj2,)
 cflags-$(CONFIG_CPU_SH2A)              += $(call cc-option,-m2a,) \
                                           $(call cc-option,-m2a-nofpu,) \
                                           $(call cc-option,-m4-nofpu,)
@@ -130,6 +131,8 @@ head-y      := arch/sh/kernel/head_$(BITS).o
 core-y                         += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/
 core-$(CONFIG_SH_FPU_EMU)      += arch/sh/math-emu/
 
+core-$(CONFIG_USE_BUILTIN_DTB) += arch/sh/boot/dts/
+
 # Mach groups
 machdir-$(CONFIG_SOLUTION_ENGINE)              += mach-se
 machdir-$(CONFIG_SH_HP6XX)                     += mach-hp6xx
index e0db046..e9c2c42 100644 (file)
@@ -11,6 +11,7 @@ config SH_DEVICE_TREE
        select OF
        select OF_EARLY_FLATTREE
        select CLKSRC_OF
+       select COMMON_CLK
        select GENERIC_CALIBRATE_DELAY
        help
          Select Board Described by Device Tree to build a kernel that
index 98b3620..97ec67f 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
-#include <linux/module.h>
 #include <linux/sched.h>
 #include <asm/machvec.h>
 #include <mach/secureedge5410.h>
@@ -49,7 +48,7 @@ static int __init eraseconfig_init(void)
                                irq);
        return 0;
 }
-module_init(eraseconfig_init);
+device_initcall(eraseconfig_init);
 
 /*
  * Initialize IRQ setting
index 911ffb9..1fb6d57 100644 (file)
@@ -124,13 +124,22 @@ static void __init sh_of_time_init(void)
 
 static void __init sh_of_setup(char **cmdline_p)
 {
+       struct device_node *root;
+
+#ifdef CONFIG_USE_BUILTIN_DTB
+       unflatten_and_copy_device_tree();
+#else
        unflatten_device_tree();
+#endif
 
        board_time_init = sh_of_time_init;
 
-       sh_mv.mv_name = of_flat_dt_get_machine_name();
-       if (!sh_mv.mv_name)
-               sh_mv.mv_name = "Unknown SH model";
+       sh_mv.mv_name = "Unknown SH model";
+       root = of_find_node_by_path("/");
+       if (root) {
+               of_property_read_string(root, "model", &sh_mv.mv_name);
+               of_node_put(root);
+       }
 
        sh_of_smp_probe();
 }
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile
new file mode 100644 (file)
index 0000000..e5ce3a0
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+
+clean-files := *.dtb.S
diff --git a/arch/sh/boot/dts/j2_mimas_v2.dts b/arch/sh/boot/dts/j2_mimas_v2.dts
new file mode 100755 (executable)
index 0000000..880de75
--- /dev/null
@@ -0,0 +1,96 @@
+/dts-v1/;
+
+/ {
+       compatible = "jcore,j2-soc";
+       model = "J2 FPGA SoC on Mimas v2 board";
+
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&aic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "jcore,j2";
+                       reg = <0>;
+                       clock-frequency = <50000000>;
+                       d-cache-size = <8192>;
+                       i-cache-size = <8192>;
+                       d-cache-block-size = <16>;
+                       i-cache-block-size = <16>;
+               };
+       };
+
+       memory@10000000 {
+               device_type = "memory";
+               reg = <0x10000000 0x4000000>;
+       };
+
+       aliases {
+               serial0 = &uart0;
+               spi0 = &spi0;
+       };
+
+       chosen {
+               stdout-path = "serial0";
+       };
+
+       soc@abcd0000 {
+               compatible = "simple-bus";
+               ranges = <0 0xabcd0000 0x100000>;
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               aic: interrupt-controller@200 {
+                       compatible = "jcore,aic1";
+                       reg = <0x200 0x10>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               cache-controller@c0 {
+                       compatible = "jcore,cache";
+                       reg = <0xc0 4>;
+               };
+
+               timer@200 {
+                       compatible = "jcore,pit";
+                       reg = <0x200 0x30>;
+                       interrupts = <0x48>;
+               };
+
+               spi0: spi@40 {
+                       compatible = "jcore,spi2";
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       spi-max-frequency = <25000000>;
+
+                       reg = <0x40 0x8>;
+
+                       sdcard@0 {
+                               compatible = "mmc-spi-slot";
+                               reg = <0>;
+                               spi-max-frequency = <25000000>;
+                               voltage-ranges = <3200 3400>;
+                               mode = <0>;
+                       };
+               };
+
+               uart0: serial@100 {
+                       clock-frequency = <125000000>;
+                       compatible = "xlnx,xps-uartlite-1.00.a";
+                       current-speed = <19200>;
+                       device_type = "serial";
+                       interrupts = <0x12>;
+                       port-number = <0>;
+                       reg = <0x100 0x10>;
+               };
+       };
+};
diff --git a/arch/sh/configs/j2_defconfig b/arch/sh/configs/j2_defconfig
new file mode 100644 (file)
index 0000000..94d1eca
--- /dev/null
@@ -0,0 +1,40 @@
+CONFIG_SMP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_CPU_SUBTYPE_J2=y
+CONFIG_MEMORY_START=0x10000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_DEVICE_TREE=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttyUL0 earlycon"
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_NETDEVICES=y
+CONFIG_SERIAL_UARTLITE=y
+CONFIG_SERIAL_UARTLITE_CONSOLE=y
+CONFIG_I2C=y
+CONFIG_SPI=y
+CONFIG_SPI_JCORE=y
+CONFIG_WATCHDOG=y
+CONFIG_MMC=y
+CONFIG_MMC_SPI=y
+CONFIG_CLKSRC_JCORE_PIT=y
+CONFIG_JCORE_AIC=y
+CONFIG_EXT4_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_UTF8=y
index 7efc9c3..49bace4 100644 (file)
@@ -19,7 +19,6 @@
  * for more details.
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -139,26 +138,11 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
        return mod_timer(&hd->timer, jiffies + 1);
 }
 
-static int heartbeat_drv_remove(struct platform_device *pdev)
-{
-       struct heartbeat_data *hd = platform_get_drvdata(pdev);
-
-       del_timer_sync(&hd->timer);
-       iounmap(hd->base);
-
-       platform_set_drvdata(pdev, NULL);
-
-       if (!pdev->dev.platform_data)
-               kfree(hd);
-
-       return 0;
-}
-
 static struct platform_driver heartbeat_driver = {
        .probe          = heartbeat_drv_probe,
-       .remove         = heartbeat_drv_remove,
        .driver         = {
-               .name   = DRV_NAME,
+               .name                   = DRV_NAME,
+               .suppress_bind_attrs    = true,
        },
 };
 
@@ -167,14 +151,4 @@ static int __init heartbeat_init(void)
        printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION);
        return platform_driver_register(&heartbeat_driver);
 }
-
-static void __exit heartbeat_exit(void)
-{
-       platform_driver_unregister(&heartbeat_driver);
-}
-module_init(heartbeat_init);
-module_exit(heartbeat_exit);
-
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPL v2");
+device_initcall(heartbeat_init);
index d5462b7..84563e3 100644 (file)
@@ -221,7 +221,7 @@ pcibios_bus_report_status_early(struct pci_channel *hose,
  * We can't use pci_find_device() here since we are
  * called from interrupt context.
  */
-static void __init_refok
+static void __ref
 pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
                          int warn)
 {
@@ -256,7 +256,7 @@ pcibios_bus_report_status(struct pci_bus *bus, unsigned int status_mask,
                        pcibios_bus_report_status(dev->subordinate, status_mask, warn);
 }
 
-void __init_refok pcibios_report_status(unsigned int status_mask, int warn)
+void __ref pcibios_report_status(unsigned int status_mask, int warn)
 {
        struct pci_channel *hose;
 
index c399e1c..8a7bd80 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef __ASM_SH_ATOMIC_H
 #define __ASM_SH_ATOMIC_H
 
+#if defined(CONFIG_CPU_J2)
+
+#include <asm-generic/atomic.h>
+
+#else
+
 /*
  * Atomic operations that C can't guarantee us.  Useful for
  * resource counting etc..
@@ -63,4 +69,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
        return c;
 }
 
+#endif /* CONFIG_CPU_J2 */
+
 #endif /* __ASM_SH_ATOMIC_H */
index 8a84e05..3c30b6e 100644 (file)
 #define wmb()          mb()
 #define ctrl_barrier() __icbi(PAGE_OFFSET)
 #else
+#if defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
+#define __smp_mb()     do { int tmp = 0; __asm__ __volatile__ ("cas.l %0,%0,@%1" : "+r"(tmp) : "z"(&tmp) : "memory", "t"); } while(0)
+#define __smp_rmb()    __smp_mb()
+#define __smp_wmb()    __smp_mb()
+#endif
 #define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
 #endif
 
diff --git a/arch/sh/include/asm/bitops-cas.h b/arch/sh/include/asm/bitops-cas.h
new file mode 100644 (file)
index 0000000..88f793c
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __ASM_SH_BITOPS_CAS_H
+#define __ASM_SH_BITOPS_CAS_H
+
+static inline unsigned __bo_cas(volatile unsigned *p, unsigned old, unsigned new)
+{
+       __asm__ __volatile__("cas.l %1,%0,@r0"
+               : "+r"(new)
+               : "r"(old), "z"(p)
+               : "t", "memory" );
+       return new;
+}
+
+static inline void set_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old|mask) != old);
+}
+
+static inline void clear_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old&~mask) != old);
+}
+
+static inline void change_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old^mask) != old);
+}
+
+static inline int test_and_set_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old|mask) != old);
+
+       return !!(old & mask);
+}
+
+static inline int test_and_clear_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old&~mask) != old);
+
+       return !!(old & mask);
+}
+
+static inline int test_and_change_bit(int nr, volatile void *addr)
+{
+       unsigned mask, old;
+       volatile unsigned *a = addr;
+
+       a += nr >> 5;
+       mask = 1U << (nr & 0x1f);
+
+       do old = *a;
+       while (__bo_cas(a, old, old^mask) != old);
+
+       return !!(old & mask);
+}
+
+#include <asm-generic/bitops/non-atomic.h>
+
+#endif /* __ASM_SH_BITOPS_CAS_H */
index fc8e652..a8699d6 100644 (file)
@@ -18,6 +18,8 @@
 #include <asm/bitops-op32.h>
 #elif defined(CONFIG_CPU_SH4A)
 #include <asm/bitops-llsc.h>
+#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
+#include <asm/bitops-cas.h>
 #else
 #include <asm-generic/bitops/atomic.h>
 #include <asm-generic/bitops/non-atomic.h>
diff --git a/arch/sh/include/asm/cmpxchg-cas.h b/arch/sh/include/asm/cmpxchg-cas.h
new file mode 100644 (file)
index 0000000..d0d8664
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __ASM_SH_CMPXCHG_CAS_H
+#define __ASM_SH_CMPXCHG_CAS_H
+
+static inline unsigned long
+__cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new)
+{
+       __asm__ __volatile__("cas.l %1,%0,@r0"
+               : "+r"(new)
+               : "r"(old), "z"(m)
+               : "t", "memory" );
+       return new;
+}
+
+static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
+{
+       unsigned long old;
+       do old = *m;
+       while (__cmpxchg_u32(m, old, val) != old);
+       return old;
+}
+
+#include <asm/cmpxchg-xchg.h>
+
+#endif /* __ASM_SH_CMPXCHG_CAS_H */
index 7219719..1e881f5 100644 (file)
@@ -21,7 +21,7 @@ static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size)
        int off = (unsigned long)ptr % sizeof(u32);
        volatile u32 *p = ptr - off;
 #ifdef __BIG_ENDIAN
-       int bitoff = (sizeof(u32) - 1 - off) * BITS_PER_BYTE;
+       int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
 #else
        int bitoff = off * BITS_PER_BYTE;
 #endif
index 5225916..3dfe046 100644 (file)
@@ -13,6 +13,8 @@
 #include <asm/cmpxchg-grb.h>
 #elif defined(CONFIG_CPU_SH4A)
 #include <asm/cmpxchg-llsc.h>
+#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
+#include <asm/cmpxchg-cas.h>
 #else
 #include <asm/cmpxchg-irq.h>
 #endif
index e11cf0c..0052ad4 100644 (file)
@@ -17,9 +17,9 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 /* arch/sh/mm/consistent.c */
 extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                        dma_addr_t *dma_addr, gfp_t flag,
-                                       struct dma_attrs *attrs);
+                                       unsigned long attrs);
 extern void dma_generic_free_coherent(struct device *dev, size_t size,
                                      void *vaddr, dma_addr_t dma_handle,
-                                     struct dma_attrs *attrs);
+                                     unsigned long attrs);
 
 #endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/include/asm/futex-cas.h b/arch/sh/include/asm/futex-cas.h
new file mode 100644 (file)
index 0000000..267cb7a
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __ASM_SH_FUTEX_CAS_H
+#define __ASM_SH_FUTEX_CAS_H
+
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+                                                  u32 __user *uaddr,
+                                                  u32 oldval, u32 newval)
+{
+       int err = 0;
+       __asm__ __volatile__(
+               "1:\n\t"
+               "cas.l  %2, %1, @r0\n"
+               "2:\n\t"
+#ifdef CONFIG_MMU
+               ".section       .fixup,\"ax\"\n"
+               "3:\n\t"
+               "mov.l  4f, %0\n\t"
+               "jmp    @%0\n\t"
+               " mov   %3, %0\n\t"
+               ".balign        4\n"
+               "4:     .long   2b\n\t"
+               ".previous\n"
+               ".section       __ex_table,\"a\"\n\t"
+               ".long  1b, 3b\n\t"
+               ".previous"
+#endif
+               :"+r" (err), "+r" (newval)
+               :"r" (oldval), "i" (-EFAULT), "z" (uaddr)
+               :"t", "memory");
+       if (err) return err;
+       *uval = newval;
+       return 0;
+}
+
+#endif /* __ASM_SH_FUTEX_CAS_H */
index 63d3312..ab01dbe 100644 (file)
@@ -1,92 +1,6 @@
 #ifndef __ASM_SH_FUTEX_IRQ_H
 #define __ASM_SH_FUTEX_IRQ_H
 
-
-static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
-                                          int *oldval)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-
-       ret = get_user(*oldval, uaddr);
-       if (!ret)
-               ret = put_user(oparg, uaddr);
-
-       local_irq_restore(flags);
-
-       return ret;
-}
-
-static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
-                                          int *oldval)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-
-       ret = get_user(*oldval, uaddr);
-       if (!ret)
-               ret = put_user(*oldval + oparg, uaddr);
-
-       local_irq_restore(flags);
-
-       return ret;
-}
-
-static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
-                                         int *oldval)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-
-       ret = get_user(*oldval, uaddr);
-       if (!ret)
-               ret = put_user(*oldval | oparg, uaddr);
-
-       local_irq_restore(flags);
-
-       return ret;
-}
-
-static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
-                                          int *oldval)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-
-       ret = get_user(*oldval, uaddr);
-       if (!ret)
-               ret = put_user(*oldval & oparg, uaddr);
-
-       local_irq_restore(flags);
-
-       return ret;
-}
-
-static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
-                                          int *oldval)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-
-       ret = get_user(*oldval, uaddr);
-       if (!ret)
-               ret = put_user(*oldval ^ oparg, uaddr);
-
-       local_irq_restore(flags);
-
-       return ret;
-}
-
 static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
                                                   u32 __user *uaddr,
                                                   u32 oldval, u32 newval)
diff --git a/arch/sh/include/asm/futex-llsc.h b/arch/sh/include/asm/futex-llsc.h
new file mode 100644 (file)
index 0000000..2359170
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __ASM_SH_FUTEX_LLSC_H
+#define __ASM_SH_FUTEX_LLSC_H
+
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+                                                  u32 __user *uaddr,
+                                                  u32 oldval, u32 newval)
+{
+       int err = 0;
+       __asm__ __volatile__(
+               "synco\n"
+               "1:\n\t"
+               "movli.l        @%2, r0\n\t"
+               "mov    r0, %1\n\t"
+               "cmp/eq %1, %4\n\t"
+               "bf     2f\n\t"
+               "mov    %5, r0\n\t"
+               "movco.l        r0, @%2\n\t"
+               "bf     1b\n"
+               "2:\n\t"
+               "synco\n\t"
+#ifdef CONFIG_MMU
+               ".section       .fixup,\"ax\"\n"
+               "3:\n\t"
+               "mov.l  4f, %0\n\t"
+               "jmp    @%0\n\t"
+               " mov   %3, %0\n\t"
+               ".balign        4\n"
+               "4:     .long   2b\n\t"
+               ".previous\n"
+               ".section       __ex_table,\"a\"\n\t"
+               ".long  1b, 3b\n\t"
+               ".previous"
+#endif
+               :"+r" (err), "=&r" (*uval)
+               :"r" (uaddr), "i" (-EFAULT), "r" (oldval), "r" (newval)
+               :"t", "memory", "r0");
+       if (err) return err;
+       return 0;
+}
+
+#endif /* __ASM_SH_FUTEX_LLSC_H */
index 7be39a6..d007874 100644 (file)
@@ -7,16 +7,34 @@
 #include <linux/uaccess.h>
 #include <asm/errno.h>
 
-/* XXX: UP variants, fix for SH-4A and SMP.. */
+#if !defined(CONFIG_SMP)
 #include <asm/futex-irq.h>
+#elif defined(CONFIG_CPU_J2)
+#include <asm/futex-cas.h>
+#elif defined(CONFIG_CPU_SH4A)
+#include <asm/futex-llsc.h>
+#else
+#error SMP not supported on this configuration.
+#endif
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
+{
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+               return -EFAULT;
+
+       return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
+}
 
 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
-       int oparg = (encoded_op << 8) >> 20;
-       int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
+       u32 oparg = (encoded_op << 8) >> 20;
+       u32 cmparg = (encoded_op << 20) >> 20;
+       u32 oldval, newval, prev;
+       int ret;
 
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
@@ -26,26 +44,39 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 
        pagefault_disable();
 
-       switch (op) {
-       case FUTEX_OP_SET:
-               ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval);
-               break;
-       case FUTEX_OP_ADD:
-               ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
-               break;
-       case FUTEX_OP_OR:
-               ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval);
-               break;
-       case FUTEX_OP_ANDN:
-               ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval);
-               break;
-       case FUTEX_OP_XOR:
-               ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval);
-               break;
-       default:
-               ret = -ENOSYS;
-               break;
-       }
+       do {
+               if (op == FUTEX_OP_SET)
+                       ret = oldval = 0;
+               else
+                       ret = get_user(oldval, uaddr);
+
+               if (ret) break;
+
+               switch (op) {
+               case FUTEX_OP_SET:
+                       newval = oparg;
+                       break;
+               case FUTEX_OP_ADD:
+                       newval = oldval + oparg;
+                       break;
+               case FUTEX_OP_OR:
+                       newval = oldval | oparg;
+                       break;
+               case FUTEX_OP_ANDN:
+                       newval = oldval & ~oparg;
+                       break;
+               case FUTEX_OP_XOR:
+                       newval = oldval ^ oparg;
+                       break;
+               default:
+                       ret = -ENOSYS;
+                       break;
+               }
+
+               if (ret) break;
+
+               ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval);
+       } while (!ret && prev != oldval);
 
        pagefault_enable();
 
@@ -53,10 +84,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
                switch (cmp) {
                case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
                case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
-               case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
-               case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
-               case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
-               case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+               case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break;
+               case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break;
+               case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break;
+               case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break;
                default: ret = -ENOSYS;
                }
        }
@@ -64,15 +95,5 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
        return ret;
 }
 
-static inline int
-futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
-                             u32 oldval, u32 newval)
-{
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
-               return -EFAULT;
-
-       return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
-}
-
 #endif /* __KERNEL__ */
 #endif /* __ASM_SH_FUTEX_H */
diff --git a/arch/sh/include/asm/mc146818rtc.h b/arch/sh/include/asm/mc146818rtc.h
deleted file mode 100644 (file)
index 0aee96a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Machine dependent access functions for RTC registers.
- */
-#ifndef _ASM_MC146818RTC_H
-#define _ASM_MC146818RTC_H
-
-#endif /* _ASM_MC146818RTC_H */
index 1506897..f9a0994 100644 (file)
@@ -15,7 +15,7 @@
  */
 enum cpu_type {
        /* SH-2 types */
-       CPU_SH7619,
+       CPU_SH7619, CPU_J2,
 
        /* SH-2A types */
        CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269,
index 52b0c2d..f7b010d 100644 (file)
@@ -6,17 +6,6 @@ extern void (*board_time_init)(void);
 extern void (*rtc_sh_get_time)(struct timespec *);
 extern int (*rtc_sh_set_time)(const time_t);
 
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100     /* battery bad */
-#define RTC_SQWE 0x08          /* enable square-wave output */
-#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
-#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
-
-struct rtc_time;
-unsigned int get_rtc_time(struct rtc_time *);
-int set_rtc_time(struct rtc_time *);
-
 #define RTC_CAP_4_DIGIT_YEAR   (1 << 0)
 
 struct sh_rtc_platform_info {
diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h
new file mode 100644 (file)
index 0000000..c46e8cc
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * include/asm-sh/spinlock-cas.h
+ *
+ * Copyright (C) 2015 SEI
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_SH_SPINLOCK_CAS_H
+#define __ASM_SH_SPINLOCK_CAS_H
+
+#include <asm/barrier.h>
+#include <asm/processor.h>
+
+static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new)
+{
+       __asm__ __volatile__("cas.l %1,%0,@r0"
+               : "+r"(new)
+               : "r"(old), "z"(p)
+               : "t", "memory" );
+       return new;
+}
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+#define arch_spin_is_locked(x)         ((x)->lock <= 0)
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       smp_cond_load_acquire(&lock->lock, VAL > 0);
+}
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       while (!__sl_cas(&lock->lock, 1, 0));
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       __sl_cas(&lock->lock, 0, 1);
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       return __sl_cas(&lock->lock, 1, 0);
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts but no interrupt
+ * writers. For those circumstances we can "mix" irq-safe locks - any writer
+ * needs to get a irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_read_can_lock(x)  ((x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned old;
+       do old = rw->lock;
+       while (!old || __sl_cas(&rw->lock, old, old-1) != old);
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned old;
+       do old = rw->lock;
+       while (__sl_cas(&rw->lock, old, old+1) != old);
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS);
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       __sl_cas(&rw->lock, 0, RW_LOCK_BIAS);
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned old;
+       do old = rw->lock;
+       while (old && __sl_cas(&rw->lock, old, old-1) != old);
+       return !!old;
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define arch_spin_relax(lock)  cpu_relax()
+#define arch_read_relax(lock)  cpu_relax()
+#define arch_write_relax(lock) cpu_relax()
+
+#endif /* __ASM_SH_SPINLOCK_CAS_H */
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h
new file mode 100644 (file)
index 0000000..cec7814
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * include/asm-sh/spinlock-llsc.h
+ *
+ * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2006, 2007 Akio Idehara
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __ASM_SH_SPINLOCK_LLSC_H
+#define __ASM_SH_SPINLOCK_LLSC_H
+
+#include <asm/barrier.h>
+#include <asm/processor.h>
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+#define arch_spin_is_locked(x)         ((x)->lock <= 0)
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       smp_cond_load_acquire(&lock->lock, VAL > 0);
+}
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions.  They have a cost.
+ */
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned long tmp;
+       unsigned long oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! arch_spin_lock        \n\t"
+               "mov            %0, %1                          \n\t"
+               "mov            #0, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "cmp/pl         %1                              \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&lock->lock)
+               : "t", "memory"
+       );
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+               "mov            #1, %0 ! arch_spin_unlock       \n\t"
+               "mov.l          %0, @%1                         \n\t"
+               : "=&z" (tmp)
+               : "r" (&lock->lock)
+               : "t", "memory"
+       );
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned long tmp, oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! arch_spin_trylock     \n\t"
+               "mov            %0, %1                          \n\t"
+               "mov            #0, %0                          \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&lock->lock)
+               : "t", "memory"
+       );
+
+       return oldval;
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts but no interrupt
+ * writers. For those circumstances we can "mix" irq-safe locks - any writer
+ * needs to get a irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_read_can_lock(x)  ((x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! arch_read_lock        \n\t"
+               "cmp/pl         %0                              \n\t"
+               "bf             1b                              \n\t"
+               "add            #-1, %0                         \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! arch_read_unlock      \n\t"
+               "add            #1, %0                          \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%1, %0 ! arch_write_lock       \n\t"
+               "cmp/hs         %2, %0                          \n\t"
+               "bf             1b                              \n\t"
+               "sub            %2, %0                          \n\t"
+               "movco.l        %0, @%1                         \n\t"
+               "bf             1b                              \n\t"
+               : "=&z" (tmp)
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       __asm__ __volatile__ (
+               "mov.l          %1, @%0 ! arch_write_unlock     \n\t"
+               :
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned long tmp, oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! arch_read_trylock     \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/pl         %0                              \n\t"
+               "bf             2f                              \n\t"
+               "add            #-1, %0                         \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "2:                                             \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&rw->lock)
+               : "t", "memory"
+       );
+
+       return (oldval > 0);
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned long tmp, oldval;
+
+       __asm__ __volatile__ (
+               "1:                                             \n\t"
+               "movli.l        @%2, %0 ! arch_write_trylock    \n\t"
+               "mov            %0, %1                          \n\t"
+               "cmp/hs         %3, %0                          \n\t"
+               "bf             2f                              \n\t"
+               "sub            %3, %0                          \n\t"
+               "2:                                             \n\t"
+               "movco.l        %0, @%2                         \n\t"
+               "bf             1b                              \n\t"
+               "synco                                          \n\t"
+               : "=&z" (tmp), "=&r" (oldval)
+               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
+               : "t", "memory"
+       );
+
+       return (oldval > (RW_LOCK_BIAS - 1));
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define arch_spin_relax(lock)  cpu_relax()
+#define arch_read_relax(lock)  cpu_relax()
+#define arch_write_relax(lock) cpu_relax()
+
+#endif /* __ASM_SH_SPINLOCK_LLSC_H */
index 416834b..c2c61ea 100644 (file)
 #ifndef __ASM_SH_SPINLOCK_H
 #define __ASM_SH_SPINLOCK_H
 
-/*
- * The only locking implemented here uses SH-4A opcodes. For others,
- * split this out as per atomic-*.h.
- */
-#ifndef CONFIG_CPU_SH4A
-#error "Need movli.l/movco.l for spinlocks"
+#if defined(CONFIG_CPU_SH4A)
+#include <asm/spinlock-llsc.h>
+#elif defined(CONFIG_CPU_J2)
+#include <asm/spinlock-cas.h>
+#else
+#error "The configured cpu type does not support spinlocks"
 #endif
 
-#include <asm/barrier.h>
-#include <asm/processor.h>
-
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- */
-
-#define arch_spin_is_locked(x)         ((x)->lock <= 0)
-#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
-
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-       smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
-/*
- * Simple spin lock operations.  There are two variants, one clears IRQ's
- * on the local processor, one does not.
- *
- * We make no fairness assumptions.  They have a cost.
- */
-static inline void arch_spin_lock(arch_spinlock_t *lock)
-{
-       unsigned long tmp;
-       unsigned long oldval;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%2, %0 ! arch_spin_lock        \n\t"
-               "mov            %0, %1                          \n\t"
-               "mov            #0, %0                          \n\t"
-               "movco.l        %0, @%2                         \n\t"
-               "bf             1b                              \n\t"
-               "cmp/pl         %1                              \n\t"
-               "bf             1b                              \n\t"
-               : "=&z" (tmp), "=&r" (oldval)
-               : "r" (&lock->lock)
-               : "t", "memory"
-       );
-}
-
-static inline void arch_spin_unlock(arch_spinlock_t *lock)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-               "mov            #1, %0 ! arch_spin_unlock       \n\t"
-               "mov.l          %0, @%1                         \n\t"
-               : "=&z" (tmp)
-               : "r" (&lock->lock)
-               : "t", "memory"
-       );
-}
-
-static inline int arch_spin_trylock(arch_spinlock_t *lock)
-{
-       unsigned long tmp, oldval;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%2, %0 ! arch_spin_trylock     \n\t"
-               "mov            %0, %1                          \n\t"
-               "mov            #0, %0                          \n\t"
-               "movco.l        %0, @%2                         \n\t"
-               "bf             1b                              \n\t"
-               "synco                                          \n\t"
-               : "=&z" (tmp), "=&r" (oldval)
-               : "r" (&lock->lock)
-               : "t", "memory"
-       );
-
-       return oldval;
-}
-
-/*
- * Read-write spinlocks, allowing multiple readers but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts but no interrupt
- * writers. For those circumstances we can "mix" irq-safe locks - any writer
- * needs to get a irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-
-/**
- * read_can_lock - would read_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_read_can_lock(x)  ((x)->lock > 0)
-
-/**
- * write_can_lock - would write_trylock() succeed?
- * @lock: the rwlock in question.
- */
-#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
-
-static inline void arch_read_lock(arch_rwlock_t *rw)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%1, %0 ! arch_read_lock        \n\t"
-               "cmp/pl         %0                              \n\t"
-               "bf             1b                              \n\t"
-               "add            #-1, %0                         \n\t"
-               "movco.l        %0, @%1                         \n\t"
-               "bf             1b                              \n\t"
-               : "=&z" (tmp)
-               : "r" (&rw->lock)
-               : "t", "memory"
-       );
-}
-
-static inline void arch_read_unlock(arch_rwlock_t *rw)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%1, %0 ! arch_read_unlock      \n\t"
-               "add            #1, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
-               "bf             1b                              \n\t"
-               : "=&z" (tmp)
-               : "r" (&rw->lock)
-               : "t", "memory"
-       );
-}
-
-static inline void arch_write_lock(arch_rwlock_t *rw)
-{
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%1, %0 ! arch_write_lock       \n\t"
-               "cmp/hs         %2, %0                          \n\t"
-               "bf             1b                              \n\t"
-               "sub            %2, %0                          \n\t"
-               "movco.l        %0, @%1                         \n\t"
-               "bf             1b                              \n\t"
-               : "=&z" (tmp)
-               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
-               : "t", "memory"
-       );
-}
-
-static inline void arch_write_unlock(arch_rwlock_t *rw)
-{
-       __asm__ __volatile__ (
-               "mov.l          %1, @%0 ! arch_write_unlock     \n\t"
-               :
-               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
-               : "t", "memory"
-       );
-}
-
-static inline int arch_read_trylock(arch_rwlock_t *rw)
-{
-       unsigned long tmp, oldval;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%2, %0 ! arch_read_trylock     \n\t"
-               "mov            %0, %1                          \n\t"
-               "cmp/pl         %0                              \n\t"
-               "bf             2f                              \n\t"
-               "add            #-1, %0                         \n\t"
-               "movco.l        %0, @%2                         \n\t"
-               "bf             1b                              \n\t"
-               "2:                                             \n\t"
-               "synco                                          \n\t"
-               : "=&z" (tmp), "=&r" (oldval)
-               : "r" (&rw->lock)
-               : "t", "memory"
-       );
-
-       return (oldval > 0);
-}
-
-static inline int arch_write_trylock(arch_rwlock_t *rw)
-{
-       unsigned long tmp, oldval;
-
-       __asm__ __volatile__ (
-               "1:                                             \n\t"
-               "movli.l        @%2, %0 ! arch_write_trylock    \n\t"
-               "mov            %0, %1                          \n\t"
-               "cmp/hs         %3, %0                          \n\t"
-               "bf             2f                              \n\t"
-               "sub            %3, %0                          \n\t"
-               "2:                                             \n\t"
-               "movco.l        %0, @%2                         \n\t"
-               "bf             1b                              \n\t"
-               "synco                                          \n\t"
-               : "=&z" (tmp), "=&r" (oldval)
-               : "r" (&rw->lock), "r" (RW_LOCK_BIAS)
-               : "t", "memory"
-       );
-
-       return (oldval > (RW_LOCK_BIAS - 1));
-}
-
-#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
-
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SH_SPINLOCK_H */
index 2afa321..6c65dcd 100644 (file)
@@ -151,19 +151,10 @@ extern void init_thread_xstate(void);
  * ever touches our thread-synchronous status, so we don't
  * have to worry about atomic accesses.
  */
-#define TS_RESTORE_SIGMASK     0x0001  /* restore signal mask in do_signal() */
 #define TS_USEDFPU             0x0002  /* FPU used by this task this quantum */
 
 #ifndef __ASSEMBLY__
 
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
-}
-
 #define TI_FLAG_FAULT_CODE_SHIFT       24
 
 /*
@@ -182,23 +173,6 @@ static inline unsigned int get_thread_fault_code(void)
        return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT;
 }
 
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 694abe4..2f1bc85 100644 (file)
@@ -22,5 +22,6 @@
 #define CPU_HAS_L2_CACHE       0x0080  /* Secondary cache / URAM */
 #define CPU_HAS_OP32           0x0100  /* 32-bit instruction support */
 #define CPU_HAS_PTEAEX         0x0200  /* PTE ASID Extension support */
+#define CPU_HAS_CAS_L          0x0400  /* cas.l atomic compare-and-swap */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
index 8ce1435..faa5d08 100644 (file)
@@ -25,8 +25,6 @@ struct sigcontext {
        unsigned long sc_mach;
        unsigned long sc_macl;
 
-#if defined(__SH4__) || defined(CONFIG_CPU_SH4) || \
-    defined(__SH2A__) || defined(CONFIG_CPU_SH2A)
        /* FPU registers */
        unsigned long sc_fpregs[16];
        unsigned long sc_xfpregs[16];
@@ -34,7 +32,6 @@ struct sigcontext {
        unsigned int sc_fpul;
        unsigned int sc_ownedfp;
 #endif
-#endif
 };
 
 #endif /* __ASM_SH_SIGCONTEXT_H */
index d13a1d6..c801bde 100644 (file)
 #define __NR_process_vm_writev 366
 #define __NR_kcmp              367
 #define __NR_finit_module      368
+#define __NR_sched_getattr     369
+#define __NR_sched_setattr     370
+#define __NR_renameat2         371
+#define __NR_seccomp           372
+#define __NR_getrandom         373
+#define __NR_memfd_create      374
+#define __NR_bpf               375
+#define __NR_execveat          376
+#define __NR_userfaultfd       377
+#define __NR_membarrier                378
+#define __NR_mlock2            379
+#define __NR_copy_file_range   380
+#define __NR_preadv2           381
+#define __NR_pwritev2          382
 
-#define NR_syscalls 369
+#define NR_syscalls 383
 
 #endif /* __ASM_SH_UNISTD_32_H */
index 47ebd5b..ce0cb35 100644 (file)
 #define __NR_process_vm_writev 377
 #define __NR_kcmp              378
 #define __NR_finit_module      379
+#define __NR_sched_getattr     380
+#define __NR_sched_setattr     381
+#define __NR_renameat2         382
+#define __NR_seccomp           383
+#define __NR_getrandom         384
+#define __NR_memfd_create      385
+#define __NR_bpf               386
+#define __NR_execveat          387
+#define __NR_userfaultfd       388
+#define __NR_membarrier                389
+#define __NR_mlock2            390
+#define __NR_copy_file_range   391
+#define __NR_preadv2           392
+#define __NR_pwritev2          393
 
-#define NR_syscalls 380
+#define NR_syscalls 394
 
 #endif /* __ASM_SH_UNISTD_64_H */
index 4187cf4..fca9b1e 100644 (file)
@@ -24,11 +24,13 @@ int __init clk_init(void)
 {
        int ret;
 
+#ifndef CONFIG_COMMON_CLK
        ret = arch_clk_init();
        if (unlikely(ret)) {
                pr_err("%s: CPU clock registration failed.\n", __func__);
                return ret;
        }
+#endif
 
        if (sh_mv.mv_clk_init) {
                ret = sh_mv.mv_clk_init();
@@ -39,11 +41,13 @@ int __init clk_init(void)
                }
        }
 
+#ifndef CONFIG_COMMON_CLK
        /* Kick the child clocks.. */
        recalculate_root_clocks();
 
        /* Enable the necessary init clocks */
        clk_enable_init_clocks();
+#endif
 
        return ret;
 }
index 0d7360d..c8b3be1 100644 (file)
@@ -106,7 +106,7 @@ void __attribute__ ((weak)) l2_cache_init(void)
 /*
  * Generic first-level cache init
  */
-#ifdef CONFIG_SUPERH32
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_CPU_J2)
 static void cache_init(void)
 {
        unsigned long ccr, flags;
@@ -323,9 +323,13 @@ asmlinkage void cpu_init(void)
        cache_init();
 
        if (raw_smp_processor_id() == 0) {
+#ifdef CONFIG_MMU
                shm_align_mask = max_t(unsigned long,
                                       current_cpu_data.dcache.way_size - 1,
                                       PAGE_SIZE - 1);
+#else
+               shm_align_mask = PAGE_SIZE - 1;
+#endif
 
                /* Boot CPU sets the cache shape */
                detect_cache_shape();
index 9e6624c..4df4b28 100644 (file)
@@ -27,6 +27,7 @@ static const char *cpu_name[] = {
        [CPU_MXG]       = "MX-G",       [CPU_SH7723]    = "SH7723",
        [CPU_SH7366]    = "SH7366",     [CPU_SH7724]    = "SH7724",
        [CPU_SH7372]    = "SH7372",     [CPU_SH7734]    = "SH7734",
+       [CPU_J2]        = "J2",
        [CPU_SH_NONE]   = "Unknown"
 };
 
index f0f059a..904c428 100644 (file)
@@ -5,3 +5,7 @@
 obj-y  := ex.o probe.o entry.o
 
 obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o
+
+# SMP setup
+smp-$(CONFIG_CPU_J2)                   := smp-j2.o
+obj-$(CONFIG_SMP)                      += $(smp-y)
index a150595..1ee0a6e 100644 (file)
@@ -47,6 +47,13 @@ ENTRY(exception_handler)
        mov.l   r3,@-sp
        cli
        mov.l   $cpu_mode,r2
+#ifdef CONFIG_SMP
+       mov.l   $cpuid,r3
+       mov.l   @r3,r3
+       mov.l   @r3,r3
+       shll2   r3
+       add     r3,r2
+#endif
        mov.l   @r2,r0
        mov.l   @(5*4,r15),r3   ! previous SR
        or      r0,r3           ! set MD
@@ -57,6 +64,13 @@ ENTRY(exception_handler)
        mov.l   __md_bit,r0
        mov.l   r0,@r2          ! enter kernel mode
        mov.l   $current_thread_info,r2
+#ifdef CONFIG_SMP
+       mov.l   $cpuid,r0
+       mov.l   @r0,r0
+       mov.l   @r0,r0
+       shll2   r0
+       add     r0,r2
+#endif
        mov.l   @r2,r2
        mov     #(THREAD_SIZE >> 8),r0
        shll8   r0
@@ -147,6 +161,11 @@ ENTRY(exception_handler)
        mov     #31,r8
        cmp/hs  r8,r9
        bt      trap_entry      ! 64 > vec >= 31  is trap
+#ifdef CONFIG_CPU_J2
+       mov     #16,r8
+       cmp/hs  r8,r9
+       bt      interrupt_entry ! 31 > vec >= 16 is interrupt
+#endif
 
        mov.l   4f,r8
        mov     r9,r4
@@ -260,6 +279,13 @@ restore_all:
        lds.l   @r0+,macl
        mov     r15,r0
        mov.l   $cpu_mode,r2
+#ifdef CONFIG_SMP
+       mov.l   $cpuid,r3
+       mov.l   @r3,r3
+       mov.l   @r3,r3
+       shll2   r3
+       add     r3,r2
+#endif
        mov     #OFF_SR,r3
        mov.l   @(r0,r3),r1
        mov.l   __md_bit,r3
@@ -276,6 +302,13 @@ restore_all:
        mov.l   r1,@r2                          ! set pc
        get_current_thread_info r0, r1
        mov.l   $current_thread_info,r1
+#ifdef CONFIG_SMP
+       mov.l   $cpuid,r3
+       mov.l   @r3,r3
+       mov.l   @r3,r3
+       shll2   r3
+       add     r3,r1
+#endif
        mov.l   r0,@r1
        mov.l   @r15+,r0
        mov.l   @r15+,r1
@@ -303,19 +336,41 @@ $current_thread_info:
        .long   __current_thread_info
 $cpu_mode:     
        .long   __cpu_mode
+#ifdef CONFIG_SMP
+$cpuid:
+       .long sh2_cpuid_addr
+#endif
                
 ! common exception handler
 #include "../../entry-common.S"
+
+#ifdef CONFIG_NR_CPUS
+#define NR_CPUS CONFIG_NR_CPUS
+#else
+#define NR_CPUS 1
+#endif
        
        .data
 ! cpu operation mode 
 ! bit30 = MD (compatible SH3/4)
 __cpu_mode:
+       .rept   NR_CPUS
        .long   0x40000000
+       .endr
+
+#ifdef CONFIG_SMP
+.global sh2_cpuid_addr
+sh2_cpuid_addr:
+       .long   dummy_cpuid
+dummy_cpuid:
+       .long   0
+#endif
                
        .section        .bss
 __current_thread_info:
+       .rept   NR_CPUS
        .long   0
+       .endr
 
 ENTRY(exception_handling_table)
        .space  4*32
index 6c687ae..4205f6d 100644 (file)
  * for more details.
  */
 #include <linux/init.h>
+#include <linux/of_fdt.h>
+#include <linux/smp.h>
+#include <linux/io.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
 
-void cpu_probe(void)
+#if defined(CONFIG_CPU_J2)
+extern u32 __iomem *j2_ccr_base;
+static int __init scan_cache(unsigned long node, const char *uname,
+                            int depth, void *data)
+{
+       if (!of_flat_dt_is_compatible(node, "jcore,cache"))
+               return 0;
+
+       j2_ccr_base = (u32 __iomem *)of_flat_dt_translate_address(node);
+
+       return 1;
+}
+#endif
+
+void __ref cpu_probe(void)
 {
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
        boot_cpu_data.type                      = CPU_SH7619;
@@ -24,10 +41,30 @@ void cpu_probe(void)
        boot_cpu_data.dcache.linesz             = L1_CACHE_BYTES;
        boot_cpu_data.dcache.flags              = 0;
 #endif
+
+#if defined(CONFIG_CPU_J2)
+       unsigned cpu = hard_smp_processor_id();
+       if (cpu == 0) of_scan_flat_dt(scan_cache, NULL);
+       if (j2_ccr_base) __raw_writel(0x80000303, j2_ccr_base + 4*cpu);
+       if (cpu != 0) return;
+       boot_cpu_data.type                      = CPU_J2;
+
+       /* These defaults are appropriate for the original/current
+        * J2 cache. Once there is a proper framework for getting cache
+        * info from device tree, we should switch to that. */
+       boot_cpu_data.dcache.ways               = 1;
+       boot_cpu_data.dcache.sets               = 256;
+       boot_cpu_data.dcache.entry_shift        = 5;
+       boot_cpu_data.dcache.linesz             = 32;
+       boot_cpu_data.dcache.flags              = 0;
+
+       boot_cpu_data.flags |= CPU_HAS_CAS_L;
+#else
        /*
         * SH-2 doesn't have separate caches
         */
        boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED;
+#endif
        boot_cpu_data.icache = boot_cpu_data.dcache;
        boot_cpu_data.family = CPU_FAMILY_SH2;
 }
diff --git a/arch/sh/kernel/cpu/sh2/smp-j2.c b/arch/sh/kernel/cpu/sh2/smp-j2.c
new file mode 100644 (file)
index 0000000..6ccd7e4
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * SMP support for J2 processor
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/cmpxchg.h>
+
+DEFINE_PER_CPU(unsigned, j2_ipi_messages);
+
+extern u32 *sh2_cpuid_addr;
+static u32 *j2_ipi_trigger;
+static int j2_ipi_irq;
+
+static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg)
+{
+       unsigned cpu = hard_smp_processor_id();
+       volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu);
+       unsigned messages, i;
+
+       do messages = *pmsg;
+       while (cmpxchg(pmsg, messages, 0) != messages);
+
+       if (!messages) return IRQ_NONE;
+
+       for (i=0; i<SMP_MSG_NR; i++)
+               if (messages & (1U<<i))
+                       smp_message_recv(i);
+
+       return IRQ_HANDLED;
+}
+
+static void j2_smp_setup(void)
+{
+}
+
+static void j2_prepare_cpus(unsigned int max_cpus)
+{
+       struct device_node *np;
+       unsigned i, max = 1;
+
+       np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller");
+       if (!np)
+               goto out;
+
+       j2_ipi_irq = irq_of_parse_and_map(np, 0);
+       j2_ipi_trigger = of_iomap(np, 0);
+       if (!j2_ipi_irq || !j2_ipi_trigger)
+               goto out;
+
+       np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio");
+       if (!np)
+               goto out;
+
+       sh2_cpuid_addr = of_iomap(np, 0);
+       if (!sh2_cpuid_addr)
+               goto out;
+
+       if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU,
+                       "ipi", (void *)j2_ipi_interrupt_handler) != 0)
+               goto out;
+
+       max = max_cpus;
+out:
+       /* Disable any cpus past max_cpus, or all secondaries if we didn't
+        * get the necessary resources to support SMP. */
+       for (i=max; i<NR_CPUS; i++) {
+               set_cpu_possible(i, false);
+               set_cpu_present(i, false);
+       }
+}
+
+static void j2_start_cpu(unsigned int cpu, unsigned long entry_point)
+{
+       struct device_node *np;
+       u32 regs[2];
+       void __iomem *release, *initpc;
+
+       if (!cpu) return;
+
+       np = of_get_cpu_node(cpu, NULL);
+       if (!np) return;
+
+       if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return;
+       release = ioremap_nocache(regs[0], sizeof(u32));
+       initpc = ioremap_nocache(regs[1], sizeof(u32));
+
+       __raw_writel(entry_point, initpc);
+       __raw_writel(1, release);
+
+       iounmap(initpc);
+       iounmap(release);
+
+       pr_info("J2 SMP: requested start of cpu %u\n", cpu);
+}
+
+static unsigned int j2_smp_processor_id(void)
+{
+       return __raw_readl(sh2_cpuid_addr);
+}
+
+static void j2_send_ipi(unsigned int cpu, unsigned int message)
+{
+       volatile unsigned *pmsg;
+       unsigned old;
+       unsigned long val;
+
+       /* There is only one IPI interrupt shared by all messages, so
+        * we keep a separate interrupt flag per message type in sw. */
+       pmsg = &per_cpu(j2_ipi_messages, cpu);
+       do old = *pmsg;
+       while (cmpxchg(pmsg, old, old|(1U<<message)) != old);
+
+       /* Generate the actual interrupt by writing to CCRn bit 28. */
+       val = __raw_readl(j2_ipi_trigger + cpu);
+       __raw_writel(val | (1U<<28), j2_ipi_trigger + cpu);
+}
+
+static struct plat_smp_ops j2_smp_ops = {
+       .smp_setup              = j2_smp_setup,
+       .prepare_cpus           = j2_prepare_cpus,
+       .start_cpu              = j2_start_cpu,
+       .smp_processor_id       = j2_smp_processor_id,
+       .send_ipi               = j2_send_ipi,
+       .cpu_die                = native_cpu_die,
+       .cpu_disable            = native_cpu_disable,
+       .play_dead              = native_play_dead,
+};
+
+CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops);
index 5b0bfcd..eadb669 100644 (file)
@@ -13,7 +13,7 @@
 static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
                                 unsigned long offset, size_t size,
                                 enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        dma_addr_t addr = page_to_phys(page) + offset;
 
@@ -25,7 +25,7 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
 
 static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
                        int nents, enum dma_data_direction dir,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
index 9d209a0..e1d751a 100644 (file)
@@ -1009,10 +1009,8 @@ static void __init dwarf_unwinder_cleanup(void)
        rbtree_postorder_for_each_entry_safe(cie, next_cie, &cie_root, node)
                kfree(cie);
 
-       if (dwarf_reg_pool)
-               mempool_destroy(dwarf_reg_pool);
-       if (dwarf_frame_pool)
-               mempool_destroy(dwarf_frame_pool);
+       mempool_destroy(dwarf_reg_pool);
+       mempool_destroy(dwarf_frame_pool);
        kmem_cache_destroy(dwarf_reg_cachep);
        kmem_cache_destroy(dwarf_frame_cachep);
 }
index 974bc15..4e352c3 100644 (file)
@@ -67,7 +67,7 @@ ENTRY(_stext)
        ldc     r0, r6_bank
 #endif
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_FLATTREE
        mov     r4, r12         ! Store device tree blob pointer in r12
 #endif
        
@@ -318,7 +318,7 @@ ENTRY(_stext)
 10:            
 #endif
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_FLATTREE
        mov.l   8f, r0          ! Make flat device tree available early.
        jsr     @r0
         mov    r12, r4
@@ -349,7 +349,7 @@ ENTRY(stack_start)
 5:     .long   start_kernel
 6:     .long   cpu_init
 7:     .long   init_thread_union
-#if defined(CONFIG_OF)
+#if defined(CONFIG_OF_FLATTREE)
 8:     .long   sh_fdt_init
 #endif
 
index 5d34605..e7b49d8 100644 (file)
@@ -242,7 +242,7 @@ void __init __weak plat_early_device_setup(void)
 {
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_FLATTREE
 void __ref sh_fdt_init(phys_addr_t dt_phys)
 {
        static int done = 0;
@@ -251,7 +251,11 @@ void __ref sh_fdt_init(phys_addr_t dt_phys)
        /* Avoid calling an __init function on secondary cpus. */
        if (done) return;
 
+#ifdef CONFIG_USE_BUILTIN_DTB
+       dt_virt = __dtb_start;
+#else
        dt_virt = phys_to_virt(dt_phys);
+#endif
 
        if (!dt_virt || !early_init_dt_scan(dt_virt)) {
                pr_crit("Error: invalid device tree blob"
index 734234b..254bc22 100644 (file)
@@ -386,3 +386,17 @@ ENTRY(sys_call_table)
        .long sys_process_vm_writev
        .long sys_kcmp
        .long sys_finit_module
+       .long sys_sched_getattr
+       .long sys_sched_setattr         /* 370 */
+       .long sys_renameat2
+       .long sys_seccomp
+       .long sys_getrandom
+       .long sys_memfd_create
+       .long sys_bpf                   /* 375 */
+       .long sys_execveat
+       .long sys_userfaultfd
+       .long sys_membarrier
+       .long sys_mlock2
+       .long sys_copy_file_range       /* 380 */
+       .long sys_preadv2
+       .long sys_pwritev2
index 579fcb9..d6a27f7 100644 (file)
@@ -406,3 +406,17 @@ sys_call_table:
        .long sys_process_vm_writev
        .long sys_kcmp
        .long sys_finit_module
+       .long sys_sched_getattr         /* 380 */
+       .long sys_sched_setattr
+       .long sys_renameat2
+       .long sys_seccomp
+       .long sys_getrandom
+       .long sys_memfd_create          /* 385 */
+       .long sys_bpf
+       .long sys_execveat
+       .long sys_userfaultfd
+       .long sys_membarrier
+       .long sys_mlock2                /* 390 */
+       .long sys_copy_file_range
+       .long sys_preadv2
+       .long sys_pwritev2
index d6d0a98..fcd5e41 100644 (file)
@@ -11,7 +11,6 @@
  * for more details.
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/profile.h>
 #include <linux/timex.h>
@@ -50,27 +49,31 @@ int update_persistent_clock(struct timespec now)
 }
 #endif
 
-unsigned int get_rtc_time(struct rtc_time *tm)
+static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
 {
-       if (rtc_sh_get_time != null_rtc_get_time) {
-               struct timespec tv;
+       struct timespec tv;
 
-               rtc_sh_get_time(&tv);
-               rtc_time_to_tm(tv.tv_sec, tm);
-       }
-
-       return RTC_24H;
+       rtc_sh_get_time(&tv);
+       rtc_time_to_tm(tv.tv_sec, tm);
+       return 0;
 }
-EXPORT_SYMBOL(get_rtc_time);
 
-int set_rtc_time(struct rtc_time *tm)
+static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
 {
        unsigned long secs;
 
        rtc_tm_to_time(tm, &secs);
-       return rtc_sh_set_time(secs);
+       if ((rtc_sh_set_time == null_rtc_set_time) ||
+           (rtc_sh_set_time(secs) < 0))
+               return -EOPNOTSUPP;
+
+       return 0;
 }
-EXPORT_SYMBOL(set_rtc_time);
+
+static const struct rtc_class_ops rtc_generic_ops = {
+       .read_time = rtc_generic_get_time,
+       .set_time = rtc_generic_set_time,
+};
 
 static int __init rtc_generic_init(void)
 {
@@ -79,11 +82,14 @@ static int __init rtc_generic_init(void)
        if (rtc_sh_get_time == null_rtc_get_time)
                return -ENODEV;
 
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+                                            &rtc_generic_ops,
+                                            sizeof(rtc_generic_ops));
+
 
        return PTR_ERR_OR_ZERO(pdev);
 }
-module_init(rtc_generic_init);
+device_initcall(rtc_generic_init);
 
 void (*board_time_init)(void);
 
index cee6b99..92c3bd9 100644 (file)
@@ -4,7 +4,8 @@
 
 obj-y                  := alignment.o cache.o init.o consistent.o mmap.o
 
-cacheops-$(CONFIG_CPU_SH2)             := cache-sh2.o
+cacheops-$(CONFIG_CPU_J2)              := cache-j2.o
+cacheops-$(CONFIG_CPU_SUBTYPE_SH7619)  := cache-sh2.o
 cacheops-$(CONFIG_CPU_SH2A)            := cache-sh2a.o
 cacheops-$(CONFIG_CPU_SH3)             := cache-sh3.o
 cacheops-$(CONFIG_CPU_SH4)             := cache-sh4.o flush-sh4.o
index ecfc6b0..bf95fda 100644 (file)
@@ -17,7 +17,6 @@
  * for more details.
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
@@ -70,6 +69,4 @@ static int __init asids_debugfs_init(void)
 
        return PTR_ERR_OR_ZERO(asids_dentry);
 }
-module_init(asids_debugfs_init);
-
-MODULE_LICENSE("GPL v2");
+device_initcall(asids_debugfs_init);
diff --git a/arch/sh/mm/cache-j2.c b/arch/sh/mm/cache-j2.c
new file mode 100644 (file)
index 0000000..391698b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * arch/sh/mm/cache-j2.c
+ *
+ * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpumask.h>
+
+#include <asm/cache.h>
+#include <asm/addrspace.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+
+#define ICACHE_ENABLE  0x1
+#define DCACHE_ENABLE  0x2
+#define CACHE_ENABLE   (ICACHE_ENABLE | DCACHE_ENABLE)
+#define ICACHE_FLUSH   0x100
+#define DCACHE_FLUSH   0x200
+#define CACHE_FLUSH    (ICACHE_FLUSH | DCACHE_FLUSH)
+
+u32 __iomem *j2_ccr_base;
+
+static void j2_flush_icache(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | ICACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+static void j2_flush_dcache(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | DCACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+static void j2_flush_both(void *args)
+{
+       unsigned cpu;
+       for_each_possible_cpu(cpu)
+               __raw_writel(CACHE_ENABLE | CACHE_FLUSH, j2_ccr_base + cpu);
+}
+
+void __init j2_cache_init(void)
+{
+       if (!j2_ccr_base)
+               return;
+
+       local_flush_cache_all = j2_flush_both;
+       local_flush_cache_mm = j2_flush_both;
+       local_flush_cache_dup_mm = j2_flush_both;
+       local_flush_cache_page = j2_flush_both;
+       local_flush_cache_range = j2_flush_both;
+       local_flush_dcache_page = j2_flush_dcache;
+       local_flush_icache_range = j2_flush_icache;
+       local_flush_icache_page = j2_flush_icache;
+       local_flush_cache_sigtramp = j2_flush_icache;
+
+       pr_info("Initial J2 CCR is %.8x\n", __raw_readl(j2_ccr_base));
+}
index e58cfbf..36554a9 100644 (file)
@@ -42,6 +42,8 @@ static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info,
 {
        preempt_disable();
 
+       /* Needing IPI for cross-core flush is SHX3-specific. */
+#ifdef CONFIG_CPU_SHX3
        /*
         * It's possible that this gets called early on when IRQs are
         * still disabled due to ioremapping by the boot CPU, so don't
@@ -49,6 +51,7 @@ static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info,
         */
        if (num_online_cpus() > 1)
                smp_call_function(func, info, wait);
+#endif
 
        func(info);
 
@@ -244,7 +247,11 @@ void flush_cache_sigtramp(unsigned long address)
 
 static void compute_alias(struct cache_info *c)
 {
+#ifdef CONFIG_MMU
        c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
+#else
+       c->alias_mask = 0;
+#endif
        c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0;
 }
 
@@ -305,7 +312,11 @@ void __init cpu_cache_init(void)
        if (unlikely(cache_disabled))
                goto skip;
 
-       if (boot_cpu_data.family == CPU_FAMILY_SH2) {
+       if (boot_cpu_data.type == CPU_J2) {
+               extern void __weak j2_cache_init(void);
+
+               j2_cache_init();
+       } else if (boot_cpu_data.family == CPU_FAMILY_SH2) {
                extern void __weak sh2_cache_init(void);
 
                sh2_cache_init();
index b81d9db..92b6976 100644 (file)
@@ -34,7 +34,7 @@ fs_initcall(dma_init);
 
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_handle, gfp_t gfp,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        void *ret, *ret_nocache;
        int order = get_order(size);
@@ -66,7 +66,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 
 void dma_generic_free_coherent(struct device *dev, size_t size,
                               void *vaddr, dma_addr_t dma_handle,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        int order = get_order(size);
        unsigned long pfn = dma_handle >> PAGE_SHIFT;
index 0c99ec2..d09ddfe 100644 (file)
@@ -34,7 +34,7 @@
  * have to convert them into an offset in a page-aligned mapping, but the
  * caller shouldn't need to know that small detail.
  */
-void __iomem * __init_refok
+void __iomem * __ref
 __ioremap_caller(phys_addr_t phys_addr, unsigned long size,
                 pgprot_t pgprot, void *caller)
 {
index 546293d..59b0960 100644 (file)
@@ -43,6 +43,7 @@ config SPARC
        select OLD_SIGSUSPEND
        select ARCH_HAS_SG_CHAIN
        select CPU_NO_EFFICIENT_FFS
+       select HAVE_ARCH_HARDENED_USERCOPY
 
 config SPARC32
        def_bool !64BIT
index 57f26c3..4dd268a 100644 (file)
@@ -140,16 +140,6 @@ void ioport_unmap(void __iomem *);
 struct pci_dev;
 void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
-
-
-/*
- * At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
- * so rtc_port is static in it. This should not change unless a new
- * hardware pops up.
- */
-#define RTC_PORT(x)   (rtc_port + (x))
-#define RTC_ALWAYS_BCD  0
-
 static inline int sbus_can_dma_64bit(void)
 {
        return 0; /* actually, sparc_cpu_model==sun4d */
index 022d160..2303635 100644 (file)
@@ -55,9 +55,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 }
 
 #define HAVE_ARCH_PCI_RESOURCE_TO_USER
-void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                         const struct resource *rsrc,
-                         resource_size_t *start, resource_size_t *end);
 #endif /* __KERNEL__ */
 
 #endif /* __SPARC64_PCI_H */
index bde5982..3d7b925 100644 (file)
@@ -222,32 +222,8 @@ register struct thread_info *current_thread_info_reg asm("g6");
  *
  * Note that there are only 8 bits available.
  */
-#define TS_RESTORE_SIGMASK     0x0001  /* restore signal mask in do_signal() */
 
 #ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
 
 #define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0)
 #define test_thread_64bit_stack(__SP) \
index 57aca27..341a5a1 100644 (file)
@@ -248,22 +248,28 @@ unsigned long __copy_user(void __user *to, const void __user *from, unsigned lon
 
 static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       if (n && __access_ok((unsigned long) to, n))
+       if (n && __access_ok((unsigned long) to, n)) {
+               if (!__builtin_constant_p(n))
+                       check_object_size(from, n, true);
                return __copy_user(to, (__force void __user *) from, n);
-       else
+       else
                return n;
 }
 
 static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
+       if (!__builtin_constant_p(n))
+               check_object_size(from, n, true);
        return __copy_user(to, (__force void __user *) from, n);
 }
 
 static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       if (n && __access_ok((unsigned long) from, n))
+       if (n && __access_ok((unsigned long) from, n)) {
+               if (!__builtin_constant_p(n))
+                       check_object_size(to, n, false);
                return __copy_user((__force void __user *) to, from, n);
-       else
+       else
                return n;
 }
 
index e9a51d6..8bda94f 100644 (file)
@@ -210,8 +210,12 @@ unsigned long copy_from_user_fixup(void *to, const void __user *from,
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long size)
 {
-       unsigned long ret = ___copy_from_user(to, from, size);
+       unsigned long ret;
 
+       if (!__builtin_constant_p(size))
+               check_object_size(to, size, false);
+
+       ret = ___copy_from_user(to, from, size);
        if (unlikely(ret))
                ret = copy_from_user_fixup(to, from, size);
 
@@ -227,8 +231,11 @@ unsigned long copy_to_user_fixup(void __user *to, const void *from,
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long size)
 {
-       unsigned long ret = ___copy_to_user(to, from, size);
+       unsigned long ret;
 
+       if (!__builtin_constant_p(size))
+               check_object_size(from, size, true);
+       ret = ___copy_to_user(to, from, size);
        if (unlikely(ret))
                ret = copy_to_user_fixup(to, from, size);
        return ret;
index 3768682..5c615ab 100644 (file)
@@ -196,7 +196,7 @@ static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
 
 static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
                                   dma_addr_t *dma_addrp, gfp_t gfp,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        unsigned long order, first_page;
        struct iommu *iommu;
@@ -245,7 +245,7 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
 
 static void dma_4u_free_coherent(struct device *dev, size_t size,
                                 void *cpu, dma_addr_t dvma,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        struct iommu *iommu;
        unsigned long order, npages;
@@ -263,7 +263,7 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
 static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
                                  unsigned long offset, size_t sz,
                                  enum dma_data_direction direction,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -385,7 +385,7 @@ do_flush_sync:
 
 static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
                              size_t sz, enum dma_data_direction direction,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -431,7 +431,7 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
 
 static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        struct scatterlist *s, *outs, *segstart;
        unsigned long flags, handle, prot, ctx;
@@ -607,7 +607,7 @@ static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg)
 
 static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        unsigned long flags, ctx;
        struct scatterlist *sg;
index ffd5ff4..2344103 100644 (file)
@@ -260,7 +260,7 @@ EXPORT_SYMBOL(sbus_set_sbus64);
  */
 static void *sbus_alloc_coherent(struct device *dev, size_t len,
                                 dma_addr_t *dma_addrp, gfp_t gfp,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        struct platform_device *op = to_platform_device(dev);
        unsigned long len_total = PAGE_ALIGN(len);
@@ -315,7 +315,7 @@ err_nopages:
 }
 
 static void sbus_free_coherent(struct device *dev, size_t n, void *p,
-                              dma_addr_t ba, struct dma_attrs *attrs)
+                              dma_addr_t ba, unsigned long attrs)
 {
        struct resource *res;
        struct page *pgv;
@@ -355,7 +355,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
 static dma_addr_t sbus_map_page(struct device *dev, struct page *page,
                                unsigned long offset, size_t len,
                                enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        void *va = page_address(page) + offset;
 
@@ -371,20 +371,20 @@ static dma_addr_t sbus_map_page(struct device *dev, struct page *page,
 }
 
 static void sbus_unmap_page(struct device *dev, dma_addr_t ba, size_t n,
-                           enum dma_data_direction dir, struct dma_attrs *attrs)
+                           enum dma_data_direction dir, unsigned long attrs)
 {
        mmu_release_scsi_one(dev, ba, n);
 }
 
 static int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n,
-                      enum dma_data_direction dir, struct dma_attrs *attrs)
+                      enum dma_data_direction dir, unsigned long attrs)
 {
        mmu_get_scsi_sgl(dev, sg, n);
        return n;
 }
 
 static void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n,
-                         enum dma_data_direction dir, struct dma_attrs *attrs)
+                         enum dma_data_direction dir, unsigned long attrs)
 {
        mmu_release_scsi_sgl(dev, sg, n);
 }
@@ -429,7 +429,7 @@ arch_initcall(sparc_register_ioport);
  */
 static void *pci32_alloc_coherent(struct device *dev, size_t len,
                                  dma_addr_t *pba, gfp_t gfp,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        unsigned long len_total = PAGE_ALIGN(len);
        void *va;
@@ -482,7 +482,7 @@ err_nopages:
  * past this call are illegal.
  */
 static void pci32_free_coherent(struct device *dev, size_t n, void *p,
-                               dma_addr_t ba, struct dma_attrs *attrs)
+                               dma_addr_t ba, unsigned long attrs)
 {
        struct resource *res;
 
@@ -518,14 +518,14 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
 static dma_addr_t pci32_map_page(struct device *dev, struct page *page,
                                 unsigned long offset, size_t size,
                                 enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        /* IIep is write-through, not flushing. */
        return page_to_phys(page) + offset;
 }
 
 static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
-                            enum dma_data_direction dir, struct dma_attrs *attrs)
+                            enum dma_data_direction dir, unsigned long attrs)
 {
        if (dir != PCI_DMA_TODEVICE)
                dma_make_coherent(ba, PAGE_ALIGN(size));
@@ -548,7 +548,7 @@ static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
  */
 static int pci32_map_sg(struct device *device, struct scatterlist *sgl,
                        int nents, enum dma_data_direction dir,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        struct scatterlist *sg;
        int n;
@@ -567,7 +567,7 @@ static int pci32_map_sg(struct device *device, struct scatterlist *sgl,
  */
 static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl,
                           int nents, enum dma_data_direction dir,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        struct scatterlist *sg;
        int n;
index c2b202d..9c1878f 100644 (file)
@@ -986,16 +986,18 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
                          const struct resource *rp, resource_size_t *start,
                          resource_size_t *end)
 {
-       struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       unsigned long offset;
-
-       if (rp->flags & IORESOURCE_IO)
-               offset = pbm->io_space.start;
-       else
-               offset = pbm->mem_space.start;
+       struct pci_bus_region region;
 
-       *start = rp->start - offset;
-       *end = rp->end - offset;
+       /*
+        * "User" addresses are shown in /sys/devices/pci.../.../resource
+        * and /proc/bus/pci/devices and used as mmap offsets for
+        * /proc/bus/pci/BB/DD.F files (see proc_bus_pci_mmap()).
+        *
+        * On sparc, these are PCI bus addresses, i.e., raw BAR values.
+        */
+       pcibios_resource_to_bus(pdev->bus, &region, (struct resource *) rp);
+       *start = region.start;
+       *end = region.end;
 }
 
 void pcibios_set_master(struct pci_dev *dev)
index 836e8ce..61c6f93 100644 (file)
@@ -130,7 +130,7 @@ static inline long iommu_batch_end(void)
 
 static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
                                   dma_addr_t *dma_addrp, gfp_t gfp,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        unsigned long flags, order, first_page, npages, n;
        struct iommu *iommu;
@@ -213,7 +213,7 @@ static void dma_4v_iommu_demap(void *demap_arg, unsigned long entry,
 }
 
 static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
-                                dma_addr_t dvma, struct dma_attrs *attrs)
+                                dma_addr_t dvma, unsigned long attrs)
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
@@ -235,7 +235,7 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
 static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
                                  unsigned long offset, size_t sz,
                                  enum dma_data_direction direction,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        struct iommu *iommu;
        unsigned long flags, npages, oaddr;
@@ -294,7 +294,7 @@ iommu_map_fail:
 
 static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
                              size_t sz, enum dma_data_direction direction,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
@@ -322,7 +322,7 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
 
 static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                         int nelems, enum dma_data_direction direction,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        struct scatterlist *s, *outs, *segstart;
        unsigned long flags, handle, prot;
@@ -466,7 +466,7 @@ iommu_map_failed:
 
 static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct pci_pbm_info *pbm;
        struct scatterlist *sg;
index 7d02b1f..d79b3b7 100644 (file)
@@ -150,6 +150,13 @@ SECTIONS
        }
        PERCPU_SECTION(SMP_CACHE_BYTES)
 
+#ifdef CONFIG_JUMP_LABEL
+       . = ALIGN(PAGE_SIZE);
+       .exit.text : {
+               EXIT_TEXT
+       }
+#endif
+
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        BSS_SECTION(0, 0, 0)
index c1467ac..b7659b8 100644 (file)
@@ -166,32 +166,5 @@ extern void _cpu_idle(void);
 #ifdef __tilegx__
 #define TS_COMPAT              0x0001  /* 32-bit compatibility mode */
 #endif
-#define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal */
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
-#endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_TILE_THREAD_INFO_H */
index b6bc054..09bb774 100644 (file)
@@ -34,7 +34,7 @@
 
 static void *tile_dma_alloc_coherent(struct device *dev, size_t size,
                                     dma_addr_t *dma_handle, gfp_t gfp,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        u64 dma_mask = (dev && dev->coherent_dma_mask) ?
                dev->coherent_dma_mask : DMA_BIT_MASK(32);
@@ -78,7 +78,7 @@ static void *tile_dma_alloc_coherent(struct device *dev, size_t size,
  */
 static void tile_dma_free_coherent(struct device *dev, size_t size,
                                   void *vaddr, dma_addr_t dma_handle,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        homecache_free_pages((unsigned long)vaddr, get_order(size));
 }
@@ -202,7 +202,7 @@ static void __dma_complete_pa_range(dma_addr_t dma_addr, size_t size,
 
 static int tile_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                           int nents, enum dma_data_direction direction,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -224,7 +224,7 @@ static int tile_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 
 static void tile_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                              int nents, enum dma_data_direction direction,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -240,7 +240,7 @@ static void tile_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
 static dma_addr_t tile_dma_map_page(struct device *dev, struct page *page,
                                    unsigned long offset, size_t size,
                                    enum dma_data_direction direction,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        BUG_ON(!valid_dma_direction(direction));
 
@@ -252,7 +252,7 @@ static dma_addr_t tile_dma_map_page(struct device *dev, struct page *page,
 
 static void tile_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
                                size_t size, enum dma_data_direction direction,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        BUG_ON(!valid_dma_direction(direction));
 
@@ -343,7 +343,7 @@ EXPORT_SYMBOL(tile_dma_map_ops);
 
 static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
                                         dma_addr_t *dma_handle, gfp_t gfp,
-                                        struct dma_attrs *attrs)
+                                        unsigned long attrs)
 {
        int node = dev_to_node(dev);
        int order = get_order(size);
@@ -368,14 +368,14 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size,
  */
 static void tile_pci_dma_free_coherent(struct device *dev, size_t size,
                                       void *vaddr, dma_addr_t dma_handle,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        homecache_free_pages((unsigned long)vaddr, get_order(size));
 }
 
 static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
                               int nents, enum dma_data_direction direction,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -400,7 +400,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist,
 static void tile_pci_dma_unmap_sg(struct device *dev,
                                  struct scatterlist *sglist, int nents,
                                  enum dma_data_direction direction,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -416,7 +416,7 @@ static void tile_pci_dma_unmap_sg(struct device *dev,
 static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
                                        unsigned long offset, size_t size,
                                        enum dma_data_direction direction,
-                                       struct dma_attrs *attrs)
+                                       unsigned long attrs)
 {
        BUG_ON(!valid_dma_direction(direction));
 
@@ -429,7 +429,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page,
 static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address,
                                    size_t size,
                                    enum dma_data_direction direction,
-                                   struct dma_attrs *attrs)
+                                   unsigned long attrs)
 {
        BUG_ON(!valid_dma_direction(direction));
 
@@ -531,7 +531,7 @@ EXPORT_SYMBOL(gx_pci_dma_map_ops);
 #ifdef CONFIG_SWIOTLB
 static void *tile_swiotlb_alloc_coherent(struct device *dev, size_t size,
                                         dma_addr_t *dma_handle, gfp_t gfp,
-                                        struct dma_attrs *attrs)
+                                        unsigned long attrs)
 {
        gfp |= GFP_DMA;
        return swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
@@ -539,7 +539,7 @@ static void *tile_swiotlb_alloc_coherent(struct device *dev, size_t size,
 
 static void tile_swiotlb_free_coherent(struct device *dev, size_t size,
                                       void *vaddr, dma_addr_t dma_addr,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_addr);
 }
index 378f5d8..9d449ca 100644 (file)
@@ -60,6 +60,18 @@ SECTIONS
   /* "Init" is divided into two areas with very different virtual addresses. */
   INIT_TEXT_SECTION(PAGE_SIZE)
 
+  /*
+   * Some things, like the __jump_table, may contain symbol references
+   * to __exit text, so include such text in the final image if so.
+   * In that case we also override the _einittext from INIT_TEXT_SECTION.
+   */
+#ifdef CONFIG_JUMP_LABEL
+  .exit.text : {
+    EXIT_TEXT
+    _einittext = .;
+  }
+#endif
+
   /* Now we skip back to PAGE_OFFSET for the data. */
   . = (. - TEXT_OFFSET + PAGE_OFFSET);
   #undef LOAD_OFFSET
index cc00134..fd44385 100644 (file)
@@ -1,14 +1,17 @@
 config UML
        bool
        default y
+       select ARCH_HAS_KCOV
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_UID16
        select HAVE_FUTEX_CMPXCHG if FUTEX
+       select HAVE_DEBUG_KMEMLEAK
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
        select GENERIC_IO
        select GENERIC_CLOCKEVENTS
+       select HAVE_GCC_PLUGINS
        select TTY # Needed for line.c
 
 config MMU
@@ -30,10 +33,9 @@ config PCI
 config PCMCIA
        bool
 
-# Yet to do!
 config TRACE_IRQFLAGS_SUPPORT
        bool
-       default n
+       default y
 
 config LOCKDEP_SUPPORT
        bool
index e3abe6f..0ca46ed 100644 (file)
@@ -78,8 +78,8 @@ include $(ARCH_DIR)/Makefile-os-$(OS)
 
 KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \
                   -I$(srctree)/$(HOST_DIR)/include/uapi \
-                  -I$(HOST_DIR)/include/generated \
-                  -I$(HOST_DIR)/include/generated/uapi
+                  -I$(objtree)/$(HOST_DIR)/include/generated \
+                  -I$(objtree)/$(HOST_DIR)/include/generated/uapi
 
 # -Derrno=kernel_errno - This turns all kernel references to errno into
 # kernel_errno to separate them from the libc errno.  This allows -fno-common
index c780d8a..3bb221e 100644 (file)
@@ -6,37 +6,33 @@ extern int set_signals(int enable);
 extern void block_signals(void);
 extern void unblock_signals(void);
 
+#define arch_local_save_flags arch_local_save_flags
 static inline unsigned long arch_local_save_flags(void)
 {
        return get_signals();
 }
 
+#define arch_local_irq_restore arch_local_irq_restore
 static inline void arch_local_irq_restore(unsigned long flags)
 {
        set_signals(flags);
 }
 
+#define arch_local_irq_enable arch_local_irq_enable
 static inline void arch_local_irq_enable(void)
 {
        unblock_signals();
 }
 
+#define arch_local_irq_disable arch_local_irq_disable
 static inline void arch_local_irq_disable(void)
 {
        block_signals();
 }
 
-static inline unsigned long arch_local_irq_save(void)
-{
-       unsigned long flags;
-       flags = arch_local_save_flags();
-       arch_local_irq_disable();
-       return flags;
-}
+#define ARCH_IRQ_DISABLED      0
+#define ARCh_IRQ_ENABLED       (SIGIO|SIGVTALRM)
 
-static inline bool arch_irqs_disabled(void)
-{
-       return arch_local_save_flags() == 0;
-}
+#include <asm-generic/irqflags.h>
 
 #endif
index a6a5e42..2f36d51 100644 (file)
@@ -3,6 +3,11 @@
 # Licensed under the GPL
 #
 
+# Don't instrument UML-specific code; without this, we may crash when
+# accessing the instrumentation buffer for the first time from the
+# kernel.
+KCOV_INSTRUMENT                := n
+
 CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START)           \
                         -DELF_ARCH=$(LDS_ELF_ARCH)     \
                         -DELF_FORMAT=$(LDS_ELF_FORMAT) \
index 55cead8..48bae81 100644 (file)
@@ -37,8 +37,6 @@ static int __init read_initrd(void)
        }
 
        area = alloc_bootmem(size);
-       if (area == NULL)
-               return 0;
 
        if (load_initrd(initrd, area, size) == -1)
                return 0;
index 16630e7..e8175a8 100644 (file)
@@ -319,9 +319,6 @@ int __init linux_main(int argc, char **argv)
 
        start_vm = VMALLOC_START;
 
-       setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
-       mem_total_pages(physmem_size, iomem_size, highmem);
-
        virtmem_size = physmem_size;
        stack = (unsigned long) argv;
        stack &= ~(1024 * 1024 - 1);
@@ -334,7 +331,6 @@ int __init linux_main(int argc, char **argv)
                printf("Kernel virtual memory size shrunk to %lu bytes\n",
                       virtmem_size);
 
-       stack_protections((unsigned long) &init_thread_info);
        os_flush_stdout();
 
        return start_uml();
@@ -342,6 +338,10 @@ int __init linux_main(int argc, char **argv)
 
 void __init setup_arch(char **cmdline_p)
 {
+       stack_protections((unsigned long) &init_thread_info);
+       setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
+       mem_total_pages(physmem_size, iomem_size, highmem);
+
        paging_init();
        strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
index 08ff509..ada473b 100644 (file)
@@ -3,6 +3,9 @@
 # Licensed under the GPL
 #
 
+# Don't instrument UML-specific code
+KCOV_INSTRUMENT                := n
+
 obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
        registers.o sigio.o signal.o start_up.o time.o tty.o \
        umid.o user_syms.o util.o drivers/ skas/
index 8acaf4e..a86d7cc 100644 (file)
@@ -15,6 +15,7 @@
 #include <kern_util.h>
 #include <os.h>
 #include <sysdep/mcontext.h>
+#include <um_malloc.h>
 
 void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
        [SIGTRAP]       = relay_signal,
@@ -32,7 +33,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
        struct uml_pt_regs *r;
        int save_errno = errno;
 
-       r = malloc(sizeof(struct uml_pt_regs));
+       r = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC);
        if (!r)
                panic("out of memory");
 
@@ -91,7 +92,7 @@ static void timer_real_alarm_handler(mcontext_t *mc)
 {
        struct uml_pt_regs *regs;
 
-       regs = malloc(sizeof(struct uml_pt_regs));
+       regs = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC);
        if (!regs)
                panic("out of memory");
 
index d45fa5f..62137d1 100644 (file)
@@ -265,10 +265,8 @@ static int __init pci_common_init(void)
 
        pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
-               pci_bus_size_bridges(puv3_bus);
-               pci_bus_assign_resources(puv3_bus);
-       }
+       pci_bus_size_bridges(puv3_bus);
+       pci_bus_assign_resources(puv3_bus);
        pci_bus_add_devices(puv3_bus);
        return 0;
 }
@@ -279,9 +277,6 @@ char * __init pcibios_setup(char *str)
        if (!strcmp(str, "debug")) {
                debug_pci = 1;
                return NULL;
-       } else if (!strcmp(str, "firmware")) {
-               pci_add_flags(PCI_PROBE_ONLY);
-               return NULL;
        }
        return str;
 }
index 16c08b2..3e9f648 100644 (file)
 
 static void *unicore_swiotlb_alloc_coherent(struct device *dev, size_t size,
                                            dma_addr_t *dma_handle, gfp_t flags,
-                                           struct dma_attrs *attrs)
+                                           unsigned long attrs)
 {
        return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
 }
 
 static void unicore_swiotlb_free_coherent(struct device *dev, size_t size,
                                          void *vaddr, dma_addr_t dma_addr,
-                                         struct dma_attrs *attrs)
+                                         unsigned long attrs)
 {
        swiotlb_free_coherent(dev, size, vaddr, dma_addr);
 }
index 2fa5585..c580d8c 100644 (file)
@@ -80,6 +80,7 @@ config X86
        select HAVE_ALIGNED_STRUCT_PAGE         if SLUB
        select HAVE_AOUT                        if X86_32
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_HUGE_VMAP              if X86_64 || X86_PAE
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KASAN                  if X86_64 && SPARSEMEM_VMEMMAP
@@ -91,6 +92,7 @@ config X86
        select HAVE_ARCH_SOFT_DIRTY             if X86_64
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+       select HAVE_ARCH_WITHIN_STACK_FRAMES
        select HAVE_EBPF_JIT                    if X86_64
        select HAVE_CC_STACKPROTECTOR
        select HAVE_CMPXCHG_DOUBLE
@@ -111,6 +113,7 @@ config X86
        select HAVE_FUNCTION_GRAPH_FP_TEST
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
+       select HAVE_GCC_PLUGINS
        select HAVE_GENERIC_DMA_COHERENT        if X86_32
        select HAVE_HW_BREAKPOINT
        select HAVE_IDE
@@ -151,6 +154,7 @@ config X86
        select OLD_SIGSUSPEND3                  if X86_32 || IA32_EMULATION
        select PERF_EVENTS
        select RTC_LIB
+       select RTC_MC146818_LIB
        select SPARSE_IRQ
        select SRCU
        select SYSCTL_EXCEPTION_TRACE
index be8e688..12ea8f8 100644 (file)
@@ -96,7 +96,7 @@ $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,zoffset)
 
 
-AFLAGS_header.o += -I$(obj)
+AFLAGS_header.o += -I$(objtree)/$(obj)
 $(obj)/header.o: $(obj)/zoffset.h
 
 LDFLAGS_setup.elf      := -T
index a1e71d4..1433f6b 100644 (file)
@@ -204,8 +204,12 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
         * handling, because syscall restart has a fixup for compat
         * syscalls.  The fixup is exercised by the ptrace_syscall_32
         * selftest.
+        *
+        * We also need to clear TS_REGS_POKED_I386: the 32-bit tracer
+        * special case only applies after poking regs and before the
+        * very next return to user mode.
         */
-       ti->status &= ~TS_COMPAT;
+       ti->status &= ~(TS_COMPAT|TS_I386_REGS_POKED);
 #endif
 
        user_enter_irqoff();
index 4cddd17..f848572 100644 (file)
 # 285 sys_setaltroot
 286    i386    add_key                 sys_add_key
 287    i386    request_key             sys_request_key
-288    i386    keyctl                  sys_keyctl
+288    i386    keyctl                  sys_keyctl                      compat_sys_keyctl
 289    i386    ioprio_set              sys_ioprio_set
 290    i386    ioprio_get              sys_ioprio_get
 291    i386    inotify_init            sys_inotify_init
index 6ba89a1..d540966 100644 (file)
@@ -75,7 +75,7 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
        -fno-omit-frame-pointer -foptimize-sibling-calls \
        -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
 
-$(vobjs): KBUILD_CFLAGS += $(CFL)
+$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
 
 #
 # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
@@ -145,6 +145,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
 KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32))
+KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32))
 KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic
 KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector)
 KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls)
index 2f02d23..94d54d0 100644 (file)
@@ -96,9 +96,8 @@ static notrace cycle_t vread_pvclock(int *mode)
 {
        const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
        cycle_t ret;
-       u64 tsc, pvti_tsc;
-       u64 last, delta, pvti_system_time;
-       u32 version, pvti_tsc_to_system_mul, pvti_tsc_shift;
+       u64 last;
+       u32 version;
 
        /*
         * Note: The kernel and hypervisor must guarantee that cpu ID
@@ -123,29 +122,15 @@ static notrace cycle_t vread_pvclock(int *mode)
         */
 
        do {
-               version = pvti->version;
-
-               smp_rmb();
+               version = pvclock_read_begin(pvti);
 
                if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
                        *mode = VCLOCK_NONE;
                        return 0;
                }
 
-               tsc = rdtsc_ordered();
-               pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
-               pvti_tsc_shift = pvti->tsc_shift;
-               pvti_system_time = pvti->system_time;
-               pvti_tsc = pvti->tsc_timestamp;
-
-               /* Make sure that the version double-check is last. */
-               smp_rmb();
-       } while (unlikely((version & 1) || version != pvti->version));
-
-       delta = tsc - pvti_tsc;
-       ret = pvti_system_time +
-               pvclock_scale_delta(delta, pvti_tsc_to_system_mul,
-                                   pvti_tsc_shift);
+               ret = __pvclock_read_cycles(pvti);
+       } while (pvclock_read_retry(pvti, version));
 
        /* refer to vread_tsc() comment for rationale */
        last = gtod->cycle_last;
index 63a03bb..4f74119 100644 (file)
@@ -22,6 +22,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
 
        ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_LE(&hdr->e_phoff));
 
+       if (hdr->e_type != ET_DYN)
+               fail("input is not a shared object\n");
+
        /* Walk the segment table. */
        for (i = 0; i < GET_LE(&hdr->e_phnum); i++) {
                if (GET_LE(&pt[i].p_type) == PT_LOAD) {
@@ -49,6 +52,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len,
        if (stripped_len < load_size)
                fail("stripped input is too short\n");
 
+       if (!dyn)
+               fail("input has no PT_DYNAMIC section -- your toolchain is buggy\n");
+
        /* Walk the dynamic table */
        for (i = 0; dyn + i < dyn_end &&
                     GET_LE(&dyn[i].d_tag) != DT_NULL; i++) {
index fad9788..d0efb5c 100644 (file)
@@ -263,10 +263,13 @@ static bool check_hw_exists(void)
        return true;
 
 msr_fail:
-       pr_cont("Broken PMU hardware detected, using software events only.\n");
-       printk("%sFailed to access perfctr msr (MSR %x is %Lx)\n",
-               boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR,
-               reg, val_new);
+       if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+               pr_cont("PMU not available due to virtualization, using software events only.\n");
+       } else {
+               pr_cont("Broken PMU hardware detected, using software events only.\n");
+               pr_err("Failed to access perfctr msr (MSR %x is %Lx)\n",
+                      reg, val_new);
+       }
 
        return false;
 }
index 3a27b93..4446162 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kmemcheck.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
-#include <linux/dma-attrs.h>
 #include <asm/io.h>
 #include <asm/swiotlb.h>
 #include <linux/dma-contiguous.h>
@@ -48,11 +47,11 @@ extern int dma_supported(struct device *hwdev, u64 mask);
 
 extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                        dma_addr_t *dma_addr, gfp_t flag,
-                                       struct dma_attrs *attrs);
+                                       unsigned long attrs);
 
 extern void dma_generic_free_coherent(struct device *dev, size_t size,
                                      void *vaddr, dma_addr_t dma_addr,
-                                     struct dma_attrs *attrs);
+                                     unsigned long attrs);
 
 #ifdef CONFIG_X86_DMA_REMAP /* Platform code defines bridge-specific code */
 extern bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
index fea7724..e7f155c 100644 (file)
@@ -344,8 +344,8 @@ extern int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
  */
 static inline int mmap_is_ia32(void)
 {
-       return config_enabled(CONFIG_X86_32) ||
-              (config_enabled(CONFIG_COMPAT) &&
+       return IS_ENABLED(CONFIG_X86_32) ||
+              (IS_ENABLED(CONFIG_COMPAT) &&
                test_thread_flag(TIF_ADDR32));
 }
 
index 116b583..2737366 100644 (file)
@@ -137,9 +137,9 @@ static inline int copy_fregs_to_user(struct fregs_state __user *fx)
 
 static inline int copy_fxregs_to_user(struct fxregs_state __user *fx)
 {
-       if (config_enabled(CONFIG_X86_32))
+       if (IS_ENABLED(CONFIG_X86_32))
                return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
-       else if (config_enabled(CONFIG_AS_FXSAVEQ))
+       else if (IS_ENABLED(CONFIG_AS_FXSAVEQ))
                return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
 
        /* See comment in copy_fxregs_to_kernel() below. */
@@ -150,10 +150,10 @@ static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
 {
        int err;
 
-       if (config_enabled(CONFIG_X86_32)) {
+       if (IS_ENABLED(CONFIG_X86_32)) {
                err = check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
        } else {
-               if (config_enabled(CONFIG_AS_FXSAVEQ)) {
+               if (IS_ENABLED(CONFIG_AS_FXSAVEQ)) {
                        err = check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
                } else {
                        /* See comment in copy_fxregs_to_kernel() below. */
@@ -166,9 +166,9 @@ static inline void copy_kernel_to_fxregs(struct fxregs_state *fx)
 
 static inline int copy_user_to_fxregs(struct fxregs_state __user *fx)
 {
-       if (config_enabled(CONFIG_X86_32))
+       if (IS_ENABLED(CONFIG_X86_32))
                return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
-       else if (config_enabled(CONFIG_AS_FXSAVEQ))
+       else if (IS_ENABLED(CONFIG_AS_FXSAVEQ))
                return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
 
        /* See comment in copy_fxregs_to_kernel() below. */
@@ -190,9 +190,9 @@ static inline int copy_user_to_fregs(struct fregs_state __user *fx)
 
 static inline void copy_fxregs_to_kernel(struct fpu *fpu)
 {
-       if (config_enabled(CONFIG_X86_32))
+       if (IS_ENABLED(CONFIG_X86_32))
                asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave));
-       else if (config_enabled(CONFIG_AS_FXSAVEQ))
+       else if (IS_ENABLED(CONFIG_AS_FXSAVEQ))
                asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
        else {
                /* Using "rex64; fxsave %0" is broken because, if the memory
index 69e6286..33ae3a4 100644 (file)
@@ -35,8 +35,9 @@
 #include <asm/asm.h>
 #include <asm/kvm_page_track.h>
 
-#define KVM_MAX_VCPUS 255
-#define KVM_SOFT_MAX_VCPUS 160
+#define KVM_MAX_VCPUS 288
+#define KVM_SOFT_MAX_VCPUS 240
+#define KVM_MAX_VCPU_ID 1023
 #define KVM_USER_MEM_SLOTS 509
 /* memory slots that are not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 3
@@ -599,6 +600,7 @@ struct kvm_vcpu_arch {
        u64 mcg_cap;
        u64 mcg_status;
        u64 mcg_ctl;
+       u64 mcg_ext_ctl;
        u64 *mce_banks;
 
        /* Cache MMIO info */
@@ -682,9 +684,12 @@ struct kvm_arch_memory_slot {
 struct kvm_apic_map {
        struct rcu_head rcu;
        u8 mode;
-       struct kvm_lapic *phys_map[256];
-       /* first index is cluster id second is cpu id in a cluster */
-       struct kvm_lapic *logical_map[16][16];
+       u32 max_apic_id;
+       union {
+               struct kvm_lapic *xapic_flat_map[8];
+               struct kvm_lapic *xapic_cluster_map[16][4];
+       };
+       struct kvm_lapic *phys_map[];
 };
 
 /* Hyper-V emulation context */
@@ -779,6 +784,9 @@ struct kvm_arch {
        u32 ldr_mode;
        struct page *avic_logical_id_table_page;
        struct page *avic_physical_id_table_page;
+
+       bool x2apic_format;
+       bool x2apic_broadcast_quirk_disabled;
 };
 
 struct kvm_vm_stat {
@@ -1006,6 +1014,11 @@ struct kvm_x86_ops {
        int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq,
                              uint32_t guest_irq, bool set);
        void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);
+
+       int (*set_hv_timer)(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc);
+       void (*cancel_hv_timer)(struct kvm_vcpu *vcpu);
+
+       void (*setup_mce)(struct kvm_vcpu *vcpu);
 };
 
 struct kvm_arch_async_pf {
@@ -1026,7 +1039,7 @@ void kvm_mmu_setup(struct kvm_vcpu *vcpu);
 void kvm_mmu_init_vm(struct kvm *kvm);
 void kvm_mmu_uninit_vm(struct kvm *kvm);
 void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
-               u64 dirty_mask, u64 nx_mask, u64 x_mask);
+               u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 p_mask);
 
 void kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
@@ -1077,6 +1090,10 @@ extern u32  kvm_max_guest_tsc_khz;
 extern u8   kvm_tsc_scaling_ratio_frac_bits;
 /* maximum allowed value of TSC scaling ratio */
 extern u64  kvm_max_tsc_scaling_ratio;
+/* 1ull << kvm_tsc_scaling_ratio_frac_bits */
+extern u64  kvm_default_tsc_scaling_ratio;
+
+extern u64 kvm_mce_cap_supported;
 
 enum emulation_result {
        EMULATE_DONE,         /* no further processing */
@@ -1352,7 +1369,7 @@ bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu);
 bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq,
                             struct kvm_vcpu **dest_vcpu);
 
-void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e,
+void kvm_set_msi_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
                     struct kvm_lapic_irq *irq);
 
 static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
index 0f555cc..24acd9b 100644 (file)
@@ -6,7 +6,6 @@
 
 #include <asm/io.h>
 #include <asm/processor.h>
-#include <linux/mc146818rtc.h>
 
 #ifndef RTC_PORT
 #define RTC_PORT(x)    (0x70 + (x))
index 3963481..d8abfcf 100644 (file)
@@ -155,7 +155,7 @@ static inline void arch_exit_mmap(struct mm_struct *mm)
 #ifdef CONFIG_X86_64
 static inline bool is_64bit_mm(struct mm_struct *mm)
 {
-       return  !config_enabled(CONFIG_IA32_EMULATION) ||
+       return  !IS_ENABLED(CONFIG_IA32_EMULATION) ||
                !(mm->context.ia32_compat == TIF_IA32);
 }
 #else
index 7c1c895..d019f0c 100644 (file)
@@ -25,6 +25,24 @@ void pvclock_resume(void);
 
 void pvclock_touch_watchdogs(void);
 
+static __always_inline
+unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src)
+{
+       unsigned version = src->version & ~1;
+       /* Make sure that the version is read before the data. */
+       virt_rmb();
+       return version;
+}
+
+static __always_inline
+bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src,
+                       unsigned version)
+{
+       /* Make sure that the version is re-read after the data. */
+       virt_rmb();
+       return unlikely(version != src->version);
+}
+
 /*
  * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
  * yielding a 64-bit result.
@@ -69,23 +87,12 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
 }
 
 static __always_inline
-unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
-                              cycle_t *cycles, u8 *flags)
+cycle_t __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src)
 {
-       unsigned version;
-       cycle_t offset;
-       u64 delta;
-
-       version = src->version;
-       /* Make the latest version visible */
-       smp_rmb();
-
-       delta = rdtsc_ordered() - src->tsc_timestamp;
-       offset = pvclock_scale_delta(delta, src->tsc_to_system_mul,
-                                  src->tsc_shift);
-       *cycles = src->system_time + offset;
-       *flags = src->flags;
-       return version;
+       u64 delta = rdtsc_ordered() - src->tsc_timestamp;
+       cycle_t offset = pvclock_scale_delta(delta, src->tsc_to_system_mul,
+                                            src->tsc_shift);
+       return src->system_time + offset;
 }
 
 struct pvclock_vsyscall_time_info {
diff --git a/arch/x86/include/asm/rtc.h b/arch/x86/include/asm/rtc.h
deleted file mode 100644 (file)
index f71c3b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/rtc.h>
index d0fe23e..14824fc 100644 (file)
@@ -193,7 +193,6 @@ struct __attribute__ ((__packed__)) vmcb {
        struct vmcb_save_area save;
 };
 
-#define SVM_CPUID_FEATURE_SHIFT 2
 #define SVM_CPUID_FUNC 0x8000000a
 
 #define SVM_VM_CR_SVM_DISABLE 4
index ab05d73..d2f69b9 100644 (file)
@@ -31,9 +31,9 @@ static inline void dma_mark_clean(void *addr, size_t size) {}
 
 extern void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                                        dma_addr_t *dma_handle, gfp_t flags,
-                                       struct dma_attrs *attrs);
+                                       unsigned long attrs);
 extern void x86_swiotlb_free_coherent(struct device *dev, size_t size,
                                        void *vaddr, dma_addr_t dma_addr,
-                                       struct dma_attrs *attrs);
+                                       unsigned long attrs);
 
 #endif /* _ASM_X86_SWIOTLB_H */
index 999b7cd..4e23dd1 100644 (file)
@@ -60,7 +60,7 @@ static inline long syscall_get_error(struct task_struct *task,
         * TS_COMPAT is set for 32-bit syscall entries and then
         * remains set until we return to user mode.
         */
-       if (task_thread_info(task)->status & TS_COMPAT)
+       if (task_thread_info(task)->status & (TS_COMPAT|TS_I386_REGS_POKED))
                /*
                 * Sign-extend the value so (int)-EFOO becomes (long)-EFOO
                 * and will match correctly in comparisons.
@@ -239,9 +239,6 @@ static inline int syscall_get_arch(void)
         * TS_COMPAT is set for 32-bit syscall entry and then
         * remains set until we return to user mode.
         *
-        * TIF_IA32 tasks should always have TS_COMPAT set at
-        * system call time.
-        *
         * x32 tasks should be considered AUDIT_ARCH_X86_64.
         */
        if (task_thread_info(current)->status & TS_COMPAT)
index 89bff04..8b7c8d8 100644 (file)
@@ -176,6 +176,50 @@ static inline unsigned long current_stack_pointer(void)
        return sp;
 }
 
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *              1 if within a frame
+ *             -1 if placed across a frame boundary (or outside stack)
+ *              0 unable to determine (no frame pointers, etc)
+ */
+static inline int arch_within_stack_frames(const void * const stack,
+                                          const void * const stackend,
+                                          const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+       const void *frame = NULL;
+       const void *oldframe;
+
+       oldframe = __builtin_frame_address(1);
+       if (oldframe)
+               frame = __builtin_frame_address(2);
+       /*
+        * low ----------------------------------------------> high
+        * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+        *                     ^----------------^
+        *               allow copies only within here
+        */
+       while (stack <= frame && frame < stackend) {
+               /*
+                * If obj + len extends past the last frame, this
+                * check won't pass and the next frame will be 0,
+                * causing us to bail out and correctly report
+                * the copy as invalid.
+                */
+               if (obj + len <= frame)
+                       return obj >= oldframe + 2 * sizeof(void *) ? 1 : -1;
+               oldframe = frame;
+               frame = *(const void * const *)frame;
+       }
+       return -1;
+#else
+       return 0;
+#endif
+}
+
 #else /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_64
@@ -219,32 +263,11 @@ static inline unsigned long current_stack_pointer(void)
  * have to worry about atomic accesses.
  */
 #define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
-#define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
+#ifdef CONFIG_COMPAT
+#define TS_I386_REGS_POKED     0x0004  /* regs poked by 32-bit ptracer */
+#endif
 
 #ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
-}
-static inline void clear_restore_sigmask(void)
-{
-       current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
-}
-static inline bool test_restore_sigmask(void)
-{
-       return current_thread_info()->status & TS_RESTORE_SIGMASK;
-}
-static inline bool test_and_clear_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       if (!(ti->status & TS_RESTORE_SIGMASK))
-               return false;
-       ti->status &= ~TS_RESTORE_SIGMASK;
-       return true;
-}
 
 static inline bool in_ia32_syscall(void)
 {
index c03bfb6..a0ae610 100644 (file)
@@ -761,9 +761,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
         * case, and do only runtime checking for non-constant sizes.
         */
 
-       if (likely(sz < 0 || sz >= n))
+       if (likely(sz < 0 || sz >= n)) {
+               check_object_size(to, n, false);
                n = _copy_from_user(to, from, n);
-       else if(__builtin_constant_p(n))
+       } else if (__builtin_constant_p(n))
                copy_from_user_overflow();
        else
                __copy_from_user_overflow(sz, n);
@@ -781,9 +782,10 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
        might_fault();
 
        /* See the comment in copy_from_user() above. */
-       if (likely(sz < 0 || sz >= n))
+       if (likely(sz < 0 || sz >= n)) {
+               check_object_size(from, n, true);
                n = _copy_to_user(to, from, n);
-       else if(__builtin_constant_p(n))
+       } else if (__builtin_constant_p(n))
                copy_to_user_overflow();
        else
                __copy_to_user_overflow(sz, n);
@@ -812,21 +814,21 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
 #define user_access_begin()    __uaccess_begin()
 #define user_access_end()      __uaccess_end()
 
-#define unsafe_put_user(x, ptr)                                                \
-({                                                                             \
+#define unsafe_put_user(x, ptr, err_label)                                     \
+do {                                                                           \
        int __pu_err;                                                           \
        __put_user_size((x), (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);         \
-       __builtin_expect(__pu_err, 0);                                          \
-})
+       if (unlikely(__pu_err)) goto err_label;                                 \
+} while (0)
 
-#define unsafe_get_user(x, ptr)                                                \
-({                                                                             \
+#define unsafe_get_user(x, ptr, err_label)                                     \
+do {                                                                           \
        int __gu_err;                                                           \
        unsigned long __gu_val;                                                 \
        __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);    \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
-       __builtin_expect(__gu_err, 0);                                          \
-})
+       if (unlikely(__gu_err)) goto err_label;                                 \
+} while (0)
 
 #endif /* _ASM_X86_UACCESS_H */
 
index 4b32da2..7d3bdd1 100644 (file)
@@ -37,6 +37,7 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero
 static __always_inline unsigned long __must_check
 __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
+       check_object_size(from, n, true);
        return __copy_to_user_ll(to, from, n);
 }
 
@@ -95,6 +96,7 @@ static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        might_fault();
+       check_object_size(to, n, false);
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
index 2eac2aa..673059a 100644 (file)
@@ -54,6 +54,7 @@ int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
 
+       check_object_size(dst, size, false);
        if (!__builtin_constant_p(size))
                return copy_user_generic(dst, (__force void *)src, size);
        switch (size) {
@@ -119,6 +120,7 @@ int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size)
 {
        int ret = 0;
 
+       check_object_size(src, size, true);
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst, src, size);
        switch (size) {
index cce9ee6..0116b2e 100644 (file)
@@ -83,23 +83,19 @@ static inline void cpu_emergency_vmxoff(void)
  */
 static inline int cpu_has_svm(const char **msg)
 {
-       uint32_t eax, ebx, ecx, edx;
-
        if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
                if (msg)
                        *msg = "not amd";
                return 0;
        }
 
-       cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
-       if (eax < SVM_CPUID_FUNC) {
+       if (boot_cpu_data.extended_cpuid_level < SVM_CPUID_FUNC) {
                if (msg)
                        *msg = "can't execute cpuid_8000000a";
                return 0;
        }
 
-       cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
-       if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
+       if (!boot_cpu_has(X86_FEATURE_SVM)) {
                if (msg)
                        *msg = "svm not available";
                return 0;
index acd844c..f02f025 100644 (file)
@@ -2,12 +2,11 @@
 #define _ASM_X86_XEN_PAGE_COHERENT_H
 
 #include <asm/page.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-mapping.h>
 
 static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
                dma_addr_t *dma_handle, gfp_t flags,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        void *vstart = (void*)__get_free_pages(flags, get_order(size));
        *dma_handle = virt_to_phys(vstart);
@@ -16,18 +15,18 @@ static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size,
 
 static inline void xen_free_coherent_pages(struct device *hwdev, size_t size,
                void *cpu_addr, dma_addr_t dma_handle,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        free_pages((unsigned long) cpu_addr, get_order(size));
 }
 
 static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
             dma_addr_t dev_addr, unsigned long offset, size_t size,
-            enum dma_data_direction dir, struct dma_attrs *attrs) { }
+            enum dma_data_direction dir, unsigned long attrs) { }
 
 static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle,
                size_t size, enum dma_data_direction dir,
-               struct dma_attrs *attrs) { }
+               unsigned long attrs) { }
 
 static inline void xen_dma_sync_single_for_cpu(struct device *hwdev,
                dma_addr_t handle, size_t size, enum dma_data_direction dir) { }
index 42d27a6..63ff468 100644 (file)
@@ -241,7 +241,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
 static dma_addr_t gart_map_page(struct device *dev, struct page *page,
                                unsigned long offset, size_t size,
                                enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        unsigned long bus;
        phys_addr_t paddr = page_to_phys(page) + offset;
@@ -263,7 +263,7 @@ static dma_addr_t gart_map_page(struct device *dev, struct page *page,
  */
 static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
                            size_t size, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        unsigned long iommu_page;
        int npages;
@@ -285,7 +285,7 @@ static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
  * Wrapper for pci_unmap_single working with scatterlists.
  */
 static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-                         enum dma_data_direction dir, struct dma_attrs *attrs)
+                         enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
@@ -293,7 +293,7 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
        for_each_sg(sg, s, nents, i) {
                if (!s->dma_length || !s->length)
                        break;
-               gart_unmap_page(dev, s->dma_address, s->dma_length, dir, NULL);
+               gart_unmap_page(dev, s->dma_address, s->dma_length, dir, 0);
        }
 }
 
@@ -315,7 +315,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
                        addr = dma_map_area(dev, addr, s->length, dir, 0);
                        if (addr == bad_dma_addr) {
                                if (i > 0)
-                                       gart_unmap_sg(dev, sg, i, dir, NULL);
+                                       gart_unmap_sg(dev, sg, i, dir, 0);
                                nents = 0;
                                sg[0].dma_length = 0;
                                break;
@@ -386,7 +386,7 @@ dma_map_cont(struct device *dev, struct scatterlist *start, int nelems,
  * Merge chunks that have page aligned sizes into a continuous mapping.
  */
 static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-                      enum dma_data_direction dir, struct dma_attrs *attrs)
+                      enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *s, *ps, *start_sg, *sgmap;
        int need = 0, nextneed, i, out, start;
@@ -456,7 +456,7 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 
 error:
        flush_gart();
-       gart_unmap_sg(dev, sg, out, dir, NULL);
+       gart_unmap_sg(dev, sg, out, dir, 0);
 
        /* When it was forced or merged try again in a dumb way */
        if (force_iommu || iommu_merge) {
@@ -476,7 +476,7 @@ error:
 /* allocate and map a coherent mapping */
 static void *
 gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
-                   gfp_t flag, struct dma_attrs *attrs)
+                   gfp_t flag, unsigned long attrs)
 {
        dma_addr_t paddr;
        unsigned long align_mask;
@@ -508,9 +508,9 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
 /* free a coherent mapping */
 static void
 gart_free_coherent(struct device *dev, size_t size, void *vaddr,
-                  dma_addr_t dma_addr, struct dma_attrs *attrs)
+                  dma_addr_t dma_addr, unsigned long attrs)
 {
-       gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL);
+       gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
        dma_generic_free_coherent(dev, size, vaddr, dma_addr, attrs);
 }
 
index 7943d38..20abd91 100644 (file)
@@ -147,7 +147,7 @@ static int force_enable_local_apic __initdata;
  */
 static int __init parse_lapic(char *arg)
 {
-       if (config_enabled(CONFIG_X86_32) && !arg)
+       if (IS_ENABLED(CONFIG_X86_32) && !arg)
                force_enable_local_apic = 1;
        else if (arg && !strncmp(arg, "notscdeadline", 13))
                setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
index a5e400a..6066d94 100644 (file)
@@ -523,7 +523,7 @@ static int apic_set_affinity(struct irq_data *irq_data,
        struct apic_chip_data *data = irq_data->chip_data;
        int err, irq = irq_data->irq;
 
-       if (!config_enabled(CONFIG_SMP))
+       if (!IS_ENABLED(CONFIG_SMP))
                return -EPERM;
 
        if (!cpumask_intersects(dest, cpu_online_mask))
index 9e231d8..a184c21 100644 (file)
@@ -159,8 +159,8 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
        struct task_struct *tsk = current;
        int ia32_fxstate = (buf != buf_fx);
 
-       ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
-                        config_enabled(CONFIG_IA32_EMULATION));
+       ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
+                        IS_ENABLED(CONFIG_IA32_EMULATION));
 
        if (!access_ok(VERIFY_WRITE, buf, size))
                return -EACCES;
@@ -268,8 +268,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
        u64 xfeatures = 0;
        int fx_only = 0;
 
-       ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
-                        config_enabled(CONFIG_IA32_EMULATION));
+       ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
+                        IS_ENABLED(CONFIG_IA32_EMULATION));
 
        if (!buf) {
                fpu__clear(fpu);
@@ -416,8 +416,8 @@ void fpu__init_prepare_fx_sw_frame(void)
        fx_sw_reserved.xfeatures = xfeatures_mask;
        fx_sw_reserved.xstate_size = fpu_user_xstate_size;
 
-       if (config_enabled(CONFIG_IA32_EMULATION) ||
-           config_enabled(CONFIG_X86_32)) {
+       if (IS_ENABLED(CONFIG_IA32_EMULATION) ||
+           IS_ENABLED(CONFIG_X86_32)) {
                int fsave_header_size = sizeof(struct fregs_state);
 
                fx_sw_reserved_ia32 = fx_sw_reserved;
index 3d74707..ed16e58 100644 (file)
@@ -1019,7 +1019,6 @@ void hpet_disable(void)
  */
 #include <linux/mc146818rtc.h>
 #include <linux/rtc.h>
-#include <asm/rtc.h>
 
 #define DEFAULT_RTC_INT_FREQ   64
 #define DEFAULT_RTC_SHIFT      6
@@ -1243,7 +1242,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
        memset(&curr_time, 0, sizeof(struct rtc_time));
 
        if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
-               get_rtc_time(&curr_time);
+               mc146818_set_time(&curr_time);
 
        if (hpet_rtc_flags & RTC_UIE &&
            curr_time.tm_sec != hpet_prev_update_sec) {
index 04b132a..bfe4d6c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/hardirq.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 #include <linux/export.h>
 
index 833b1d3..5d400ba 100644 (file)
@@ -340,7 +340,7 @@ static inline struct iommu_table *find_iommu_table(struct device *dev)
 
 static void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
                             int nelems,enum dma_data_direction dir,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        struct scatterlist *s;
@@ -364,7 +364,7 @@ static void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
 
 static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                          int nelems, enum dma_data_direction dir,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        struct scatterlist *s;
@@ -396,7 +396,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
 
        return nelems;
 error:
-       calgary_unmap_sg(dev, sg, nelems, dir, NULL);
+       calgary_unmap_sg(dev, sg, nelems, dir, 0);
        for_each_sg(sg, s, nelems, i) {
                sg->dma_address = DMA_ERROR_CODE;
                sg->dma_length = 0;
@@ -407,7 +407,7 @@ error:
 static dma_addr_t calgary_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        void *vaddr = page_address(page) + offset;
        unsigned long uaddr;
@@ -422,7 +422,7 @@ static dma_addr_t calgary_map_page(struct device *dev, struct page *page,
 
 static void calgary_unmap_page(struct device *dev, dma_addr_t dma_addr,
                               size_t size, enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        struct iommu_table *tbl = find_iommu_table(dev);
        unsigned int npages;
@@ -432,7 +432,7 @@ static void calgary_unmap_page(struct device *dev, dma_addr_t dma_addr,
 }
 
 static void* calgary_alloc_coherent(struct device *dev, size_t size,
-       dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs)
+       dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs)
 {
        void *ret = NULL;
        dma_addr_t mapping;
@@ -466,7 +466,7 @@ error:
 
 static void calgary_free_coherent(struct device *dev, size_t size,
                                  void *vaddr, dma_addr_t dma_handle,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        unsigned int npages;
        struct iommu_table *tbl = find_iommu_table(dev);
index 6ba014c..d30c377 100644 (file)
@@ -77,7 +77,7 @@ void __init pci_iommu_alloc(void)
 }
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t flag,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        unsigned long dma_mask;
        struct page *page;
@@ -120,7 +120,7 @@ again:
 }
 
 void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr,
-                              dma_addr_t dma_addr, struct dma_attrs *attrs)
+                              dma_addr_t dma_addr, unsigned long attrs)
 {
        unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page *page = virt_to_page(vaddr);
index da15918..00e71ce 100644 (file)
@@ -28,7 +28,7 @@ check_addr(char *name, struct device *hwdev, dma_addr_t bus, size_t size)
 static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
                                 unsigned long offset, size_t size,
                                 enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        dma_addr_t bus = page_to_phys(page) + offset;
        WARN_ON(size == 0);
@@ -55,7 +55,7 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
  */
 static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
                        int nents, enum dma_data_direction dir,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
index 5069ef5..b47edb8 100644 (file)
@@ -16,7 +16,7 @@ int swiotlb __read_mostly;
 
 void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                                        dma_addr_t *dma_handle, gfp_t flags,
-                                       struct dma_attrs *attrs)
+                                       unsigned long attrs)
 {
        void *vaddr;
 
@@ -37,7 +37,7 @@ void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 
 void x86_swiotlb_free_coherent(struct device *dev, size_t size,
                                      void *vaddr, dma_addr_t dma_addr,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        if (is_swiotlb_buffer(dma_to_phys(dev, dma_addr)))
                swiotlb_free_coherent(dev, size, vaddr, dma_addr);
index 600edd2..f79576a 100644 (file)
@@ -923,15 +923,18 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 value)
 
        case offsetof(struct user32, regs.orig_eax):
                /*
-                * A 32-bit debugger setting orig_eax means to restore
-                * the state of the task restarting a 32-bit syscall.
-                * Make sure we interpret the -ERESTART* codes correctly
-                * in case the task is not actually still sitting at the
-                * exit from a 32-bit syscall with TS_COMPAT still set.
+                * Warning: bizarre corner case fixup here.  A 32-bit
+                * debugger setting orig_eax to -1 wants to disable
+                * syscall restart.  Make sure that the syscall
+                * restart code sign-extends orig_ax.  Also make sure
+                * we interpret the -ERESTART* codes correctly if
+                * loaded into regs->ax in case the task is not
+                * actually still sitting at the exit from a 32-bit
+                * syscall with TS_COMPAT still set.
                 */
                regs->orig_ax = value;
                if (syscall_get_nr(child, regs) >= 0)
-                       task_thread_info(child)->status |= TS_COMPAT;
+                       task_thread_info(child)->status |= TS_I386_REGS_POKED;
                break;
 
        case offsetof(struct user32, regs.eflags):
index 06c58ce..3599404 100644 (file)
@@ -64,14 +64,9 @@ u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src)
        u8 flags;
 
        do {
-               version = src->version;
-               /* Make the latest version visible */
-               smp_rmb();
-
+               version = pvclock_read_begin(src);
                flags = src->flags;
-               /* Make sure that the version double-check is last. */
-               smp_rmb();
-       } while ((src->version & 1) || version != src->version);
+       } while (pvclock_read_retry(src, version));
 
        return flags & valid_flags;
 }
@@ -84,10 +79,10 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
        u8 flags;
 
        do {
-               version = __pvclock_read_cycles(src, &ret, &flags);
-               /* Make sure that the version double-check is last. */
-               smp_rmb();
-       } while ((src->version & 1) || version != src->version);
+               version = pvclock_read_begin(src);
+               ret = __pvclock_read_cycles(src);
+               flags = src->flags;
+       } while (pvclock_read_retry(src, version));
 
        if (unlikely((flags & PVCLOCK_GUEST_STOPPED) != 0)) {
                src->flags &= ~PVCLOCK_GUEST_STOPPED;
index eceaa08..79c6311 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/x86_init.h>
 #include <asm/time.h>
 #include <asm/intel-mid.h>
-#include <asm/rtc.h>
 #include <asm/setup.h>
 
 #ifdef CONFIG_X86_32
@@ -47,7 +46,7 @@ int mach_set_rtc_mmss(const struct timespec *now)
 
        rtc_time_to_tm(nowtime, &tm);
        if (!rtc_valid_tm(&tm)) {
-               retval = set_rtc_time(&tm);
+               retval = mc146818_set_time(&tm);
                if (retval)
                        printk(KERN_ERR "%s: RTC write failed with error %d\n",
                               __func__, retval);
index 22cc2f9..04cb321 100644 (file)
@@ -146,7 +146,7 @@ static int restore_sigcontext(struct pt_regs *regs,
                buf = (void __user *)buf_val;
        } get_user_catch(err);
 
-       err |= fpu__restore_sig(buf, config_enabled(CONFIG_X86_32));
+       err |= fpu__restore_sig(buf, IS_ENABLED(CONFIG_X86_32));
 
        force_iret();
 
@@ -245,14 +245,14 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
        struct fpu *fpu = &current->thread.fpu;
 
        /* redzone */
-       if (config_enabled(CONFIG_X86_64))
+       if (IS_ENABLED(CONFIG_X86_64))
                sp -= 128;
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if (ka->sa.sa_flags & SA_ONSTACK) {
                if (sas_ss_flags(sp) == 0)
                        sp = current->sas_ss_sp + current->sas_ss_size;
-       } else if (config_enabled(CONFIG_X86_32) &&
+       } else if (IS_ENABLED(CONFIG_X86_32) &&
                   !onsigstack &&
                   (regs->ss & 0xffff) != __USER_DS &&
                   !(ka->sa.sa_flags & SA_RESTORER) &&
@@ -262,7 +262,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
        }
 
        if (fpu->fpstate_active) {
-               sp = fpu__alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
+               sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32),
                                          &buf_fx, &math_size);
                *fpstate = (void __user *)sp;
        }
@@ -662,18 +662,18 @@ badframe:
 
 static inline int is_ia32_compat_frame(void)
 {
-       return config_enabled(CONFIG_IA32_EMULATION) &&
+       return IS_ENABLED(CONFIG_IA32_EMULATION) &&
               test_thread_flag(TIF_IA32);
 }
 
 static inline int is_ia32_frame(void)
 {
-       return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
+       return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame();
 }
 
 static inline int is_x32_frame(void)
 {
-       return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
+       return IS_ENABLED(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
 }
 
 static int
@@ -760,8 +760,30 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 
 static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
 {
-#ifdef CONFIG_X86_64
-       if (in_ia32_syscall())
+       /*
+        * This function is fundamentally broken as currently
+        * implemented.
+        *
+        * The idea is that we want to trigger a call to the
+        * restart_block() syscall and that we want in_ia32_syscall(),
+        * in_x32_syscall(), etc. to match whatever they were in the
+        * syscall being restarted.  We assume that the syscall
+        * instruction at (regs->ip - 2) matches whatever syscall
+        * instruction we used to enter in the first place.
+        *
+        * The problem is that we can get here when ptrace pokes
+        * syscall-like values into regs even if we're not in a syscall
+        * at all.
+        *
+        * For now, we maintain historical behavior and guess based on
+        * stored state.  We could do better by saving the actual
+        * syscall arch in restart_block or (with caveats on x32) by
+        * checking if regs->ip points to 'int $0x80'.  The current
+        * behavior is incorrect if a tracer has a different bitness
+        * than the tracee.
+        */
+#ifdef CONFIG_IA32_EMULATION
+       if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
                return __NR_ia32_restart_syscall;
 #endif
 #ifdef CONFIG_X86_X32_ABI
index 639a6e3..ab8e32f 100644 (file)
@@ -32,7 +32,6 @@ config KVM
        select HAVE_KVM_IRQ_BYPASS
        select HAVE_KVM_IRQ_ROUTING
        select HAVE_KVM_EVENTFD
-       select KVM_APIC_ARCHITECTURE
        select KVM_ASYNC_PF
        select USER_RETURN_NOTIFIER
        select KVM_MMIO
index a4bf5b4..5fb6c62 100644 (file)
@@ -645,7 +645,6 @@ static const struct kvm_io_device_ops speaker_dev_ops = {
        .write    = speaker_ioport_write,
 };
 
-/* Caller must hold slots_lock */
 struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
        struct kvm_pit *pit;
@@ -690,6 +689,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 
        kvm_pit_set_reinject(pit, true);
 
+       mutex_lock(&kvm->slots_lock);
        kvm_iodevice_init(&pit->dev, &pit_dev_ops);
        ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
                                      KVM_PIT_MEM_LENGTH, &pit->dev);
@@ -704,12 +704,14 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
                if (ret < 0)
                        goto fail_register_speaker;
        }
+       mutex_unlock(&kvm->slots_lock);
 
        return pit;
 
 fail_register_speaker:
        kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->dev);
 fail_register_pit:
+       mutex_unlock(&kvm->slots_lock);
        kvm_pit_set_reinject(pit, false);
        kthread_stop(pit->worker_task);
 fail_kthread:
index 95e0e64..b181426 100644 (file)
@@ -28,9 +28,7 @@
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/stat.h>
-#include <linux/dmar.h>
 #include <linux/iommu.h>
-#include <linux/intel-iommu.h>
 #include "assigned-dev.h"
 
 static bool allow_unsafe_assigned_interrupts;
index 61ebdc1..035731e 100644 (file)
@@ -120,4 +120,7 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu);
 
 int apic_has_pending_timer(struct kvm_vcpu *vcpu);
 
+int kvm_setup_default_irq_routing(struct kvm *kvm);
+int kvm_setup_empty_irq_routing(struct kvm *kvm);
+
 #endif
index dfb4c64..25810b1 100644 (file)
@@ -110,13 +110,17 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
        return r;
 }
 
-void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e,
+void kvm_set_msi_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
                     struct kvm_lapic_irq *irq)
 {
-       trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data);
+       trace_kvm_msi_set_irq(e->msi.address_lo | (kvm->arch.x2apic_format ?
+                                            (u64)e->msi.address_hi << 32 : 0),
+                             e->msi.data);
 
        irq->dest_id = (e->msi.address_lo &
                        MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+       if (kvm->arch.x2apic_format)
+               irq->dest_id |= MSI_ADDR_EXT_DEST_ID(e->msi.address_hi);
        irq->vector = (e->msi.data &
                        MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
        irq->dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
@@ -129,15 +133,24 @@ void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e,
 }
 EXPORT_SYMBOL_GPL(kvm_set_msi_irq);
 
+static inline bool kvm_msi_route_invalid(struct kvm *kvm,
+               struct kvm_kernel_irq_routing_entry *e)
+{
+       return kvm->arch.x2apic_format && (e->msi.address_hi & 0xff);
+}
+
 int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
                struct kvm *kvm, int irq_source_id, int level, bool line_status)
 {
        struct kvm_lapic_irq irq;
 
+       if (kvm_msi_route_invalid(kvm, e))
+               return -EINVAL;
+
        if (!level)
                return -1;
 
-       kvm_set_msi_irq(e, &irq);
+       kvm_set_msi_irq(kvm, e, &irq);
 
        return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL);
 }
@@ -153,7 +166,10 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
        if (unlikely(e->type != KVM_IRQ_ROUTING_MSI))
                return -EWOULDBLOCK;
 
-       kvm_set_msi_irq(e, &irq);
+       if (kvm_msi_route_invalid(kvm, e))
+               return -EINVAL;
+
+       kvm_set_msi_irq(kvm, e, &irq);
 
        if (kvm_irq_delivery_to_apic_fast(kvm, NULL, &irq, &r, NULL))
                return r;
@@ -248,7 +264,8 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
        return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
 }
 
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
 {
        int r = -EINVAL;
@@ -285,6 +302,9 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                e->msi.address_lo = ue->u.msi.address_lo;
                e->msi.address_hi = ue->u.msi.address_hi;
                e->msi.data = ue->u.msi.data;
+
+               if (kvm_msi_route_invalid(kvm, e))
+                       goto out;
                break;
        case KVM_IRQ_ROUTING_HV_SINT:
                e->set = kvm_hv_set_sint;
@@ -388,21 +408,16 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
                               kvm->arch.nr_reserved_ioapic_pins);
        for (i = 0; i < nr_ioapic_pins; ++i) {
                hlist_for_each_entry(entry, &table->map[i], link) {
-                       u32 dest_id, dest_mode;
-                       bool level;
+                       struct kvm_lapic_irq irq;
 
                        if (entry->type != KVM_IRQ_ROUTING_MSI)
                                continue;
-                       dest_id = (entry->msi.address_lo >> 12) & 0xff;
-                       dest_mode = (entry->msi.address_lo >> 2) & 0x1;
-                       level = entry->msi.data & MSI_DATA_TRIGGER_LEVEL;
-                       if (level && kvm_apic_match_dest(vcpu, NULL, 0,
-                                               dest_id, dest_mode)) {
-                               u32 vector = entry->msi.data & 0xff;
-
-                               __set_bit(vector,
-                                         ioapic_handled_vectors);
-                       }
+
+                       kvm_set_msi_irq(vcpu->kvm, entry, &irq);
+
+                       if (irq.level && kvm_apic_match_dest(vcpu, NULL, 0,
+                                               irq.dest_id, irq.dest_mode))
+                               __set_bit(irq.vector, ioapic_handled_vectors);
                }
        }
        srcu_read_unlock(&kvm->irq_srcu, idx);
index 57549ed..b62c852 100644 (file)
@@ -115,26 +115,43 @@ static inline int apic_enabled(struct kvm_lapic *apic)
        (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
         APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
 
-/* The logical map is definitely wrong if we have multiple
- * modes at the same time.  (Physical map is always right.)
- */
-static inline bool kvm_apic_logical_map_valid(struct kvm_apic_map *map)
-{
-       return !(map->mode & (map->mode - 1));
+static inline bool kvm_apic_map_get_logical_dest(struct kvm_apic_map *map,
+               u32 dest_id, struct kvm_lapic ***cluster, u16 *mask) {
+       switch (map->mode) {
+       case KVM_APIC_MODE_X2APIC: {
+               u32 offset = (dest_id >> 16) * 16;
+               u32 max_apic_id = map->max_apic_id;
+
+               if (offset <= max_apic_id) {
+                       u8 cluster_size = min(max_apic_id - offset + 1, 16U);
+
+                       *cluster = &map->phys_map[offset];
+                       *mask = dest_id & (0xffff >> (16 - cluster_size));
+               } else {
+                       *mask = 0;
+               }
+
+               return true;
+               }
+       case KVM_APIC_MODE_XAPIC_FLAT:
+               *cluster = map->xapic_flat_map;
+               *mask = dest_id & 0xff;
+               return true;
+       case KVM_APIC_MODE_XAPIC_CLUSTER:
+               *cluster = map->xapic_cluster_map[dest_id >> 4];
+               *mask = dest_id & 0xf;
+               return true;
+       default:
+               /* Not optimized. */
+               return false;
+       }
 }
 
-static inline void
-apic_logical_id(struct kvm_apic_map *map, u32 dest_id, u16 *cid, u16 *lid)
+static void kvm_apic_map_free(struct rcu_head *rcu)
 {
-       unsigned lid_bits;
+       struct kvm_apic_map *map = container_of(rcu, struct kvm_apic_map, rcu);
 
-       BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_CLUSTER !=  4);
-       BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_FLAT    !=  8);
-       BUILD_BUG_ON(KVM_APIC_MODE_X2APIC        != 16);
-       lid_bits = map->mode;
-
-       *cid = dest_id >> lid_bits;
-       *lid = dest_id & ((1 << lid_bits) - 1);
+       kvfree(map);
 }
 
 static void recalculate_apic_map(struct kvm *kvm)
@@ -142,17 +159,26 @@ static void recalculate_apic_map(struct kvm *kvm)
        struct kvm_apic_map *new, *old = NULL;
        struct kvm_vcpu *vcpu;
        int i;
-
-       new = kzalloc(sizeof(struct kvm_apic_map), GFP_KERNEL);
+       u32 max_id = 255;
 
        mutex_lock(&kvm->arch.apic_map_lock);
 
+       kvm_for_each_vcpu(i, vcpu, kvm)
+               if (kvm_apic_present(vcpu))
+                       max_id = max(max_id, kvm_apic_id(vcpu->arch.apic));
+
+       new = kvm_kvzalloc(sizeof(struct kvm_apic_map) +
+                          sizeof(struct kvm_lapic *) * ((u64)max_id + 1));
+
        if (!new)
                goto out;
 
+       new->max_apic_id = max_id;
+
        kvm_for_each_vcpu(i, vcpu, kvm) {
                struct kvm_lapic *apic = vcpu->arch.apic;
-               u16 cid, lid;
+               struct kvm_lapic **cluster;
+               u16 mask;
                u32 ldr, aid;
 
                if (!kvm_apic_present(vcpu))
@@ -161,7 +187,7 @@ static void recalculate_apic_map(struct kvm *kvm)
                aid = kvm_apic_id(apic);
                ldr = kvm_lapic_get_reg(apic, APIC_LDR);
 
-               if (aid < ARRAY_SIZE(new->phys_map))
+               if (aid <= new->max_apic_id)
                        new->phys_map[aid] = apic;
 
                if (apic_x2apic_mode(apic)) {
@@ -174,13 +200,11 @@ static void recalculate_apic_map(struct kvm *kvm)
                                new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
                }
 
-               if (!kvm_apic_logical_map_valid(new))
+               if (!kvm_apic_map_get_logical_dest(new, ldr, &cluster, &mask))
                        continue;
 
-               apic_logical_id(new, ldr, &cid, &lid);
-
-               if (lid && cid < ARRAY_SIZE(new->logical_map))
-                       new->logical_map[cid][ffs(lid) - 1] = apic;
+               if (mask)
+                       cluster[ffs(mask) - 1] = apic;
        }
 out:
        old = rcu_dereference_protected(kvm->arch.apic_map,
@@ -189,7 +213,7 @@ out:
        mutex_unlock(&kvm->arch.apic_map_lock);
 
        if (old)
-               kfree_rcu(old, rcu);
+               call_rcu(&old->rcu, kvm_apic_map_free);
 
        kvm_make_scan_ioapic_request(kvm);
 }
@@ -210,7 +234,7 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
        }
 }
 
-static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id)
+static inline void kvm_apic_set_xapic_id(struct kvm_lapic *apic, u8 id)
 {
        kvm_lapic_set_reg(apic, APIC_ID, id << 24);
        recalculate_apic_map(apic->vcpu->kvm);
@@ -222,11 +246,11 @@ static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id)
        recalculate_apic_map(apic->vcpu->kvm);
 }
 
-static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u8 id)
+static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u32 id)
 {
        u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
 
-       kvm_lapic_set_reg(apic, APIC_ID, id << 24);
+       kvm_lapic_set_reg(apic, APIC_ID, id);
        kvm_lapic_set_reg(apic, APIC_LDR, ldr);
        recalculate_apic_map(apic->vcpu->kvm);
 }
@@ -599,17 +623,30 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
        }
 }
 
-/* KVM APIC implementation has two quirks
- *  - dest always begins at 0 while xAPIC MDA has offset 24,
- *  - IOxAPIC messages have to be delivered (directly) to x2APIC.
+/* The KVM local APIC implementation has two quirks:
+ *
+ *  - the xAPIC MDA stores the destination at bits 24-31, while this
+ *    is not true of struct kvm_lapic_irq's dest_id field.  This is
+ *    just a quirk in the API and is not problematic.
+ *
+ *  - in-kernel IOAPIC messages have to be delivered directly to
+ *    x2APIC, because the kernel does not support interrupt remapping.
+ *    In order to support broadcast without interrupt remapping, x2APIC
+ *    rewrites the destination of non-IPI messages from APIC_BROADCAST
+ *    to X2APIC_BROADCAST.
+ *
+ * The broadcast quirk can be disabled with KVM_CAP_X2APIC_API.  This is
+ * important when userspace wants to use x2APIC-format MSIs, because
+ * APIC_BROADCAST (0xff) is a legal route for "cluster 0, CPUs 0-7".
  */
-static u32 kvm_apic_mda(unsigned int dest_id, struct kvm_lapic *source,
-                                              struct kvm_lapic *target)
+static u32 kvm_apic_mda(struct kvm_vcpu *vcpu, unsigned int dest_id,
+               struct kvm_lapic *source, struct kvm_lapic *target)
 {
        bool ipi = source != NULL;
        bool x2apic_mda = apic_x2apic_mode(ipi ? source : target);
 
-       if (!ipi && dest_id == APIC_BROADCAST && x2apic_mda)
+       if (!vcpu->kvm->arch.x2apic_broadcast_quirk_disabled &&
+           !ipi && dest_id == APIC_BROADCAST && x2apic_mda)
                return X2APIC_BROADCAST;
 
        return x2apic_mda ? dest_id : SET_APIC_DEST_FIELD(dest_id);
@@ -619,7 +656,7 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                           int short_hand, unsigned int dest, int dest_mode)
 {
        struct kvm_lapic *target = vcpu->arch.apic;
-       u32 mda = kvm_apic_mda(dest, source, target);
+       u32 mda = kvm_apic_mda(vcpu, dest, source, target);
 
        apic_debug("target %p, source %p, dest 0x%x, "
                   "dest_mode 0x%x, short_hand 0x%x\n",
@@ -671,102 +708,126 @@ static void kvm_apic_disabled_lapic_found(struct kvm *kvm)
        }
 }
 
-bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
-               struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map)
+static bool kvm_apic_is_broadcast_dest(struct kvm *kvm, struct kvm_lapic **src,
+               struct kvm_lapic_irq *irq, struct kvm_apic_map *map)
 {
-       struct kvm_apic_map *map;
-       unsigned long bitmap = 1;
-       struct kvm_lapic **dst;
-       int i;
-       bool ret, x2apic_ipi;
+       if (kvm->arch.x2apic_broadcast_quirk_disabled) {
+               if ((irq->dest_id == APIC_BROADCAST &&
+                               map->mode != KVM_APIC_MODE_X2APIC))
+                       return true;
+               if (irq->dest_id == X2APIC_BROADCAST)
+                       return true;
+       } else {
+               bool x2apic_ipi = src && *src && apic_x2apic_mode(*src);
+               if (irq->dest_id == (x2apic_ipi ?
+                                    X2APIC_BROADCAST : APIC_BROADCAST))
+                       return true;
+       }
 
-       *r = -1;
+       return false;
+}
 
-       if (irq->shorthand == APIC_DEST_SELF) {
-               *r = kvm_apic_set_irq(src->vcpu, irq, dest_map);
-               return true;
-       }
+/* Return true if the interrupt can be handled by using *bitmap as index mask
+ * for valid destinations in *dst array.
+ * Return false if kvm_apic_map_get_dest_lapic did nothing useful.
+ * Note: we may have zero kvm_lapic destinations when we return true, which
+ * means that the interrupt should be dropped.  In this case, *bitmap would be
+ * zero and *dst undefined.
+ */
+static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm,
+               struct kvm_lapic **src, struct kvm_lapic_irq *irq,
+               struct kvm_apic_map *map, struct kvm_lapic ***dst,
+               unsigned long *bitmap)
+{
+       int i, lowest;
 
-       if (irq->shorthand)
+       if (irq->shorthand == APIC_DEST_SELF && src) {
+               *dst = src;
+               *bitmap = 1;
+               return true;
+       } else if (irq->shorthand)
                return false;
 
-       x2apic_ipi = src && apic_x2apic_mode(src);
-       if (irq->dest_id == (x2apic_ipi ? X2APIC_BROADCAST : APIC_BROADCAST))
+       if (!map || kvm_apic_is_broadcast_dest(kvm, src, irq, map))
                return false;
 
-       ret = true;
-       rcu_read_lock();
-       map = rcu_dereference(kvm->arch.apic_map);
-
-       if (!map) {
-               ret = false;
-               goto out;
+       if (irq->dest_mode == APIC_DEST_PHYSICAL) {
+               if (irq->dest_id > map->max_apic_id) {
+                       *bitmap = 0;
+               } else {
+                       *dst = &map->phys_map[irq->dest_id];
+                       *bitmap = 1;
+               }
+               return true;
        }
 
-       if (irq->dest_mode == APIC_DEST_PHYSICAL) {
-               if (irq->dest_id >= ARRAY_SIZE(map->phys_map))
-                       goto out;
+       *bitmap = 0;
+       if (!kvm_apic_map_get_logical_dest(map, irq->dest_id, dst,
+                               (u16 *)bitmap))
+               return false;
 
-               dst = &map->phys_map[irq->dest_id];
-       } else {
-               u16 cid;
+       if (!kvm_lowest_prio_delivery(irq))
+               return true;
 
-               if (!kvm_apic_logical_map_valid(map)) {
-                       ret = false;
-                       goto out;
+       if (!kvm_vector_hashing_enabled()) {
+               lowest = -1;
+               for_each_set_bit(i, bitmap, 16) {
+                       if (!(*dst)[i])
+                               continue;
+                       if (lowest < 0)
+                               lowest = i;
+                       else if (kvm_apic_compare_prio((*dst)[i]->vcpu,
+                                               (*dst)[lowest]->vcpu) < 0)
+                               lowest = i;
                }
+       } else {
+               if (!*bitmap)
+                       return true;
 
-               apic_logical_id(map, irq->dest_id, &cid, (u16 *)&bitmap);
+               lowest = kvm_vector_to_index(irq->vector, hweight16(*bitmap),
+                               bitmap, 16);
 
-               if (cid >= ARRAY_SIZE(map->logical_map))
-                       goto out;
+               if (!(*dst)[lowest]) {
+                       kvm_apic_disabled_lapic_found(kvm);
+                       *bitmap = 0;
+                       return true;
+               }
+       }
 
-               dst = map->logical_map[cid];
+       *bitmap = (lowest >= 0) ? 1 << lowest : 0;
 
-               if (!kvm_lowest_prio_delivery(irq))
-                       goto set_irq;
+       return true;
+}
 
-               if (!kvm_vector_hashing_enabled()) {
-                       int l = -1;
-                       for_each_set_bit(i, &bitmap, 16) {
-                               if (!dst[i])
-                                       continue;
-                               if (l < 0)
-                                       l = i;
-                               else if (kvm_apic_compare_prio(dst[i]->vcpu,
-                                                       dst[l]->vcpu) < 0)
-                                       l = i;
-                       }
-                       bitmap = (l >= 0) ? 1 << l : 0;
-               } else {
-                       int idx;
-                       unsigned int dest_vcpus;
+bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
+               struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map)
+{
+       struct kvm_apic_map *map;
+       unsigned long bitmap;
+       struct kvm_lapic **dst = NULL;
+       int i;
+       bool ret;
 
-                       dest_vcpus = hweight16(bitmap);
-                       if (dest_vcpus == 0)
-                               goto out;
+       *r = -1;
 
-                       idx = kvm_vector_to_index(irq->vector,
-                               dest_vcpus, &bitmap, 16);
+       if (irq->shorthand == APIC_DEST_SELF) {
+               *r = kvm_apic_set_irq(src->vcpu, irq, dest_map);
+               return true;
+       }
 
-                       if (!dst[idx]) {
-                               kvm_apic_disabled_lapic_found(kvm);
-                               goto out;
-                       }
+       rcu_read_lock();
+       map = rcu_dereference(kvm->arch.apic_map);
 
-                       bitmap = (idx >= 0) ? 1 << idx : 0;
+       ret = kvm_apic_map_get_dest_lapic(kvm, &src, irq, map, &dst, &bitmap);
+       if (ret)
+               for_each_set_bit(i, &bitmap, 16) {
+                       if (!dst[i])
+                               continue;
+                       if (*r < 0)
+                               *r = 0;
+                       *r += kvm_apic_set_irq(dst[i]->vcpu, irq, dest_map);
                }
-       }
 
-set_irq:
-       for_each_set_bit(i, &bitmap, 16) {
-               if (!dst[i])
-                       continue;
-               if (*r < 0)
-                       *r = 0;
-               *r += kvm_apic_set_irq(dst[i]->vcpu, irq, dest_map);
-       }
-out:
        rcu_read_unlock();
        return ret;
 }
@@ -789,8 +850,9 @@ bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
                        struct kvm_vcpu **dest_vcpu)
 {
        struct kvm_apic_map *map;
+       unsigned long bitmap;
+       struct kvm_lapic **dst = NULL;
        bool ret = false;
-       struct kvm_lapic *dst = NULL;
 
        if (irq->shorthand)
                return false;
@@ -798,69 +860,16 @@ bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
        rcu_read_lock();
        map = rcu_dereference(kvm->arch.apic_map);
 
-       if (!map)
-               goto out;
-
-       if (irq->dest_mode == APIC_DEST_PHYSICAL) {
-               if (irq->dest_id == 0xFF)
-                       goto out;
-
-               if (irq->dest_id >= ARRAY_SIZE(map->phys_map))
-                       goto out;
-
-               dst = map->phys_map[irq->dest_id];
-               if (dst && kvm_apic_present(dst->vcpu))
-                       *dest_vcpu = dst->vcpu;
-               else
-                       goto out;
-       } else {
-               u16 cid;
-               unsigned long bitmap = 1;
-               int i, r = 0;
-
-               if (!kvm_apic_logical_map_valid(map))
-                       goto out;
-
-               apic_logical_id(map, irq->dest_id, &cid, (u16 *)&bitmap);
-
-               if (cid >= ARRAY_SIZE(map->logical_map))
-                       goto out;
-
-               if (kvm_vector_hashing_enabled() &&
-                               kvm_lowest_prio_delivery(irq)) {
-                       int idx;
-                       unsigned int dest_vcpus;
-
-                       dest_vcpus = hweight16(bitmap);
-                       if (dest_vcpus == 0)
-                               goto out;
+       if (kvm_apic_map_get_dest_lapic(kvm, NULL, irq, map, &dst, &bitmap) &&
+                       hweight16(bitmap) == 1) {
+               unsigned long i = find_first_bit(&bitmap, 16);
 
-                       idx = kvm_vector_to_index(irq->vector, dest_vcpus,
-                                                 &bitmap, 16);
-
-                       dst = map->logical_map[cid][idx];
-                       if (!dst) {
-                               kvm_apic_disabled_lapic_found(kvm);
-                               goto out;
-                       }
-
-                       *dest_vcpu = dst->vcpu;
-               } else {
-                       for_each_set_bit(i, &bitmap, 16) {
-                               dst = map->logical_map[cid][i];
-                               if (++r == 2)
-                                       goto out;
-                       }
-
-                       if (dst && kvm_apic_present(dst->vcpu))
-                               *dest_vcpu = dst->vcpu;
-                       else
-                               goto out;
+               if (dst[i]) {
+                       *dest_vcpu = dst[i]->vcpu;
+                       ret = true;
                }
        }
 
-       ret = true;
-out:
        rcu_read_unlock();
        return ret;
 }
@@ -1127,12 +1136,6 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
                return 0;
 
        switch (offset) {
-       case APIC_ID:
-               if (apic_x2apic_mode(apic))
-                       val = kvm_apic_id(apic);
-               else
-                       val = kvm_apic_id(apic) << 24;
-               break;
        case APIC_ARBPRI:
                apic_debug("Access APIC ARBPRI register which is for P6\n");
                break;
@@ -1314,6 +1317,111 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu)
                        nsec_to_cycles(vcpu, lapic_timer_advance_ns)));
 }
 
+static void start_sw_tscdeadline(struct kvm_lapic *apic)
+{
+       u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
+       u64 ns = 0;
+       ktime_t expire;
+       struct kvm_vcpu *vcpu = apic->vcpu;
+       unsigned long this_tsc_khz = vcpu->arch.virtual_tsc_khz;
+       unsigned long flags;
+       ktime_t now;
+
+       if (unlikely(!tscdeadline || !this_tsc_khz))
+               return;
+
+       local_irq_save(flags);
+
+       now = apic->lapic_timer.timer.base->get_time();
+       guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
+       if (likely(tscdeadline > guest_tsc)) {
+               ns = (tscdeadline - guest_tsc) * 1000000ULL;
+               do_div(ns, this_tsc_khz);
+               expire = ktime_add_ns(now, ns);
+               expire = ktime_sub_ns(expire, lapic_timer_advance_ns);
+               hrtimer_start(&apic->lapic_timer.timer,
+                               expire, HRTIMER_MODE_ABS_PINNED);
+       } else
+               apic_timer_expired(apic);
+
+       local_irq_restore(flags);
+}
+
+bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
+{
+       if (!lapic_in_kernel(vcpu))
+               return false;
+
+       return vcpu->arch.apic->lapic_timer.hv_timer_in_use;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_hv_timer_in_use);
+
+static void cancel_hv_tscdeadline(struct kvm_lapic *apic)
+{
+       kvm_x86_ops->cancel_hv_timer(apic->vcpu);
+       apic->lapic_timer.hv_timer_in_use = false;
+}
+
+void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
+       WARN_ON(!apic->lapic_timer.hv_timer_in_use);
+       WARN_ON(swait_active(&vcpu->wq));
+       cancel_hv_tscdeadline(apic);
+       apic_timer_expired(apic);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_expired_hv_timer);
+
+static bool start_hv_tscdeadline(struct kvm_lapic *apic)
+{
+       u64 tscdeadline = apic->lapic_timer.tscdeadline;
+
+       if (atomic_read(&apic->lapic_timer.pending) ||
+               kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline)) {
+               if (apic->lapic_timer.hv_timer_in_use)
+                       cancel_hv_tscdeadline(apic);
+       } else {
+               apic->lapic_timer.hv_timer_in_use = true;
+               hrtimer_cancel(&apic->lapic_timer.timer);
+
+               /* In case the sw timer triggered in the window */
+               if (atomic_read(&apic->lapic_timer.pending))
+                       cancel_hv_tscdeadline(apic);
+       }
+       trace_kvm_hv_timer_state(apic->vcpu->vcpu_id,
+                       apic->lapic_timer.hv_timer_in_use);
+       return apic->lapic_timer.hv_timer_in_use;
+}
+
+void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
+       WARN_ON(apic->lapic_timer.hv_timer_in_use);
+
+       if (apic_lvtt_tscdeadline(apic))
+               start_hv_tscdeadline(apic);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_switch_to_hv_timer);
+
+void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
+       /* Possibly the TSC deadline timer is not enabled yet */
+       if (!apic->lapic_timer.hv_timer_in_use)
+               return;
+
+       cancel_hv_tscdeadline(apic);
+
+       if (atomic_read(&apic->lapic_timer.pending))
+               return;
+
+       start_sw_tscdeadline(apic);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_switch_to_sw_timer);
+
 static void start_apic_timer(struct kvm_lapic *apic)
 {
        ktime_t now;
@@ -1360,32 +1468,8 @@ static void start_apic_timer(struct kvm_lapic *apic)
                           ktime_to_ns(ktime_add_ns(now,
                                        apic->lapic_timer.period)));
        } else if (apic_lvtt_tscdeadline(apic)) {
-               /* lapic timer in tsc deadline mode */
-               u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
-               u64 ns = 0;
-               ktime_t expire;
-               struct kvm_vcpu *vcpu = apic->vcpu;
-               unsigned long this_tsc_khz = vcpu->arch.virtual_tsc_khz;
-               unsigned long flags;
-
-               if (unlikely(!tscdeadline || !this_tsc_khz))
-                       return;
-
-               local_irq_save(flags);
-
-               now = apic->lapic_timer.timer.base->get_time();
-               guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
-               if (likely(tscdeadline > guest_tsc)) {
-                       ns = (tscdeadline - guest_tsc) * 1000000ULL;
-                       do_div(ns, this_tsc_khz);
-                       expire = ktime_add_ns(now, ns);
-                       expire = ktime_sub_ns(expire, lapic_timer_advance_ns);
-                       hrtimer_start(&apic->lapic_timer.timer,
-                                     expire, HRTIMER_MODE_ABS_PINNED);
-               } else
-                       apic_timer_expired(apic);
-
-               local_irq_restore(flags);
+               if (!(kvm_x86_ops->set_hv_timer && start_hv_tscdeadline(apic)))
+                       start_sw_tscdeadline(apic);
        }
 }
 
@@ -1413,7 +1497,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
        switch (reg) {
        case APIC_ID:           /* Local APIC ID */
                if (!apic_x2apic_mode(apic))
-                       kvm_apic_set_id(apic, val >> 24);
+                       kvm_apic_set_xapic_id(apic, val >> 24);
                else
                        ret = 1;
                break;
@@ -1674,9 +1758,10 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
 
        /* update jump label if enable bit changes */
        if ((old_value ^ value) & MSR_IA32_APICBASE_ENABLE) {
-               if (value & MSR_IA32_APICBASE_ENABLE)
+               if (value & MSR_IA32_APICBASE_ENABLE) {
+                       kvm_apic_set_xapic_id(apic, vcpu->vcpu_id);
                        static_key_slow_dec_deferred(&apic_hw_disabled);
-               else
+               else
                        static_key_slow_inc(&apic_hw_disabled.key);
                recalculate_apic_map(vcpu->kvm);
        }
@@ -1716,8 +1801,11 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        /* Stop the timer in case it's a reset to an active apic */
        hrtimer_cancel(&apic->lapic_timer.timer);
 
-       if (!init_event)
-               kvm_apic_set_id(apic, vcpu->vcpu_id);
+       if (!init_event) {
+               kvm_lapic_set_base(vcpu, APIC_DEFAULT_PHYS_BASE |
+                                        MSR_IA32_APICBASE_ENABLE);
+               kvm_apic_set_xapic_id(apic, vcpu->vcpu_id);
+       }
        kvm_apic_set_version(apic->vcpu);
 
        for (i = 0; i < KVM_APIC_LVT_NUM; i++)
@@ -1856,9 +1944,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
         * thinking that APIC satet has changed.
         */
        vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE;
-       kvm_lapic_set_base(vcpu,
-                       APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE);
-
        static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
        kvm_lapic_reset(vcpu, false);
        kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
@@ -1938,17 +2023,48 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
        return vector;
 }
 
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
-               struct kvm_lapic_state *s)
+static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
+               struct kvm_lapic_state *s, bool set)
+{
+       if (apic_x2apic_mode(vcpu->arch.apic)) {
+               u32 *id = (u32 *)(s->regs + APIC_ID);
+
+               if (vcpu->kvm->arch.x2apic_format) {
+                       if (*id != vcpu->vcpu_id)
+                               return -EINVAL;
+               } else {
+                       if (set)
+                               *id >>= 24;
+                       else
+                               *id <<= 24;
+               }
+       }
+
+       return 0;
+}
+
+int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
+{
+       memcpy(s->regs, vcpu->arch.apic->regs, sizeof(*s));
+       return kvm_apic_state_fixup(vcpu, s, false);
+}
+
+int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
+       int r;
+
 
        kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
        /* set SPIV separately to get count of SW disabled APICs right */
        apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
+
+       r = kvm_apic_state_fixup(vcpu, s, true);
+       if (r)
+               return r;
        memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
-       /* call kvm_apic_set_id() to put apic into apic_map */
-       kvm_apic_set_id(apic, kvm_apic_id(apic));
+
+       recalculate_apic_map(vcpu->kvm);
        kvm_apic_set_version(vcpu);
 
        apic_update_ppr(apic);
@@ -1974,6 +2090,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
                kvm_rtc_eoi_tracking_restore_one(vcpu);
 
        vcpu->arch.apic_arb_prio = 0;
+
+       return 0;
 }
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
index 891c6da..f60d01c 100644 (file)
@@ -20,6 +20,7 @@ struct kvm_timer {
        u64 tscdeadline;
        u64 expired_tscdeadline;
        atomic_t pending;                       /* accumulated triggered timers */
+       bool hv_timer_in_use;
 };
 
 struct kvm_lapic {
@@ -80,8 +81,8 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
 int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
-               struct kvm_lapic_state *s);
+int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
+int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
@@ -199,9 +200,15 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
        return lapic_in_kernel(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
 }
 
-static inline int kvm_apic_id(struct kvm_lapic *apic)
+static inline u32 kvm_apic_id(struct kvm_lapic *apic)
 {
-       return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+       /* To avoid a race between apic_base and following APIC_ID update when
+        * switching to x2apic_mode, the x2apic mode returns initial x2apic id.
+        */
+       if (apic_x2apic_mode(apic))
+               return apic->vcpu->vcpu_id;
+
+       return kvm_lapic_get_reg(apic, APIC_ID) >> 24;
 }
 
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
@@ -212,4 +219,8 @@ bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
                        struct kvm_vcpu **dest_vcpu);
 int kvm_vector_to_index(u32 vector, u32 dest_vcpus,
                        const unsigned long *bitmap, u32 bitmap_size);
+void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu);
+void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu);
+void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu);
+bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu);
 #endif
index 745a5f4..3d4cc8c 100644 (file)
@@ -176,6 +176,7 @@ static u64 __read_mostly shadow_user_mask;
 static u64 __read_mostly shadow_accessed_mask;
 static u64 __read_mostly shadow_dirty_mask;
 static u64 __read_mostly shadow_mmio_mask;
+static u64 __read_mostly shadow_present_mask;
 
 static void mmu_spte_set(u64 *sptep, u64 spte);
 static void mmu_free_roots(struct kvm_vcpu *vcpu);
@@ -283,13 +284,14 @@ static bool check_mmio_spte(struct kvm_vcpu *vcpu, u64 spte)
 }
 
 void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask,
-               u64 dirty_mask, u64 nx_mask, u64 x_mask)
+               u64 dirty_mask, u64 nx_mask, u64 x_mask, u64 p_mask)
 {
        shadow_user_mask = user_mask;
        shadow_accessed_mask = accessed_mask;
        shadow_dirty_mask = dirty_mask;
        shadow_nx_mask = nx_mask;
        shadow_x_mask = x_mask;
+       shadow_present_mask = p_mask;
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes);
 
@@ -305,7 +307,7 @@ static int is_nx(struct kvm_vcpu *vcpu)
 
 static int is_shadow_present_pte(u64 pte)
 {
-       return pte & PT_PRESENT_MASK && !is_mmio_spte(pte);
+       return (pte & 0xFFFFFFFFull) && !is_mmio_spte(pte);
 }
 
 static int is_large_pte(u64 pte)
@@ -524,7 +526,7 @@ static void mmu_spte_set(u64 *sptep, u64 new_spte)
 }
 
 /* Rules for using mmu_spte_update:
- * Update the state bits, it means the mapped pfn is not changged.
+ * Update the state bits, it means the mapped pfn is not changed.
  *
  * Whenever we overwrite a writable spte with a read-only one we
  * should flush remote TLBs. Otherwise rmap_write_protect
@@ -2246,10 +2248,9 @@ static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
 {
        u64 spte;
 
-       BUILD_BUG_ON(VMX_EPT_READABLE_MASK != PT_PRESENT_MASK ||
-                       VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
+       BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
 
-       spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
+       spte = __pa(sp->spt) | shadow_present_mask | PT_WRITABLE_MASK |
               shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
 
        mmu_spte_set(sptep, spte);
@@ -2516,13 +2517,19 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                    gfn_t gfn, kvm_pfn_t pfn, bool speculative,
                    bool can_unsync, bool host_writable)
 {
-       u64 spte;
+       u64 spte = 0;
        int ret = 0;
 
        if (set_mmio_spte(vcpu, sptep, gfn, pfn, pte_access))
                return 0;
 
-       spte = PT_PRESENT_MASK;
+       /*
+        * For the EPT case, shadow_present_mask is 0 if hardware
+        * supports exec-only page table entries.  In that case,
+        * ACC_USER_MASK and shadow_user_mask are used to represent
+        * read access.  See FNAME(gpte_access) in paging_tmpl.h.
+        */
+       spte |= shadow_present_mask;
        if (!speculative)
                spte |= shadow_accessed_mask;
 
@@ -3190,7 +3197,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
                MMU_WARN_ON(VALID_PAGE(root));
                if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
                        pdptr = vcpu->arch.mmu.get_pdptr(vcpu, i);
-                       if (!is_present_gpte(pdptr)) {
+                       if (!(pdptr & PT_PRESENT_MASK)) {
                                vcpu->arch.mmu.pae_root[i] = 0;
                                continue;
                        }
@@ -3915,9 +3922,7 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
                                 *   clearer.
                                 */
                                smap = cr4_smap && u && !uf && !ff;
-                       } else
-                               /* Not really needed: no U/S accesses on ept  */
-                               u = 1;
+                       }
 
                        fault = (ff && !x) || (uf && !u) || (wf && !w) ||
                                (smapf && smap);
index 66b33b9..ddc56e9 100644 (file)
@@ -93,11 +93,6 @@ static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
        return kvm_mmu_load(vcpu);
 }
 
-static inline int is_present_gpte(unsigned long pte)
-{
-       return pte & PT_PRESENT_MASK;
-}
-
 /*
  * Currently, we have two sorts of write-protection, a) the first one
  * write-protects guest page to sync the guest modification, b) another one is
index bc019f7..a011054 100644 (file)
@@ -131,7 +131,7 @@ static inline void FNAME(protect_clean_gpte)(unsigned *access, unsigned gpte)
 static inline int FNAME(is_present_gpte)(unsigned long pte)
 {
 #if PTTYPE != PTTYPE_EPT
-       return is_present_gpte(pte);
+       return pte & PT_PRESENT_MASK;
 #else
        return pte & 7;
 #endif
@@ -181,13 +181,19 @@ no_present:
        return true;
 }
 
+/*
+ * For PTTYPE_EPT, a page table can be executable but not readable
+ * on supported processors. Therefore, set_spte does not automatically
+ * set bit 0 if execute only is supported. Here, we repurpose ACC_USER_MASK
+ * to signify readability since it isn't used in the EPT case
+ */
 static inline unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, u64 gpte)
 {
        unsigned access;
 #if PTTYPE == PTTYPE_EPT
        access = ((gpte & VMX_EPT_WRITABLE_MASK) ? ACC_WRITE_MASK : 0) |
                ((gpte & VMX_EPT_EXECUTABLE_MASK) ? ACC_EXEC_MASK : 0) |
-               ACC_USER_MASK;
+               ((gpte & VMX_EPT_READABLE_MASK) ? ACC_USER_MASK : 0);
 #else
        BUILD_BUG_ON(ACC_EXEC_MASK != PT_PRESENT_MASK);
        BUILD_BUG_ON(ACC_EXEC_MASK != 1);
index ab38af4..9d4a850 100644 (file)
@@ -93,7 +93,7 @@ static unsigned intel_find_fixed_event(int idx)
        return intel_arch_events[fixed_pmc_events[idx]].event_type;
 }
 
-/* check if a PMC is enabled by comparising it with globl_ctrl bits. */
+/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
 static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
 {
        struct kvm_pmu *pmu = pmc_to_pmu(pmc);
index 16ef31b..af523d8 100644 (file)
@@ -1577,7 +1577,7 @@ static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
        /*
-        * Any change of EFLAGS.VM is accompained by a reload of SS
+        * Any change of EFLAGS.VM is accompanied by a reload of SS
         * (caused by either a task switch or an inter-privilege IRET),
         * so we do not need to update the CPL here.
         */
@@ -4940,6 +4940,12 @@ out:
 static void svm_handle_external_intr(struct kvm_vcpu *vcpu)
 {
        local_irq_enable();
+       /*
+        * We must have an instruction with interrupts enabled, so
+        * the timer interrupt isn't delayed by the interrupt shadow.
+        */
+       asm("nop");
+       local_irq_disable();
 }
 
 static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
index 8de9250..0a6cc67 100644 (file)
@@ -1348,6 +1348,21 @@ TRACE_EVENT(kvm_avic_unaccelerated_access,
                  __entry->vec)
 );
 
+TRACE_EVENT(kvm_hv_timer_state,
+               TP_PROTO(unsigned int vcpu_id, unsigned int hv_timer_in_use),
+               TP_ARGS(vcpu_id, hv_timer_in_use),
+               TP_STRUCT__entry(
+                       __field(unsigned int, vcpu_id)
+                       __field(unsigned int, hv_timer_in_use)
+                       ),
+               TP_fast_assign(
+                       __entry->vcpu_id = vcpu_id;
+                       __entry->hv_timer_in_use = hv_timer_in_use;
+                       ),
+               TP_printk("vcpu_id %x hv_timer %x\n",
+                       __entry->vcpu_id,
+                       __entry->hv_timer_in_use)
+);
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
index df07a0a..a45d858 100644 (file)
@@ -110,6 +110,13 @@ module_param_named(pml, enable_pml, bool, S_IRUGO);
 
 #define KVM_VMX_TSC_MULTIPLIER_MAX     0xffffffffffffffffULL
 
+/* Guest_tsc -> host_tsc conversion requires 64-bit division.  */
+static int __read_mostly cpu_preemption_timer_multi;
+static bool __read_mostly enable_preemption_timer = 1;
+#ifdef CONFIG_X86_64
+module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
+#endif
+
 #define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD)
 #define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST (X86_CR0_WP | X86_CR0_NE)
 #define KVM_VM_CR0_ALWAYS_ON                                           \
@@ -398,6 +405,12 @@ struct nested_vmx {
        /* The host-usable pointer to the above */
        struct page *current_vmcs12_page;
        struct vmcs12 *current_vmcs12;
+       /*
+        * Cache of the guest's VMCS, existing outside of guest memory.
+        * Loaded from guest memory during VMPTRLD. Flushed to guest
+        * memory during VMXOFF, VMCLEAR, VMPTRLD.
+        */
+       struct vmcs12 *cached_vmcs12;
        struct vmcs *current_shadow_vmcs;
        /*
         * Indicates if the shadow vmcs must be updated with the
@@ -421,7 +434,6 @@ struct nested_vmx {
        struct pi_desc *pi_desc;
        bool pi_pending;
        u16 posted_intr_nv;
-       u64 msr_ia32_feature_control;
 
        struct hrtimer preemption_timer;
        bool preemption_timer_expired;
@@ -597,11 +609,22 @@ struct vcpu_vmx {
 #define PML_ENTITY_NUM         512
        struct page *pml_pg;
 
+       /* apic deadline value in host tsc */
+       u64 hv_deadline_tsc;
+
        u64 current_tsc_ratio;
 
        bool guest_pkru_valid;
        u32 guest_pkru;
        u32 host_pkru;
+
+       /*
+        * Only bits masked by msr_ia32_feature_control_valid_bits can be set in
+        * msr_ia32_feature_control. FEATURE_CONTROL_LOCKED is always included
+        * in msr_ia32_feature_control_valid_bits.
+        */
+       u64 msr_ia32_feature_control;
+       u64 msr_ia32_feature_control_valid_bits;
 };
 
 enum segment_cache_field {
@@ -841,7 +864,7 @@ static inline short vmcs_field_to_offset(unsigned long field)
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 {
-       return to_vmx(vcpu)->nested.current_vmcs12;
+       return to_vmx(vcpu)->nested.cached_vmcs12;
 }
 
 static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr)
@@ -1056,6 +1079,58 @@ static inline bool cpu_has_vmx_virtual_intr_delivery(void)
                SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
 }
 
+/*
+ * Comment's format: document - errata name - stepping - processor name.
+ * Refer from
+ * https://www.virtualbox.org/svn/vbox/trunk/src/VBox/VMM/VMMR0/HMR0.cpp
+ */
+static u32 vmx_preemption_cpu_tfms[] = {
+/* 323344.pdf - BA86   - D0 - Xeon 7500 Series */
+0x000206E6,
+/* 323056.pdf - AAX65  - C2 - Xeon L3406 */
+/* 322814.pdf - AAT59  - C2 - i7-600, i5-500, i5-400 and i3-300 Mobile */
+/* 322911.pdf - AAU65  - C2 - i5-600, i3-500 Desktop and Pentium G6950 */
+0x00020652,
+/* 322911.pdf - AAU65  - K0 - i5-600, i3-500 Desktop and Pentium G6950 */
+0x00020655,
+/* 322373.pdf - AAO95  - B1 - Xeon 3400 Series */
+/* 322166.pdf - AAN92  - B1 - i7-800 and i5-700 Desktop */
+/*
+ * 320767.pdf - AAP86  - B1 -
+ * i7-900 Mobile Extreme, i7-800 and i7-700 Mobile
+ */
+0x000106E5,
+/* 321333.pdf - AAM126 - C0 - Xeon 3500 */
+0x000106A0,
+/* 321333.pdf - AAM126 - C1 - Xeon 3500 */
+0x000106A1,
+/* 320836.pdf - AAJ124 - C0 - i7-900 Desktop Extreme and i7-900 Desktop */
+0x000106A4,
+ /* 321333.pdf - AAM126 - D0 - Xeon 3500 */
+ /* 321324.pdf - AAK139 - D0 - Xeon 5500 */
+ /* 320836.pdf - AAJ124 - D0 - i7-900 Extreme and i7-900 Desktop */
+0x000106A5,
+};
+
+static inline bool cpu_has_broken_vmx_preemption_timer(void)
+{
+       u32 eax = cpuid_eax(0x00000001), i;
+
+       /* Clear the reserved bits */
+       eax &= ~(0x3U << 14 | 0xfU << 28);
+       for (i = 0; i < ARRAY_SIZE(vmx_preemption_cpu_tfms); i++)
+               if (eax == vmx_preemption_cpu_tfms[i])
+                       return true;
+
+       return false;
+}
+
+static inline bool cpu_has_vmx_preemption_timer(void)
+{
+       return vmcs_config.pin_based_exec_ctrl &
+               PIN_BASED_VMX_PREEMPTION_TIMER;
+}
+
 static inline bool cpu_has_vmx_posted_intr(void)
 {
        return IS_ENABLED(CONFIG_X86_LOCAL_APIC) &&
@@ -1603,6 +1678,11 @@ static __always_inline void vmcs_set_bits(unsigned long field, u32 mask)
        __vmcs_writel(field, __vmcs_readl(field) | mask);
 }
 
+static inline void vm_entry_controls_reset_shadow(struct vcpu_vmx *vmx)
+{
+       vmx->vm_entry_controls_shadow = vmcs_read32(VM_ENTRY_CONTROLS);
+}
+
 static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
 {
        vmcs_write32(VM_ENTRY_CONTROLS, val);
@@ -1631,6 +1711,11 @@ static inline void vm_entry_controls_clearbit(struct vcpu_vmx *vmx, u32 val)
        vm_entry_controls_set(vmx, vm_entry_controls_get(vmx) & ~val);
 }
 
+static inline void vm_exit_controls_reset_shadow(struct vcpu_vmx *vmx)
+{
+       vmx->vm_exit_controls_shadow = vmcs_read32(VM_EXIT_CONTROLS);
+}
+
 static inline void vm_exit_controls_init(struct vcpu_vmx *vmx, u32 val)
 {
        vmcs_write32(VM_EXIT_CONTROLS, val);
@@ -2121,22 +2206,14 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
+       bool already_loaded = vmx->loaded_vmcs->cpu == cpu;
 
        if (!vmm_exclusive)
                kvm_cpu_vmxon(phys_addr);
-       else if (vmx->loaded_vmcs->cpu != cpu)
+       else if (!already_loaded)
                loaded_vmcs_clear(vmx->loaded_vmcs);
 
-       if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
-               per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
-               vmcs_load(vmx->loaded_vmcs->vmcs);
-       }
-
-       if (vmx->loaded_vmcs->cpu != cpu) {
-               struct desc_ptr *gdt = this_cpu_ptr(&host_gdt);
-               unsigned long sysenter_esp;
-
-               kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+       if (!already_loaded) {
                local_irq_disable();
                crash_disable_local_vmclear(cpu);
 
@@ -2151,6 +2228,18 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                         &per_cpu(loaded_vmcss_on_cpu, cpu));
                crash_enable_local_vmclear(cpu);
                local_irq_enable();
+       }
+
+       if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
+               per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
+               vmcs_load(vmx->loaded_vmcs->vmcs);
+       }
+
+       if (!already_loaded) {
+               struct desc_ptr *gdt = this_cpu_ptr(&host_gdt);
+               unsigned long sysenter_esp;
+
+               kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 
                /*
                 * Linux uses per-cpu TSS and GDT, so set these when switching
@@ -2716,13 +2805,12 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
                vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
                         VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT |
                         VMX_EPT_INVEPT_BIT;
+               if (cpu_has_vmx_ept_execute_only())
+                       vmx->nested.nested_vmx_ept_caps |=
+                               VMX_EPT_EXECUTE_ONLY_BIT;
                vmx->nested.nested_vmx_ept_caps &= vmx_capability.ept;
-               /*
-                * For nested guests, we don't do anything specific
-                * for single context invalidation. Hence, only advertise
-                * support for global context invalidation.
-                */
-               vmx->nested.nested_vmx_ept_caps |= VMX_EPT_EXTENT_GLOBAL_BIT;
+               vmx->nested.nested_vmx_ept_caps |= VMX_EPT_EXTENT_GLOBAL_BIT |
+                       VMX_EPT_EXTENT_CONTEXT_BIT;
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
@@ -2853,7 +2941,6 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
                        vmx->nested.nested_vmx_secondary_ctls_high);
                break;
        case MSR_IA32_VMX_EPT_VPID_CAP:
-               /* Currently, no nested vpid support */
                *pdata = vmx->nested.nested_vmx_ept_caps |
                        ((u64)vmx->nested.nested_vmx_vpid_caps << 32);
                break;
@@ -2864,6 +2951,14 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
        return 0;
 }
 
+static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
+                                                uint64_t val)
+{
+       uint64_t valid_bits = to_vmx(vcpu)->msr_ia32_feature_control_valid_bits;
+
+       return !(val & ~valid_bits);
+}
+
 /*
  * Reads an msr value (of 'msr_index') into 'pdata'.
  * Returns 0 on success, non-0 otherwise.
@@ -2905,10 +3000,15 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                msr_info->data = vmcs_read64(GUEST_BNDCFGS);
                break;
-       case MSR_IA32_FEATURE_CONTROL:
-               if (!nested_vmx_allowed(vcpu))
+       case MSR_IA32_MCG_EXT_CTL:
+               if (!msr_info->host_initiated &&
+                   !(to_vmx(vcpu)->msr_ia32_feature_control &
+                     FEATURE_CONTROL_LMCE))
                        return 1;
-               msr_info->data = to_vmx(vcpu)->nested.msr_ia32_feature_control;
+               msr_info->data = vcpu->arch.mcg_ext_ctl;
+               break;
+       case MSR_IA32_FEATURE_CONTROL:
+               msr_info->data = to_vmx(vcpu)->msr_ia32_feature_control;
                break;
        case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
                if (!nested_vmx_allowed(vcpu))
@@ -2998,12 +3098,20 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_IA32_TSC_ADJUST:
                ret = kvm_set_msr_common(vcpu, msr_info);
                break;
+       case MSR_IA32_MCG_EXT_CTL:
+               if ((!msr_info->host_initiated &&
+                    !(to_vmx(vcpu)->msr_ia32_feature_control &
+                      FEATURE_CONTROL_LMCE)) ||
+                   (data & ~MCG_EXT_CTL_LMCE_EN))
+                       return 1;
+               vcpu->arch.mcg_ext_ctl = data;
+               break;
        case MSR_IA32_FEATURE_CONTROL:
-               if (!nested_vmx_allowed(vcpu) ||
-                   (to_vmx(vcpu)->nested.msr_ia32_feature_control &
+               if (!vmx_feature_control_msr_valid(vcpu, data) ||
+                   (to_vmx(vcpu)->msr_ia32_feature_control &
                     FEATURE_CONTROL_LOCKED && !msr_info->host_initiated))
                        return 1;
-               vmx->nested.msr_ia32_feature_control = data;
+               vmx->msr_ia32_feature_control = data;
                if (msr_info->host_initiated && data == 0)
                        vmx_leave_nested(vcpu);
                break;
@@ -3297,25 +3405,27 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                      vmx_capability.ept, vmx_capability.vpid);
        }
 
-       min = VM_EXIT_SAVE_DEBUG_CONTROLS;
+       min = VM_EXIT_SAVE_DEBUG_CONTROLS | VM_EXIT_ACK_INTR_ON_EXIT;
 #ifdef CONFIG_X86_64
        min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
 #endif
        opt = VM_EXIT_SAVE_IA32_PAT | VM_EXIT_LOAD_IA32_PAT |
-               VM_EXIT_ACK_INTR_ON_EXIT | VM_EXIT_CLEAR_BNDCFGS;
+               VM_EXIT_CLEAR_BNDCFGS;
        if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
                                &_vmexit_control) < 0)
                return -EIO;
 
        min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
-       opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR;
+       opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR |
+                PIN_BASED_VMX_PREEMPTION_TIMER;
        if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
                                &_pin_based_exec_control) < 0)
                return -EIO;
 
+       if (cpu_has_broken_vmx_preemption_timer())
+               _pin_based_exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
        if (!(_cpu_based_2nd_exec_control &
-               SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY) ||
-               !(_vmexit_control & VM_EXIT_ACK_INTR_ON_EXIT))
+               SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY))
                _pin_based_exec_control &= ~PIN_BASED_POSTED_INTR;
 
        min = VM_ENTRY_LOAD_DEBUG_CONTROLS;
@@ -3364,7 +3474,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
 
        /*
         * Some cpus support VM_ENTRY_(LOAD|SAVE)_IA32_PERF_GLOBAL_CTRL
-        * but due to arrata below it can't be used. Workaround is to use
+        * but due to errata below it can't be used. Workaround is to use
         * msr load mechanism to switch IA32_PERF_GLOBAL_CTRL.
         *
         * VM Exit May Incorrectly Clear IA32_PERF_GLOBAL_CTRL [34:32]
@@ -4781,6 +4891,8 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
 
        if (!kvm_vcpu_apicv_active(&vmx->vcpu))
                pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR;
+       /* Enable the preemption timer dynamically */
+       pin_based_exec_ctrl &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
        return pin_based_exec_ctrl;
 }
 
@@ -4896,6 +5008,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 
        /* Control */
        vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+       vmx->hv_deadline_tsc = -1;
 
        vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, vmx_exec_control(vmx));
 
@@ -6016,12 +6129,14 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
        gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
        trace_kvm_page_fault(gpa, exit_qualification);
 
-       /* It is a write fault? */
-       error_code = exit_qualification & PFERR_WRITE_MASK;
+       /* it is a read fault? */
+       error_code = (exit_qualification << 2) & PFERR_USER_MASK;
+       /* it is a write fault? */
+       error_code |= exit_qualification & PFERR_WRITE_MASK;
        /* It is a fetch fault? */
        error_code |= (exit_qualification << 2) & PFERR_FETCH_MASK;
        /* ept page table is present? */
-       error_code |= (exit_qualification >> 3) & PFERR_PRESENT_MASK;
+       error_code |= (exit_qualification & 0x38) != 0;
 
        vcpu->arch.exit_qualification = exit_qualification;
 
@@ -6355,9 +6470,6 @@ static __init int hardware_setup(void)
        for (msr = 0x800; msr <= 0x8ff; msr++)
                vmx_disable_intercept_msr_read_x2apic(msr);
 
-       /* According SDM, in x2apic mode, the whole id reg is used.  But in
-        * KVM, it only use the highest eight bits. Need to intercept it */
-       vmx_enable_intercept_msr_read_x2apic(0x802);
        /* TMCCT */
        vmx_enable_intercept_msr_read_x2apic(0x839);
        /* TPR */
@@ -6368,10 +6480,12 @@ static __init int hardware_setup(void)
        vmx_disable_intercept_msr_write_x2apic(0x83f);
 
        if (enable_ept) {
-               kvm_mmu_set_mask_ptes(0ull,
+               kvm_mmu_set_mask_ptes(VMX_EPT_READABLE_MASK,
                        (enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
                        (enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
-                       0ull, VMX_EPT_EXECUTABLE_MASK);
+                       0ull, VMX_EPT_EXECUTABLE_MASK,
+                       cpu_has_vmx_ept_execute_only() ?
+                                     0ull : VMX_EPT_READABLE_MASK);
                ept_set_mmio_spte_mask();
                kvm_enable_tdp();
        } else
@@ -6393,8 +6507,21 @@ static __init int hardware_setup(void)
                kvm_x86_ops->enable_log_dirty_pt_masked = NULL;
        }
 
+       if (cpu_has_vmx_preemption_timer() && enable_preemption_timer) {
+               u64 vmx_msr;
+
+               rdmsrl(MSR_IA32_VMX_MISC, vmx_msr);
+               cpu_preemption_timer_multi =
+                        vmx_msr & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
+       } else {
+               kvm_x86_ops->set_hv_timer = NULL;
+               kvm_x86_ops->cancel_hv_timer = NULL;
+       }
+
        kvm_set_posted_intr_wakeup_handler(wakeup_handler);
 
+       kvm_mce_cap_supported |= MCG_LMCE_P;
+
        return alloc_kvm_area();
 
 out8:
@@ -6862,16 +6989,22 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
                return 1;
        }
 
-       if ((vmx->nested.msr_ia32_feature_control & VMXON_NEEDED_FEATURES)
+       if ((vmx->msr_ia32_feature_control & VMXON_NEEDED_FEATURES)
                        != VMXON_NEEDED_FEATURES) {
                kvm_inject_gp(vcpu, 0);
                return 1;
        }
 
+       vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL);
+       if (!vmx->nested.cached_vmcs12)
+               return -ENOMEM;
+
        if (enable_shadow_vmcs) {
                shadow_vmcs = alloc_vmcs();
-               if (!shadow_vmcs)
+               if (!shadow_vmcs) {
+                       kfree(vmx->nested.cached_vmcs12);
                        return -ENOMEM;
+               }
                /* mark vmcs as shadow */
                shadow_vmcs->revision_id |= (1u << 31);
                /* init shadow vmcs */
@@ -6942,6 +7075,11 @@ static inline void nested_release_vmcs12(struct vcpu_vmx *vmx)
                vmcs_write64(VMCS_LINK_POINTER, -1ull);
        }
        vmx->nested.posted_intr_nv = -1;
+
+       /* Flush VMCS12 to guest memory */
+       memcpy(vmx->nested.current_vmcs12, vmx->nested.cached_vmcs12,
+              VMCS12_SIZE);
+
        kunmap(vmx->nested.current_vmcs12_page);
        nested_release_page(vmx->nested.current_vmcs12_page);
        vmx->nested.current_vmptr = -1ull;
@@ -6962,6 +7100,7 @@ static void free_nested(struct vcpu_vmx *vmx)
        nested_release_vmcs12(vmx);
        if (enable_shadow_vmcs)
                free_vmcs(vmx->nested.current_shadow_vmcs);
+       kfree(vmx->nested.cached_vmcs12);
        /* Unpin physical memory we referred to in current vmcs02 */
        if (vmx->nested.apic_access_page) {
                nested_release_page(vmx->nested.apic_access_page);
@@ -7365,6 +7504,13 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                vmx->nested.current_vmptr = vmptr;
                vmx->nested.current_vmcs12 = new_vmcs12;
                vmx->nested.current_vmcs12_page = page;
+               /*
+                * Load VMCS12 from guest memory since it is not already
+                * cached.
+                */
+               memcpy(vmx->nested.cached_vmcs12,
+                      vmx->nested.current_vmcs12, VMCS12_SIZE);
+
                if (enable_shadow_vmcs) {
                        vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
                                      SECONDARY_EXEC_SHADOW_VMCS);
@@ -7458,12 +7604,16 @@ static int handle_invept(struct kvm_vcpu *vcpu)
 
        switch (type) {
        case VMX_EPT_EXTENT_GLOBAL:
+       /*
+        * TODO: track mappings and invalidate
+        * single context requests appropriately
+        */
+       case VMX_EPT_EXTENT_CONTEXT:
                kvm_mmu_sync_roots(vcpu);
                kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
                nested_vmx_succeed(vcpu);
                break;
        default:
-               /* Trap single context invalidation invept calls */
                BUG_ON(1);
                break;
        }
@@ -7560,6 +7710,12 @@ static int handle_pml_full(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+static int handle_preemption_timer(struct kvm_vcpu *vcpu)
+{
+       kvm_lapic_expired_hv_timer(vcpu);
+       return 1;
+}
+
 /*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
@@ -7610,6 +7766,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
        [EXIT_REASON_XSAVES]                  = handle_xsaves,
        [EXIT_REASON_XRSTORS]                 = handle_xrstors,
        [EXIT_REASON_PML_FULL]                = handle_pml_full,
+       [EXIT_REASON_PREEMPTION_TIMER]        = handle_preemption_timer,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -7918,6 +8075,8 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                 * the XSS exit bitmap in vmcs12.
                 */
                return nested_cpu_has2(vmcs12, SECONDARY_EXEC_XSAVES);
+       case EXIT_REASON_PREEMPTION_TIMER:
+               return false;
        default:
                return true;
        }
@@ -8303,7 +8462,7 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu, hpa_t hpa)
         * the next L2->L1 exit.
         */
        if (!is_guest_mode(vcpu) ||
-           !nested_cpu_has2(vmx->nested.current_vmcs12,
+           !nested_cpu_has2(get_vmcs12(&vmx->vcpu),
                             SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
                vmcs_write64(APIC_ACCESS_ADDR, hpa);
 }
@@ -8436,7 +8595,6 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
                        "push %[sp]\n\t"
 #endif
                        "pushf\n\t"
-                       "orl $0x200, (%%" _ASM_SP ")\n\t"
                        __ASM_SIZE(push) " $%c[cs]\n\t"
                        "call *%[entry]\n\t"
                        :
@@ -8449,8 +8607,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
                        [ss]"i"(__KERNEL_DS),
                        [cs]"i"(__KERNEL_CS)
                        );
-       } else
-               local_irq_enable();
+       }
 }
 
 static bool vmx_has_high_real_mode_segbase(void)
@@ -8601,6 +8758,26 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
                                        msrs[i].host);
 }
 
+void vmx_arm_hv_timer(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u64 tscl;
+       u32 delta_tsc;
+
+       if (vmx->hv_deadline_tsc == -1)
+               return;
+
+       tscl = rdtsc();
+       if (vmx->hv_deadline_tsc > tscl)
+               /* sure to be 32 bit only because checked on set_hv_timer */
+               delta_tsc = (u32)((vmx->hv_deadline_tsc - tscl) >>
+                       cpu_preemption_timer_multi);
+       else
+               delta_tsc = 0;
+
+       vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc);
+}
+
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -8650,6 +8827,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        atomic_switch_perf_msrs(vmx);
        debugctlmsr = get_debugctlmsr();
 
+       vmx_arm_hv_timer(vcpu);
+
        vmx->__launched = vmx->loaded_vmcs->launched;
        asm(
                /* Store host registers */
@@ -8940,6 +9119,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
        vmx->nested.current_vmptr = -1ull;
        vmx->nested.current_vmcs12 = NULL;
 
+       vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED;
+
        return &vmx->vcpu;
 
 free_vmcs:
@@ -9080,6 +9261,13 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
 
        if (cpu_has_secondary_exec_ctrls())
                vmcs_set_secondary_exec_control(secondary_exec_ctl);
+
+       if (nested_vmx_allowed(vcpu))
+               to_vmx(vcpu)->msr_ia32_feature_control_valid_bits |=
+                       FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
+       else
+               to_vmx(vcpu)->msr_ia32_feature_control_valid_bits &=
+                       ~FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
 }
 
 static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
@@ -9636,9 +9824,14 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        vmcs_write64(VMCS_LINK_POINTER, -1ull);
 
        exec_control = vmcs12->pin_based_vm_exec_control;
-       exec_control |= vmcs_config.pin_based_exec_ctrl;
+
+       /* Preemption timer setting is only taken from vmcs01.  */
        exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
+       exec_control |= vmcs_config.pin_based_exec_ctrl;
+       if (vmx->hv_deadline_tsc == -1)
+               exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
 
+       /* Posted interrupts setting is only taken from vmcs12.  */
        if (nested_cpu_has_posted_intr(vmcs12)) {
                /*
                 * Note that we use L0's vector here and in
@@ -10556,8 +10749,8 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
                                       vmcs12->vm_exit_intr_error_code,
                                       KVM_ISA_VMX);
 
-       vm_entry_controls_init(vmx, vmcs_read32(VM_ENTRY_CONTROLS));
-       vm_exit_controls_init(vmx, vmcs_read32(VM_EXIT_CONTROLS));
+       vm_entry_controls_reset_shadow(vmx);
+       vm_exit_controls_reset_shadow(vmx);
        vmx_segment_cache_clear(vmx);
 
        /* if no vmcs02 cache requested, remove the one we used */
@@ -10566,8 +10759,14 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
 
        load_vmcs12_host_state(vcpu, vmcs12);
 
-       /* Update TSC_OFFSET if TSC was changed while L2 ran */
+       /* Update any VMCS fields that might have changed while L2 ran */
        vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
+       if (vmx->hv_deadline_tsc == -1)
+               vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
+                               PIN_BASED_VMX_PREEMPTION_TIMER);
+       else
+               vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
+                             PIN_BASED_VMX_PREEMPTION_TIMER);
 
        /* This is needed for same reason as it was needed in prepare_vmcs02 */
        vmx->host_rsp = 0;
@@ -10647,6 +10846,64 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
        return X86EMUL_CONTINUE;
 }
 
+#ifdef CONFIG_X86_64
+/* (a << shift) / divisor, return 1 if overflow otherwise 0 */
+static inline int u64_shl_div_u64(u64 a, unsigned int shift,
+                                 u64 divisor, u64 *result)
+{
+       u64 low = a << shift, high = a >> (64 - shift);
+
+       /* To avoid the overflow on divq */
+       if (high >= divisor)
+               return 1;
+
+       /* Low hold the result, high hold rem which is discarded */
+       asm("divq %2\n\t" : "=a" (low), "=d" (high) :
+           "rm" (divisor), "0" (low), "1" (high));
+       *result = low;
+
+       return 0;
+}
+
+static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u64 tscl = rdtsc();
+       u64 guest_tscl = kvm_read_l1_tsc(vcpu, tscl);
+       u64 delta_tsc = max(guest_deadline_tsc, guest_tscl) - guest_tscl;
+
+       /* Convert to host delta tsc if tsc scaling is enabled */
+       if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio &&
+                       u64_shl_div_u64(delta_tsc,
+                               kvm_tsc_scaling_ratio_frac_bits,
+                               vcpu->arch.tsc_scaling_ratio,
+                               &delta_tsc))
+               return -ERANGE;
+
+       /*
+        * If the delta tsc can't fit in the 32 bit after the multi shift,
+        * we can't use the preemption timer.
+        * It's possible that it fits on later vmentries, but checking
+        * on every vmentry is costly so we just use an hrtimer.
+        */
+       if (delta_tsc >> (cpu_preemption_timer_multi + 32))
+               return -ERANGE;
+
+       vmx->hv_deadline_tsc = tscl + delta_tsc;
+       vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
+                       PIN_BASED_VMX_PREEMPTION_TIMER);
+       return 0;
+}
+
+static void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       vmx->hv_deadline_tsc = -1;
+       vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
+                       PIN_BASED_VMX_PREEMPTION_TIMER);
+}
+#endif
+
 static void vmx_sched_in(struct kvm_vcpu *vcpu, int cpu)
 {
        if (ple_gap)
@@ -10691,7 +10948,7 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
  *   this case, return 1, otherwise, return 0.
  *
  */
-static int vmx_pre_block(struct kvm_vcpu *vcpu)
+static int pi_pre_block(struct kvm_vcpu *vcpu)
 {
        unsigned long flags;
        unsigned int dest;
@@ -10758,7 +11015,18 @@ static int vmx_pre_block(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static void vmx_post_block(struct kvm_vcpu *vcpu)
+static int vmx_pre_block(struct kvm_vcpu *vcpu)
+{
+       if (pi_pre_block(vcpu))
+               return 1;
+
+       if (kvm_lapic_hv_timer_in_use(vcpu))
+               kvm_lapic_switch_to_sw_timer(vcpu);
+
+       return 0;
+}
+
+static void pi_post_block(struct kvm_vcpu *vcpu)
 {
        struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
        struct pi_desc old, new;
@@ -10800,6 +11068,14 @@ static void vmx_post_block(struct kvm_vcpu *vcpu)
        }
 }
 
+static void vmx_post_block(struct kvm_vcpu *vcpu)
+{
+       if (kvm_x86_ops->set_hv_timer)
+               kvm_lapic_switch_to_hv_timer(vcpu);
+
+       pi_post_block(vcpu);
+}
+
 /*
  * vmx_update_pi_irte - set IRTE for Posted-Interrupts
  *
@@ -10844,7 +11120,7 @@ static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
                 * We will support full lowest-priority interrupt later.
                 */
 
-               kvm_set_msi_irq(e, &irq);
+               kvm_set_msi_irq(kvm, e, &irq);
                if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu)) {
                        /*
                         * Make sure the IRTE is in remapped mode if
@@ -10889,6 +11165,16 @@ out:
        return ret;
 }
 
+static void vmx_setup_mce(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->arch.mcg_cap & MCG_LMCE_P)
+               to_vmx(vcpu)->msr_ia32_feature_control_valid_bits |=
+                       FEATURE_CONTROL_LMCE;
+       else
+               to_vmx(vcpu)->msr_ia32_feature_control_valid_bits &=
+                       ~FEATURE_CONTROL_LMCE;
+}
+
 static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
@@ -11013,6 +11299,13 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .pmu_ops = &intel_pmu_ops,
 
        .update_pi_irte = vmx_update_pi_irte,
+
+#ifdef CONFIG_X86_64
+       .set_hv_timer = vmx_set_hv_timer,
+       .cancel_hv_timer = vmx_cancel_hv_timer,
+#endif
+
+       .setup_mce = vmx_setup_mce,
 };
 
 static int __init vmx_init(void)
index 9c496c7..19f9f9e 100644 (file)
@@ -71,7 +71,8 @@
 
 #define MAX_IO_MSRS 256
 #define KVM_MAX_MCE_BANKS 32
-#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
+u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P;
+EXPORT_SYMBOL_GPL(kvm_mce_cap_supported);
 
 #define emul_to_vcpu(ctxt) \
        container_of(ctxt, struct kvm_vcpu, arch.emulate_ctxt)
@@ -90,8 +91,12 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
 #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
 
+#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
+                                    KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
+
 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
 static void process_nmi(struct kvm_vcpu *vcpu);
+static void enter_smm(struct kvm_vcpu *vcpu);
 static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
 
 struct kvm_x86_ops *kvm_x86_ops __read_mostly;
@@ -114,7 +119,8 @@ u8   __read_mostly kvm_tsc_scaling_ratio_frac_bits;
 EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
 u64  __read_mostly kvm_max_tsc_scaling_ratio;
 EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
-static u64 __read_mostly kvm_default_tsc_scaling_ratio;
+u64 __read_mostly kvm_default_tsc_scaling_ratio;
+EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
 
 /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
 static u32 __read_mostly tsc_tolerance_ppm = 250;
@@ -538,7 +544,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
                goto out;
        }
        for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
-               if (is_present_gpte(pdpte[i]) &&
+               if ((pdpte[i] & PT_PRESENT_MASK) &&
                    (pdpte[i] &
                     vcpu->arch.mmu.guest_rsvd_check.rsvd_bits_mask[0][2])) {
                        ret = 0;
@@ -983,6 +989,7 @@ static u32 emulated_msrs[] = {
        MSR_IA32_MISC_ENABLE,
        MSR_IA32_MCG_STATUS,
        MSR_IA32_MCG_CTL,
+       MSR_IA32_MCG_EXT_CTL,
        MSR_IA32_SMBASE,
 };
 
@@ -1162,7 +1169,7 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
        int version;
        int r;
        struct pvclock_wall_clock wc;
-       struct timespec boot;
+       struct timespec64 boot;
 
        if (!wall_clock)
                return;
@@ -1185,13 +1192,13 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
         * wall clock specified here.  guest system time equals host
         * system time for us, thus we must fill in host boot time here.
         */
-       getboottime(&boot);
+       getboottime64(&boot);
 
        if (kvm->arch.kvmclock_offset) {
-               struct timespec ts = ns_to_timespec(kvm->arch.kvmclock_offset);
-               boot = timespec_sub(boot, ts);
+               struct timespec64 ts = ns_to_timespec64(kvm->arch.kvmclock_offset);
+               boot = timespec64_sub(boot, ts);
        }
-       wc.sec = boot.tv_sec;
+       wc.sec = (u32)boot.tv_sec; /* overflow in 2106 guest time */
        wc.nsec = boot.tv_nsec;
        wc.version = version;
 
@@ -2616,6 +2623,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_TSC_CONTROL:
                r = kvm_has_tsc_control;
                break;
+       case KVM_CAP_X2APIC_API:
+               r = KVM_X2APIC_API_VALID_FLAGS;
+               break;
        default:
                r = 0;
                break;
@@ -2678,11 +2688,9 @@ long kvm_arch_dev_ioctl(struct file *filp,
                break;
        }
        case KVM_X86_GET_MCE_CAP_SUPPORTED: {
-               u64 mce_cap;
-
-               mce_cap = KVM_MCE_CAP_SUPPORTED;
                r = -EFAULT;
-               if (copy_to_user(argp, &mce_cap, sizeof mce_cap))
+               if (copy_to_user(argp, &kvm_mce_cap_supported,
+                                sizeof(kvm_mce_cap_supported)))
                        goto out;
                r = 0;
                break;
@@ -2734,6 +2742,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                                rdtsc() - vcpu->arch.last_host_tsc;
                if (tsc_delta < 0)
                        mark_tsc_unstable("KVM discovered backwards TSC");
+
+               if (kvm_lapic_hv_timer_in_use(vcpu) &&
+                               kvm_x86_ops->set_hv_timer(vcpu,
+                                       kvm_get_lapic_tscdeadline_msr(vcpu)))
+                       kvm_lapic_switch_to_sw_timer(vcpu);
                if (check_tsc_unstable()) {
                        u64 offset = kvm_compute_tsc_offset(vcpu,
                                                vcpu->arch.last_guest_tsc);
@@ -2767,15 +2780,17 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
        if (vcpu->arch.apicv_active)
                kvm_x86_ops->sync_pir_to_irr(vcpu);
 
-       memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
-
-       return 0;
+       return kvm_apic_get_state(vcpu, s);
 }
 
 static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
                                    struct kvm_lapic_state *s)
 {
-       kvm_apic_post_state_restore(vcpu, s);
+       int r;
+
+       r = kvm_apic_set_state(vcpu, s);
+       if (r)
+               return r;
        update_cr8_intercept(vcpu);
 
        return 0;
@@ -2860,7 +2875,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
        r = -EINVAL;
        if (!bank_num || bank_num >= KVM_MAX_MCE_BANKS)
                goto out;
-       if (mcg_cap & ~(KVM_MCE_CAP_SUPPORTED | 0xff | 0xff0000))
+       if (mcg_cap & ~(kvm_mce_cap_supported | 0xff | 0xff0000))
                goto out;
        r = 0;
        vcpu->arch.mcg_cap = mcg_cap;
@@ -2870,6 +2885,9 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu,
        /* Init IA32_MCi_CTL to all 1s */
        for (bank = 0; bank < bank_num; bank++)
                vcpu->arch.mce_banks[bank*4] = ~(u64)0;
+
+       if (kvm_x86_ops->setup_mce)
+               kvm_x86_ops->setup_mce(vcpu);
 out:
        return r;
 }
@@ -3768,7 +3786,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
                r = -EEXIST;
                if (irqchip_in_kernel(kvm))
                        goto split_irqchip_unlock;
-               if (atomic_read(&kvm->online_vcpus))
+               if (kvm->created_vcpus)
                        goto split_irqchip_unlock;
                r = kvm_setup_empty_irq_routing(kvm);
                if (r)
@@ -3782,6 +3800,18 @@ split_irqchip_unlock:
                mutex_unlock(&kvm->lock);
                break;
        }
+       case KVM_CAP_X2APIC_API:
+               r = -EINVAL;
+               if (cap->args[0] & ~KVM_X2APIC_API_VALID_FLAGS)
+                       break;
+
+               if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)
+                       kvm->arch.x2apic_format = true;
+               if (cap->args[0] & KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
+                       kvm->arch.x2apic_broadcast_quirk_disabled = true;
+
+               r = 0;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -3833,7 +3863,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                if (kvm->arch.vpic)
                        goto create_irqchip_unlock;
                r = -EINVAL;
-               if (atomic_read(&kvm->online_vcpus))
+               if (kvm->created_vcpus)
                        goto create_irqchip_unlock;
                r = -ENOMEM;
                vpic = kvm_create_pic(kvm);
@@ -3873,7 +3903,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                                   sizeof(struct kvm_pit_config)))
                        goto out;
        create_pit:
-               mutex_lock(&kvm->slots_lock);
+               mutex_lock(&kvm->lock);
                r = -EEXIST;
                if (kvm->arch.vpit)
                        goto create_pit_unlock;
@@ -3882,7 +3912,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                if (kvm->arch.vpit)
                        r = 0;
        create_pit_unlock:
-               mutex_unlock(&kvm->slots_lock);
+               mutex_unlock(&kvm->lock);
                break;
        case KVM_GET_IRQCHIP: {
                /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
@@ -3989,7 +4019,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
        case KVM_SET_BOOT_CPU_ID:
                r = 0;
                mutex_lock(&kvm->lock);
-               if (atomic_read(&kvm->online_vcpus) != 0)
+               if (kvm->created_vcpus)
                        r = -EBUSY;
                else
                        kvm->arch.bsp_vcpu_id = arg;
@@ -5297,13 +5327,8 @@ static void kvm_smm_changed(struct kvm_vcpu *vcpu)
                /* This is a good place to trace that we are exiting SMM.  */
                trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, false);
 
-               if (unlikely(vcpu->arch.smi_pending)) {
-                       kvm_make_request(KVM_REQ_SMI, vcpu);
-                       vcpu->arch.smi_pending = 0;
-               } else {
-                       /* Process a latched INIT, if any.  */
-                       kvm_make_request(KVM_REQ_EVENT, vcpu);
-               }
+               /* Process a latched INIT or SMI, if any.  */
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
        }
 
        kvm_mmu_reset_context(vcpu);
@@ -5849,8 +5874,8 @@ int kvm_arch_init(void *opaque)
        kvm_x86_ops = ops;
 
        kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
-                       PT_DIRTY_MASK, PT64_NX_MASK, 0);
-
+                       PT_DIRTY_MASK, PT64_NX_MASK, 0,
+                       PT_PRESENT_MASK);
        kvm_timer_init();
 
        perf_register_guest_info_callbacks(&kvm_guest_cbs);
@@ -6084,7 +6109,10 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
        }
 
        /* try to inject new event if pending */
-       if (vcpu->arch.nmi_pending && kvm_x86_ops->nmi_allowed(vcpu)) {
+       if (vcpu->arch.smi_pending && !is_smm(vcpu)) {
+               vcpu->arch.smi_pending = false;
+               enter_smm(vcpu);
+       } else if (vcpu->arch.nmi_pending && kvm_x86_ops->nmi_allowed(vcpu)) {
                --vcpu->arch.nmi_pending;
                vcpu->arch.nmi_injected = true;
                kvm_x86_ops->set_nmi(vcpu);
@@ -6107,6 +6135,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
                        kvm_x86_ops->set_irq(vcpu);
                }
        }
+
        return 0;
 }
 
@@ -6130,7 +6159,7 @@ static void process_nmi(struct kvm_vcpu *vcpu)
 #define put_smstate(type, buf, offset, val)                      \
        *(type *)((buf) + (offset) - 0x7e00) = val
 
-static u32 process_smi_get_segment_flags(struct kvm_segment *seg)
+static u32 enter_smm_get_segment_flags(struct kvm_segment *seg)
 {
        u32 flags = 0;
        flags |= seg->g       << 23;
@@ -6144,7 +6173,7 @@ static u32 process_smi_get_segment_flags(struct kvm_segment *seg)
        return flags;
 }
 
-static void process_smi_save_seg_32(struct kvm_vcpu *vcpu, char *buf, int n)
+static void enter_smm_save_seg_32(struct kvm_vcpu *vcpu, char *buf, int n)
 {
        struct kvm_segment seg;
        int offset;
@@ -6159,11 +6188,11 @@ static void process_smi_save_seg_32(struct kvm_vcpu *vcpu, char *buf, int n)
 
        put_smstate(u32, buf, offset + 8, seg.base);
        put_smstate(u32, buf, offset + 4, seg.limit);
-       put_smstate(u32, buf, offset, process_smi_get_segment_flags(&seg));
+       put_smstate(u32, buf, offset, enter_smm_get_segment_flags(&seg));
 }
 
 #ifdef CONFIG_X86_64
-static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n)
+static void enter_smm_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n)
 {
        struct kvm_segment seg;
        int offset;
@@ -6172,7 +6201,7 @@ static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n)
        kvm_get_segment(vcpu, &seg, n);
        offset = 0x7e00 + n * 16;
 
-       flags = process_smi_get_segment_flags(&seg) >> 8;
+       flags = enter_smm_get_segment_flags(&seg) >> 8;
        put_smstate(u16, buf, offset, seg.selector);
        put_smstate(u16, buf, offset + 2, flags);
        put_smstate(u32, buf, offset + 4, seg.limit);
@@ -6180,7 +6209,7 @@ static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n)
 }
 #endif
 
-static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf)
+static void enter_smm_save_state_32(struct kvm_vcpu *vcpu, char *buf)
 {
        struct desc_ptr dt;
        struct kvm_segment seg;
@@ -6204,13 +6233,13 @@ static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf)
        put_smstate(u32, buf, 0x7fc4, seg.selector);
        put_smstate(u32, buf, 0x7f64, seg.base);
        put_smstate(u32, buf, 0x7f60, seg.limit);
-       put_smstate(u32, buf, 0x7f5c, process_smi_get_segment_flags(&seg));
+       put_smstate(u32, buf, 0x7f5c, enter_smm_get_segment_flags(&seg));
 
        kvm_get_segment(vcpu, &seg, VCPU_SREG_LDTR);
        put_smstate(u32, buf, 0x7fc0, seg.selector);
        put_smstate(u32, buf, 0x7f80, seg.base);
        put_smstate(u32, buf, 0x7f7c, seg.limit);
-       put_smstate(u32, buf, 0x7f78, process_smi_get_segment_flags(&seg));
+       put_smstate(u32, buf, 0x7f78, enter_smm_get_segment_flags(&seg));
 
        kvm_x86_ops->get_gdt(vcpu, &dt);
        put_smstate(u32, buf, 0x7f74, dt.address);
@@ -6221,7 +6250,7 @@ static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf)
        put_smstate(u32, buf, 0x7f54, dt.size);
 
        for (i = 0; i < 6; i++)
-               process_smi_save_seg_32(vcpu, buf, i);
+               enter_smm_save_seg_32(vcpu, buf, i);
 
        put_smstate(u32, buf, 0x7f14, kvm_read_cr4(vcpu));
 
@@ -6230,7 +6259,7 @@ static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf)
        put_smstate(u32, buf, 0x7ef8, vcpu->arch.smbase);
 }
 
-static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
+static void enter_smm_save_state_64(struct kvm_vcpu *vcpu, char *buf)
 {
 #ifdef CONFIG_X86_64
        struct desc_ptr dt;
@@ -6262,7 +6291,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
 
        kvm_get_segment(vcpu, &seg, VCPU_SREG_TR);
        put_smstate(u16, buf, 0x7e90, seg.selector);
-       put_smstate(u16, buf, 0x7e92, process_smi_get_segment_flags(&seg) >> 8);
+       put_smstate(u16, buf, 0x7e92, enter_smm_get_segment_flags(&seg) >> 8);
        put_smstate(u32, buf, 0x7e94, seg.limit);
        put_smstate(u64, buf, 0x7e98, seg.base);
 
@@ -6272,7 +6301,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
 
        kvm_get_segment(vcpu, &seg, VCPU_SREG_LDTR);
        put_smstate(u16, buf, 0x7e70, seg.selector);
-       put_smstate(u16, buf, 0x7e72, process_smi_get_segment_flags(&seg) >> 8);
+       put_smstate(u16, buf, 0x7e72, enter_smm_get_segment_flags(&seg) >> 8);
        put_smstate(u32, buf, 0x7e74, seg.limit);
        put_smstate(u64, buf, 0x7e78, seg.base);
 
@@ -6281,31 +6310,26 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
        put_smstate(u64, buf, 0x7e68, dt.address);
 
        for (i = 0; i < 6; i++)
-               process_smi_save_seg_64(vcpu, buf, i);
+               enter_smm_save_seg_64(vcpu, buf, i);
 #else
        WARN_ON_ONCE(1);
 #endif
 }
 
-static void process_smi(struct kvm_vcpu *vcpu)
+static void enter_smm(struct kvm_vcpu *vcpu)
 {
        struct kvm_segment cs, ds;
        struct desc_ptr dt;
        char buf[512];
        u32 cr0;
 
-       if (is_smm(vcpu)) {
-               vcpu->arch.smi_pending = true;
-               return;
-       }
-
        trace_kvm_enter_smm(vcpu->vcpu_id, vcpu->arch.smbase, true);
        vcpu->arch.hflags |= HF_SMM_MASK;
        memset(buf, 0, 512);
        if (guest_cpuid_has_longmode(vcpu))
-               process_smi_save_state_64(vcpu, buf);
+               enter_smm_save_state_64(vcpu, buf);
        else
-               process_smi_save_state_32(vcpu, buf);
+               enter_smm_save_state_32(vcpu, buf);
 
        kvm_vcpu_write_guest(vcpu, vcpu->arch.smbase + 0xfe00, buf, sizeof(buf));
 
@@ -6361,6 +6385,12 @@ static void process_smi(struct kvm_vcpu *vcpu)
        kvm_mmu_reset_context(vcpu);
 }
 
+static void process_smi(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.smi_pending = true;
+       kvm_make_request(KVM_REQ_EVENT, vcpu);
+}
+
 void kvm_make_scan_ioapic_request(struct kvm *kvm)
 {
        kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
@@ -6555,8 +6585,18 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
                if (inject_pending_event(vcpu, req_int_win) != 0)
                        req_immediate_exit = true;
-               /* enable NMI/IRQ window open exits if needed */
                else {
+                       /* Enable NMI/IRQ window open exits if needed.
+                        *
+                        * SMIs have two cases: 1) they can be nested, and
+                        * then there is nothing to do here because RSM will
+                        * cause a vmexit anyway; 2) or the SMI can be pending
+                        * because inject_pending_event has completed the
+                        * injection of an IRQ or NMI from the previous vmexit,
+                        * and then we request an immediate exit to inject the SMI.
+                        */
+                       if (vcpu->arch.smi_pending && !is_smm(vcpu))
+                               req_immediate_exit = true;
                        if (vcpu->arch.nmi_pending)
                                kvm_x86_ops->enable_nmi_window(vcpu);
                        if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
@@ -6607,12 +6647,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
        kvm_load_guest_xcr0(vcpu);
 
-       if (req_immediate_exit)
+       if (req_immediate_exit) {
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
                smp_send_reschedule(vcpu->cpu);
+       }
 
        trace_kvm_entry(vcpu->vcpu_id);
        wait_lapic_expire(vcpu);
-       __kvm_guest_enter();
+       guest_enter_irqoff();
 
        if (unlikely(vcpu->arch.switch_db_regs)) {
                set_debugreg(0, 7);
@@ -6663,16 +6705,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
        ++vcpu->stat.exits;
 
-       /*
-        * We must have an instruction between local_irq_enable() and
-        * kvm_guest_exit(), so the timer interrupt isn't delayed by
-        * the interrupt shadow.  The stat.exits increment will do nicely.
-        * But we need to prevent reordering, hence this barrier():
-        */
-       barrier();
-
-       kvm_guest_exit();
+       guest_exit_irqoff();
 
+       local_irq_enable();
        preempt_enable();
 
        vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
@@ -7409,6 +7444,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
        vcpu->arch.hflags = 0;
 
+       vcpu->arch.smi_pending = 0;
        atomic_set(&vcpu->arch.nmi_queued, 0);
        vcpu->arch.nmi_pending = 0;
        vcpu->arch.nmi_injected = false;
@@ -7601,11 +7637,6 @@ bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
        return (vcpu->arch.apic_base & MSR_IA32_APICBASE_BSP) != 0;
 }
 
-bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
-{
-       return irqchip_in_kernel(vcpu->kvm) == lapic_in_kernel(vcpu);
-}
-
 struct static_key kvm_no_apic_vcpu __read_mostly;
 EXPORT_SYMBOL_GPL(kvm_no_apic_vcpu);
 
@@ -7872,7 +7903,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        kfree(kvm->arch.vpic);
        kfree(kvm->arch.vioapic);
        kvm_free_vcpus(kvm);
-       kfree(rcu_dereference_check(kvm->arch.apic_map, 1));
+       kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
        kvm_mmu_uninit_vm(kvm);
 }
 
@@ -8380,7 +8411,7 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
        /*
         * When producer of consumer is unregistered, we change back to
         * remapped mode, so we can re-use the current implementation
-        * when the irq is masked/disabed or the consumer side (KVM
+        * when the irq is masked/disabled or the consumer side (KVM
         * int this case doesn't want to receive the interrupts.
        */
        ret = kvm_x86_ops->update_pi_irte(irqfd->kvm, prod->irq, irqfd->gsi, 0);
index 02de3d7..8a602a1 100644 (file)
@@ -35,6 +35,7 @@ ENDPROC(__sw_hweight32)
 
 ENTRY(__sw_hweight64)
 #ifdef CONFIG_X86_64
+       pushq   %rdi
        pushq   %rdx
 
        movq    %rdi, %rdx                      # w -> t
@@ -60,6 +61,7 @@ ENTRY(__sw_hweight64)
        shrq    $56, %rax                       # w = w_tmp >> 56
 
        popq    %rdx
+       popq    %rdi
        ret
 #else /* CONFIG_X86_32 */
        /* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */
index fb4c1b4..6209289 100644 (file)
@@ -208,7 +208,7 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,
  * adjust the page_size_mask for small range to go with
  *     big page size instead small one if nearby are ram too.
  */
-static void __init_refok adjust_range_page_size_mask(struct map_range *mr,
+static void __ref adjust_range_page_size_mask(struct map_range *mr,
                                                         int nr_range)
 {
        int i;
@@ -396,7 +396,7 @@ bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn)
  * This runs before bootmem is initialized and gets pages directly from
  * the physical memory. To access them they are temporarily mapped.
  */
-unsigned long __init_refok init_memory_mapping(unsigned long start,
+unsigned long __ref init_memory_mapping(unsigned long start,
                                               unsigned long end)
 {
        struct map_range mr[NR_RANGE_MR];
index 8196054..7b6a9d1 100644 (file)
@@ -133,7 +133,7 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev)
        if (pci_probe & PCI_NOASSIGN_BARS) {
                /*
                * If the BIOS did not assign the BAR, zero out the
-               * resource so the kernel doesn't attmept to assign
+               * resource so the kernel doesn't attempt to assign
                * it later on in pci_assign_unassigned_resources
                */
                for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
index 5ceda85..052c1cb 100644 (file)
@@ -169,7 +169,7 @@ static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
                                            size_t size,
                                            dma_addr_t *dma_handle,
                                            gfp_t flags,
-                                           struct dma_attrs *attrs)
+                                           unsigned long attrs)
 {
        void *vaddr;
 
index 613cac7..b814ca6 100644 (file)
@@ -119,10 +119,11 @@ static void vmd_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 static void vmd_irq_enable(struct irq_data *data)
 {
        struct vmd_irq *vmdirq = data->chip_data;
+       unsigned long flags;
 
-       raw_spin_lock(&list_lock);
+       raw_spin_lock_irqsave(&list_lock, flags);
        list_add_tail_rcu(&vmdirq->node, &vmdirq->irq->irq_list);
-       raw_spin_unlock(&list_lock);
+       raw_spin_unlock_irqrestore(&list_lock, flags);
 
        data->chip->irq_unmask(data);
 }
@@ -130,12 +131,14 @@ static void vmd_irq_enable(struct irq_data *data)
 static void vmd_irq_disable(struct irq_data *data)
 {
        struct vmd_irq *vmdirq = data->chip_data;
+       unsigned long flags;
 
        data->chip->irq_mask(data);
 
-       raw_spin_lock(&list_lock);
+       raw_spin_lock_irqsave(&list_lock, flags);
        list_del_rcu(&vmdirq->node);
-       raw_spin_unlock(&list_lock);
+       INIT_LIST_HEAD_RCU(&vmdirq->node);
+       raw_spin_unlock_irqrestore(&list_lock, flags);
 }
 
 /*
@@ -166,16 +169,20 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
  * XXX: We can be even smarter selecting the best IRQ once we solve the
  * affinity problem.
  */
-static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd)
+static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
 {
-       int i, best = 0;
+       int i, best = 1;
+       unsigned long flags;
 
-       raw_spin_lock(&list_lock);
+       if (!desc->msi_attrib.is_msix || vmd->msix_count == 1)
+               return &vmd->irqs[0];
+
+       raw_spin_lock_irqsave(&list_lock, flags);
        for (i = 1; i < vmd->msix_count; i++)
                if (vmd->irqs[i].count < vmd->irqs[best].count)
                        best = i;
        vmd->irqs[best].count++;
-       raw_spin_unlock(&list_lock);
+       raw_spin_unlock_irqrestore(&list_lock, flags);
 
        return &vmd->irqs[best];
 }
@@ -184,14 +191,15 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
                        unsigned int virq, irq_hw_number_t hwirq,
                        msi_alloc_info_t *arg)
 {
-       struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(arg->desc)->bus);
+       struct msi_desc *desc = arg->desc;
+       struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
        struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
 
        if (!vmdirq)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&vmdirq->node);
-       vmdirq->irq = vmd_next_irq(vmd);
+       vmdirq->irq = vmd_next_irq(vmd, desc);
        vmdirq->virq = virq;
 
        irq_domain_set_info(domain, virq, vmdirq->irq->vmd_vector, info->chip,
@@ -203,11 +211,12 @@ static void vmd_msi_free(struct irq_domain *domain,
                        struct msi_domain_info *info, unsigned int virq)
 {
        struct vmd_irq *vmdirq = irq_get_chip_data(virq);
+       unsigned long flags;
 
        /* XXX: Potential optimization to rebalance */
-       raw_spin_lock(&list_lock);
+       raw_spin_lock_irqsave(&list_lock, flags);
        vmdirq->irq->count--;
-       raw_spin_unlock(&list_lock);
+       raw_spin_unlock_irqrestore(&list_lock, flags);
 
        kfree_rcu(vmdirq, rcu);
 }
@@ -261,18 +270,18 @@ static struct device *to_vmd_dev(struct device *dev)
 
 static struct dma_map_ops *vmd_dma_ops(struct device *dev)
 {
-       return to_vmd_dev(dev)->archdata.dma_ops;
+       return get_dma_ops(to_vmd_dev(dev));
 }
 
 static void *vmd_alloc(struct device *dev, size_t size, dma_addr_t *addr,
-                      gfp_t flag, struct dma_attrs *attrs)
+                      gfp_t flag, unsigned long attrs)
 {
        return vmd_dma_ops(dev)->alloc(to_vmd_dev(dev), size, addr, flag,
                                       attrs);
 }
 
 static void vmd_free(struct device *dev, size_t size, void *vaddr,
-                    dma_addr_t addr, struct dma_attrs *attrs)
+                    dma_addr_t addr, unsigned long attrs)
 {
        return vmd_dma_ops(dev)->free(to_vmd_dev(dev), size, vaddr, addr,
                                      attrs);
@@ -280,7 +289,7 @@ static void vmd_free(struct device *dev, size_t size, void *vaddr,
 
 static int vmd_mmap(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t addr, size_t size,
-                   struct dma_attrs *attrs)
+                   unsigned long attrs)
 {
        return vmd_dma_ops(dev)->mmap(to_vmd_dev(dev), vma, cpu_addr, addr,
                                      size, attrs);
@@ -288,7 +297,7 @@ static int vmd_mmap(struct device *dev, struct vm_area_struct *vma,
 
 static int vmd_get_sgtable(struct device *dev, struct sg_table *sgt,
                           void *cpu_addr, dma_addr_t addr, size_t size,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        return vmd_dma_ops(dev)->get_sgtable(to_vmd_dev(dev), sgt, cpu_addr,
                                             addr, size, attrs);
@@ -297,26 +306,26 @@ static int vmd_get_sgtable(struct device *dev, struct sg_table *sgt,
 static dma_addr_t vmd_map_page(struct device *dev, struct page *page,
                               unsigned long offset, size_t size,
                               enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        return vmd_dma_ops(dev)->map_page(to_vmd_dev(dev), page, offset, size,
                                          dir, attrs);
 }
 
 static void vmd_unmap_page(struct device *dev, dma_addr_t addr, size_t size,
-                          enum dma_data_direction dir, struct dma_attrs *attrs)
+                          enum dma_data_direction dir, unsigned long attrs)
 {
        vmd_dma_ops(dev)->unmap_page(to_vmd_dev(dev), addr, size, dir, attrs);
 }
 
 static int vmd_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-                     enum dma_data_direction dir, struct dma_attrs *attrs)
+                     enum dma_data_direction dir, unsigned long attrs)
 {
        return vmd_dma_ops(dev)->map_sg(to_vmd_dev(dev), sg, nents, dir, attrs);
 }
 
 static void vmd_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-                        enum dma_data_direction dir, struct dma_attrs *attrs)
+                        enum dma_data_direction dir, unsigned long attrs)
 {
        vmd_dma_ops(dev)->unmap_sg(to_vmd_dev(dev), sg, nents, dir, attrs);
 }
@@ -367,7 +376,7 @@ static void vmd_teardown_dma_ops(struct vmd_dev *vmd)
 {
        struct dma_domain *domain = &vmd->dma_domain;
 
-       if (vmd->dev->dev.archdata.dma_ops)
+       if (get_dma_ops(&vmd->dev->dev))
                del_dma_domain(domain);
 }
 
@@ -379,7 +388,7 @@ static void vmd_teardown_dma_ops(struct vmd_dev *vmd)
 
 static void vmd_setup_dma_ops(struct vmd_dev *vmd)
 {
-       const struct dma_map_ops *source = vmd->dev->dev.archdata.dma_ops;
+       const struct dma_map_ops *source = get_dma_ops(&vmd->dev->dev);
        struct dma_map_ops *dest = &vmd->dma_ops;
        struct dma_domain *domain = &vmd->dma_domain;
 
@@ -594,7 +603,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
        sd->node = pcibus_to_node(vmd->dev->bus);
 
        vmd->irq_domain = pci_msi_create_irq_domain(NULL, &vmd_msi_domain_info,
-                                                   NULL);
+                                                   x86_vector_domain);
        if (!vmd->irq_domain)
                return -ENODEV;
 
index 5241421..5fdacb3 100644 (file)
@@ -44,7 +44,7 @@ early_initcall(early_efi_map_fb);
  * In case earlyprintk=efi,keep we have the whole framebuffer mapped already
  * so just return the offset efi_fb + start.
  */
-static __init_refok void *early_efi_map(unsigned long start, unsigned long len)
+static __ref void *early_efi_map(unsigned long start, unsigned long len)
 {
        unsigned long base;
 
@@ -56,7 +56,7 @@ static __init_refok void *early_efi_map(unsigned long start, unsigned long len)
                return early_ioremap(base + start, len);
 }
 
-static __init_refok void early_efi_unmap(void *addr, unsigned long len)
+static __ref void early_efi_unmap(void *addr, unsigned long len)
 {
        if (!efi_fb)
                early_iounmap(addr, len);
index 17c8bbd..1fbb408 100644 (file)
@@ -51,7 +51,6 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
-#include <asm/rtc.h>
 #include <asm/uv/uv.h>
 
 static struct efi efi_phys __initdata;
index 04db6fb..677e29e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/bootmem.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/mc146818rtc.h>
 #include <linux/efi.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
index ee40fcb..5802486 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/sfi.h>
 #include <linux/platform_device.h>
+#include <linux/mc146818rtc.h>
 
 #include <asm/intel-mid.h>
 #include <asm/intel_mid_vrtc.h>
index f2b5e6a..f0b5f2d 100644 (file)
@@ -37,11 +37,11 @@ unsigned long jump_address_phys;
  */
 unsigned long restore_cr3 __visible;
 
-pgd_t *temp_level4_pgt __visible;
+unsigned long temp_level4_pgt __visible;
 
 unsigned long relocated_restore_code __visible;
 
-static int set_up_temporary_text_mapping(void)
+static int set_up_temporary_text_mapping(pgd_t *pgd)
 {
        pmd_t *pmd;
        pud_t *pud;
@@ -71,7 +71,7 @@ static int set_up_temporary_text_mapping(void)
                __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC));
        set_pud(pud + pud_index(restore_jump_address),
                __pud(__pa(pmd) | _KERNPG_TABLE));
-       set_pgd(temp_level4_pgt + pgd_index(restore_jump_address),
+       set_pgd(pgd + pgd_index(restore_jump_address),
                __pgd(__pa(pud) | _KERNPG_TABLE));
 
        return 0;
@@ -90,15 +90,16 @@ static int set_up_temporary_mappings(void)
                .kernel_mapping = true,
        };
        unsigned long mstart, mend;
+       pgd_t *pgd;
        int result;
        int i;
 
-       temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC);
-       if (!temp_level4_pgt)
+       pgd = (pgd_t *)get_safe_page(GFP_ATOMIC);
+       if (!pgd)
                return -ENOMEM;
 
        /* Prepare a temporary mapping for the kernel text */
-       result = set_up_temporary_text_mapping();
+       result = set_up_temporary_text_mapping(pgd);
        if (result)
                return result;
 
@@ -107,13 +108,12 @@ static int set_up_temporary_mappings(void)
                mstart = pfn_mapped[i].start << PAGE_SHIFT;
                mend   = pfn_mapped[i].end << PAGE_SHIFT;
 
-               result = kernel_ident_mapping_init(&info, temp_level4_pgt,
-                                                  mstart, mend);
-
+               result = kernel_ident_mapping_init(&info, pgd, mstart, mend);
                if (result)
                        return result;
        }
 
+       temp_level4_pgt = (unsigned long)pgd - __PAGE_OFFSET;
        return 0;
 }
 
index 8eee0e9..ce8da3a 100644 (file)
@@ -72,8 +72,6 @@ ENTRY(restore_image)
        /* code below has been relocated to a safe page */
 ENTRY(core_restore_code)
        /* switch to temporary page tables */
-       movq    $__PAGE_OFFSET, %rcx
-       subq    %rcx, %rax
        movq    %rax, %cr3
        /* flush TLB */
        movq    %rbx, %rcx
index 12734a9..ac58c16 100644 (file)
@@ -8,6 +8,8 @@ PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y))
 LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib
 targets += purgatory.ro
 
+KCOV_INSTRUMENT := n
+
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
 # sure how to relocate those. Like kexec-tools, use custom flags.
index c556c5a..25012ab 100644 (file)
@@ -48,7 +48,7 @@ targets += realmode.lds
 $(obj)/realmode.lds: $(obj)/pasyms.h
 
 LDFLAGS_realmode.elf := --emit-relocs -T
-CPPFLAGS_realmode.lds += -P -C -I$(obj)
+CPPFLAGS_realmode.lds += -P -C -I$(objtree)/$(obj)
 
 targets += realmode.elf
 $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE
index 6c803ca..d72dec4 100644 (file)
@@ -2,6 +2,9 @@
 # Building vDSO images for x86.
 #
 
+# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
+KCOV_INSTRUMENT                := n
+
 VDSO64-y               := y
 
 vdso-install-$(VDSO64-y)       += vdso.so
index cd99305..8ffb089 100644 (file)
@@ -34,9 +34,7 @@
 #include <linux/edd.h>
 #include <linux/frame.h>
 
-#ifdef CONFIG_KEXEC_CORE
 #include <linux/kexec.h>
-#endif
 
 #include <xen/xen.h>
 #include <xen/events.h>
@@ -1334,7 +1332,8 @@ static void xen_crash_shutdown(struct pt_regs *regs)
 static int
 xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
-       xen_reboot(SHUTDOWN_crash);
+       if (!kexec_crash_loaded())
+               xen_reboot(SHUTDOWN_crash);
        return NOTIFY_DONE;
 }
 
index cd66698..1e68806 100644 (file)
@@ -142,7 +142,7 @@ static void xtensa_sync_sg_for_device(struct device *dev,
 
 static void *xtensa_dma_alloc(struct device *dev, size_t size,
                              dma_addr_t *handle, gfp_t flag,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        unsigned long ret;
        unsigned long uncached = 0;
@@ -171,7 +171,7 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 }
 
 static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
-                           dma_addr_t dma_handle, struct dma_attrs *attrs)
+                           dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long)vaddr +
                XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
@@ -185,7 +185,7 @@ static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
 static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
                                  unsigned long offset, size_t size,
                                  enum dma_data_direction dir,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        dma_addr_t dma_handle = page_to_phys(page) + offset;
 
@@ -195,14 +195,14 @@ static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
 
 static void xtensa_unmap_page(struct device *dev, dma_addr_t dma_handle,
                              size_t size, enum dma_data_direction dir,
-                             struct dma_attrs *attrs)
+                             unsigned long attrs)
 {
        xtensa_sync_single_for_cpu(dev, dma_handle, size, dir);
 }
 
 static int xtensa_map_sg(struct device *dev, struct scatterlist *sg,
                         int nents, enum dma_data_direction dir,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
@@ -217,7 +217,7 @@ static int xtensa_map_sg(struct device *dev, struct scatterlist *sg,
 static void xtensa_unmap_sg(struct device *dev,
                            struct scatterlist *sg, int nents,
                            enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct scatterlist *s;
        int i;
index 0363cd7..161491d 100644 (file)
@@ -88,19 +88,6 @@ config BLK_DEV_INTEGRITY
        T10/SCSI Data Integrity Field or the T13/ATA External Path
        Protection.  If in doubt, say N.
 
-config BLK_DEV_DAX
-       bool "Block device DAX support"
-       depends on FS_DAX
-       depends on BROKEN
-       help
-         When DAX support is available (CONFIG_FS_DAX) raw block
-         devices can also support direct userspace access to the
-         storage capacity via MMAP(2) similar to a file on a
-         DAX-enabled filesystem.  However, the DAX I/O-path disables
-         some standard I/O-statistics, and the MMAP(2) path has some
-         operational differences due to bypassing the page
-         cache.  If in doubt, say N.
-
 config BLK_DEV_THROTTLING
        bool "Block layer bio throttling support"
        depends on BLK_CGROUP=y
index f70cc3b..63f72f0 100644 (file)
@@ -86,7 +86,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
 
        bip->bip_bio = bio;
        bio->bi_integrity = bip;
-       bio->bi_rw |= REQ_INTEGRITY;
+       bio->bi_opf |= REQ_INTEGRITY;
 
        return bip;
 err:
index 54ee384..f394775 100644 (file)
@@ -580,9 +580,11 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
         */
        bio->bi_bdev = bio_src->bi_bdev;
        bio_set_flag(bio, BIO_CLONED);
-       bio->bi_rw = bio_src->bi_rw;
+       bio->bi_opf = bio_src->bi_opf;
        bio->bi_iter = bio_src->bi_iter;
        bio->bi_io_vec = bio_src->bi_io_vec;
+
+       bio_clone_blkcg_association(bio, bio_src);
 }
 EXPORT_SYMBOL(__bio_clone_fast);
 
@@ -661,7 +663,7 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
        if (!bio)
                return NULL;
        bio->bi_bdev            = bio_src->bi_bdev;
-       bio->bi_rw              = bio_src->bi_rw;
+       bio->bi_opf             = bio_src->bi_opf;
        bio->bi_iter.bi_sector  = bio_src->bi_iter.bi_sector;
        bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
 
@@ -687,6 +689,8 @@ integrity_clone:
                }
        }
 
+       bio_clone_blkcg_association(bio, bio_src);
+
        return bio;
 }
 EXPORT_SYMBOL(bio_clone_bioset);
@@ -869,7 +873,7 @@ int submit_bio_wait(struct bio *bio)
        init_completion(&ret.event);
        bio->bi_private = &ret;
        bio->bi_end_io = submit_bio_wait_endio;
-       bio->bi_rw |= REQ_SYNC;
+       bio->bi_opf |= REQ_SYNC;
        submit_bio(bio);
        wait_for_completion_io(&ret.event);
 
@@ -2004,6 +2008,17 @@ void bio_disassociate_task(struct bio *bio)
        }
 }
 
+/**
+ * bio_clone_blkcg_association - clone blkcg association from src to dst bio
+ * @dst: destination bio
+ * @src: source bio
+ */
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
+{
+       if (src->bi_css)
+               WARN_ON(bio_associate_blkcg(dst, src->bi_css));
+}
+
 #endif /* CONFIG_BLK_CGROUP */
 
 static void __init biovec_init_slabs(void)
index a687e9c..999442e 100644 (file)
@@ -1029,7 +1029,7 @@ static bool blk_rq_should_init_elevator(struct bio *bio)
         * Flush requests do not use the elevator so skip initialization.
         * This allows a request to share the flush and elevator data.
         */
-       if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA))
+       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA))
                return false;
 
        return true;
@@ -1504,7 +1504,7 @@ EXPORT_SYMBOL_GPL(blk_add_request_payload);
 bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
                            struct bio *bio)
 {
-       const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
+       const int ff = bio->bi_opf & REQ_FAILFAST_MASK;
 
        if (!ll_back_merge_fn(q, req, bio))
                return false;
@@ -1526,7 +1526,7 @@ bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
 bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
                             struct bio *bio)
 {
-       const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
+       const int ff = bio->bi_opf & REQ_FAILFAST_MASK;
 
        if (!ll_front_merge_fn(q, req, bio))
                return false;
@@ -1648,8 +1648,8 @@ void init_request_from_bio(struct request *req, struct bio *bio)
 {
        req->cmd_type = REQ_TYPE_FS;
 
-       req->cmd_flags |= bio->bi_rw & REQ_COMMON_MASK;
-       if (bio->bi_rw & REQ_RAHEAD)
+       req->cmd_flags |= bio->bi_opf & REQ_COMMON_MASK;
+       if (bio->bi_opf & REQ_RAHEAD)
                req->cmd_flags |= REQ_FAILFAST_MASK;
 
        req->errors = 0;
@@ -1660,7 +1660,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
 
 static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
 {
-       const bool sync = !!(bio->bi_rw & REQ_SYNC);
+       const bool sync = !!(bio->bi_opf & REQ_SYNC);
        struct blk_plug *plug;
        int el_ret, rw_flags = 0, where = ELEVATOR_INSERT_SORT;
        struct request *req;
@@ -1681,7 +1681,7 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
                return BLK_QC_T_NONE;
        }
 
-       if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) {
+       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) {
                spin_lock_irq(q->queue_lock);
                where = ELEVATOR_INSERT_FLUSH;
                goto get_rq;
@@ -1728,7 +1728,7 @@ get_rq:
        /*
         * Add in META/PRIO flags, if set, before we get to the IO scheduler
         */
-       rw_flags |= (bio->bi_rw & (REQ_META | REQ_PRIO));
+       rw_flags |= (bio->bi_opf & (REQ_META | REQ_PRIO));
 
        /*
         * Grab a free request. This is might sleep but can not fail.
@@ -1805,7 +1805,7 @@ static void handle_bad_sector(struct bio *bio)
        printk(KERN_INFO "attempt to access beyond end of device\n");
        printk(KERN_INFO "%s: rw=%d, want=%Lu, limit=%Lu\n",
                        bdevname(bio->bi_bdev, b),
-                       bio->bi_rw,
+                       bio->bi_opf,
                        (unsigned long long)bio_end_sector(bio),
                        (long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
 }
@@ -1918,9 +1918,9 @@ generic_make_request_checks(struct bio *bio)
         * drivers without flush support don't have to worry
         * about them.
         */
-       if ((bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) &&
+       if ((bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) &&
            !test_bit(QUEUE_FLAG_WC, &q->queue_flags)) {
-               bio->bi_rw &= ~(REQ_PREFLUSH | REQ_FUA);
+               bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA);
                if (!nr_sectors) {
                        err = 0;
                        goto end_io;
@@ -2219,7 +2219,7 @@ unsigned int blk_rq_err_bytes(const struct request *rq)
         * one.
         */
        for (bio = rq->bio; bio; bio = bio->bi_next) {
-               if ((bio->bi_rw & ff) != ff)
+               if ((bio->bi_opf & ff) != ff)
                        break;
                bytes += bio->bi_iter.bi_size;
        }
@@ -2630,7 +2630,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
        /* mixed attributes always follow the first bio */
        if (req->cmd_flags & REQ_MIXED_MERGE) {
                req->cmd_flags &= ~REQ_FAILFAST_MASK;
-               req->cmd_flags |= req->bio->bi_rw & REQ_FAILFAST_MASK;
+               req->cmd_flags |= req->bio->bi_opf & REQ_FAILFAST_MASK;
        }
 
        /*
index 41cbd48..3eec75a 100644 (file)
@@ -186,7 +186,7 @@ void blk_queue_split(struct request_queue *q, struct bio **bio,
 
        if (split) {
                /* there isn't chance to merge the splitted bio */
-               split->bi_rw |= REQ_NOMERGE;
+               split->bi_opf |= REQ_NOMERGE;
 
                bio_chain(split, *bio);
                trace_block_split(q, split, (*bio)->bi_iter.bi_sector);
@@ -616,9 +616,9 @@ void blk_rq_set_mixed_merge(struct request *rq)
         * Distributes the attributs to each bio.
         */
        for (bio = rq->bio; bio; bio = bio->bi_next) {
-               WARN_ON_ONCE((bio->bi_rw & REQ_FAILFAST_MASK) &&
-                            (bio->bi_rw & REQ_FAILFAST_MASK) != ff);
-               bio->bi_rw |= ff;
+               WARN_ON_ONCE((bio->bi_opf & REQ_FAILFAST_MASK) &&
+                            (bio->bi_opf & REQ_FAILFAST_MASK) != ff);
+               bio->bi_opf |= ff;
        }
        rq->cmd_flags |= REQ_MIXED_MERGE;
 }
index 4ea4dd8..fe822aa 100644 (file)
@@ -380,15 +380,13 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
        return ret;
 }
 
-void blk_mq_unregister_disk(struct gendisk *disk)
+static void __blk_mq_unregister_disk(struct gendisk *disk)
 {
        struct request_queue *q = disk->queue;
        struct blk_mq_hw_ctx *hctx;
        struct blk_mq_ctx *ctx;
        int i, j;
 
-       blk_mq_disable_hotplug();
-
        queue_for_each_hw_ctx(q, hctx, i) {
                blk_mq_unregister_hctx(hctx);
 
@@ -405,6 +403,12 @@ void blk_mq_unregister_disk(struct gendisk *disk)
        kobject_put(&disk_to_dev(disk)->kobj);
 
        q->mq_sysfs_init_done = false;
+}
+
+void blk_mq_unregister_disk(struct gendisk *disk)
+{
+       blk_mq_disable_hotplug();
+       __blk_mq_unregister_disk(disk);
        blk_mq_enable_hotplug();
 }
 
@@ -450,7 +454,7 @@ int blk_mq_register_disk(struct gendisk *disk)
        }
 
        if (ret)
-               blk_mq_unregister_disk(disk);
+               __blk_mq_unregister_disk(disk);
        else
                q->mq_sysfs_init_done = true;
 out:
index 576e711..e931a0e 100644 (file)
@@ -672,7 +672,20 @@ static void blk_mq_timeout_work(struct work_struct *work)
        };
        int i;
 
-       if (blk_queue_enter(q, true))
+       /* A deadlock might occur if a request is stuck requiring a
+        * timeout at the same time a queue freeze is waiting
+        * completion, since the timeout code would not be able to
+        * acquire the queue reference here.
+        *
+        * That's why we don't use blk_queue_enter here; instead, we use
+        * percpu_ref_tryget directly, because we need to be able to
+        * obtain a reference even in the short window between the queue
+        * starting to freeze, by dropping the first reference in
+        * blk_mq_freeze_queue_start, and the moment the last request is
+        * consumed, marked by the instant q_usage_counter reaches
+        * zero.
+        */
+       if (!percpu_ref_tryget(&q->q_usage_counter))
                return;
 
        blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data);
@@ -1221,7 +1234,7 @@ static struct request *blk_mq_map_request(struct request_queue *q,
        ctx = blk_mq_get_ctx(q);
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
-       if (rw_is_sync(bio_op(bio), bio->bi_rw))
+       if (rw_is_sync(bio_op(bio), bio->bi_opf))
                op_flags |= REQ_SYNC;
 
        trace_block_getrq(q, bio, op);
@@ -1289,8 +1302,8 @@ static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie)
  */
 static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
 {
-       const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw);
-       const int is_flush_fua = bio->bi_rw & (REQ_PREFLUSH | REQ_FUA);
+       const int is_sync = rw_is_sync(bio_op(bio), bio->bi_opf);
+       const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
        struct blk_map_ctx data;
        struct request *rq;
        unsigned int request_count = 0;
@@ -1383,8 +1396,8 @@ done:
  */
 static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
 {
-       const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw);
-       const int is_flush_fua = bio->bi_rw & (REQ_PREFLUSH | REQ_FUA);
+       const int is_sync = rw_is_sync(bio_op(bio), bio->bi_opf);
+       const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
        struct blk_plug *plug;
        unsigned int request_count = 0;
        struct blk_map_ctx data;
index 47a3e54..f1aba26 100644 (file)
@@ -145,11 +145,6 @@ struct throtl_data
        /* Total Number of queued bios on READ and WRITE lists */
        unsigned int nr_queued[2];
 
-       /*
-        * number of total undestroyed groups
-        */
-       unsigned int nr_undestroyed_grps;
-
        /* Work for dispatching throttled bios */
        struct work_struct dispatch_work;
 };
@@ -826,8 +821,8 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
         * second time when it eventually gets issued.  Set it when a bio
         * is being charged to a tg.
         */
-       if (!(bio->bi_rw & REQ_THROTTLED))
-               bio->bi_rw |= REQ_THROTTLED;
+       if (!(bio->bi_opf & REQ_THROTTLED))
+               bio->bi_opf |= REQ_THROTTLED;
 }
 
 /**
@@ -1404,7 +1399,7 @@ bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg,
        WARN_ON_ONCE(!rcu_read_lock_held());
 
        /* see throtl_charge_bio() */
-       if ((bio->bi_rw & REQ_THROTTLED) || !tg->has_rules[rw])
+       if ((bio->bi_opf & REQ_THROTTLED) || !tg->has_rules[rw])
                goto out;
 
        spin_lock_irq(q->queue_lock);
@@ -1483,7 +1478,7 @@ out:
         * being issued.
         */
        if (!throttled)
-               bio->bi_rw &= ~REQ_THROTTLED;
+               bio->bi_opf &= ~REQ_THROTTLED;
        return throttled;
 }
 
index acabba1..cc2f6db 100644 (file)
@@ -918,7 +918,7 @@ static inline struct cfq_data *cic_to_cfqd(struct cfq_io_cq *cic)
  */
 static inline bool cfq_bio_sync(struct bio *bio)
 {
-       return bio_data_dir(bio) == READ || (bio->bi_rw & REQ_SYNC);
+       return bio_data_dir(bio) == READ || (bio->bi_opf & REQ_SYNC);
 }
 
 /*
@@ -2565,7 +2565,7 @@ static void cfq_merged_request(struct request_queue *q, struct request *req,
 static void cfq_bio_merged(struct request_queue *q, struct request *req,
                                struct bio *bio)
 {
-       cfqg_stats_update_io_merged(RQ_CFQG(req), bio_op(bio), bio->bi_rw);
+       cfqg_stats_update_io_merged(RQ_CFQG(req), bio_op(bio), bio->bi_opf);
 }
 
 static void
index 3c9dede..fcd6d4f 100644 (file)
@@ -614,7 +614,7 @@ void device_add_disk(struct device *parent, struct gendisk *disk)
 
        /* Register BDI before referencing it from bdev */
        bdi = &disk->queue->backing_dev_info;
-       bdi_register_dev(bdi, disk_devt(disk));
+       bdi_register_owner(bdi, disk_to_dev(disk));
 
        blk_register_region(disk_devt(disk), disk->minors, NULL,
                            exact_match, exact_lock, disk);
@@ -856,6 +856,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
        if (iter) {
                class_dev_iter_exit(iter);
                kfree(iter);
+               seqf->private = NULL;
        }
 }
 
index 9548244..53abb4a 100644 (file)
@@ -138,6 +138,7 @@ obj-$(CONFIG_OF)            += of/
 obj-$(CONFIG_SSB)              += ssb/
 obj-$(CONFIG_BCMA)             += bcma/
 obj-$(CONFIG_VHOST_RING)       += vhost/
+obj-$(CONFIG_VHOST)            += vhost/
 obj-$(CONFIG_VLYNQ)            += vlynq/
 obj-$(CONFIG_STAGING)          += staging/
 obj-y                          += platform/
index aebd944..445ce28 100644 (file)
@@ -221,6 +221,9 @@ config ACPI_PROCESSOR_IDLE
        bool
        select CPU_IDLE
 
+config ACPI_MCFG
+       bool
+
 config ACPI_CPPC_LIB
        bool
        depends on ACPI_PROCESSOR
index 35a6ccb..5ae9d85 100644 (file)
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y                         += ec.o
 acpi-$(CONFIG_ACPI_DOCK)       += dock.o
 acpi-y                         += pci_root.o pci_link.o pci_irq.o
+obj-$(CONFIG_ACPI_MCFG)                += pci_mcfg.o
 acpi-y                         += acpi_lpss.o acpi_apd.o
 acpi-y                         += acpi_platform.o
 acpi-y                         += acpi_pnp.o
index 81dc750..0980a13 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <asm-generic/rtc.h>
+#include <linux/mc146818rtc.h>
 
 #include "internal.h"
 
index 148f4e5..31abb0b 100644 (file)
@@ -232,8 +232,10 @@ remove_dev_dir:
        acpi_device_dir(device) = NULL;
 remove_lid_dir:
        remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+       acpi_lid_dir = NULL;
 remove_button_dir:
        remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+       acpi_button_dir = NULL;
        goto done;
 }
 
@@ -250,7 +252,9 @@ static int acpi_button_remove_fs(struct acpi_device *device)
                          acpi_lid_dir);
        acpi_device_dir(device) = NULL;
        remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+       acpi_lid_dir = NULL;
        remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+       acpi_button_dir = NULL;
 
        return 0;
 }
index 999a109..e7bd57c 100644 (file)
@@ -101,6 +101,7 @@ enum ec_command {
 #define ACPI_EC_UDELAY_POLL    550     /* Wait 1ms for EC transaction polling */
 #define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
                                         * when trying to clear the EC */
+#define ACPI_EC_MAX_QUERIES    16      /* Maximum number of parallel queries */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
@@ -121,6 +122,10 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
 module_param(ec_delay, uint, 0644);
 MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
 
+static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
+module_param(ec_max_queries, uint, 0644);
+MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
+
 static bool ec_busy_polling __read_mostly;
 module_param(ec_busy_polling, bool, 0644);
 MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
@@ -174,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work);
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
+static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
@@ -1098,7 +1104,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
         * work queue execution.
         */
        ec_dbg_evt("Query(0x%02x) scheduled", value);
-       if (!schedule_work(&q->work)) {
+       if (!queue_work(ec_query_wq, &q->work)) {
                ec_dbg_evt("Query(0x%02x) overlapped", value);
                result = -EBUSY;
        }
@@ -1660,15 +1666,41 @@ static struct acpi_driver acpi_ec_driver = {
                },
 };
 
+static inline int acpi_ec_query_init(void)
+{
+       if (!ec_query_wq) {
+               ec_query_wq = alloc_workqueue("kec_query", 0,
+                                             ec_max_queries);
+               if (!ec_query_wq)
+                       return -ENODEV;
+       }
+       return 0;
+}
+
+static inline void acpi_ec_query_exit(void)
+{
+       if (ec_query_wq) {
+               destroy_workqueue(ec_query_wq);
+               ec_query_wq = NULL;
+       }
+}
+
 int __init acpi_ec_init(void)
 {
-       int result = 0;
+       int result;
 
+       /* register workqueue for _Qxx evaluations */
+       result = acpi_ec_query_init();
+       if (result)
+               goto err_exit;
        /* Now register the driver for the EC */
        result = acpi_bus_register_driver(&acpi_ec_driver);
-       if (result < 0)
-               return -ENODEV;
+       if (result)
+               goto err_exit;
 
+err_exit:
+       if (result)
+               acpi_ec_query_exit();
        return result;
 }
 
@@ -1678,5 +1710,6 @@ static void __exit acpi_ec_exit(void)
 {
 
        acpi_bus_unregister_driver(&acpi_ec_driver);
+       acpi_ec_query_exit();
 }
 #endif /* 0 */
index b108f13..4305ee9 100644 (file)
@@ -309,7 +309,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
  * During early init (when acpi_gbl_permanent_mmap has not been set yet) this
  * routine simply calls __acpi_map_table() to get the job done.
  */
-void __iomem *__init_refok
+void __iomem *__ref
 acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
 {
        struct acpi_ioremap *map;
@@ -362,8 +362,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_iomem);
 
-void *__init_refok
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+void *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        return (void *)acpi_os_map_iomem(phys, size);
 }
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644 (file)
index 0000000..b5b376e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *     Author: Jayachandran C <jchandra@broadcom.com>
+ * Copyright (C) 2016 Semihalf
+ *     Author: Tomasz Nowicki <tn@semihalf.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 (the "GPL").
+ *
+ * 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 version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#define pr_fmt(fmt) "ACPI: " fmt
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci-acpi.h>
+
+/* Structure to hold entries from the MCFG table */
+struct mcfg_entry {
+       struct list_head        list;
+       phys_addr_t             addr;
+       u16                     segment;
+       u8                      bus_start;
+       u8                      bus_end;
+};
+
+/* List to save MCFG entries */
+static LIST_HEAD(pci_mcfg_list);
+
+phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
+{
+       struct mcfg_entry *e;
+
+       /*
+        * We expect exact match, unless MCFG entry end bus covers more than
+        * specified by caller.
+        */
+       list_for_each_entry(e, &pci_mcfg_list, list) {
+               if (e->segment == seg && e->bus_start == bus_res->start &&
+                   e->bus_end >= bus_res->end)
+                       return e->addr;
+       }
+
+       return 0;
+}
+
+static __init int pci_mcfg_parse(struct acpi_table_header *header)
+{
+       struct acpi_table_mcfg *mcfg;
+       struct acpi_mcfg_allocation *mptr;
+       struct mcfg_entry *e, *arr;
+       int i, n;
+
+       if (header->length < sizeof(struct acpi_table_mcfg))
+               return -EINVAL;
+
+       n = (header->length - sizeof(struct acpi_table_mcfg)) /
+                                       sizeof(struct acpi_mcfg_allocation);
+       mcfg = (struct acpi_table_mcfg *)header;
+       mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
+
+       arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
+       if (!arr)
+               return -ENOMEM;
+
+       for (i = 0, e = arr; i < n; i++, mptr++, e++) {
+               e->segment = mptr->pci_segment;
+               e->addr =  mptr->address;
+               e->bus_start = mptr->start_bus_number;
+               e->bus_end = mptr->end_bus_number;
+               list_add(&e->list, &pci_mcfg_list);
+       }
+
+       pr_info("MCFG table detected, %d entries\n", n);
+       return 0;
+}
+
+/* Interface called by ACPI - parse and save MCFG table */
+void __init pci_mmcfg_late_init(void)
+{
+       int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
+       if (err)
+               pr_err("Failed to parse MCFG (%d)\n", err);
+}
index ae3fe4e..d144168 100644 (file)
@@ -720,6 +720,36 @@ next:
        }
 }
 
+static void acpi_pci_root_remap_iospace(struct resource_entry *entry)
+{
+#ifdef PCI_IOBASE
+       struct resource *res = entry->res;
+       resource_size_t cpu_addr = res->start;
+       resource_size_t pci_addr = cpu_addr - entry->offset;
+       resource_size_t length = resource_size(res);
+       unsigned long port;
+
+       if (pci_register_io_range(cpu_addr, length))
+               goto err;
+
+       port = pci_address_to_pio(cpu_addr);
+       if (port == (unsigned long)-1)
+               goto err;
+
+       res->start = port;
+       res->end = port + length - 1;
+       entry->offset = port - pci_addr;
+
+       if (pci_remap_iospace(res, cpu_addr) < 0)
+               goto err;
+
+       pr_info("Remapped I/O %pa to %pR\n", &cpu_addr, res);
+       return;
+err:
+       res->flags |= IORESOURCE_DISABLED;
+#endif
+}
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
        int ret;
@@ -740,6 +770,9 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
                        "no IO and memory resources present in _CRS\n");
        else {
                resource_list_for_each_entry_safe(entry, tmp, list) {
+                       if (entry->res->flags & IORESOURCE_IO)
+                               acpi_pci_root_remap_iospace(entry);
+
                        if (entry->res->flags & IORESOURCE_DISABLED)
                                resource_list_destroy_entry(entry);
                        else
@@ -811,6 +844,8 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
 
        resource_list_for_each_entry(entry, &bridge->windows) {
                res = entry->res;
+               if (res->flags & IORESOURCE_IO)
+                       pci_unmap_iospace(res);
                if (res->parent &&
                    (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
                        release_resource(res);
index 773fc30..22d1760 100644 (file)
@@ -46,7 +46,8 @@ MODULE_LICENSE("GPL");
 extern struct builtin_fw __start_builtin_fw[];
 extern struct builtin_fw __end_builtin_fw[];
 
-static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
+                                   void *buf, size_t size)
 {
        struct builtin_fw *b_fw;
 
@@ -54,6 +55,9 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
                if (strcmp(name, b_fw->name) == 0) {
                        fw->size = b_fw->size;
                        fw->data = b_fw->data;
+
+                       if (buf && fw->size <= size)
+                               memcpy(buf, fw->data, fw->size);
                        return true;
                }
        }
@@ -74,7 +78,9 @@ static bool fw_is_builtin_firmware(const struct firmware *fw)
 
 #else /* Module case - no builtin firmware support */
 
-static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static inline bool fw_get_builtin_firmware(struct firmware *fw,
+                                          const char *name, void *buf,
+                                          size_t size)
 {
        return false;
 }
@@ -112,6 +118,7 @@ static inline long firmware_loading_timeout(void)
 #define FW_OPT_FALLBACK                0
 #endif
 #define FW_OPT_NO_WARN (1U << 3)
+#define FW_OPT_NOCACHE (1U << 4)
 
 struct firmware_cache {
        /* firmware_buf instance will be added into the below list */
@@ -143,6 +150,7 @@ struct firmware_buf {
        unsigned long status;
        void *data;
        size_t size;
+       size_t allocated_size;
 #ifdef CONFIG_FW_LOADER_USER_HELPER
        bool is_paged_buf;
        bool need_uevent;
@@ -178,7 +186,8 @@ static DEFINE_MUTEX(fw_lock);
 static struct firmware_cache fw_cache;
 
 static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
-                                             struct firmware_cache *fwc)
+                                             struct firmware_cache *fwc,
+                                             void *dbuf, size_t size)
 {
        struct firmware_buf *buf;
 
@@ -194,6 +203,8 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
 
        kref_init(&buf->ref);
        buf->fwc = fwc;
+       buf->data = dbuf;
+       buf->allocated_size = size;
        init_completion(&buf->completion);
 #ifdef CONFIG_FW_LOADER_USER_HELPER
        INIT_LIST_HEAD(&buf->pending_list);
@@ -217,7 +228,8 @@ static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
 
 static int fw_lookup_and_allocate_buf(const char *fw_name,
                                      struct firmware_cache *fwc,
-                                     struct firmware_buf **buf)
+                                     struct firmware_buf **buf, void *dbuf,
+                                     size_t size)
 {
        struct firmware_buf *tmp;
 
@@ -229,7 +241,7 @@ static int fw_lookup_and_allocate_buf(const char *fw_name,
                *buf = tmp;
                return 1;
        }
-       tmp = __allocate_fw_buf(fw_name, fwc);
+       tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
        if (tmp)
                list_add(&tmp->list, &fwc->head);
        spin_unlock(&fwc->lock);
@@ -261,6 +273,7 @@ static void __fw_free_buf(struct kref *ref)
                vfree(buf->pages);
        } else
 #endif
+       if (!buf->allocated_size)
                vfree(buf->data);
        kfree_const(buf->fw_id);
        kfree(buf);
@@ -301,13 +314,21 @@ static void fw_finish_direct_load(struct device *device,
        mutex_unlock(&fw_lock);
 }
 
-static int fw_get_filesystem_firmware(struct device *device,
-                                      struct firmware_buf *buf)
+static int
+fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 {
        loff_t size;
        int i, len;
        int rc = -ENOENT;
        char *path;
+       enum kernel_read_file_id id = READING_FIRMWARE;
+       size_t msize = INT_MAX;
+
+       /* Already populated data member means we're loading into a buffer */
+       if (buf->data) {
+               id = READING_FIRMWARE_PREALLOC_BUFFER;
+               msize = buf->allocated_size;
+       }
 
        path = __getname();
        if (!path)
@@ -326,8 +347,8 @@ static int fw_get_filesystem_firmware(struct device *device,
                }
 
                buf->size = 0;
-               rc = kernel_read_file_from_path(path, &buf->data, &size,
-                                               INT_MAX, READING_FIRMWARE);
+               rc = kernel_read_file_from_path(path, &buf->data, &size, msize,
+                                               id);
                if (rc) {
                        if (rc == -ENOENT)
                                dev_dbg(device, "loading %s failed with error %d\n",
@@ -691,6 +712,38 @@ out:
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 
+static void firmware_rw_buf(struct firmware_buf *buf, char *buffer,
+                          loff_t offset, size_t count, bool read)
+{
+       if (read)
+               memcpy(buffer, buf->data + offset, count);
+       else
+               memcpy(buf->data + offset, buffer, count);
+}
+
+static void firmware_rw(struct firmware_buf *buf, char *buffer,
+                       loff_t offset, size_t count, bool read)
+{
+       while (count) {
+               void *page_data;
+               int page_nr = offset >> PAGE_SHIFT;
+               int page_ofs = offset & (PAGE_SIZE-1);
+               int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+               page_data = kmap(buf->pages[page_nr]);
+
+               if (read)
+                       memcpy(buffer, page_data + page_ofs, page_cnt);
+               else
+                       memcpy(page_data + page_ofs, buffer, page_cnt);
+
+               kunmap(buf->pages[page_nr]);
+               buffer += page_cnt;
+               offset += page_cnt;
+               count -= page_cnt;
+       }
+}
+
 static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
                                  struct bin_attribute *bin_attr,
                                  char *buffer, loff_t offset, size_t count)
@@ -715,21 +768,11 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 
        ret_count = count;
 
-       while (count) {
-               void *page_data;
-               int page_nr = offset >> PAGE_SHIFT;
-               int page_ofs = offset & (PAGE_SIZE-1);
-               int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
-
-               page_data = kmap(buf->pages[page_nr]);
-
-               memcpy(buffer, page_data + page_ofs, page_cnt);
+       if (buf->data)
+               firmware_rw_buf(buf, buffer, offset, count, true);
+       else
+               firmware_rw(buf, buffer, offset, count, true);
 
-               kunmap(buf->pages[page_nr]);
-               buffer += page_cnt;
-               offset += page_cnt;
-               count -= page_cnt;
-       }
 out:
        mutex_unlock(&fw_lock);
        return ret_count;
@@ -804,29 +847,23 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
                goto out;
        }
 
-       retval = fw_realloc_buffer(fw_priv, offset + count);
-       if (retval)
-               goto out;
-
-       retval = count;
-
-       while (count) {
-               void *page_data;
-               int page_nr = offset >> PAGE_SHIFT;
-               int page_ofs = offset & (PAGE_SIZE - 1);
-               int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
-
-               page_data = kmap(buf->pages[page_nr]);
-
-               memcpy(page_data + page_ofs, buffer, page_cnt);
+       if (buf->data) {
+               if (offset + count > buf->allocated_size) {
+                       retval = -ENOMEM;
+                       goto out;
+               }
+               firmware_rw_buf(buf, buffer, offset, count, false);
+               retval = count;
+       } else {
+               retval = fw_realloc_buffer(fw_priv, offset + count);
+               if (retval)
+                       goto out;
 
-               kunmap(buf->pages[page_nr]);
-               buffer += page_cnt;
-               offset += page_cnt;
-               count -= page_cnt;
+               retval = count;
+               firmware_rw(buf, buffer, offset, count, false);
        }
 
-       buf->size = max_t(size_t, offset, buf->size);
+       buf->size = max_t(size_t, offset + count, buf->size);
 out:
        mutex_unlock(&fw_lock);
        return retval;
@@ -894,7 +931,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
        struct firmware_buf *buf = fw_priv->buf;
 
        /* fall back on userspace loading */
-       buf->is_paged_buf = true;
+       if (!buf->data)
+               buf->is_paged_buf = true;
 
        dev_set_uevent_suppress(f_dev, true);
 
@@ -929,7 +967,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
 
        if (is_fw_load_aborted(buf))
                retval = -EAGAIN;
-       else if (!buf->data)
+       else if (buf->is_paged_buf && !buf->data)
                retval = -ENOMEM;
 
        device_del(f_dev);
@@ -1012,7 +1050,7 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf)
  */
 static int
 _request_firmware_prepare(struct firmware **firmware_p, const char *name,
-                         struct device *device)
+                         struct device *device, void *dbuf, size_t size)
 {
        struct firmware *firmware;
        struct firmware_buf *buf;
@@ -1025,12 +1063,12 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
                return -ENOMEM;
        }
 
-       if (fw_get_builtin_firmware(firmware, name)) {
+       if (fw_get_builtin_firmware(firmware, name, dbuf, size)) {
                dev_dbg(device, "using built-in %s\n", name);
                return 0; /* assigned */
        }
 
-       ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+       ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
 
        /*
         * bind with 'buf' now to avoid warning in failure path
@@ -1070,14 +1108,16 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
         * should be fixed in devres or driver core.
         */
        /* don't cache firmware handled without uevent */
-       if (device && (opt_flags & FW_OPT_UEVENT))
+       if (device && (opt_flags & FW_OPT_UEVENT) &&
+           !(opt_flags & FW_OPT_NOCACHE))
                fw_add_devm_name(device, buf->fw_id);
 
        /*
         * After caching firmware image is started, let it piggyback
         * on request firmware.
         */
-       if (buf->fwc->state == FW_LOADER_START_CACHE) {
+       if (!(opt_flags & FW_OPT_NOCACHE) &&
+           buf->fwc->state == FW_LOADER_START_CACHE) {
                if (fw_cache_piggyback_on_request(buf->fw_id))
                        kref_get(&buf->ref);
        }
@@ -1091,7 +1131,8 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
-                 struct device *device, unsigned int opt_flags)
+                 struct device *device, void *buf, size_t size,
+                 unsigned int opt_flags)
 {
        struct firmware *fw = NULL;
        long timeout;
@@ -1105,7 +1146,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
                goto out;
        }
 
-       ret = _request_firmware_prepare(&fw, name, device);
+       ret = _request_firmware_prepare(&fw, name, device, buf, size);
        if (ret <= 0) /* error or already assigned */
                goto out;
 
@@ -1184,7 +1225,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
 
        /* Need to pin this module until return */
        __module_get(THIS_MODULE);
-       ret = _request_firmware(firmware_p, name, device,
+       ret = _request_firmware(firmware_p, name, device, NULL, 0,
                                FW_OPT_UEVENT | FW_OPT_FALLBACK);
        module_put(THIS_MODULE);
        return ret;
@@ -1208,13 +1249,43 @@ int request_firmware_direct(const struct firmware **firmware_p,
        int ret;
 
        __module_get(THIS_MODULE);
-       ret = _request_firmware(firmware_p, name, device,
+       ret = _request_firmware(firmware_p, name, device, NULL, 0,
                                FW_OPT_UEVENT | FW_OPT_NO_WARN);
        module_put(THIS_MODULE);
        return ret;
 }
 EXPORT_SYMBOL_GPL(request_firmware_direct);
 
+/**
+ * request_firmware_into_buf - load firmware into a previously allocated buffer
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded and DMA region allocated
+ * @buf: address of buffer to load firmware into
+ * @size: size of buffer
+ *
+ * This function works pretty much like request_firmware(), but it doesn't
+ * allocate a buffer to hold the firmware data. Instead, the firmware
+ * is loaded directly into the buffer pointed to by @buf and the @firmware_p
+ * data member is pointed at @buf.
+ *
+ * This function doesn't cache firmware either.
+ */
+int
+request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
+                         struct device *device, void *buf, size_t size)
+{
+       int ret;
+
+       __module_get(THIS_MODULE);
+       ret = _request_firmware(firmware_p, name, device, buf, size,
+                               FW_OPT_UEVENT | FW_OPT_FALLBACK |
+                               FW_OPT_NOCACHE);
+       module_put(THIS_MODULE);
+       return ret;
+}
+EXPORT_SYMBOL(request_firmware_into_buf);
+
 /**
  * release_firmware: - release the resource associated with a firmware image
  * @fw: firmware resource to release
@@ -1247,7 +1318,7 @@ static void request_firmware_work_func(struct work_struct *work)
 
        fw_work = container_of(work, struct firmware_work, work);
 
-       _request_firmware(&fw, fw_work->name, fw_work->device,
+       _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
                          fw_work->opt_flags);
        fw_work->cont(fw, fw_work->context);
        put_device(fw_work->device); /* taken in request_firmware_nowait() */
@@ -1380,7 +1451,7 @@ static int uncache_firmware(const char *fw_name)
 
        pr_debug("%s: %s\n", __func__, fw_name);
 
-       if (fw_get_builtin_firmware(&fw, fw_name))
+       if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0))
                return 0;
 
        buf = fw_lookup_buf(fw_name);
index 29cd966..5548f96 100644 (file)
@@ -370,7 +370,7 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
 #define page_initialized(page)  (page->lru.next)
 
-static int __init_refok get_nid_for_pfn(unsigned long pfn)
+static int __ref get_nid_for_pfn(unsigned long pfn)
 {
        struct page *page;
 
index 7c04c87..df0c709 100644 (file)
@@ -402,6 +402,22 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
 
+static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
+                                                  unsigned long *freq)
+{
+       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
+
+       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
+               if (temp_opp->available && temp_opp->rate >= *freq) {
+                       opp = temp_opp;
+                       *freq = opp->rate;
+                       break;
+               }
+       }
+
+       return opp;
+}
+
 /**
  * dev_pm_opp_find_freq_ceil() - Search for an rounded ceil freq
  * @dev:       device for which we do this operation
@@ -427,7 +443,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                             unsigned long *freq)
 {
        struct opp_table *opp_table;
-       struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
        opp_rcu_lockdep_assert();
 
@@ -440,15 +455,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
        if (IS_ERR(opp_table))
                return ERR_CAST(opp_table);
 
-       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
-               if (temp_opp->available && temp_opp->rate >= *freq) {
-                       opp = temp_opp;
-                       *freq = opp->rate;
-                       break;
-               }
-       }
-
-       return opp;
+       return _find_freq_ceil(opp_table, freq);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 
@@ -612,7 +619,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                return PTR_ERR(opp_table);
        }
 
-       old_opp = dev_pm_opp_find_freq_ceil(dev, &old_freq);
+       old_opp = _find_freq_ceil(opp_table, &old_freq);
        if (!IS_ERR(old_opp)) {
                ou_volt = old_opp->u_volt;
                ou_volt_min = old_opp->u_volt_min;
@@ -622,7 +629,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                        __func__, old_freq, PTR_ERR(old_opp));
        }
 
-       opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+       opp = _find_freq_ceil(opp_table, &freq);
        if (IS_ERR(opp)) {
                ret = PTR_ERR(opp);
                dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
index a697579..efec10b 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/export.h>
 #include <linux/rtc.h>
 
-#include <asm/rtc.h>
+#include <linux/mc146818rtc.h>
 
 #include "power.h"
 
@@ -103,7 +103,7 @@ static int set_magic_time(unsigned int user, unsigned int file, unsigned int dev
        n /= 24;
        time.tm_min = (n % 20) * 3;
        n /= 20;
-       set_rtc_time(&time);
+       mc146818_set_time(&time);
        return n ? -1 : 0;
 }
 
@@ -112,7 +112,7 @@ static unsigned int read_magic_time(void)
        struct rtc_time time;
        unsigned int val;
 
-       get_rtc_time(&time);
+       mc146818_get_time(&time);
        pr_info("RTC time: %2d:%02d:%02d, date: %02d/%02d/%02d\n",
                time.tm_hour, time.tm_min, time.tm_sec,
                time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
index 5fb7718..62e4de2 100644 (file)
@@ -334,10 +334,9 @@ void device_wakeup_arm_wake_irqs(void)
        struct wakeup_source *ws;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
-               if (ws->wakeirq)
-                       dev_pm_arm_wake_irq(ws->wakeirq);
-       }
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+               dev_pm_arm_wake_irq(ws->wakeirq);
+
        rcu_read_unlock();
 }
 
@@ -351,10 +350,9 @@ void device_wakeup_disarm_wake_irqs(void)
        struct wakeup_source *ws;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
-               if (ws->wakeirq)
-                       dev_pm_disarm_wake_irq(ws->wakeirq);
-       }
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+               dev_pm_disarm_wake_irq(ws->wakeirq);
+
        rcu_read_unlock();
 }
 
@@ -390,9 +388,7 @@ int device_wakeup_disable(struct device *dev)
                return -EINVAL;
 
        ws = device_wakeup_detach(dev);
-       if (ws)
-               wakeup_source_unregister(ws);
-
+       wakeup_source_unregister(ws);
        return 0;
 }
 EXPORT_SYMBOL_GPL(device_wakeup_disable);
index 3022dad..0c76d40 100644 (file)
@@ -300,20 +300,20 @@ static void copy_from_brd(void *dst, struct brd_device *brd,
  * Process a single bvec of a bio.
  */
 static int brd_do_bvec(struct brd_device *brd, struct page *page,
-                       unsigned int len, unsigned int off, int rw,
+                       unsigned int len, unsigned int off, bool is_write,
                        sector_t sector)
 {
        void *mem;
        int err = 0;
 
-       if (rw != READ) {
+       if (is_write) {
                err = copy_to_brd_setup(brd, sector, len);
                if (err)
                        goto out;
        }
 
        mem = kmap_atomic(page);
-       if (rw == READ) {
+       if (!is_write) {
                copy_from_brd(mem + off, brd, sector, len);
                flush_dcache_page(page);
        } else {
@@ -330,7 +330,6 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
 {
        struct block_device *bdev = bio->bi_bdev;
        struct brd_device *brd = bdev->bd_disk->private_data;
-       int rw;
        struct bio_vec bvec;
        sector_t sector;
        struct bvec_iter iter;
@@ -347,14 +346,12 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
                goto out;
        }
 
-       rw = bio_data_dir(bio);
-
        bio_for_each_segment(bvec, bio, iter) {
                unsigned int len = bvec.bv_len;
                int err;
 
-               err = brd_do_bvec(brd, bvec.bv_page, len,
-                                       bvec.bv_offset, rw, sector);
+               err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset,
+                                       op_is_write(bio_op(bio)), sector);
                if (err)
                        goto io_error;
                sector += len >> SECTOR_SHIFT;
@@ -369,11 +366,11 @@ io_error:
 }
 
 static int brd_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, int rw)
+                      struct page *page, bool is_write)
 {
        struct brd_device *brd = bdev->bd_disk->private_data;
-       int err = brd_do_bvec(brd, page, PAGE_SIZE, 0, rw, sector);
-       page_endio(page, rw & WRITE, err);
+       int err = brd_do_bvec(brd, page, PAGE_SIZE, 0, is_write, sector);
+       page_endio(page, is_write, err);
        return err;
 }
 
index 0a1aaf8..2d3d50a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/crc32c.h>
 #include <linux/drbd.h>
 #include <linux/drbd_limits.h>
-#include <linux/dynamic_debug.h>
 #include "drbd_int.h"
 
 
index 7b54354..4cb8f21 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/backing-dev.h>
 #include <linux/genhd.h>
 #include <linux/idr.h>
+#include <linux/dynamic_debug.h>
 #include <net/tcp.h>
 #include <linux/lru_cache.h>
 #include <linux/prefetch.h>
index 0501ae0..100be55 100644 (file)
@@ -1663,13 +1663,13 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection,
                             struct bio *bio)
 {
        if (connection->agreed_pro_version >= 95)
-               return  (bio->bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
-                       (bio->bi_rw & REQ_FUA ? DP_FUA : 0) |
-                       (bio->bi_rw & REQ_PREFLUSH ? DP_FLUSH : 0) |
+               return  (bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0) |
+                       (bio->bi_opf & REQ_FUA ? DP_FUA : 0) |
+                       (bio->bi_opf & REQ_PREFLUSH ? DP_FLUSH : 0) |
                        (bio_op(bio) == REQ_OP_WRITE_SAME ? DP_WSAME : 0) |
                        (bio_op(bio) == REQ_OP_DISCARD ? DP_DISCARD : 0);
        else
-               return bio->bi_rw & REQ_SYNC ? DP_RW_SYNC : 0;
+               return bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0;
 }
 
 /* Used to send write or TRIM aka REQ_DISCARD requests
index df45713..942384f 100644 (file)
@@ -1564,7 +1564,7 @@ static void drbd_issue_peer_wsame(struct drbd_device *device,
  * drbd_submit_peer_request()
  * @device:    DRBD device.
  * @peer_req:  peer request
- * @rw:                flag field, see bio->bi_rw
+ * @rw:                flag field, see bio->bi_opf
  *
  * May spread the pages to multiple bios,
  * depending on bio_add_page restrictions.
index 66b8e4b..de279fe 100644 (file)
@@ -288,7 +288,7 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
         */
        if (!ok &&
            bio_op(req->master_bio) == REQ_OP_READ &&
-           !(req->master_bio->bi_rw & REQ_RAHEAD) &&
+           !(req->master_bio->bi_opf & REQ_RAHEAD) &&
            !list_empty(&req->tl_requests))
                req->rq_state |= RQ_POSTPONED;
 
@@ -1137,7 +1137,7 @@ static int drbd_process_write_request(struct drbd_request *req)
         * replicating, in which case there is no point. */
        if (unlikely(req->i.size == 0)) {
                /* The only size==0 bios we expect are empty flushes. */
-               D_ASSERT(device, req->master_bio->bi_rw & REQ_PREFLUSH);
+               D_ASSERT(device, req->master_bio->bi_opf & REQ_PREFLUSH);
                if (remote)
                        _req_mod(req, QUEUE_AS_DRBD_BARRIER);
                return remote;
@@ -1176,7 +1176,7 @@ drbd_submit_req_private_bio(struct drbd_request *req)
 
        if (bio_op(bio) != REQ_OP_READ)
                type = DRBD_FAULT_DT_WR;
-       else if (bio->bi_rw & REQ_RAHEAD)
+       else if (bio->bi_opf & REQ_RAHEAD)
                type = DRBD_FAULT_DT_RA;
        else
                type = DRBD_FAULT_DT_RD;
index 35dbb3d..c6755c9 100644 (file)
@@ -256,7 +256,7 @@ void drbd_request_endio(struct bio *bio)
                                what = DISCARD_COMPLETED_WITH_ERROR;
                        break;
                case REQ_OP_READ:
-                       if (bio->bi_rw & REQ_RAHEAD)
+                       if (bio->bi_opf & REQ_RAHEAD)
                                what = READ_AHEAD_COMPLETED_WITH_ERROR;
                        else
                                what = READ_COMPLETED_WITH_ERROR;
index c557057..b71a9c7 100644 (file)
@@ -3663,11 +3663,6 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
 
        opened_bdev[drive] = bdev;
 
-       if (!(mode & (FMODE_READ|FMODE_WRITE))) {
-               res = -EINVAL;
-               goto out;
-       }
-
        res = -ENXIO;
 
        if (!floppy_track_buffer) {
@@ -3711,13 +3706,15 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        if (UFDCS->rawcmd == 1)
                UFDCS->rawcmd = 2;
 
-       UDRS->last_checked = 0;
-       clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
-       check_disk_change(bdev);
-       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
-               goto out;
-       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
-               goto out;
+       if (mode & (FMODE_READ|FMODE_WRITE)) {
+               UDRS->last_checked = 0;
+               clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+               check_disk_change(bdev);
+               if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+                       goto out;
+               if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+                       goto out;
+       }
 
        res = -EROFS;
 
index 075377e..c9f2107 100644 (file)
@@ -510,14 +510,10 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
        return 0;
 }
 
-
-static inline int lo_rw_simple(struct loop_device *lo,
-               struct request *rq, loff_t pos, bool rw)
+static int do_req_filebacked(struct loop_device *lo, struct request *rq)
 {
        struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
-
-       if (cmd->use_aio)
-               return lo_rw_aio(lo, cmd, pos, rw);
+       loff_t pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset;
 
        /*
         * lo_write_simple and lo_read_simple should have been covered
@@ -528,37 +524,30 @@ static inline int lo_rw_simple(struct loop_device *lo,
         * of the req at one time. And direct read IO doesn't need to
         * run flush_dcache_page().
         */
-       if (rw == WRITE)
-               return lo_write_simple(lo, rq, pos);
-       else
-               return lo_read_simple(lo, rq, pos);
-}
-
-static int do_req_filebacked(struct loop_device *lo, struct request *rq)
-{
-       loff_t pos;
-       int ret;
-
-       pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset;
-
-       if (op_is_write(req_op(rq))) {
-               if (req_op(rq) == REQ_OP_FLUSH)
-                       ret = lo_req_flush(lo, rq);
-               else if (req_op(rq) == REQ_OP_DISCARD)
-                       ret = lo_discard(lo, rq, pos);
-               else if (lo->transfer)
-                       ret = lo_write_transfer(lo, rq, pos);
+       switch (req_op(rq)) {
+       case REQ_OP_FLUSH:
+               return lo_req_flush(lo, rq);
+       case REQ_OP_DISCARD:
+               return lo_discard(lo, rq, pos);
+       case REQ_OP_WRITE:
+               if (lo->transfer)
+                       return lo_write_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+                       return lo_rw_aio(lo, cmd, pos, WRITE);
                else
-                       ret = lo_rw_simple(lo, rq, pos, WRITE);
-
-       } else {
+                       return lo_write_simple(lo, rq, pos);
+       case REQ_OP_READ:
                if (lo->transfer)
-                       ret = lo_read_transfer(lo, rq, pos);
+                       return lo_read_transfer(lo, rq, pos);
+               else if (cmd->use_aio)
+                       return lo_rw_aio(lo, cmd, pos, READ);
                else
-                       ret = lo_rw_simple(lo, rq, pos, READ);
+                       return lo_read_simple(lo, rq, pos);
+       default:
+               WARN_ON_ONCE(1);
+               return -EIO;
+               break;
        }
-
-       return ret;
 }
 
 struct switch_request {
@@ -1659,11 +1648,15 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (lo->lo_state != Lo_bound)
                return -EIO;
 
-       if (lo->use_dio && (req_op(cmd->rq) != REQ_OP_FLUSH ||
-           req_op(cmd->rq) == REQ_OP_DISCARD))
-               cmd->use_aio = true;
-       else
+       switch (req_op(cmd->rq)) {
+       case REQ_OP_FLUSH:
+       case REQ_OP_DISCARD:
                cmd->use_aio = false;
+               break;
+       default:
+               cmd->use_aio = lo->use_dio;
+               break;
+       }
 
        queue_kthread_work(&lo->worker, &cmd->work);
 
index 6f55b26..a9e3980 100644 (file)
@@ -451,14 +451,9 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
 
        sk_set_memalloc(nbd->sock->sk);
 
-       nbd->task_recv = current;
-
        ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
        if (ret) {
                dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
-
-               nbd->task_recv = NULL;
-
                return ret;
        }
 
@@ -477,9 +472,6 @@ static int nbd_thread_recv(struct nbd_device *nbd, struct block_device *bdev)
        nbd_size_clear(nbd, bdev);
 
        device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
-
-       nbd->task_recv = NULL;
-
        return ret;
 }
 
@@ -788,6 +780,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                if (!nbd->sock)
                        return -EINVAL;
 
+               /* We have to claim the device under the lock */
+               nbd->task_recv = current;
                mutex_unlock(&nbd->tx_lock);
 
                nbd_parse_flags(nbd, bdev);
@@ -796,6 +790,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                                     nbd_name(nbd));
                if (IS_ERR(thread)) {
                        mutex_lock(&nbd->tx_lock);
+                       nbd->task_recv = NULL;
                        return PTR_ERR(thread);
                }
 
@@ -805,6 +800,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                kthread_stop(thread);
 
                mutex_lock(&nbd->tx_lock);
+               nbd->task_recv = NULL;
 
                sock_shutdown(nbd);
                nbd_clear_que(nbd);
index 9393bc7..90fa4ac 100644 (file)
@@ -1157,7 +1157,7 @@ static int pkt_start_recovery(struct packet_data *pkt)
 
        bio_reset(pkt->bio);
        pkt->bio->bi_bdev = pd->bdev;
-       pkt->bio->bi_rw = REQ_WRITE;
+       bio_set_op_attrs(pkt->bio, REQ_OP_WRITE, 0);
        pkt->bio->bi_iter.bi_sector = new_sector;
        pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE;
        pkt->bio->bi_vcnt = pkt->frames;
index 4506620..6c6519f 100644 (file)
@@ -1937,7 +1937,7 @@ static struct ceph_osd_request *rbd_osd_req_create(
        osd_req->r_callback = rbd_osd_req_callback;
        osd_req->r_priv = obj_request;
 
-       osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout);
+       osd_req->r_base_oloc.pool = rbd_dev->layout.pool_id;
        if (ceph_oid_aprintf(&osd_req->r_base_oid, GFP_NOIO, "%s",
                             obj_request->object_name))
                goto fail;
@@ -1991,7 +1991,7 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
        osd_req->r_callback = rbd_osd_req_callback;
        osd_req->r_priv = obj_request;
 
-       osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout);
+       osd_req->r_base_oloc.pool = rbd_dev->layout.pool_id;
        if (ceph_oid_aprintf(&osd_req->r_base_oid, GFP_NOIO, "%s",
                             obj_request->object_name))
                goto fail;
@@ -3950,6 +3950,7 @@ static void rbd_dev_release(struct device *dev)
        bool need_put = !!rbd_dev->opts;
 
        ceph_oid_destroy(&rbd_dev->header_oid);
+       ceph_oloc_destroy(&rbd_dev->header_oloc);
 
        rbd_put_client(rbd_dev->rbd_client);
        rbd_spec_put(rbd_dev->spec);
@@ -3995,10 +3996,11 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
 
        /* Initialize the layout used for all rbd requests */
 
-       rbd_dev->layout.fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
-       rbd_dev->layout.fl_stripe_count = cpu_to_le32(1);
-       rbd_dev->layout.fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
-       rbd_dev->layout.fl_pg_pool = cpu_to_le32((u32) spec->pool_id);
+       rbd_dev->layout.stripe_unit = 1 << RBD_MAX_OBJ_ORDER;
+       rbd_dev->layout.stripe_count = 1;
+       rbd_dev->layout.object_size = 1 << RBD_MAX_OBJ_ORDER;
+       rbd_dev->layout.pool_id = spec->pool_id;
+       RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL);
 
        /*
         * If this is a mapping rbd_dev (as opposed to a parent one),
@@ -5187,7 +5189,7 @@ static int rbd_dev_header_name(struct rbd_device *rbd_dev)
 
        rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
 
-       rbd_dev->header_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout);
+       rbd_dev->header_oloc.pool = rbd_dev->layout.pool_id;
        if (rbd_dev->image_format == 1)
                ret = ceph_oid_aprintf(&rbd_dev->header_oid, GFP_KERNEL, "%s%s",
                                       spec->image_name, RBD_SUFFIX);
@@ -5335,15 +5337,6 @@ static ssize_t do_rbd_add(struct bus_type *bus,
        }
        spec->pool_id = (u64)rc;
 
-       /* The ceph file layout needs to fit pool id in 32 bits */
-
-       if (spec->pool_id > (u64)U32_MAX) {
-               rbd_warn(NULL, "pool id too large (%llu > %u)",
-                               (unsigned long long)spec->pool_id, U32_MAX);
-               rc = -EIO;
-               goto err_out_client;
-       }
-
        rbd_dev = rbd_dev_create(rbdc, spec, rbd_opts);
        if (!rbd_dev) {
                rc = -ENOMEM;
index d0a3e6d..be90e15 100644 (file)
@@ -535,7 +535,7 @@ static blk_qc_t mm_make_request(struct request_queue *q, struct bio *bio)
        *card->biotail = bio;
        bio->bi_next = NULL;
        card->biotail = &bio->bi_next;
-       if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card))
+       if (bio->bi_opf & REQ_SYNC || !mm_check_plugged(card))
                activate(card);
        spin_unlock_irq(&card->lock);
 
index 1523e05..93b1aaa 100644 (file)
@@ -391,22 +391,16 @@ static int init_vq(struct virtio_blk *vblk)
                num_vqs = 1;
 
        vblk->vqs = kmalloc(sizeof(*vblk->vqs) * num_vqs, GFP_KERNEL);
-       if (!vblk->vqs) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!vblk->vqs)
+               return -ENOMEM;
 
        names = kmalloc(sizeof(*names) * num_vqs, GFP_KERNEL);
-       if (!names)
-               goto err_names;
-
        callbacks = kmalloc(sizeof(*callbacks) * num_vqs, GFP_KERNEL);
-       if (!callbacks)
-               goto err_callbacks;
-
        vqs = kmalloc(sizeof(*vqs) * num_vqs, GFP_KERNEL);
-       if (!vqs)
-               goto err_vqs;
+       if (!names || !callbacks || !vqs) {
+               err = -ENOMEM;
+               goto out;
+       }
 
        for (i = 0; i < num_vqs; i++) {
                callbacks[i] = virtblk_done;
@@ -417,7 +411,7 @@ static int init_vq(struct virtio_blk *vblk)
        /* Discover virtqueues and write information to configuration.  */
        err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names);
        if (err)
-               goto err_find_vqs;
+               goto out;
 
        for (i = 0; i < num_vqs; i++) {
                spin_lock_init(&vblk->vqs[i].lock);
@@ -425,16 +419,12 @@ static int init_vq(struct virtio_blk *vblk)
        }
        vblk->num_vqs = num_vqs;
 
- err_find_vqs:
+out:
        kfree(vqs);
- err_vqs:
        kfree(callbacks);
- err_callbacks:
        kfree(names);
- err_names:
        if (err)
                kfree(vblk->vqs);
- out:
        return err;
 }
 
index 7454cf1..04365b1 100644 (file)
@@ -843,15 +843,16 @@ static void zram_bio_discard(struct zram *zram, u32 index,
 }
 
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
-                       int offset, int rw)
+                       int offset, bool is_write)
 {
        unsigned long start_time = jiffies;
+       int rw_acct = is_write ? REQ_OP_WRITE : REQ_OP_READ;
        int ret;
 
-       generic_start_io_acct(rw, bvec->bv_len >> SECTOR_SHIFT,
+       generic_start_io_acct(rw_acct, bvec->bv_len >> SECTOR_SHIFT,
                        &zram->disk->part0);
 
-       if (rw == READ) {
+       if (!is_write) {
                atomic64_inc(&zram->stats.num_reads);
                ret = zram_bvec_read(zram, bvec, index, offset);
        } else {
@@ -859,10 +860,10 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
                ret = zram_bvec_write(zram, bvec, index, offset);
        }
 
-       generic_end_io_acct(rw, &zram->disk->part0, start_time);
+       generic_end_io_acct(rw_acct, &zram->disk->part0, start_time);
 
        if (unlikely(ret)) {
-               if (rw == READ)
+               if (!is_write)
                        atomic64_inc(&zram->stats.failed_reads);
                else
                        atomic64_inc(&zram->stats.failed_writes);
@@ -873,7 +874,7 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
 
 static void __zram_make_request(struct zram *zram, struct bio *bio)
 {
-       int offset, rw;
+       int offset;
        u32 index;
        struct bio_vec bvec;
        struct bvec_iter iter;
@@ -888,7 +889,6 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
                return;
        }
 
-       rw = bio_data_dir(bio);
        bio_for_each_segment(bvec, bio, iter) {
                int max_transfer_size = PAGE_SIZE - offset;
 
@@ -903,15 +903,18 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
                        bv.bv_len = max_transfer_size;
                        bv.bv_offset = bvec.bv_offset;
 
-                       if (zram_bvec_rw(zram, &bv, index, offset, rw) < 0)
+                       if (zram_bvec_rw(zram, &bv, index, offset,
+                                        op_is_write(bio_op(bio))) < 0)
                                goto out;
 
                        bv.bv_len = bvec.bv_len - max_transfer_size;
                        bv.bv_offset += max_transfer_size;
-                       if (zram_bvec_rw(zram, &bv, index + 1, 0, rw) < 0)
+                       if (zram_bvec_rw(zram, &bv, index + 1, 0,
+                                        op_is_write(bio_op(bio))) < 0)
                                goto out;
                } else
-                       if (zram_bvec_rw(zram, &bvec, index, offset, rw) < 0)
+                       if (zram_bvec_rw(zram, &bvec, index, offset,
+                                        op_is_write(bio_op(bio))) < 0)
                                goto out;
 
                update_position(&index, &offset, &bvec);
@@ -968,7 +971,7 @@ static void zram_slot_free_notify(struct block_device *bdev,
 }
 
 static int zram_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, int rw)
+                      struct page *page, bool is_write)
 {
        int offset, err = -EIO;
        u32 index;
@@ -992,7 +995,7 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
        bv.bv_len = PAGE_SIZE;
        bv.bv_offset = 0;
 
-       err = zram_bvec_rw(zram, &bv, index, offset, rw);
+       err = zram_bvec_rw(zram, &bv, index, offset, is_write);
 put_zram:
        zram_meta_put(zram);
 out:
@@ -1005,7 +1008,7 @@ out:
         * (e.g., SetPageError, set_page_dirty and extra works).
         */
        if (err == 0)
-               page_endio(page, rw, 0);
+               page_endio(page, is_write, 0);
        return err;
 }
 
index fdb8f3e..dcc0973 100644 (file)
@@ -293,7 +293,7 @@ if RTC_LIB=n
 
 config RTC
        tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
-       depends on ALPHA || (MIPS && MACH_LOONGSON64) || MN10300
+       depends on ALPHA || (MIPS && MACH_LOONGSON64)
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -339,32 +339,6 @@ config JS_RTC
          To compile this driver as a module, choose M here: the
          module will be called js-rtc.
 
-config GEN_RTC
-       tristate "Generic /dev/rtc emulation"
-       depends on RTC!=y
-       depends on ALPHA || M68K || MN10300 || PARISC || PPC || X86
-       ---help---
-         If you say Y here and create a character special file /dev/rtc with
-         major number 10 and minor number 135 using mknod ("man mknod"), you
-         will get access to the real time clock (or hardware clock) built
-         into your computer.
-
-         It reports status information via the file /proc/driver/rtc and its
-         behaviour is set by various ioctls on /dev/rtc. If you enable the
-         "extended RTC operation" below it will also provide an emulation
-         for RTC_UIE which is required by some programs and may improve
-         precision in some cases.
-
-         To compile this driver as a module, choose M here: the
-         module will be called genrtc.
-
-config GEN_RTC_X
-       bool "Extended RTC operation"
-       depends on GEN_RTC
-       help
-         Provides an emulation for RTC_UIE which is required by some programs
-         and may improve precision of the generic RTC support in some cases.
-
 config EFI_RTC
        bool "EFI Real Time Clock Services"
        depends on IA64
index 55d16bf..6e6c244 100644 (file)
@@ -25,7 +25,6 @@ obj-$(CONFIG_APPLICOM)                += applicom.o
 obj-$(CONFIG_SONYPI)           += sonypi.o
 obj-$(CONFIG_RTC)              += rtc.o
 obj-$(CONFIG_HPET)             += hpet.o
-obj-$(CONFIG_GEN_RTC)          += genrtc.o
 obj-$(CONFIG_EFI_RTC)          += efirtc.o
 obj-$(CONFIG_DS1302)           += ds1302.o
 obj-$(CONFIG_XILINX_HWICAP)    += xilinx_hwicap/
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
deleted file mode 100644 (file)
index 4f94375..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- *     Real Time Clock interface for
- *             - q40 and other m68k machines,
- *             - HP PARISC machines
- *             - PowerPC machines
- *      emulate some RTC irq capabilities in software
- *
- *      Copyright (C) 1999 Richard Zidlicky
- *
- *     based on Paul Gortmaker's rtc.c device and
- *           Sam Creasey Generic rtc driver
- *
- *     This driver allows use of the real time clock (built into
- *     nearly all computers) from user space. It exports the /dev/rtc
- *     interface supporting various ioctl() and also the /proc/driver/rtc
- *     pseudo-file for status information.
- *
- *     The ioctls can be used to set the interrupt behaviour where
- *     supported.
- *
- *     The /dev/rtc interface will block on reads until an interrupt
- *     has been received. If a RTC interrupt has already happened,
- *     it will output an unsigned long and then block. The output value
- *     contains the interrupt status in the low byte and the number of
- *     interrupts since the last read in the remaining high bytes. The
- *     /dev/rtc interface can also be used with the select(2) call.
- *
- *     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.
- *
-
- *      1.01 fix for 2.3.X                    rz@linux-m68k.org
- *      1.02 merged with code from genrtc.c   rz@linux-m68k.org
- *      1.03 make it more portable            zippel@linux-m68k.org
- *      1.04 removed useless timer code       rz@linux-m68k.org
- *      1.05 portable RTC_UIE emulation       rz@linux-m68k.org
- *      1.06 set_rtc_time can return an error trini@kernel.crashing.org
- *      1.07 ported to HP PARISC (hppa)              Helge Deller <deller@gmx.de>
- */
-
-#define RTC_VERSION    "1.07"
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/fcntl.h>
-
-#include <linux/rtc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-/*
- *     We sponge a minor off of the misc major. No need slurping
- *     up another valuable major dev number for this. If you add
- *     an ioctl, make sure you don't conflict with SPARC's RTC
- *     ioctls.
- */
-
-static DEFINE_MUTEX(gen_rtc_mutex);
-static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
-
-/*
- *     Bits in gen_rtc_status.
- */
-
-#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
-
-static unsigned char gen_rtc_status;   /* bitmapped status byte.       */
-static unsigned long gen_rtc_irq_data; /* our output to the world      */
-
-/* months start at 0 now */
-static unsigned char days_in_mo[] =
-{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-static int irq_active;
-
-#ifdef CONFIG_GEN_RTC_X
-static struct work_struct genrtc_task;
-static struct timer_list timer_task;
-
-static unsigned int oldsecs;
-static int lostint;
-static unsigned long tt_exp;
-
-static void gen_rtc_timer(unsigned long data);
-
-static volatile int stask_active;              /* schedule_work */
-static volatile int ttask_active;              /* timer_task */
-static int stop_rtc_timers;                    /* don't requeue tasks */
-static DEFINE_SPINLOCK(gen_rtc_lock);
-
-static void gen_rtc_interrupt(unsigned long arg);
-
-/*
- * Routine to poll RTC seconds field for change as often as possible,
- * after first RTC_UIE use timer to reduce polling
- */
-static void genrtc_troutine(struct work_struct *work)
-{
-       unsigned int tmp = get_rtc_ss();
-       
-       if (stop_rtc_timers) {
-               stask_active = 0;
-               return;
-       }
-
-       if (oldsecs != tmp){
-               oldsecs = tmp;
-
-               timer_task.function = gen_rtc_timer;
-               timer_task.expires = jiffies + HZ - (HZ/10);
-               tt_exp=timer_task.expires;
-               ttask_active=1;
-               stask_active=0;
-               add_timer(&timer_task);
-
-               gen_rtc_interrupt(0);
-       } else if (schedule_work(&genrtc_task) == 0)
-               stask_active = 0;
-}
-
-static void gen_rtc_timer(unsigned long data)
-{
-       lostint = get_rtc_ss() - oldsecs ;
-       if (lostint<0) 
-               lostint = 60 - lostint;
-       if (time_after(jiffies, tt_exp))
-               printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n",
-                      jiffies-tt_exp);
-       ttask_active=0;
-       stask_active=1;
-       if ((schedule_work(&genrtc_task) == 0))
-               stask_active = 0;
-}
-
-/* 
- * call gen_rtc_interrupt function to signal an RTC_UIE,
- * arg is unused.
- * Could be invoked either from a real interrupt handler or
- * from some routine that periodically (eg 100HZ) monitors
- * whether RTC_SECS changed
- */
-static void gen_rtc_interrupt(unsigned long arg)
-{
-       /*  We store the status in the low byte and the number of
-        *      interrupts received since the last read in the remainder
-        *      of rtc_irq_data.  */
-
-       gen_rtc_irq_data += 0x100;
-       gen_rtc_irq_data &= ~0xff;
-       gen_rtc_irq_data |= RTC_UIE;
-
-       if (lostint){
-               printk("genrtc: system delaying clock ticks?\n");
-               /* increment count so that userspace knows something is wrong */
-               gen_rtc_irq_data += ((lostint-1)<<8);
-               lostint = 0;
-       }
-
-       wake_up_interruptible(&gen_rtc_wait);
-}
-
-/*
- *     Now all the various file operations that we export.
- */
-static ssize_t gen_rtc_read(struct file *file, char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-       unsigned long data;
-       ssize_t retval;
-
-       if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
-               return -EINVAL;
-
-       if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
-               return -EAGAIN;
-
-       retval = wait_event_interruptible(gen_rtc_wait,
-                       (data = xchg(&gen_rtc_irq_data, 0)));
-       if (retval)
-               goto out;
-
-       /* first test allows optimizer to nuke this case for 32-bit machines */
-       if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
-               unsigned int uidata = data;
-               retval = put_user(uidata, (unsigned int __user *)buf) ?:
-                       sizeof(unsigned int);
-       }
-       else {
-               retval = put_user(data, (unsigned long __user *)buf) ?:
-                       sizeof(unsigned long);
-       }
-out:
-       return retval;
-}
-
-static unsigned int gen_rtc_poll(struct file *file,
-                                struct poll_table_struct *wait)
-{
-       poll_wait(file, &gen_rtc_wait, wait);
-       if (gen_rtc_irq_data != 0)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-#endif
-
-/*
- * Used to disable/enable interrupts, only RTC_UIE supported
- * We also clear out any old irq data after an ioctl() that
- * meddles with the interrupt enable/disable bits.
- */
-
-static inline void gen_clear_rtc_irq_bit(unsigned char bit)
-{
-#ifdef CONFIG_GEN_RTC_X
-       stop_rtc_timers = 1;
-       if (ttask_active){
-               del_timer_sync(&timer_task);
-               ttask_active = 0;
-       }
-       while (stask_active)
-               schedule();
-
-       spin_lock(&gen_rtc_lock);
-       irq_active = 0;
-       spin_unlock(&gen_rtc_lock);
-#endif
-}
-
-static inline int gen_set_rtc_irq_bit(unsigned char bit)
-{
-#ifdef CONFIG_GEN_RTC_X
-       spin_lock(&gen_rtc_lock);
-       if ( !irq_active ) {
-               irq_active = 1;
-               stop_rtc_timers = 0;
-               lostint = 0;
-               INIT_WORK(&genrtc_task, genrtc_troutine);
-               oldsecs = get_rtc_ss();
-               init_timer(&timer_task);
-
-               stask_active = 1;
-               if (schedule_work(&genrtc_task) == 0){
-                       stask_active = 0;
-               }
-       }
-       spin_unlock(&gen_rtc_lock);
-       gen_rtc_irq_data = 0;
-       return 0;
-#else
-       return -EINVAL;
-#endif
-}
-
-static int gen_rtc_ioctl(struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct rtc_time wtime;
-       struct rtc_pll_info pll;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-
-       case RTC_PLL_GET:
-           if (get_rtc_pll(&pll))
-                   return -EINVAL;
-           else
-                   return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
-
-       case RTC_PLL_SET:
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-               if (copy_from_user(&pll, argp, sizeof(pll)))
-                       return -EFAULT;
-           return set_rtc_pll(&pll);
-
-       case RTC_UIE_OFF:       /* disable ints from RTC updates.       */
-               gen_clear_rtc_irq_bit(RTC_UIE);
-               return 0;
-
-       case RTC_UIE_ON:        /* enable ints for RTC updates. */
-               return gen_set_rtc_irq_bit(RTC_UIE);
-
-       case RTC_RD_TIME:       /* Read the time/date from RTC  */
-               /* this doesn't get week-day, who cares */
-               memset(&wtime, 0, sizeof(wtime));
-               get_rtc_time(&wtime);
-
-               return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
-       case RTC_SET_TIME:      /* Set the RTC */
-           {
-               int year;
-               unsigned char leap_yr;
-
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-
-               if (copy_from_user(&wtime, argp, sizeof(wtime)))
-                       return -EFAULT;
-
-               year = wtime.tm_year + 1900;
-               leap_yr = ((!(year % 4) && (year % 100)) ||
-                          !(year % 400));
-
-               if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
-                       return -EINVAL;
-
-               if (wtime.tm_mday < 0 || wtime.tm_mday >
-                   (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
-                       return -EINVAL;
-
-               if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
-                   wtime.tm_min < 0 || wtime.tm_min >= 60 ||
-                   wtime.tm_sec < 0 || wtime.tm_sec >= 60)
-                       return -EINVAL;
-
-               return set_rtc_time(&wtime);
-           }
-       }
-
-       return -EINVAL;
-}
-
-static long gen_rtc_unlocked_ioctl(struct file *file, unsigned int cmd,
-                                  unsigned long arg)
-{
-       int ret;
-
-       mutex_lock(&gen_rtc_mutex);
-       ret = gen_rtc_ioctl(file, cmd, arg);
-       mutex_unlock(&gen_rtc_mutex);
-
-       return ret;
-}
-
-/*
- *     We enforce only one user at a time here with the open/close.
- *     Also clear the previous interrupt data on an open, and clean
- *     up things on a close.
- */
-
-static int gen_rtc_open(struct inode *inode, struct file *file)
-{
-       mutex_lock(&gen_rtc_mutex);
-       if (gen_rtc_status & RTC_IS_OPEN) {
-               mutex_unlock(&gen_rtc_mutex);
-               return -EBUSY;
-       }
-
-       gen_rtc_status |= RTC_IS_OPEN;
-       gen_rtc_irq_data = 0;
-       irq_active = 0;
-       mutex_unlock(&gen_rtc_mutex);
-
-       return 0;
-}
-
-static int gen_rtc_release(struct inode *inode, struct file *file)
-{
-       /*
-        * Turn off all interrupts once the device is no longer
-        * in use and clear the data.
-        */
-
-       gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
-
-       gen_rtc_status &= ~RTC_IS_OPEN;
-       return 0;
-}
-
-
-#ifdef CONFIG_PROC_FS
-
-/*
- *     Info exported via "/proc/driver/rtc".
- */
-
-static int gen_rtc_proc_show(struct seq_file *m, void *v)
-{
-       struct rtc_time tm;
-       unsigned int flags;
-       struct rtc_pll_info pll;
-
-       flags = get_rtc_time(&tm);
-
-       seq_printf(m,
-                    "rtc_time\t: %02d:%02d:%02d\n"
-                    "rtc_date\t: %04d-%02d-%02d\n"
-                    "rtc_epoch\t: %04u\n",
-                    tm.tm_hour, tm.tm_min, tm.tm_sec,
-                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
-
-       tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
-
-       seq_puts(m, "alarm\t\t: ");
-       if (tm.tm_hour <= 24)
-               seq_printf(m, "%02d:", tm.tm_hour);
-       else
-               seq_puts(m, "**:");
-
-       if (tm.tm_min <= 59)
-               seq_printf(m, "%02d:", tm.tm_min);
-       else
-               seq_puts(m, "**:");
-
-       if (tm.tm_sec <= 59)
-               seq_printf(m, "%02d\n", tm.tm_sec);
-       else
-               seq_puts(m, "**\n");
-
-       seq_printf(m,
-                    "DST_enable\t: %s\n"
-                    "BCD\t\t: %s\n"
-                    "24hr\t\t: %s\n"
-                    "square_wave\t: %s\n"
-                    "alarm_IRQ\t: %s\n"
-                    "update_IRQ\t: %s\n"
-                    "periodic_IRQ\t: %s\n"
-                    "periodic_freq\t: %ld\n"
-                    "batt_status\t: %s\n",
-                    (flags & RTC_DST_EN) ? "yes" : "no",
-                    (flags & RTC_DM_BINARY) ? "no" : "yes",
-                    (flags & RTC_24H) ? "yes" : "no",
-                    (flags & RTC_SQWE) ? "yes" : "no",
-                    (flags & RTC_AIE) ? "yes" : "no",
-                    irq_active ? "yes" : "no",
-                    (flags & RTC_PIE) ? "yes" : "no",
-                    0L /* freq */,
-                    (flags & RTC_BATT_BAD) ? "bad" : "okay");
-       if (!get_rtc_pll(&pll))
-           seq_printf(m,
-                        "PLL adjustment\t: %d\n"
-                        "PLL max +ve adjustment\t: %d\n"
-                        "PLL max -ve adjustment\t: %d\n"
-                        "PLL +ve adjustment factor\t: %d\n"
-                        "PLL -ve adjustment factor\t: %d\n"
-                        "PLL frequency\t: %ld\n",
-                        pll.pll_value,
-                        pll.pll_max,
-                        pll.pll_min,
-                        pll.pll_posmult,
-                        pll.pll_negmult,
-                        pll.pll_clock);
-       return 0;
-}
-
-static int gen_rtc_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, gen_rtc_proc_show, NULL);
-}
-
-static const struct file_operations gen_rtc_proc_fops = {
-       .open           = gen_rtc_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init gen_rtc_proc_init(void)
-{
-       struct proc_dir_entry *r;
-
-       r = proc_create("driver/rtc", 0, NULL, &gen_rtc_proc_fops);
-       if (!r)
-               return -ENOMEM;
-       return 0;
-}
-#else
-static inline int gen_rtc_proc_init(void) { return 0; }
-#endif /* CONFIG_PROC_FS */
-
-
-/*
- *     The various file operations we support.
- */
-
-static const struct file_operations gen_rtc_fops = {
-       .owner          = THIS_MODULE,
-#ifdef CONFIG_GEN_RTC_X
-       .read           = gen_rtc_read,
-       .poll           = gen_rtc_poll,
-#endif
-       .unlocked_ioctl = gen_rtc_unlocked_ioctl,
-       .open           = gen_rtc_open,
-       .release        = gen_rtc_release,
-       .llseek         = noop_llseek,
-};
-
-static struct miscdevice rtc_gen_dev =
-{
-       .minor          = RTC_MINOR,
-       .name           = "rtc",
-       .fops           = &gen_rtc_fops,
-};
-
-static int __init rtc_generic_init(void)
-{
-       int retval;
-
-       printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
-
-       retval = misc_register(&rtc_gen_dev);
-       if (retval < 0)
-               return retval;
-
-       retval = gen_rtc_proc_init();
-       if (retval) {
-               misc_deregister(&rtc_gen_dev);
-               return retval;
-       }
-
-       return 0;
-}
-
-static void __exit rtc_generic_exit(void)
-{
-       remove_proc_entry ("driver/rtc", NULL);
-       misc_deregister(&rtc_gen_dev);
-}
-
-
-module_init(rtc_generic_init);
-module_exit(rtc_generic_exit);
-
-MODULE_AUTHOR("Richard Zidlicky");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(RTC_MINOR);
index 89cc700..97ae60f 100644 (file)
@@ -250,7 +250,7 @@ struct clk_lookup_alloc {
        char    con_id[MAX_CON_ID];
 };
 
-static struct clk_lookup * __init_refok
+static struct clk_lookup * __ref
 vclkdev_alloc(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
        va_list ap)
 {
@@ -287,7 +287,7 @@ vclkdev_create(struct clk_hw *hw, const char *con_id, const char *dev_fmt,
        return cl;
 }
 
-struct clk_lookup * __init_refok
+struct clk_lookup * __ref
 clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...)
 {
        struct clk_lookup *cl;
index c822d72..74919aa 100644 (file)
@@ -32,7 +32,6 @@ config CPU_FREQ_BOOST_SW
 
 config CPU_FREQ_STAT
        bool "CPU frequency transition statistics"
-       default y
        help
          Export CPU frequency statistics information through sysfs.
 
index 9ec033b..be9eade 100644 (file)
@@ -1374,6 +1374,8 @@ MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
 
 static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = {
        ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params),
+       ICPU(INTEL_FAM6_BROADWELL_X, core_params),
+       ICPU(INTEL_FAM6_SKYLAKE_X, core_params),
        {}
 };
 
index b6eb875..62aa3cf 100644 (file)
@@ -669,7 +669,7 @@ static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
        case BCMA_HOSTTYPE_PCI:
                memset(out, 0, sizeof(struct ssb_sprom));
                /* On BCM47XX all PCI buses share the same domain */
-               if (config_enabled(CONFIG_BCM47XX))
+               if (IS_ENABLED(CONFIG_BCM47XX))
                        snprintf(buf, sizeof(buf), "pci/%u/%u/",
                                 bus->host_pci->bus->number + 1,
                                 PCI_SLOT(bus->host_pci->devfn));
index c9b9fdf..d614102 100644 (file)
@@ -21,6 +21,7 @@ config FPGA_MGR_SOCFPGA
 
 config FPGA_MGR_ZYNQ_FPGA
        tristate "Xilinx Zynq FPGA"
+       depends on HAS_DMA
        help
          FPGA manager driver support for Xilinx Zynq FPGAs.
 
index e3dba6f..0238bf8 100644 (file)
@@ -24,7 +24,7 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
                drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
                drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
-               drm_simple_kms_helper.o
+               drm_simple_kms_helper.o drm_blend.o
 
 drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
index ff63b88..5cc7052 100644 (file)
@@ -305,7 +305,7 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
        char *table = NULL;
-       int size, i;
+       int size;
 
        if (adev->pp_enabled)
                size = amdgpu_dpm_get_pp_table(adev, &table);
@@ -315,10 +315,7 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
        if (size >= PAGE_SIZE)
                size = PAGE_SIZE - 1;
 
-       for (i = 0; i < size; i++) {
-               sprintf(buf + i, "%02x", table[i]);
-       }
-       sprintf(buf + i, "\n");
+       memcpy(buf, table, size);
 
        return size;
 }
index b7742e6..9b61c8b 100644 (file)
@@ -335,7 +335,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                goto out_cleanup;
        }
-       r = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem);
+       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem);
 out_cleanup:
        ttm_bo_mem_put(bo, &tmp_mem);
        return r;
@@ -368,7 +368,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                return r;
        }
-       r = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem);
+       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem);
        if (unlikely(r)) {
                goto out_cleanup;
        }
index e2f0e5d..a5c94b4 100644 (file)
@@ -5779,6 +5779,7 @@ static int ci_dpm_init_microcode(struct amdgpu_device *adev)
                break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
+       case CHIP_MULLINS:
        default: BUG();
        }
 
index bff8668..b818461 100644 (file)
@@ -270,7 +270,8 @@ static const u32 tonga_mgcg_cgcg_init[] =
 
 static const u32 golden_settings_polaris11_a11[] =
 {
-       mmCB_HW_CONTROL, 0xfffdf3cf, 0x00006208,
+       mmCB_HW_CONTROL, 0x0000f3cf, 0x00007208,
+       mmCB_HW_CONTROL_2, 0x0f000000, 0x0f000000,
        mmCB_HW_CONTROL_3, 0x000001ff, 0x00000040,
        mmDB_DEBUG2, 0xf00fffff, 0x00000400,
        mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
@@ -279,7 +280,7 @@ static const u32 golden_settings_polaris11_a11[] =
        mmPA_SC_RASTER_CONFIG_1, 0x0000003f, 0x00000000,
        mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0001003c,
        mmRLC_CGCG_CGLS_CTRL_3D, 0xffffffff, 0x0001003c,
-       mmSQ_CONFIG, 0x07f80000, 0x07180000,
+       mmSQ_CONFIG, 0x07f80000, 0x01180000,
        mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
        mmTCC_CTRL, 0x00100000, 0xf31fff7f,
        mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f3,
@@ -301,8 +302,8 @@ static const u32 polaris11_golden_common_all[] =
 static const u32 golden_settings_polaris10_a11[] =
 {
        mmATC_MISC_CG, 0x000c0fc0, 0x000c0200,
-       mmCB_HW_CONTROL, 0xfffdf3cf, 0x00007208,
-       mmCB_HW_CONTROL_2, 0, 0x0f000000,
+       mmCB_HW_CONTROL, 0x0001f3cf, 0x00007208,
+       mmCB_HW_CONTROL_2, 0x0f000000, 0x0f000000,
        mmCB_HW_CONTROL_3, 0x000001ff, 0x00000040,
        mmDB_DEBUG2, 0xf00fffff, 0x00000400,
        mmPA_SC_ENHANCE, 0xffffffff, 0x20000001,
@@ -409,6 +410,7 @@ static const u32 golden_settings_iceland_a11[] =
        mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
        mmPA_SC_RASTER_CONFIG, 0x3f3fffff, 0x00000002,
        mmPA_SC_RASTER_CONFIG_1, 0x0000003f, 0x00000000,
+       mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0000003c,
        mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
        mmTA_CNTL_AUX, 0x000f000f, 0x000b0000,
        mmTCC_CTRL, 0x00100000, 0xf31fff7f,
@@ -505,8 +507,10 @@ static const u32 cz_golden_settings_a11[] =
        mmGB_GPU_ID, 0x0000000f, 0x00000000,
        mmPA_SC_ENHANCE, 0xffffffff, 0x00000001,
        mmPA_SC_LINE_STIPPLE_STATE, 0x0000ff0f, 0x00000000,
+       mmRLC_CGCG_CGLS_CTRL, 0x00000003, 0x0000003c,
        mmSQ_RANDOM_WAVE_PRI, 0x001fffff, 0x000006fd,
        mmTA_CNTL_AUX, 0x000f000f, 0x00010000,
+       mmTCC_CTRL, 0x00100000, 0xf31fff7f,
        mmTCC_EXE_DISABLE, 0x00000002, 0x00000002,
        mmTCP_ADDR_CONFIG, 0x0000000f, 0x000000f3,
        mmTCP_CHAN_STEER_LO, 0xffffffff, 0x00001302
index d24a82b..0b0f086 100644 (file)
@@ -144,6 +144,7 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev)
                break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
+       case CHIP_MULLINS:
                return 0;
        default: BUG();
        }
index 717359d..2aee2c6 100644 (file)
@@ -103,6 +103,11 @@ static const u32 stoney_mgcg_cgcg_init[] =
        mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
 };
 
+static const u32 golden_settings_stoney_common[] =
+{
+       mmMC_HUB_RDREQ_UVD, MC_HUB_RDREQ_UVD__PRESCALE_MASK, 0x00000004,
+       mmMC_RD_GRP_OTH, MC_RD_GRP_OTH__UVD_MASK, 0x00600000
+};
 
 static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
 {
@@ -142,6 +147,9 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
                amdgpu_program_register_sequence(adev,
                                                 stoney_mgcg_cgcg_init,
                                                 (const u32)ARRAY_SIZE(stoney_mgcg_cgcg_init));
+               amdgpu_program_register_sequence(adev,
+                                                golden_settings_stoney_common,
+                                                (const u32)ARRAY_SIZE(golden_settings_stoney_common));
                break;
        default:
                break;
index 80446e2..76bcb43 100644 (file)
@@ -185,14 +185,23 @@ int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
                goto out;
        }
 
+       /*
+        * cirrus_modeset_init() is initializing/registering the emulated fbdev
+        * and DRM internals can access/test some of the fields in
+        * mode_config->funcs as part of the fbdev registration process.
+        * Make sure dev->mode_config.funcs is properly set to avoid
+        * dereferencing a NULL pointer.
+        * FIXME: mode_config.funcs assignment should probably be done in
+        * cirrus_modeset_init() (that's a common pattern seen in other DRM
+        * drivers).
+        */
+       dev->mode_config.funcs = &cirrus_mode_funcs;
        r = cirrus_modeset_init(cdev);
        if (r) {
                dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
                goto out;
        }
 
-       dev->mode_config.funcs = (void *)&cirrus_mode_funcs;
-
        return 0;
 out:
        cirrus_driver_unload(dev);
index 8d2f111..fa39307 100644 (file)
@@ -711,6 +711,8 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,
                state->src_h = val;
        } else if (property == config->rotation_property) {
                state->rotation = val;
+       } else if (property == plane->zpos_property) {
+               state->zpos = val;
        } else if (plane->funcs->atomic_set_property) {
                return plane->funcs->atomic_set_property(plane, state,
                                property, val);
@@ -767,6 +769,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
                *val = state->src_h;
        } else if (property == config->rotation_property) {
                *val = state->rotation;
+       } else if (property == plane->zpos_property) {
+               *val = state->zpos;
        } else if (plane->funcs->atomic_get_property) {
                return plane->funcs->atomic_get_property(plane, state, property, val);
        } else {
index de7fddc..20be86d 100644 (file)
@@ -32,6 +32,8 @@
 #include <drm/drm_atomic_helper.h>
 #include <linux/fence.h>
 
+#include "drm_crtc_internal.h"
+
 /**
  * DOC: overview
  *
@@ -592,6 +594,10 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
        struct drm_plane_state *plane_state;
        int i, ret = 0;
 
+       ret = drm_atomic_helper_normalize_zpos(dev, state);
+       if (ret)
+               return ret;
+
        for_each_plane_in_state(state, plane, plane_state, i) {
                const struct drm_plane_helper_funcs *funcs;
 
@@ -2955,6 +2961,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
        state->planes_changed = false;
        state->connectors_changed = false;
        state->color_mgmt_changed = false;
+       state->zpos_changed = false;
        state->event = NULL;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
new file mode 100644 (file)
index 0000000..f3c0942
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2016 Samsung Electronics Co.Ltd
+ * Authors:
+ *     Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * DRM core plane blending related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+
+#include "drm_internal.h"
+
+/**
+ * drm_plane_create_zpos_property - create mutable zpos property
+ * @plane: drm plane
+ * @zpos: initial value of zpos property
+ * @min: minimal possible value of zpos property
+ * @max: maximal possible value of zpos property
+ *
+ * This function initializes generic mutable zpos property and enables support
+ * for it in drm core. Drivers can then attach this property to planes to enable
+ * support for configurable planes arrangement during blending operation.
+ * Once mutable zpos property has been enabled, the DRM core will automatically
+ * calculate drm_plane_state->normalized_zpos values. Usually min should be set
+ * to 0 and max to maximal number of planes for given crtc - 1.
+ *
+ * If zpos of some planes cannot be changed (like fixed background or
+ * cursor/topmost planes), driver should adjust min/max values and assign those
+ * planes immutable zpos property with lower or higher values (for more
+ * information, see drm_mode_create_zpos_immutable_property() function). In such
+ * case driver should also assign proper initial zpos values for all planes in
+ * its plane_reset() callback, so the planes will be always sorted properly.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_plane_create_zpos_property(struct drm_plane *plane,
+                                  unsigned int zpos,
+                                  unsigned int min, unsigned int max)
+{
+       struct drm_property *prop;
+
+       prop = drm_property_create_range(plane->dev, 0, "zpos", min, max);
+       if (!prop)
+               return -ENOMEM;
+
+       drm_object_attach_property(&plane->base, prop, zpos);
+
+       plane->zpos_property = prop;
+
+       if (plane->state) {
+               plane->state->zpos = zpos;
+               plane->state->normalized_zpos = zpos;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_plane_create_zpos_property);
+
+/**
+ * drm_plane_create_zpos_immutable_property - create immuttable zpos property
+ * @plane: drm plane
+ * @zpos: value of zpos property
+ *
+ * This function initializes generic immutable zpos property and enables
+ * support for it in drm core. Using this property driver lets userspace
+ * to get the arrangement of the planes for blending operation and notifies
+ * it that the hardware (or driver) doesn't support changing of the planes'
+ * order.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
+                                            unsigned int zpos)
+{
+       struct drm_property *prop;
+
+       prop = drm_property_create_range(plane->dev, DRM_MODE_PROP_IMMUTABLE,
+                                        "zpos", zpos, zpos);
+       if (!prop)
+               return -ENOMEM;
+
+       drm_object_attach_property(&plane->base, prop, zpos);
+
+       plane->zpos_property = prop;
+
+       if (plane->state) {
+               plane->state->zpos = zpos;
+               plane->state->normalized_zpos = zpos;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_plane_create_zpos_immutable_property);
+
+static int drm_atomic_state_zpos_cmp(const void *a, const void *b)
+{
+       const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
+       const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
+
+       if (sa->zpos != sb->zpos)
+               return sa->zpos - sb->zpos;
+       else
+               return sa->plane->base.id - sb->plane->base.id;
+}
+
+/**
+ * drm_atomic_helper_crtc_normalize_zpos - calculate normalized zpos values
+ * @crtc: crtc with planes, which have to be considered for normalization
+ * @crtc_state: new atomic state to apply
+ *
+ * This function checks new states of all planes assigned to given crtc and
+ * calculates normalized zpos value for them. Planes are compared first by their
+ * zpos values, then by plane id (if zpos equals). Plane with lowest zpos value
+ * is at the bottom. The plane_state->normalized_zpos is then filled with unique
+ * values from 0 to number of active planes in crtc minus one.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
+                                         struct drm_crtc_state *crtc_state)
+{
+       struct drm_atomic_state *state = crtc_state->state;
+       struct drm_device *dev = crtc->dev;
+       int total_planes = dev->mode_config.num_total_plane;
+       struct drm_plane_state **states;
+       struct drm_plane *plane;
+       int i, n = 0;
+       int ret = 0;
+
+       DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",
+                        crtc->base.id, crtc->name);
+
+       states = kmalloc_array(total_planes, sizeof(*states), GFP_TEMPORARY);
+       if (!states)
+               return -ENOMEM;
+
+       /*
+        * Normalization process might create new states for planes which
+        * normalized_zpos has to be recalculated.
+        */
+       drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
+               struct drm_plane_state *plane_state =
+                       drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(plane_state)) {
+                       ret = PTR_ERR(plane_state);
+                       goto done;
+               }
+               states[n++] = plane_state;
+               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n",
+                                plane->base.id, plane->name,
+                                plane_state->zpos);
+       }
+
+       sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL);
+
+       for (i = 0; i < n; i++) {
+               plane = states[i]->plane;
+
+               states[i]->normalized_zpos = i;
+               DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n",
+                                plane->base.id, plane->name, i);
+       }
+       crtc_state->zpos_changed = true;
+
+done:
+       kfree(states);
+       return ret;
+}
+
+/**
+ * drm_atomic_helper_normalize_zpos - calculate normalized zpos values for all
+ *                                   crtcs
+ * @dev: DRM device
+ * @state: atomic state of DRM device
+ *
+ * This function calculates normalized zpos value for all modified planes in
+ * the provided atomic state of DRM device. For more information, see
+ * drm_atomic_helper_crtc_normalize_zpos() function.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_normalize_zpos(struct drm_device *dev,
+                                    struct drm_atomic_state *state)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
+       int i, ret = 0;
+
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               crtc = plane_state->crtc;
+               if (!crtc)
+                       continue;
+               if (plane->state->zpos != plane_state->zpos) {
+                       crtc_state =
+                               drm_atomic_get_existing_crtc_state(state, crtc);
+                       crtc_state->zpos_changed = true;
+               }
+       }
+
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (crtc_state->plane_mask != crtc->state->plane_mask ||
+                   crtc_state->zpos_changed) {
+                       ret = drm_atomic_helper_crtc_normalize_zpos(crtc,
+                                                                   crtc_state);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
index f1d9f05..b1dbb60 100644 (file)
@@ -1121,16 +1121,14 @@ static int drm_connector_register_all(struct drm_device *dev)
        struct drm_connector *connector;
        int ret;
 
-       mutex_lock(&dev->mode_config.mutex);
-
-       drm_for_each_connector(connector, dev) {
+       /* FIXME: taking the mode config mutex ends up in a clash with
+        * fbcon/backlight registration */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                ret = drm_connector_register(connector);
                if (ret)
                        goto err;
        }
 
-       mutex_unlock(&dev->mode_config.mutex);
-
        return 0;
 
 err:
index 47a500b..0c34e6d 100644 (file)
@@ -128,3 +128,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
 
 int drm_modeset_register_all(struct drm_device *dev);
 void drm_modeset_unregister_all(struct drm_device *dev);
+
+/* drm_blend.c */
+int drm_atomic_helper_normalize_zpos(struct drm_device *dev,
+                                    struct drm_atomic_state *state);
index 8f11b87..eae5ef9 100644 (file)
@@ -860,3 +860,35 @@ void drm_dp_aux_unregister(struct drm_dp_aux *aux)
        i2c_del_adapter(&aux->ddc);
 }
 EXPORT_SYMBOL(drm_dp_aux_unregister);
+
+#define PSR_SETUP_TIME(x) [DP_PSR_SETUP_TIME_ ## x >> DP_PSR_SETUP_TIME_SHIFT] = (x)
+
+/**
+ * drm_dp_psr_setup_time() - PSR setup in time usec
+ * @psr_cap: PSR capabilities from DPCD
+ *
+ * Returns:
+ * PSR setup time for the panel in microseconds,  negative
+ * error code on failure.
+ */
+int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE])
+{
+       static const u16 psr_setup_time_us[] = {
+               PSR_SETUP_TIME(330),
+               PSR_SETUP_TIME(275),
+               PSR_SETUP_TIME(165),
+               PSR_SETUP_TIME(110),
+               PSR_SETUP_TIME(55),
+               PSR_SETUP_TIME(0),
+       };
+       int i;
+
+       i = (psr_cap[1] & DP_PSR_SETUP_TIME_MASK) >> DP_PSR_SETUP_TIME_SHIFT;
+       if (i >= ARRAY_SIZE(psr_setup_time_us))
+               return -EINVAL;
+
+       return psr_setup_time_us[i];
+}
+EXPORT_SYMBOL(drm_dp_psr_setup_time);
+
+#undef PSR_SETUP_TIME
index 7df26d4..637a0aa 100644 (file)
@@ -74,6 +74,8 @@
 #define EDID_QUIRK_FORCE_8BPC                  (1 << 8)
 /* Force 12bpc */
 #define EDID_QUIRK_FORCE_12BPC                 (1 << 9)
+/* Force 6bpc */
+#define EDID_QUIRK_FORCE_6BPC                  (1 << 10)
 
 struct detailed_mode_closure {
        struct drm_connector *connector;
@@ -100,6 +102,9 @@ static struct edid_quirk {
        /* Unknown Acer */
        { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
 
+       /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
+       { "AEO", 0, EDID_QUIRK_FORCE_6BPC },
+
        /* Belinea 10 15 55 */
        { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
        { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
@@ -3862,6 +3867,20 @@ static void drm_add_display_info(struct edid *edid,
        /* HDMI deep color modes supported? Assign to info, if so */
        drm_assign_hdmi_deep_color_info(edid, info, connector);
 
+       /*
+        * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3?
+        *
+        * For such displays, the DFP spec 1.0, section 3.10 "EDID support"
+        * tells us to assume 8 bpc color depth if the EDID doesn't have
+        * extensions which tell otherwise.
+        */
+       if ((info->bpc == 0) && (edid->revision < 4) &&
+           (edid->input & DRM_EDID_DIGITAL_TYPE_DVI)) {
+               info->bpc = 8;
+               DRM_DEBUG("%s: Assigning DFP sink color depth as %d bpc.\n",
+                         connector->name, info->bpc);
+       }
+
        /* Only defined for 1.4 with digital displays */
        if (edid->revision < 4)
                return;
@@ -4082,6 +4101,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 
        drm_add_display_info(edid, &connector->display_info, connector);
 
+       if (quirks & EDID_QUIRK_FORCE_6BPC)
+               connector->display_info.bpc = 6;
+
        if (quirks & EDID_QUIRK_FORCE_8BPC)
                connector->display_info.bpc = 8;
 
index b39d521..7f1a49d 100644 (file)
@@ -64,7 +64,6 @@ struct exynos_drm_plane_state {
        struct exynos_drm_rect src;
        unsigned int h_ratio;
        unsigned int v_ratio;
-       unsigned int zpos;
 };
 
 static inline struct exynos_drm_plane_state *
@@ -221,7 +220,6 @@ struct exynos_drm_private {
         * this array is used to be aware of which crtc did it request vblank.
         */
        struct drm_crtc *crtc[MAX_CRTC];
-       struct drm_property *plane_zpos_property;
 
        struct device *dma_dev;
        void *mapping;
index fb49443..4cfb39d 100644 (file)
@@ -52,7 +52,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
 
        ret = dma_mmap_attrs(to_dma_dev(helper->dev), vma, exynos_gem->cookie,
                             exynos_gem->dma_addr, exynos_gem->size,
-                            &exynos_gem->dma_attrs);
+                            exynos_gem->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
                return ret;
index 8564c3d..4bf00f5 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/dma-mapping.h>
-#include <linux/dma-attrs.h>
 #include <linux/of.h>
 
 #include <drm/drmP.h>
@@ -235,7 +234,7 @@ struct g2d_data {
        struct mutex                    cmdlist_mutex;
        dma_addr_t                      cmdlist_pool;
        void                            *cmdlist_pool_virt;
-       struct dma_attrs                cmdlist_dma_attrs;
+       unsigned long                   cmdlist_dma_attrs;
 
        /* runqueue*/
        struct g2d_runqueue_node        *runqueue_node;
@@ -256,13 +255,12 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
        int ret;
        struct g2d_buf_info *buf_info;
 
-       init_dma_attrs(&g2d->cmdlist_dma_attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs);
+       g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE;
 
        g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev),
                                                G2D_CMDLIST_POOL_SIZE,
                                                &g2d->cmdlist_pool, GFP_KERNEL,
-                                               &g2d->cmdlist_dma_attrs);
+                                               g2d->cmdlist_dma_attrs);
        if (!g2d->cmdlist_pool_virt) {
                dev_err(dev, "failed to allocate dma memory\n");
                return -ENOMEM;
@@ -295,7 +293,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
 err:
        dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE,
                        g2d->cmdlist_pool_virt,
-                       g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs);
+                       g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
        return ret;
 }
 
@@ -309,7 +307,7 @@ static void g2d_fini_cmdlist(struct g2d_data *g2d)
                dma_free_attrs(to_dma_dev(subdrv->drm_dev),
                                G2D_CMDLIST_POOL_SIZE,
                                g2d->cmdlist_pool_virt,
-                               g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs);
+                               g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
        }
 }
 
index cdf9f1a..f2ae72b 100644 (file)
@@ -24,7 +24,7 @@
 static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
 {
        struct drm_device *dev = exynos_gem->base.dev;
-       enum dma_attr attr;
+       unsigned long attr;
        unsigned int nr_pages;
        struct sg_table sgt;
        int ret = -ENOMEM;
@@ -34,7 +34,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
                return 0;
        }
 
-       init_dma_attrs(&exynos_gem->dma_attrs);
+       exynos_gem->dma_attrs = 0;
 
        /*
         * if EXYNOS_BO_CONTIG, fully physically contiguous memory
@@ -42,7 +42,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
         * as possible.
         */
        if (!(exynos_gem->flags & EXYNOS_BO_NONCONTIG))
-               dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &exynos_gem->dma_attrs);
+               exynos_gem->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
 
        /*
         * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
@@ -54,8 +54,8 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
        else
                attr = DMA_ATTR_NON_CONSISTENT;
 
-       dma_set_attr(attr, &exynos_gem->dma_attrs);
-       dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &exynos_gem->dma_attrs);
+       exynos_gem->dma_attrs |= attr;
+       exynos_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
 
        nr_pages = exynos_gem->size >> PAGE_SHIFT;
 
@@ -67,7 +67,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
 
        exynos_gem->cookie = dma_alloc_attrs(to_dma_dev(dev), exynos_gem->size,
                                             &exynos_gem->dma_addr, GFP_KERNEL,
-                                            &exynos_gem->dma_attrs);
+                                            exynos_gem->dma_attrs);
        if (!exynos_gem->cookie) {
                DRM_ERROR("failed to allocate buffer.\n");
                goto err_free;
@@ -75,7 +75,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
 
        ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt, exynos_gem->cookie,
                                    exynos_gem->dma_addr, exynos_gem->size,
-                                   &exynos_gem->dma_attrs);
+                                   exynos_gem->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to get sgtable.\n");
                goto err_dma_free;
@@ -99,7 +99,7 @@ err_sgt_free:
        sg_free_table(&sgt);
 err_dma_free:
        dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie,
-                      exynos_gem->dma_addr, &exynos_gem->dma_attrs);
+                      exynos_gem->dma_addr, exynos_gem->dma_attrs);
 err_free:
        drm_free_large(exynos_gem->pages);
 
@@ -120,7 +120,7 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem)
 
        dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie,
                        (dma_addr_t)exynos_gem->dma_addr,
-                       &exynos_gem->dma_attrs);
+                       exynos_gem->dma_attrs);
 
        drm_free_large(exynos_gem->pages);
 }
@@ -346,7 +346,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
 
        ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, exynos_gem->cookie,
                             exynos_gem->dma_addr, exynos_gem->size,
-                            &exynos_gem->dma_attrs);
+                            exynos_gem->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
                return ret;
index 7810074..df7c543 100644 (file)
@@ -50,7 +50,7 @@ struct exynos_drm_gem {
        void                    *cookie;
        void __iomem            *kvaddr;
        dma_addr_t              dma_addr;
-       struct dma_attrs        dma_attrs;
+       unsigned long           dma_attrs;
        struct page             **pages;
        struct sg_table         *sgt;
 };
index 77f12c0..7f32419 100644 (file)
@@ -139,9 +139,9 @@ static void exynos_drm_plane_reset(struct drm_plane *plane)
 
        exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
        if (exynos_state) {
-               exynos_state->zpos = exynos_plane->config->zpos;
                plane->state = &exynos_state->base;
                plane->state->plane = plane;
+               plane->state->zpos = exynos_plane->config->zpos;
        }
 }
 
@@ -157,7 +157,6 @@ exynos_drm_plane_duplicate_state(struct drm_plane *plane)
                return NULL;
 
        __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
-       copy->zpos = exynos_state->zpos;
        return &copy->base;
 }
 
@@ -170,43 +169,6 @@ static void exynos_drm_plane_destroy_state(struct drm_plane *plane,
        kfree(old_exynos_state);
 }
 
-static int exynos_drm_plane_atomic_set_property(struct drm_plane *plane,
-                                               struct drm_plane_state *state,
-                                               struct drm_property *property,
-                                               uint64_t val)
-{
-       struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
-       struct exynos_drm_plane_state *exynos_state =
-                                       to_exynos_plane_state(state);
-       struct exynos_drm_private *dev_priv = plane->dev->dev_private;
-       const struct exynos_drm_plane_config *config = exynos_plane->config;
-
-       if (property == dev_priv->plane_zpos_property &&
-           (config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS))
-               exynos_state->zpos = val;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-static int exynos_drm_plane_atomic_get_property(struct drm_plane *plane,
-                                         const struct drm_plane_state *state,
-                                         struct drm_property *property,
-                                         uint64_t *val)
-{
-       const struct exynos_drm_plane_state *exynos_state =
-               container_of(state, const struct exynos_drm_plane_state, base);
-       struct exynos_drm_private *dev_priv = plane->dev->dev_private;
-
-       if (property == dev_priv->plane_zpos_property)
-               *val = exynos_state->zpos;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
 static struct drm_plane_funcs exynos_plane_funcs = {
        .update_plane   = drm_atomic_helper_update_plane,
        .disable_plane  = drm_atomic_helper_disable_plane,
@@ -215,8 +177,6 @@ static struct drm_plane_funcs exynos_plane_funcs = {
        .reset          = exynos_drm_plane_reset,
        .atomic_duplicate_state = exynos_drm_plane_duplicate_state,
        .atomic_destroy_state = exynos_drm_plane_destroy_state,
-       .atomic_set_property = exynos_drm_plane_atomic_set_property,
-       .atomic_get_property = exynos_drm_plane_atomic_get_property,
 };
 
 static int
@@ -304,23 +264,13 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
 };
 
 static void exynos_plane_attach_zpos_property(struct drm_plane *plane,
-                                             unsigned int zpos)
+                                             bool immutable)
 {
-       struct drm_device *dev = plane->dev;
-       struct exynos_drm_private *dev_priv = dev->dev_private;
-       struct drm_property *prop;
-
-       prop = dev_priv->plane_zpos_property;
-       if (!prop) {
-               prop = drm_property_create_range(dev, 0, "zpos",
-                                                0, MAX_PLANE - 1);
-               if (!prop)
-                       return;
-
-               dev_priv->plane_zpos_property = prop;
-       }
-
-       drm_object_attach_property(&plane->base, prop, zpos);
+       /* FIXME */
+       if (immutable)
+               drm_plane_create_zpos_immutable_property(plane, 0);
+       else
+               drm_plane_create_zpos_property(plane, 0, 0, MAX_PLANE - 1);
 }
 
 int exynos_plane_init(struct drm_device *dev,
@@ -346,7 +296,8 @@ int exynos_plane_init(struct drm_device *dev,
        exynos_plane->index = index;
        exynos_plane->config = config;
 
-       exynos_plane_attach_zpos_property(&exynos_plane->base, config->zpos);
+       exynos_plane_attach_zpos_property(&exynos_plane->base,
+                          !(config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS));
 
        return 0;
 }
index 74a4269..e1d47f9 100644 (file)
@@ -477,6 +477,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
        struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
        struct mixer_resources *res = &ctx->mixer_res;
        struct drm_framebuffer *fb = state->base.fb;
+       unsigned int priority = state->base.normalized_zpos + 1;
        unsigned long flags;
        dma_addr_t luma_addr[2], chroma_addr[2];
        bool tiled_mode = false;
@@ -561,7 +562,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
 
        mixer_cfg_scan(ctx, mode->vdisplay);
        mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
-       mixer_cfg_layer(ctx, plane->index, state->zpos + 1, true);
+       mixer_cfg_layer(ctx, plane->index, priority, true);
        mixer_cfg_vp_blend(ctx);
        mixer_run(ctx);
 
@@ -586,6 +587,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
        struct drm_display_mode *mode = &state->base.crtc->state->adjusted_mode;
        struct mixer_resources *res = &ctx->mixer_res;
        struct drm_framebuffer *fb = state->base.fb;
+       unsigned int priority = state->base.normalized_zpos + 1;
        unsigned long flags;
        unsigned int win = plane->index;
        unsigned int x_ratio = 0, y_ratio = 0;
@@ -677,7 +679,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
 
        mixer_cfg_scan(ctx, mode->vdisplay);
        mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
-       mixer_cfg_layer(ctx, win, state->zpos + 1, true);
+       mixer_cfg_layer(ctx, win, priority, true);
        mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->pixel_format));
 
        /* layer update mandatory for mixer 16.0.33.0 */
index 915a3d0..21f9390 100644 (file)
@@ -3651,8 +3651,8 @@ void i915_debugfs_unregister(struct drm_i915_private *dev_priv);
 int i915_debugfs_connector_add(struct drm_connector *connector);
 void intel_display_crc_init(struct drm_device *dev);
 #else
-static inline int i915_debugfs_register(struct drm_i915_private *) {return 0;}
-static inline void i915_debugfs_unregister(struct drm_i915_private *) {}
+static inline int i915_debugfs_register(struct drm_i915_private *dev_priv) {return 0;}
+static inline void i915_debugfs_unregister(struct drm_i915_private *dev_priv) {}
 static inline int i915_debugfs_connector_add(struct drm_connector *connector)
 { return 0; }
 static inline void intel_display_crc_init(struct drm_device *dev) {}
index c457eed..dcf93b3 100644 (file)
@@ -5691,15 +5691,7 @@ static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv)
 
 static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv)
 {
-       unsigned int i;
-
-       for (i = 0; i < 15; i++) {
-               if (skl_cdclk_pcu_ready(dev_priv))
-                       return true;
-               udelay(10);
-       }
-
-       return false;
+       return _wait_for(skl_cdclk_pcu_ready(dev_priv), 3000, 10) == 0;
 }
 
 static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco)
@@ -12114,21 +12106,11 @@ connected_sink_compute_bpp(struct intel_connector *connector,
                pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
        }
 
-       /* Clamp bpp to default limit on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0) {
-               int type = connector->base.connector_type;
-               int clamp_bpp = 24;
-
-               /* Fall back to 18 bpp when DP sink capability is unknown. */
-               if (type == DRM_MODE_CONNECTOR_DisplayPort ||
-                   type == DRM_MODE_CONNECTOR_eDP)
-                       clamp_bpp = 18;
-
-               if (bpp > clamp_bpp) {
-                       DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of %d\n",
-                                     bpp, clamp_bpp);
-                       pipe_config->pipe_bpp = clamp_bpp;
-               }
+       /* Clamp bpp to 8 on screens without EDID 1.4 */
+       if (connector->base.display_info.bpc == 0 && bpp > 24) {
+               DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
+                             bpp);
+               pipe_config->pipe_bpp = 24;
        }
 }
 
index 3329fc6..cc937a1 100644 (file)
@@ -1730,6 +1730,8 @@ bool intel_sdvo_init(struct drm_device *dev,
 
 
 /* intel_sprite.c */
+int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+                            int usecs);
 int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
index 86b00c6..3e3632c 100644 (file)
@@ -782,7 +782,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
        struct intel_fbdev *ifbdev = dev_priv->fbdev;
        struct fb_info *info;
 
-       if (!ifbdev)
+       if (!ifbdev || !ifbdev->fb)
                return;
 
        info = ifbdev->helper.fbdev;
@@ -827,31 +827,28 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
 
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       if (dev_priv->fbdev)
-               drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+       struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
+
+       if (ifbdev && ifbdev->fb)
+               drm_fb_helper_hotplug_event(&ifbdev->helper);
 }
 
 void intel_fbdev_restore_mode(struct drm_device *dev)
 {
-       int ret;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_fbdev *ifbdev = dev_priv->fbdev;
-       struct drm_fb_helper *fb_helper;
+       struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
 
        if (!ifbdev)
                return;
 
        intel_fbdev_sync(ifbdev);
+       if (!ifbdev->fb)
+               return;
 
-       fb_helper = &ifbdev->helper;
-
-       ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
-       if (ret) {
+       if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper)) {
                DRM_DEBUG("failed to restore crtc mode\n");
        } else {
-               mutex_lock(&fb_helper->dev->struct_mutex);
+               mutex_lock(&dev->struct_mutex);
                intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
-               mutex_unlock(&fb_helper->dev->struct_mutex);
+               mutex_unlock(&dev->struct_mutex);
        }
 }
index f4f3fcc..97ba6c8 100644 (file)
@@ -4892,7 +4892,8 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
                else
                        gen6_set_rps(dev_priv, dev_priv->rps.idle_freq);
                dev_priv->rps.last_adj = 0;
-               I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+               I915_WRITE(GEN6_PMINTRMSK,
+                          gen6_sanitize_rps_pm_mask(dev_priv, ~0));
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 
index 68bd0bb..2b0d1ba 100644 (file)
@@ -327,6 +327,9 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *crtc = dig_port->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       const struct drm_display_mode *adjusted_mode =
+               &intel_crtc->config->base.adjusted_mode;
+       int psr_setup_time;
 
        lockdep_assert_held(&dev_priv->psr.lock);
        WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
@@ -365,11 +368,25 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
        }
 
        if (IS_HASWELL(dev) &&
-           intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+           adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
                DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
                return false;
        }
 
+       psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
+       if (psr_setup_time < 0) {
+               DRM_DEBUG_KMS("PSR condition failed: Invalid PSR setup time (0x%02x)\n",
+                             intel_dp->psr_dpcd[1]);
+               return false;
+       }
+
+       if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
+           adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
+               DRM_DEBUG_KMS("PSR condition failed: PSR setup time (%d us) too long\n",
+                             psr_setup_time);
+               return false;
+       }
+
        dev_priv->psr.source_ok = true;
        return true;
 }
index 0de935a..7c08e4f 100644 (file)
@@ -53,8 +53,8 @@ format_is_yuv(uint32_t format)
        }
 }
 
-static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
-                             int usecs)
+int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+                            int usecs)
 {
        /* paranoia */
        if (!adjusted_mode->crtc_htotal)
@@ -91,7 +91,7 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
                vblank_start = DIV_ROUND_UP(vblank_start, 2);
 
        /* FIXME needs to be calibrated sensibly */
-       min = vblank_start - usecs_to_scanlines(adjusted_mode, 100);
+       min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, 100);
        max = vblank_start - 1;
 
        local_irq_disable();
index fa2ec0c..7abc550 100644 (file)
@@ -54,15 +54,14 @@ struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
 
        obj = &mtk_gem->base;
 
-       init_dma_attrs(&mtk_gem->dma_attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &mtk_gem->dma_attrs);
+       mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE;
 
        if (!alloc_kmap)
-               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &mtk_gem->dma_attrs);
+               mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
 
        mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size,
                                          &mtk_gem->dma_addr, GFP_KERNEL,
-                                         &mtk_gem->dma_attrs);
+                                         mtk_gem->dma_attrs);
        if (!mtk_gem->cookie) {
                DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size);
                ret = -ENOMEM;
@@ -93,7 +92,7 @@ void mtk_drm_gem_free_object(struct drm_gem_object *obj)
                drm_prime_gem_destroy(obj, mtk_gem->sg);
        else
                dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie,
-                              mtk_gem->dma_addr, &mtk_gem->dma_attrs);
+                              mtk_gem->dma_addr, mtk_gem->dma_attrs);
 
        /* release file pointer to gem object. */
        drm_gem_object_release(obj);
@@ -173,7 +172,7 @@ static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
        vma->vm_pgoff = 0;
 
        ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
-                            mtk_gem->dma_addr, obj->size, &mtk_gem->dma_attrs);
+                            mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
        if (ret)
                drm_gem_vm_close(vma);
 
@@ -224,7 +223,7 @@ struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj)
 
        ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie,
                                    mtk_gem->dma_addr, obj->size,
-                                   &mtk_gem->dma_attrs);
+                                   mtk_gem->dma_attrs);
        if (ret) {
                DRM_ERROR("failed to allocate sgt, %d\n", ret);
                kfree(sgt);
index 3a2a562..2752718 100644 (file)
@@ -35,7 +35,7 @@ struct mtk_drm_gem_obj {
        void                    *cookie;
        void                    *kvaddr;
        dma_addr_t              dma_addr;
-       struct dma_attrs        dma_attrs;
+       unsigned long           dma_attrs;
        struct sg_table         *sg;
 };
 
index 26f859e..8a02370 100644 (file)
@@ -238,11 +238,10 @@ static int msm_drm_uninit(struct device *dev)
        }
 
        if (priv->vram.paddr) {
-               DEFINE_DMA_ATTRS(attrs);
-               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+               unsigned long attrs = DMA_ATTR_NO_KERNEL_MAPPING;
                drm_mm_takedown(&priv->vram.mm);
                dma_free_attrs(dev, priv->vram.size, NULL,
-                              priv->vram.paddr, &attrs);
+                              priv->vram.paddr, attrs);
        }
 
        component_unbind_all(dev, ddev);
@@ -310,21 +309,21 @@ static int msm_init_vram(struct drm_device *dev)
        }
 
        if (size) {
-               DEFINE_DMA_ATTRS(attrs);
+               unsigned long attrs = 0;
                void *p;
 
                priv->vram.size = size;
 
                drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
 
-               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
-               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+               attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
+               attrs |= DMA_ATTR_WRITE_COMBINE;
 
                /* note that for no-kernel-mapping, the vaddr returned
                 * is bogus, but non-null if allocation succeeded:
                 */
                p = dma_alloc_attrs(dev->dev, size,
-                               &priv->vram.paddr, GFP_KERNEL, &attrs);
+                               &priv->vram.paddr, GFP_KERNEL, attrs);
                if (!p) {
                        dev_err(dev->dev, "failed to allocate VRAM\n");
                        priv->vram.paddr = 0;
index 528bdef..6190035 100644 (file)
@@ -1151,7 +1151,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                goto out;
 
-       ret = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem);
+       ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, new_mem);
 out:
        ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
@@ -1179,7 +1179,7 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       ret = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem);
+       ret = ttm_bo_move_ttm(bo, true, intr, no_wait_gpu, &tmp_mem);
        if (ret)
                goto out;
 
index 6b8f2a1..a6a7fa0 100644 (file)
@@ -109,7 +109,7 @@ struct gk20a_instmem {
        u16 iommu_bit;
 
        /* Only used by DMA API */
-       struct dma_attrs attrs;
+       unsigned long attrs;
 };
 #define gk20a_instmem(p) container_of((p), struct gk20a_instmem, base)
 
@@ -293,7 +293,7 @@ gk20a_instobj_dtor_dma(struct nvkm_memory *memory)
                goto out;
 
        dma_free_attrs(dev, node->base.mem.size << PAGE_SHIFT, node->base.vaddr,
-                      node->handle, &imem->attrs);
+                      node->handle, imem->attrs);
 
 out:
        return node;
@@ -386,7 +386,7 @@ gk20a_instobj_ctor_dma(struct gk20a_instmem *imem, u32 npages, u32 align,
 
        node->base.vaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT,
                                           &node->handle, GFP_KERNEL,
-                                          &imem->attrs);
+                                          imem->attrs);
        if (!node->base.vaddr) {
                nvkm_error(subdev, "cannot allocate DMA memory\n");
                return -ENOMEM;
@@ -597,10 +597,9 @@ gk20a_instmem_new(struct nvkm_device *device, int index,
 
                nvkm_info(&imem->base.subdev, "using IOMMU\n");
        } else {
-               init_dma_attrs(&imem->attrs);
-               dma_set_attr(DMA_ATTR_NON_CONSISTENT, &imem->attrs);
-               dma_set_attr(DMA_ATTR_WEAK_ORDERING, &imem->attrs);
-               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &imem->attrs);
+               imem->attrs = DMA_ATTR_NON_CONSISTENT |
+                             DMA_ATTR_WEAK_ORDERING |
+                             DMA_ATTR_WRITE_COMBINE;
 
                nvkm_info(&imem->base.subdev, "using DMA API\n");
        }
index ffdad81..0c00e19 100644 (file)
@@ -346,7 +346,7 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                goto out_cleanup;
        }
-       r = ttm_bo_move_ttm(bo, true, no_wait_gpu, new_mem);
+       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, new_mem);
 out_cleanup:
        ttm_bo_mem_put(bo, &tmp_mem);
        return r;
@@ -379,7 +379,7 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
        if (unlikely(r)) {
                return r;
        }
-       r = ttm_bo_move_ttm(bo, true, no_wait_gpu, &tmp_mem);
+       r = ttm_bo_move_ttm(bo, true, interruptible, no_wait_gpu, &tmp_mem);
        if (unlikely(r)) {
                goto out_cleanup;
        }
index e39fcef..7316fc7 100644 (file)
@@ -196,7 +196,7 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
 
 static unsigned int plane_zpos(struct rcar_du_plane *plane)
 {
-       return to_rcar_plane_state(plane->plane.state)->zpos;
+       return plane->plane.state->normalized_zpos;
 }
 
 static const struct rcar_du_format_info *
index ed35467..c843c31 100644 (file)
@@ -92,7 +92,6 @@ struct rcar_du_device {
        struct {
                struct drm_property *alpha;
                struct drm_property *colorkey;
-               struct drm_property *zpos;
        } props;
 
        unsigned int dpad0_source;
index 4de3ff0..e03004f 100644 (file)
@@ -125,6 +125,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
 
        /* Link drm_bridge to encoder */
        bridge->encoder = encoder;
+       encoder->bridge = bridge;
 
        ret = drm_bridge_attach(rcdu->ddev, bridge);
        if (ret) {
index 6bb032d..f03eb55 100644 (file)
@@ -527,11 +527,6 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu)
        if (rcdu->props.colorkey == NULL)
                return -ENOMEM;
 
-       rcdu->props.zpos =
-               drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
-       if (rcdu->props.zpos == NULL)
-               return -ENOMEM;
-
        return 0;
 }
 
index bfe31ca..a74f8ed 100644 (file)
@@ -652,7 +652,7 @@ static void rcar_du_plane_reset(struct drm_plane *plane)
        state->source = RCAR_DU_PLANE_MEMORY;
        state->alpha = 255;
        state->colorkey = RCAR_DU_COLORKEY_NONE;
-       state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
+       state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
 
        plane->state = &state->state;
        plane->state->plane = plane;
@@ -670,8 +670,6 @@ static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
                rstate->alpha = val;
        else if (property == rcdu->props.colorkey)
                rstate->colorkey = val;
-       else if (property == rcdu->props.zpos)
-               rstate->zpos = val;
        else
                return -EINVAL;
 
@@ -690,8 +688,6 @@ static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
                *val = rstate->alpha;
        else if (property == rcdu->props.colorkey)
                *val = rstate->colorkey;
-       else if (property == rcdu->props.zpos)
-               *val = rstate->zpos;
        else
                return -EINVAL;
 
@@ -763,8 +759,7 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
                drm_object_attach_property(&plane->plane.base,
                                           rcdu->props.colorkey,
                                           RCAR_DU_COLORKEY_NONE);
-               drm_object_attach_property(&plane->plane.base,
-                                          rcdu->props.zpos, 1);
+               drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
        }
 
        return 0;
index b18b7b2..8b91dd3 100644 (file)
@@ -51,7 +51,6 @@ static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
  * @hwindex: 0-based hardware plane index, -1 means unused
  * @alpha: value of the plane alpha property
  * @colorkey: value of the plane colorkey property
- * @zpos: value of the plane zpos property
  */
 struct rcar_du_plane_state {
        struct drm_plane_state state;
@@ -62,7 +61,6 @@ struct rcar_du_plane_state {
 
        unsigned int alpha;
        unsigned int colorkey;
-       unsigned int zpos;
 };
 
 static inline struct rcar_du_plane_state *
index 6ac717f..83ebd16 100644 (file)
@@ -43,12 +43,12 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
                        .src_y = 0,
                        .src_w = mode->hdisplay << 16,
                        .src_h = mode->vdisplay << 16,
+                       .zpos = 0,
                },
                .format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
                .source = RCAR_DU_PLANE_VSPD1,
                .alpha = 255,
                .colorkey = 0,
-               .zpos = 0,
        };
 
        if (rcdu->info->gen >= 3)
@@ -152,7 +152,7 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
                .pixelformat = 0,
                .pitch = fb->pitches[0],
                .alpha = state->alpha,
-               .zpos = state->zpos,
+               .zpos = state->state.zpos,
        };
        unsigned int i;
 
@@ -267,7 +267,7 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
                return;
 
        state->alpha = 255;
-       state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
+       state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
 
        plane->state = &state->state;
        plane->state->plane = plane;
@@ -282,8 +282,6 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane,
 
        if (property == rcdu->props.alpha)
                rstate->alpha = val;
-       else if (property == rcdu->props.zpos)
-               rstate->zpos = val;
        else
                return -EINVAL;
 
@@ -300,8 +298,6 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane,
 
        if (property == rcdu->props.alpha)
                *val = rstate->alpha;
-       else if (property == rcdu->props.zpos)
-               *val = rstate->zpos;
        else
                return -EINVAL;
 
@@ -381,8 +377,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp)
 
                drm_object_attach_property(&plane->plane.base,
                                           rcdu->props.alpha, 255);
-               drm_object_attach_property(&plane->plane.base,
-                                          rcdu->props.zpos, 1);
+               drm_plane_create_zpos_property(&plane->plane, 1, 1,
+                                              vsp->num_planes - 1);
        }
 
        return 0;
index 059e902..b70f942 100644 (file)
@@ -17,8 +17,6 @@
 #include <drm/drm_gem.h>
 #include <drm/drm_vma_manager.h>
 
-#include <linux/dma-attrs.h>
-
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 
@@ -28,15 +26,14 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
        struct drm_gem_object *obj = &rk_obj->base;
        struct drm_device *drm = obj->dev;
 
-       init_dma_attrs(&rk_obj->dma_attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
+       rk_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE;
 
        if (!alloc_kmap)
-               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
+               rk_obj->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
 
        rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
                                         &rk_obj->dma_addr, GFP_KERNEL,
-                                        &rk_obj->dma_attrs);
+                                        rk_obj->dma_attrs);
        if (!rk_obj->kvaddr) {
                DRM_ERROR("failed to allocate %zu byte dma buffer", obj->size);
                return -ENOMEM;
@@ -51,7 +48,7 @@ static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
        struct drm_device *drm = obj->dev;
 
        dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
-                      &rk_obj->dma_attrs);
+                      rk_obj->dma_attrs);
 }
 
 static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
@@ -70,7 +67,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
        vma->vm_pgoff = 0;
 
        ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
-                            obj->size, &rk_obj->dma_attrs);
+                            obj->size, rk_obj->dma_attrs);
        if (ret)
                drm_gem_vm_close(vma);
 
@@ -262,7 +259,7 @@ struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
 
        ret = dma_get_sgtable_attrs(drm->dev, sgt, rk_obj->kvaddr,
                                    rk_obj->dma_addr, obj->size,
-                                   &rk_obj->dma_attrs);
+                                   rk_obj->dma_attrs);
        if (ret) {
                DRM_ERROR("failed to allocate sgt, %d\n", ret);
                kfree(sgt);
@@ -276,7 +273,7 @@ void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 {
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 
-       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
+       if (rk_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING)
                return NULL;
 
        return rk_obj->kvaddr;
index ad22618..18b3488 100644 (file)
@@ -23,7 +23,7 @@ struct rockchip_gem_object {
 
        void *kvaddr;
        dma_addr_t dma_addr;
-       struct dma_attrs dma_attrs;
+       unsigned long dma_attrs;
 };
 
 struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj);
index a263bbb..3b53f7f 100644 (file)
@@ -349,8 +349,8 @@ struct drm_plane_funcs sti_cursor_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_cursor_destroy,
-       .set_property = sti_plane_set_property,
-       .reset = drm_atomic_helper_plane_reset,
+       .set_property = drm_atomic_helper_plane_set_property,
+       .reset = sti_plane_reset,
        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
        .late_register = sti_cursor_late_register,
index bf63086..b8d942c 100644 (file)
@@ -886,8 +886,8 @@ struct drm_plane_funcs sti_gdp_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_gdp_destroy,
-       .set_property = sti_plane_set_property,
-       .reset = drm_atomic_helper_plane_reset,
+       .set_property = drm_atomic_helper_plane_set_property,
+       .reset = sti_plane_reset,
        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
        .late_register = sti_gdp_late_register,
index b032322..b5ee783 100644 (file)
@@ -1254,8 +1254,8 @@ struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = {
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .destroy = sti_hqvdp_destroy,
-       .set_property = sti_plane_set_property,
-       .reset = drm_atomic_helper_plane_reset,
+       .set_property = drm_atomic_helper_plane_set_property,
+       .reset = sti_plane_reset,
        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
        .late_register = sti_hqvdp_late_register,
index 1885c7a..7d9aea8 100644 (file)
@@ -239,13 +239,10 @@ static void sti_mixer_set_background_area(struct sti_mixer *mixer,
 
 int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
 {
-       int plane_id, depth = plane->zorder;
+       int plane_id, depth = plane->drm_plane.state->normalized_zpos;
        unsigned int i;
        u32 mask, val;
 
-       if ((depth < 1) || (depth > GAM_MIXER_NB_DEPTH_LEVEL))
-               return 1;
-
        switch (plane->desc) {
        case STI_GDP_0:
                plane_id = GAM_DEPTH_GDP0_ID;
@@ -278,8 +275,8 @@ int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
                        break;
        }
 
-       mask |= GAM_DEPTH_MASK_ID << (3 * (depth - 1));
-       plane_id = plane_id << (3 * (depth - 1));
+       mask |= GAM_DEPTH_MASK_ID << (3 * depth);
+       plane_id = plane_id << (3 * depth);
 
        DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
                         sti_plane_to_str(plane), depth);
index 0cf3335..ca4b371 100644 (file)
 #include "sti_drv.h"
 #include "sti_plane.h"
 
-/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */
-enum sti_plane_desc sti_plane_default_zorder[] = {
-       STI_GDP_0,
-       STI_GDP_1,
-       STI_HQVDP_0,
-       STI_GDP_2,
-       STI_GDP_3,
-};
-
 const char *sti_plane_to_str(struct sti_plane *plane)
 {
        switch (plane->desc) {
@@ -96,59 +87,46 @@ void sti_plane_update_fps(struct sti_plane *plane,
                         plane->fps_info.fips_str);
 }
 
-int sti_plane_set_property(struct drm_plane *drm_plane,
-                          struct drm_property *property,
-                          uint64_t val)
+static int sti_plane_get_default_zpos(enum drm_plane_type type)
 {
-       struct drm_device *dev = drm_plane->dev;
-       struct sti_private *private = dev->dev_private;
-       struct sti_plane *plane = to_sti_plane(drm_plane);
-
-       DRM_DEBUG_DRIVER("\n");
-
-       if (property == private->plane_zorder_property) {
-               plane->zorder = val;
+       switch (type) {
+       case DRM_PLANE_TYPE_PRIMARY:
                return 0;
+       case DRM_PLANE_TYPE_OVERLAY:
+               return 1;
+       case DRM_PLANE_TYPE_CURSOR:
+               return 7;
        }
+       return 0;
+}
 
-       return -EINVAL;
+void sti_plane_reset(struct drm_plane *plane)
+{
+       drm_atomic_helper_plane_reset(plane);
+       plane->state->zpos = sti_plane_get_default_zpos(plane->type);
 }
 
-static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
+static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane,
+                                            enum drm_plane_type type)
 {
-       struct drm_device *dev = drm_plane->dev;
-       struct sti_private *private = dev->dev_private;
-       struct sti_plane *plane = to_sti_plane(drm_plane);
-       struct drm_property *prop;
-
-       prop = private->plane_zorder_property;
-       if (!prop) {
-               prop = drm_property_create_range(dev, 0, "zpos", 1,
-                                                GAM_MIXER_NB_DEPTH_LEVEL);
-               if (!prop)
-                       return;
-
-               private->plane_zorder_property = prop;
+       int zpos = sti_plane_get_default_zpos(type);
+
+       switch (type) {
+       case DRM_PLANE_TYPE_PRIMARY:
+       case DRM_PLANE_TYPE_OVERLAY:
+               drm_plane_create_zpos_property(drm_plane, zpos, 0, 6);
+               break;
+       case DRM_PLANE_TYPE_CURSOR:
+               drm_plane_create_zpos_immutable_property(drm_plane, zpos);
+               break;
        }
-
-       drm_object_attach_property(&drm_plane->base, prop, plane->zorder);
 }
 
 void sti_plane_init_property(struct sti_plane *plane,
                             enum drm_plane_type type)
 {
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++)
-               if (sti_plane_default_zorder[i] == plane->desc)
-                       break;
-
-       plane->zorder = i + 1;
-
-       if (type == DRM_PLANE_TYPE_OVERLAY)
-               sti_plane_attach_zorder_property(&plane->drm_plane);
+       sti_plane_attach_zorder_property(&plane->drm_plane, type);
 
-       DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n",
-                        plane->drm_plane.base.id,
-                        sti_plane_to_str(plane), plane->zorder);
+       DRM_DEBUG_DRIVER("drm plane:%d mapped to %s\n",
+                        plane->drm_plane.base.id, sti_plane_to_str(plane));
 }
index e0ea1dd..ce3e8d6 100644 (file)
@@ -66,14 +66,12 @@ struct sti_fps_info {
  * @plane:              drm plane it is bound to (if any)
  * @desc:               plane type & id
  * @status:             to know the status of the plane
- * @zorder:             plane z-order
  * @fps_info:           frame per second info
  */
 struct sti_plane {
        struct drm_plane drm_plane;
        enum sti_plane_desc desc;
        enum sti_plane_status status;
-       int zorder;
        struct sti_fps_info fps_info;
 };
 
@@ -82,10 +80,7 @@ void sti_plane_update_fps(struct sti_plane *plane,
                          bool new_frame,
                          bool new_field);
 
-int sti_plane_set_property(struct drm_plane *drm_plane,
-                          struct drm_property *property,
-                          uint64_t val);
-
 void sti_plane_init_property(struct sti_plane *plane,
                             enum drm_plane_type type);
+void sti_plane_reset(struct drm_plane *plane);
 #endif
index 4054d80..42c074a 100644 (file)
@@ -354,7 +354,8 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
        if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
            !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
-               ret = ttm_bo_move_ttm(bo, evict, no_wait_gpu, mem);
+               ret = ttm_bo_move_ttm(bo, evict, interruptible, no_wait_gpu,
+                                     mem);
        else if (bdev->driver->move)
                ret = bdev->driver->move(bo, evict, interruptible,
                                         no_wait_gpu, mem);
index 2df602a..f157a9e 100644 (file)
@@ -45,7 +45,7 @@ void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 }
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
-                   bool evict,
+                   bool evict, bool interruptible,
                    bool no_wait_gpu, struct ttm_mem_reg *new_mem)
 {
        struct ttm_tt *ttm = bo->ttm;
@@ -53,6 +53,14 @@ int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
        int ret;
 
        if (old_mem->mem_type != TTM_PL_SYSTEM) {
+               ret = ttm_bo_wait(bo, interruptible, no_wait_gpu);
+
+               if (unlikely(ret != 0)) {
+                       if (ret != -ERESTARTSYS)
+                               pr_err("Failed to expire sync object before unbinding TTM\n");
+                       return ret;
+               }
+
                ttm_tt_unbind(ttm);
                ttm_bo_free_old_node(bo);
                ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM,
index 2137adf..e9b7dc0 100644 (file)
@@ -84,6 +84,7 @@ source "drivers/infiniband/ulp/iser/Kconfig"
 source "drivers/infiniband/ulp/isert/Kconfig"
 
 source "drivers/infiniband/sw/rdmavt/Kconfig"
+source "drivers/infiniband/sw/rxe/Kconfig"
 
 source "drivers/infiniband/hw/hfi1/Kconfig"
 
index ad1b1ad..e6dfa1b 100644 (file)
@@ -68,6 +68,7 @@ MODULE_DESCRIPTION("Generic RDMA CM Agent");
 MODULE_LICENSE("Dual BSD/GPL");
 
 #define CMA_CM_RESPONSE_TIMEOUT 20
+#define CMA_QUERY_CLASSPORT_INFO_TIMEOUT 3000
 #define CMA_MAX_CM_RETRIES 15
 #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
 #define CMA_IBOE_PACKET_LIFETIME 18
@@ -162,6 +163,14 @@ struct rdma_bind_list {
        unsigned short          port;
 };
 
+struct class_port_info_context {
+       struct ib_class_port_info       *class_port_info;
+       struct ib_device                *device;
+       struct completion               done;
+       struct ib_sa_query              *sa_query;
+       u8                              port_num;
+};
+
 static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
                        struct rdma_bind_list *bind_list, int snum)
 {
@@ -306,6 +315,7 @@ struct cma_multicast {
        struct sockaddr_storage addr;
        struct kref             mcref;
        bool                    igmp_joined;
+       u8                      join_state;
 };
 
 struct cma_work {
@@ -3752,10 +3762,63 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
        }
 }
 
+static void cma_query_sa_classport_info_cb(int status,
+                                          struct ib_class_port_info *rec,
+                                          void *context)
+{
+       struct class_port_info_context *cb_ctx = context;
+
+       WARN_ON(!context);
+
+       if (status || !rec) {
+               pr_debug("RDMA CM: %s port %u failed query ClassPortInfo status: %d\n",
+                        cb_ctx->device->name, cb_ctx->port_num, status);
+               goto out;
+       }
+
+       memcpy(cb_ctx->class_port_info, rec, sizeof(struct ib_class_port_info));
+
+out:
+       complete(&cb_ctx->done);
+}
+
+static int cma_query_sa_classport_info(struct ib_device *device, u8 port_num,
+                                      struct ib_class_port_info *class_port_info)
+{
+       struct class_port_info_context *cb_ctx;
+       int ret;
+
+       cb_ctx = kmalloc(sizeof(*cb_ctx), GFP_KERNEL);
+       if (!cb_ctx)
+               return -ENOMEM;
+
+       cb_ctx->device = device;
+       cb_ctx->class_port_info = class_port_info;
+       cb_ctx->port_num = port_num;
+       init_completion(&cb_ctx->done);
+
+       ret = ib_sa_classport_info_rec_query(&sa_client, device, port_num,
+                                            CMA_QUERY_CLASSPORT_INFO_TIMEOUT,
+                                            GFP_KERNEL, cma_query_sa_classport_info_cb,
+                                            cb_ctx, &cb_ctx->sa_query);
+       if (ret < 0) {
+               pr_err("RDMA CM: %s port %u failed to send ClassPortInfo query, ret: %d\n",
+                      device->name, port_num, ret);
+               goto out;
+       }
+
+       wait_for_completion(&cb_ctx->done);
+
+out:
+       kfree(cb_ctx);
+       return ret;
+}
+
 static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
                                 struct cma_multicast *mc)
 {
        struct ib_sa_mcmember_rec rec;
+       struct ib_class_port_info class_port_info;
        struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
        ib_sa_comp_mask comp_mask;
        int ret;
@@ -3774,7 +3837,24 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
        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;
+       rec.join_state = mc->join_state;
+
+       if (rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) {
+               ret = cma_query_sa_classport_info(id_priv->id.device,
+                                                 id_priv->id.port_num,
+                                                 &class_port_info);
+
+               if (ret)
+                       return ret;
+
+               if (!(ib_get_cpi_capmask2(&class_port_info) &
+                     IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT)) {
+                       pr_warn("RDMA CM: %s port %u Unable to multicast join\n"
+                               "RDMA CM: SM doesn't support Send Only Full Member option\n",
+                               id_priv->id.device->name, id_priv->id.port_num);
+                       return -EOPNOTSUPP;
+               }
+       }
 
        comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
                    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
@@ -3843,6 +3923,9 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
        struct sockaddr *addr = (struct sockaddr *)&mc->addr;
        struct net_device *ndev = NULL;
        enum ib_gid_type gid_type;
+       bool send_only;
+
+       send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN);
 
        if (cma_zero_addr((struct sockaddr *)&mc->addr))
                return -EINVAL;
@@ -3878,10 +3961,12 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
        if (addr->sa_family == AF_INET) {
                if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
                        mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
-                       err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
-                                           true);
-                       if (!err)
-                               mc->igmp_joined = true;
+                       if (!send_only) {
+                               err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
+                                                   true);
+                               if (!err)
+                                       mc->igmp_joined = true;
+                       }
                }
        } else {
                if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
@@ -3911,7 +3996,7 @@ out1:
 }
 
 int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
-                       void *context)
+                       u8 join_state, void *context)
 {
        struct rdma_id_private *id_priv;
        struct cma_multicast *mc;
@@ -3930,6 +4015,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        mc->context = context;
        mc->id_priv = id_priv;
        mc->igmp_joined = false;
+       mc->join_state = join_state;
        spin_lock(&id_priv->lock);
        list_add(&mc->list, &id_priv->mc_list);
        spin_unlock(&id_priv->lock);
index 5c155fa..760ef60 100644 (file)
@@ -311,6 +311,15 @@ static int read_port_immutable(struct ib_device *device)
        return 0;
 }
 
+void ib_get_device_fw_str(struct ib_device *dev, char *str, size_t str_len)
+{
+       if (dev->get_dev_fw_str)
+               dev->get_dev_fw_str(dev, str, str_len);
+       else
+               str[0] = '\0';
+}
+EXPORT_SYMBOL(ib_get_device_fw_str);
+
 /**
  * ib_register_device - Register an IB device with IB core
  * @device:Device to register
index f057204..357624f 100644 (file)
@@ -183,15 +183,14 @@ static void free_cm_id(struct iwcm_id_private *cm_id_priv)
 
 /*
  * Release a reference on cm_id. If the last reference is being
- * released, enable the waiting thread (in iw_destroy_cm_id) to
- * get woken up, and return 1 if a thread is already waiting.
+ * released, free the cm_id and return 1.
  */
 static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
 {
        BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
        if (atomic_dec_and_test(&cm_id_priv->refcount)) {
                BUG_ON(!list_empty(&cm_id_priv->work_list));
-               complete(&cm_id_priv->destroy_comp);
+               free_cm_id(cm_id_priv);
                return 1;
        }
 
@@ -208,19 +207,10 @@ static void add_ref(struct iw_cm_id *cm_id)
 static void rem_ref(struct iw_cm_id *cm_id)
 {
        struct iwcm_id_private *cm_id_priv;
-       int cb_destroy;
 
        cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
 
-       /*
-        * Test bit before deref in case the cm_id gets freed on another
-        * thread.
-        */
-       cb_destroy = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
-       if (iwcm_deref_id(cm_id_priv) && cb_destroy) {
-               BUG_ON(!list_empty(&cm_id_priv->work_list));
-               free_cm_id(cm_id_priv);
-       }
+       (void)iwcm_deref_id(cm_id_priv);
 }
 
 static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
@@ -370,6 +360,12 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
        wait_event(cm_id_priv->connect_wait,
                   !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
 
+       /*
+        * Since we're deleting the cm_id, drop any events that
+        * might arrive before the last dereference.
+        */
+       set_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags);
+
        spin_lock_irqsave(&cm_id_priv->lock, flags);
        switch (cm_id_priv->state) {
        case IW_CM_STATE_LISTEN:
@@ -433,13 +429,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
        struct iwcm_id_private *cm_id_priv;
 
        cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
-       BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags));
-
        destroy_cm_id(cm_id);
-
-       wait_for_completion(&cm_id_priv->destroy_comp);
-
-       free_cm_id(cm_id_priv);
 }
 EXPORT_SYMBOL(iw_destroy_cm_id);
 
@@ -809,10 +799,7 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
        ret = cm_id->cm_handler(cm_id, iw_event);
        if (ret) {
                iw_cm_reject(cm_id, NULL, 0);
-               set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
-               destroy_cm_id(cm_id);
-               if (atomic_read(&cm_id_priv->refcount)==0)
-                       free_cm_id(cm_id_priv);
+               iw_destroy_cm_id(cm_id);
        }
 
 out:
@@ -1000,7 +987,6 @@ static void cm_work_handler(struct work_struct *_work)
        unsigned long flags;
        int empty;
        int ret = 0;
-       int destroy_id;
 
        spin_lock_irqsave(&cm_id_priv->lock, flags);
        empty = list_empty(&cm_id_priv->work_list);
@@ -1013,20 +999,14 @@ static void cm_work_handler(struct work_struct *_work)
                put_work(work);
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-               ret = process_event(cm_id_priv, &levent);
-               if (ret) {
-                       set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
-                       destroy_cm_id(&cm_id_priv->id);
-               }
-               BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
-               destroy_id = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
-               if (iwcm_deref_id(cm_id_priv)) {
-                       if (destroy_id) {
-                               BUG_ON(!list_empty(&cm_id_priv->work_list));
-                               free_cm_id(cm_id_priv);
-                       }
+               if (!test_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags)) {
+                       ret = process_event(cm_id_priv, &levent);
+                       if (ret)
+                               destroy_cm_id(&cm_id_priv->id);
+               } else
+                       pr_debug("dropping event %d\n", levent.event);
+               if (iwcm_deref_id(cm_id_priv))
                        return;
-               }
                if (empty)
                        return;
                spin_lock_irqsave(&cm_id_priv->lock, flags);
index 3f6cc82..82c2cd1 100644 (file)
@@ -56,7 +56,7 @@ struct iwcm_id_private {
        struct list_head work_free_list;
 };
 
-#define IWCM_F_CALLBACK_DESTROY   1
+#define IWCM_F_DROP_EVENTS       1
 #define IWCM_F_CONNECT_WAIT       2
 
 #endif /* IWCM_H */
index b65e06c..ade71e7 100644 (file)
@@ -37,6 +37,7 @@
 #define IWPM_MAPINFO_HASH_MASK (IWPM_MAPINFO_HASH_SIZE - 1)
 #define IWPM_REMINFO_HASH_SIZE 64
 #define IWPM_REMINFO_HASH_MASK (IWPM_REMINFO_HASH_SIZE - 1)
+#define IWPM_MSG_SIZE          512
 
 static LIST_HEAD(iwpm_nlmsg_req_list);
 static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
@@ -452,7 +453,7 @@ struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
 {
        struct sk_buff *skb = NULL;
 
-       skb = dev_alloc_skb(NLMSG_GOODSIZE);
+       skb = dev_alloc_skb(IWPM_MSG_SIZE);
        if (!skb) {
                pr_err("%s Unable to allocate skb\n", __func__);
                goto create_nlmsg_exit;
index a83ec28..3a3c5d7 100644 (file)
@@ -93,18 +93,6 @@ enum {
 
 struct mcast_member;
 
-/*
-* There are 4 types of join states:
-* FullMember, NonMember, SendOnlyNonMember, SendOnlyFullMember.
-*/
-enum {
-       FULLMEMBER_JOIN,
-       NONMEMBER_JOIN,
-       SENDONLY_NONMEBER_JOIN,
-       SENDONLY_FULLMEMBER_JOIN,
-       NUM_JOIN_MEMBERSHIP_TYPES,
-};
-
 struct mcast_group {
        struct ib_sa_mcmember_rec rec;
        struct rb_node          node;
index 9b8c20c..10469b0 100644 (file)
@@ -229,7 +229,10 @@ static void ibnl_rcv(struct sk_buff *skb)
 int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh,
                        __u32 pid)
 {
-       return nlmsg_unicast(nls, skb, pid);
+       int err;
+
+       err = netlink_unicast(nls, skb, pid, 0);
+       return (err < 0) ? err : 0;
 }
 EXPORT_SYMBOL(ibnl_unicast);
 
@@ -252,6 +255,7 @@ int __init ibnl_init(void)
                return -ENOMEM;
        }
 
+       nls->sk_sndtimeo = 10 * HZ;
        return 0;
 }
 
index 1eb9b12..dbfd854 100644 (file)
@@ -58,19 +58,13 @@ static inline bool rdma_rw_io_needs_mr(struct ib_device *dev, u8 port_num,
        return false;
 }
 
-static inline u32 rdma_rw_max_sge(struct ib_device *dev,
-               enum dma_data_direction dir)
-{
-       return dir == DMA_TO_DEVICE ?
-               dev->attrs.max_sge : dev->attrs.max_sge_rd;
-}
-
 static inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev)
 {
        /* arbitrary limit to avoid allocating gigantic resources */
        return min_t(u32, dev->attrs.max_fast_reg_page_list_len, 256);
 }
 
+/* Caller must have zero-initialized *reg. */
 static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num,
                struct rdma_rw_reg_ctx *reg, struct scatterlist *sg,
                u32 sg_cnt, u32 offset)
@@ -114,6 +108,7 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
                u8 port_num, struct scatterlist *sg, u32 sg_cnt, u32 offset,
                u64 remote_addr, u32 rkey, enum dma_data_direction dir)
 {
+       struct rdma_rw_reg_ctx *prev = NULL;
        u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device);
        int i, j, ret = 0, count = 0;
 
@@ -125,7 +120,6 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
        }
 
        for (i = 0; i < ctx->nr_ops; i++) {
-               struct rdma_rw_reg_ctx *prev = i ? &ctx->reg[i - 1] : NULL;
                struct rdma_rw_reg_ctx *reg = &ctx->reg[i];
                u32 nents = min(sg_cnt, pages_per_mr);
 
@@ -162,9 +156,13 @@ static int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
                sg_cnt -= nents;
                for (j = 0; j < nents; j++)
                        sg = sg_next(sg);
+               prev = reg;
                offset = 0;
        }
 
+       if (prev)
+               prev->wr.wr.next = NULL;
+
        ctx->type = RDMA_RW_MR;
        return count;
 
@@ -181,7 +179,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
                u64 remote_addr, u32 rkey, enum dma_data_direction dir)
 {
        struct ib_device *dev = qp->pd->device;
-       u32 max_sge = rdma_rw_max_sge(dev, dir);
+       u32 max_sge = dir == DMA_TO_DEVICE ? qp->max_write_sge :
+                     qp->max_read_sge;
        struct ib_sge *sge;
        u32 total_len = 0, i, j;
 
@@ -205,11 +204,10 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
                        rdma_wr->wr.opcode = IB_WR_RDMA_READ;
                rdma_wr->remote_addr = remote_addr + total_len;
                rdma_wr->rkey = rkey;
+               rdma_wr->wr.num_sge = nr_sge;
                rdma_wr->wr.sg_list = sge;
 
                for (j = 0; j < nr_sge; j++, sg = sg_next(sg)) {
-                       rdma_wr->wr.num_sge++;
-
                        sge->addr = ib_sg_dma_address(dev, sg) + offset;
                        sge->length = ib_sg_dma_len(dev, sg) - offset;
                        sge->lkey = qp->pd->local_dma_lkey;
@@ -220,8 +218,8 @@ static int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
                        offset = 0;
                }
 
-               if (i + 1 < ctx->nr_ops)
-                       rdma_wr->wr.next = &ctx->map.wrs[i + 1].wr;
+               rdma_wr->wr.next = i + 1 < ctx->nr_ops ?
+                       &ctx->map.wrs[i + 1].wr : NULL;
        }
 
        ctx->type = RDMA_RW_MULTI_WR;
index e955386..b9bf7aa 100644 (file)
@@ -65,10 +65,17 @@ struct ib_sa_sm_ah {
        u8                   src_path_mask;
 };
 
+struct ib_sa_classport_cache {
+       bool valid;
+       struct ib_class_port_info data;
+};
+
 struct ib_sa_port {
        struct ib_mad_agent *agent;
        struct ib_sa_sm_ah  *sm_ah;
        struct work_struct   update_task;
+       struct ib_sa_classport_cache classport_info;
+       spinlock_t                   classport_lock; /* protects class port info set */
        spinlock_t           ah_lock;
        u8                   port_num;
 };
@@ -998,6 +1005,13 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
                port->sm_ah = NULL;
                spin_unlock_irqrestore(&port->ah_lock, flags);
 
+               if (event->event == IB_EVENT_SM_CHANGE ||
+                   event->event == IB_EVENT_CLIENT_REREGISTER ||
+                   event->event == IB_EVENT_LID_CHANGE) {
+                       spin_lock_irqsave(&port->classport_lock, flags);
+                       port->classport_info.valid = false;
+                       spin_unlock_irqrestore(&port->classport_lock, flags);
+               }
                queue_work(ib_wq, &sa_dev->port[event->element.port_num -
                                            sa_dev->start_port].update_task);
        }
@@ -1719,6 +1733,7 @@ static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query,
                                              int status,
                                              struct ib_sa_mad *mad)
 {
+       unsigned long flags;
        struct ib_sa_classport_info_query *query =
                container_of(sa_query, struct ib_sa_classport_info_query, sa_query);
 
@@ -1728,6 +1743,16 @@ static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query,
                ib_unpack(classport_info_rec_table,
                          ARRAY_SIZE(classport_info_rec_table),
                          mad->data, &rec);
+
+               spin_lock_irqsave(&sa_query->port->classport_lock, flags);
+               if (!status && !sa_query->port->classport_info.valid) {
+                       memcpy(&sa_query->port->classport_info.data, &rec,
+                              sizeof(sa_query->port->classport_info.data));
+
+                       sa_query->port->classport_info.valid = true;
+               }
+               spin_unlock_irqrestore(&sa_query->port->classport_lock, flags);
+
                query->callback(status, &rec, query->context);
        } else {
                query->callback(status, NULL, query->context);
@@ -1754,7 +1779,9 @@ int ib_sa_classport_info_rec_query(struct ib_sa_client *client,
        struct ib_sa_port *port;
        struct ib_mad_agent *agent;
        struct ib_sa_mad *mad;
+       struct ib_class_port_info cached_class_port_info;
        int ret;
+       unsigned long flags;
 
        if (!sa_dev)
                return -ENODEV;
@@ -1762,6 +1789,17 @@ int ib_sa_classport_info_rec_query(struct ib_sa_client *client,
        port  = &sa_dev->port[port_num - sa_dev->start_port];
        agent = port->agent;
 
+       /* Use cached ClassPortInfo attribute if valid instead of sending mad */
+       spin_lock_irqsave(&port->classport_lock, flags);
+       if (port->classport_info.valid && callback) {
+               memcpy(&cached_class_port_info, &port->classport_info.data,
+                      sizeof(cached_class_port_info));
+               spin_unlock_irqrestore(&port->classport_lock, flags);
+               callback(0, &cached_class_port_info, context);
+               return 0;
+       }
+       spin_unlock_irqrestore(&port->classport_lock, flags);
+
        query = kzalloc(sizeof(*query), gfp_mask);
        if (!query)
                return -ENOMEM;
@@ -1885,6 +1923,9 @@ static void ib_sa_add_one(struct ib_device *device)
                sa_dev->port[i].sm_ah    = NULL;
                sa_dev->port[i].port_num = i + s;
 
+               spin_lock_init(&sa_dev->port[i].classport_lock);
+               sa_dev->port[i].classport_info.valid = false;
+
                sa_dev->port[i].agent =
                        ib_register_mad_agent(device, i + s, IB_QPT_GSI,
                                              NULL, 0, send_handler,
index 60df4f8..15defef 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 
 #include <rdma/ib_mad.h>
 #include <rdma/ib_pma.h>
@@ -1200,16 +1201,28 @@ static ssize_t set_node_desc(struct device *device,
        return count;
 }
 
+static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
+                          char *buf)
+{
+       struct ib_device *dev = container_of(device, struct ib_device, dev);
+
+       ib_get_device_fw_str(dev, buf, PAGE_SIZE);
+       strlcat(buf, "\n", PAGE_SIZE);
+       return strlen(buf);
+}
+
 static DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
 static DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL);
 static DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL);
 static DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc, set_node_desc);
+static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
 
 static struct device_attribute *ib_class_attributes[] = {
        &dev_attr_node_type,
        &dev_attr_sys_image_guid,
        &dev_attr_node_guid,
-       &dev_attr_node_desc
+       &dev_attr_node_desc,
+       &dev_attr_fw_ver,
 };
 
 static void free_port_list_attributes(struct ib_device *device)
index c0f3826..2825ece 100644 (file)
@@ -106,6 +106,7 @@ struct ucma_multicast {
        int                     events_reported;
 
        u64                     uid;
+       u8                      join_state;
        struct list_head        list;
        struct sockaddr_storage addr;
 };
@@ -1317,12 +1318,20 @@ static ssize_t ucma_process_join(struct ucma_file *file,
        struct ucma_multicast *mc;
        struct sockaddr *addr;
        int ret;
+       u8 join_state;
 
        if (out_len < sizeof(resp))
                return -ENOSPC;
 
        addr = (struct sockaddr *) &cmd->addr;
-       if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+       if (!cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+               return -EINVAL;
+
+       if (cmd->join_flags == RDMA_MC_JOIN_FLAG_FULLMEMBER)
+               join_state = BIT(FULLMEMBER_JOIN);
+       else if (cmd->join_flags == RDMA_MC_JOIN_FLAG_SENDONLY_FULLMEMBER)
+               join_state = BIT(SENDONLY_FULLMEMBER_JOIN);
+       else
                return -EINVAL;
 
        ctx = ucma_get_ctx(file, cmd->id);
@@ -1335,10 +1344,11 @@ static ssize_t ucma_process_join(struct ucma_file *file,
                ret = -ENOMEM;
                goto err1;
        }
-
+       mc->join_state = join_state;
        mc->uid = cmd->uid;
        memcpy(&mc->addr, addr, cmd->addr_size);
-       ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);
+       ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
+                                 join_state, mc);
        if (ret)
                goto err2;
 
@@ -1382,7 +1392,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
        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;
+       join_cmd.join_flags = RDMA_MC_JOIN_FLAG_FULLMEMBER;
        memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
 
        return ucma_process_join(file, &join_cmd, out_len);
index fe4d2e1..c68746c 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/sched.h>
 #include <linux/export.h>
 #include <linux/hugetlb.h>
-#include <linux/dma-attrs.h>
 #include <linux/slab.h>
 #include <rdma/ib_umem_odp.h>
 
@@ -92,12 +91,12 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
        unsigned long npages;
        int ret;
        int i;
-       DEFINE_DMA_ATTRS(attrs);
+       unsigned long dma_attrs = 0;
        struct scatterlist *sg, *sg_list_start;
        int need_release = 0;
 
        if (dmasync)
-               dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
+               dma_attrs |= DMA_ATTR_WRITE_BARRIER;
 
        if (!size)
                return ERR_PTR(-EINVAL);
@@ -215,7 +214,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
                                  umem->sg_head.sgl,
                                  umem->npages,
                                  DMA_BIDIRECTIONAL,
-                                 &attrs);
+                                 dma_attrs);
 
        if (umem->nmap <= 0) {
                ret = -ENOMEM;
index 612ccfd..df26a74 100644 (file)
@@ -116,6 +116,7 @@ struct ib_uverbs_event_file {
 struct ib_uverbs_file {
        struct kref                             ref;
        struct mutex                            mutex;
+       struct mutex                            cleanup_mutex; /* protect cleanup */
        struct ib_uverbs_device                *device;
        struct ib_ucontext                     *ucontext;
        struct ib_event_handler                 event_handler;
@@ -162,6 +163,10 @@ struct ib_uqp_object {
        struct ib_uxrcd_object *uxrcd;
 };
 
+struct ib_uwq_object {
+       struct ib_uevent_object uevent;
+};
+
 struct ib_ucq_object {
        struct ib_uobject       uobject;
        struct ib_uverbs_file  *uverbs_file;
@@ -181,6 +186,8 @@ extern struct idr ib_uverbs_qp_idr;
 extern struct idr ib_uverbs_srq_idr;
 extern struct idr ib_uverbs_xrcd_idr;
 extern struct idr ib_uverbs_rule_idr;
+extern struct idr ib_uverbs_wq_idr;
+extern struct idr ib_uverbs_rwq_ind_tbl_idr;
 
 void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
 
@@ -199,6 +206,7 @@ void ib_uverbs_release_uevent(struct ib_uverbs_file *file,
 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_wq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_event_handler(struct ib_event_handler *handler,
                             struct ib_event *event);
@@ -219,6 +227,7 @@ struct ib_uverbs_flow_spec {
                struct ib_uverbs_flow_spec_eth     eth;
                struct ib_uverbs_flow_spec_ipv4    ipv4;
                struct ib_uverbs_flow_spec_tcp_udp tcp_udp;
+               struct ib_uverbs_flow_spec_ipv6    ipv6;
        };
 };
 
@@ -275,5 +284,10 @@ IB_UVERBS_DECLARE_EX_CMD(destroy_flow);
 IB_UVERBS_DECLARE_EX_CMD(query_device);
 IB_UVERBS_DECLARE_EX_CMD(create_cq);
 IB_UVERBS_DECLARE_EX_CMD(create_qp);
+IB_UVERBS_DECLARE_EX_CMD(create_wq);
+IB_UVERBS_DECLARE_EX_CMD(modify_wq);
+IB_UVERBS_DECLARE_EX_CMD(destroy_wq);
+IB_UVERBS_DECLARE_EX_CMD(create_rwq_ind_table);
+IB_UVERBS_DECLARE_EX_CMD(destroy_rwq_ind_table);
 
 #endif /* UVERBS_H */
index 825021d..f664731 100644 (file)
@@ -57,6 +57,8 @@ static struct uverbs_lock_class ah_lock_class = { .name = "AH-uobj" };
 static struct uverbs_lock_class srq_lock_class = { .name = "SRQ-uobj" };
 static struct uverbs_lock_class xrcd_lock_class = { .name = "XRCD-uobj" };
 static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
+static struct uverbs_lock_class wq_lock_class = { .name = "WQ-uobj" };
+static struct uverbs_lock_class rwq_ind_table_lock_class = { .name = "IND_TBL-uobj" };
 
 /*
  * The ib_uobject locking scheme is as follows:
@@ -243,6 +245,27 @@ static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
        return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
 }
 
+static struct ib_wq *idr_read_wq(int wq_handle, struct ib_ucontext *context)
+{
+       return idr_read_obj(&ib_uverbs_wq_idr, wq_handle, context, 0);
+}
+
+static void put_wq_read(struct ib_wq *wq)
+{
+       put_uobj_read(wq->uobject);
+}
+
+static struct ib_rwq_ind_table *idr_read_rwq_indirection_table(int ind_table_handle,
+                                                              struct ib_ucontext *context)
+{
+       return idr_read_obj(&ib_uverbs_rwq_ind_tbl_idr, ind_table_handle, context, 0);
+}
+
+static void put_rwq_indirection_table_read(struct ib_rwq_ind_table *ind_table)
+{
+       put_uobj_read(ind_table->uobject);
+}
+
 static struct ib_qp *idr_write_qp(int qp_handle, struct ib_ucontext *context)
 {
        struct ib_uobject *uobj;
@@ -326,6 +349,8 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
        INIT_LIST_HEAD(&ucontext->qp_list);
        INIT_LIST_HEAD(&ucontext->srq_list);
        INIT_LIST_HEAD(&ucontext->ah_list);
+       INIT_LIST_HEAD(&ucontext->wq_list);
+       INIT_LIST_HEAD(&ucontext->rwq_ind_tbl_list);
        INIT_LIST_HEAD(&ucontext->xrcd_list);
        INIT_LIST_HEAD(&ucontext->rule_list);
        rcu_read_lock();
@@ -1750,6 +1775,8 @@ static int create_qp(struct ib_uverbs_file *file,
        struct ib_qp_init_attr          attr = {};
        struct ib_uverbs_ex_create_qp_resp resp;
        int                             ret;
+       struct ib_rwq_ind_table *ind_tbl = NULL;
+       bool has_sq = true;
 
        if (cmd->qp_type == IB_QPT_RAW_PACKET && !capable(CAP_NET_RAW))
                return -EPERM;
@@ -1761,6 +1788,32 @@ static int create_qp(struct ib_uverbs_file *file,
        init_uobj(&obj->uevent.uobject, cmd->user_handle, file->ucontext,
                  &qp_lock_class);
        down_write(&obj->uevent.uobject.mutex);
+       if (cmd_sz >= offsetof(typeof(*cmd), rwq_ind_tbl_handle) +
+                     sizeof(cmd->rwq_ind_tbl_handle) &&
+                     (cmd->comp_mask & IB_UVERBS_CREATE_QP_MASK_IND_TABLE)) {
+               ind_tbl = idr_read_rwq_indirection_table(cmd->rwq_ind_tbl_handle,
+                                                        file->ucontext);
+               if (!ind_tbl) {
+                       ret = -EINVAL;
+                       goto err_put;
+               }
+
+               attr.rwq_ind_tbl = ind_tbl;
+       }
+
+       if ((cmd_sz >= offsetof(typeof(*cmd), reserved1) +
+                      sizeof(cmd->reserved1)) && cmd->reserved1) {
+               ret = -EOPNOTSUPP;
+               goto err_put;
+       }
+
+       if (ind_tbl && (cmd->max_recv_wr || cmd->max_recv_sge || cmd->is_srq)) {
+               ret = -EINVAL;
+               goto err_put;
+       }
+
+       if (ind_tbl && !cmd->max_send_wr)
+               has_sq = false;
 
        if (cmd->qp_type == IB_QPT_XRC_TGT) {
                xrcd = idr_read_xrcd(cmd->pd_handle, file->ucontext,
@@ -1784,20 +1837,24 @@ static int create_qp(struct ib_uverbs_file *file,
                                }
                        }
 
-                       if (cmd->recv_cq_handle != cmd->send_cq_handle) {
-                               rcq = idr_read_cq(cmd->recv_cq_handle,
-                                                 file->ucontext, 0);
-                               if (!rcq) {
-                                       ret = -EINVAL;
-                                       goto err_put;
+                       if (!ind_tbl) {
+                               if (cmd->recv_cq_handle != cmd->send_cq_handle) {
+                                       rcq = idr_read_cq(cmd->recv_cq_handle,
+                                                         file->ucontext, 0);
+                                       if (!rcq) {
+                                               ret = -EINVAL;
+                                               goto err_put;
+                                       }
                                }
                        }
                }
 
-               scq = idr_read_cq(cmd->send_cq_handle, file->ucontext, !!rcq);
-               rcq = rcq ?: scq;
+               if (has_sq)
+                       scq = idr_read_cq(cmd->send_cq_handle, file->ucontext, !!rcq);
+               if (!ind_tbl)
+                       rcq = rcq ?: scq;
                pd  = idr_read_pd(cmd->pd_handle, file->ucontext);
-               if (!pd || !scq) {
+               if (!pd || (!scq && has_sq)) {
                        ret = -EINVAL;
                        goto err_put;
                }
@@ -1864,16 +1921,20 @@ static int create_qp(struct ib_uverbs_file *file,
                qp->send_cq       = attr.send_cq;
                qp->recv_cq       = attr.recv_cq;
                qp->srq           = attr.srq;
+               qp->rwq_ind_tbl   = ind_tbl;
                qp->event_handler = attr.event_handler;
                qp->qp_context    = attr.qp_context;
                qp->qp_type       = attr.qp_type;
                atomic_set(&qp->usecnt, 0);
                atomic_inc(&pd->usecnt);
-               atomic_inc(&attr.send_cq->usecnt);
+               if (attr.send_cq)
+                       atomic_inc(&attr.send_cq->usecnt);
                if (attr.recv_cq)
                        atomic_inc(&attr.recv_cq->usecnt);
                if (attr.srq)
                        atomic_inc(&attr.srq->usecnt);
+               if (ind_tbl)
+                       atomic_inc(&ind_tbl->usecnt);
        }
        qp->uobject = &obj->uevent.uobject;
 
@@ -1913,6 +1974,8 @@ static int create_qp(struct ib_uverbs_file *file,
                put_cq_read(rcq);
        if (srq)
                put_srq_read(srq);
+       if (ind_tbl)
+               put_rwq_indirection_table_read(ind_tbl);
 
        mutex_lock(&file->mutex);
        list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list);
@@ -1940,6 +2003,8 @@ err_put:
                put_cq_read(rcq);
        if (srq)
                put_srq_read(srq);
+       if (ind_tbl)
+               put_rwq_indirection_table_read(ind_tbl);
 
        put_uobj_write(&obj->uevent.uobject);
        return ret;
@@ -2033,7 +2098,7 @@ int ib_uverbs_ex_create_qp(struct ib_uverbs_file *file,
        if (err)
                return err;
 
-       if (cmd.comp_mask)
+       if (cmd.comp_mask & ~IB_UVERBS_CREATE_QP_SUP_COMP_MASK)
                return -EINVAL;
 
        if (cmd.reserved)
@@ -3040,6 +3105,15 @@ static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
                memcpy(&ib_spec->ipv4.mask, &kern_spec->ipv4.mask,
                       sizeof(struct ib_flow_ipv4_filter));
                break;
+       case IB_FLOW_SPEC_IPV6:
+               ib_spec->ipv6.size = sizeof(struct ib_flow_spec_ipv6);
+               if (ib_spec->ipv6.size != kern_spec->ipv6.size)
+                       return -EINVAL;
+               memcpy(&ib_spec->ipv6.val, &kern_spec->ipv6.val,
+                      sizeof(struct ib_flow_ipv6_filter));
+               memcpy(&ib_spec->ipv6.mask, &kern_spec->ipv6.mask,
+                      sizeof(struct ib_flow_ipv6_filter));
+               break;
        case IB_FLOW_SPEC_TCP:
        case IB_FLOW_SPEC_UDP:
                ib_spec->tcp_udp.size = sizeof(struct ib_flow_spec_tcp_udp);
@@ -3056,6 +3130,445 @@ static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec,
        return 0;
 }
 
+int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
+                          struct ib_device *ib_dev,
+                          struct ib_udata *ucore,
+                          struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_create_wq     cmd = {};
+       struct ib_uverbs_ex_create_wq_resp resp = {};
+       struct ib_uwq_object           *obj;
+       int err = 0;
+       struct ib_cq *cq;
+       struct ib_pd *pd;
+       struct ib_wq *wq;
+       struct ib_wq_init_attr wq_init_attr = {};
+       size_t required_cmd_sz;
+       size_t required_resp_len;
+
+       required_cmd_sz = offsetof(typeof(cmd), max_sge) + sizeof(cmd.max_sge);
+       required_resp_len = offsetof(typeof(resp), wqn) + sizeof(resp.wqn);
+
+       if (ucore->inlen < required_cmd_sz)
+               return -EINVAL;
+
+       if (ucore->outlen < required_resp_len)
+               return -ENOSPC;
+
+       if (ucore->inlen > sizeof(cmd) &&
+           !ib_is_udata_cleared(ucore, sizeof(cmd),
+                                ucore->inlen - sizeof(cmd)))
+               return -EOPNOTSUPP;
+
+       err = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
+       if (err)
+               return err;
+
+       if (cmd.comp_mask)
+               return -EOPNOTSUPP;
+
+       obj = kmalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               return -ENOMEM;
+
+       init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext,
+                 &wq_lock_class);
+       down_write(&obj->uevent.uobject.mutex);
+       pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
+       if (!pd) {
+               err = -EINVAL;
+               goto err_uobj;
+       }
+
+       cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+       if (!cq) {
+               err = -EINVAL;
+               goto err_put_pd;
+       }
+
+       wq_init_attr.cq = cq;
+       wq_init_attr.max_sge = cmd.max_sge;
+       wq_init_attr.max_wr = cmd.max_wr;
+       wq_init_attr.wq_context = file;
+       wq_init_attr.wq_type = cmd.wq_type;
+       wq_init_attr.event_handler = ib_uverbs_wq_event_handler;
+       obj->uevent.events_reported = 0;
+       INIT_LIST_HEAD(&obj->uevent.event_list);
+       wq = pd->device->create_wq(pd, &wq_init_attr, uhw);
+       if (IS_ERR(wq)) {
+               err = PTR_ERR(wq);
+               goto err_put_cq;
+       }
+
+       wq->uobject = &obj->uevent.uobject;
+       obj->uevent.uobject.object = wq;
+       wq->wq_type = wq_init_attr.wq_type;
+       wq->cq = cq;
+       wq->pd = pd;
+       wq->device = pd->device;
+       wq->wq_context = wq_init_attr.wq_context;
+       atomic_set(&wq->usecnt, 0);
+       atomic_inc(&pd->usecnt);
+       atomic_inc(&cq->usecnt);
+       wq->uobject = &obj->uevent.uobject;
+       obj->uevent.uobject.object = wq;
+       err = idr_add_uobj(&ib_uverbs_wq_idr, &obj->uevent.uobject);
+       if (err)
+               goto destroy_wq;
+
+       memset(&resp, 0, sizeof(resp));
+       resp.wq_handle = obj->uevent.uobject.id;
+       resp.max_sge = wq_init_attr.max_sge;
+       resp.max_wr = wq_init_attr.max_wr;
+       resp.wqn = wq->wq_num;
+       resp.response_length = required_resp_len;
+       err = ib_copy_to_udata(ucore,
+                              &resp, resp.response_length);
+       if (err)
+               goto err_copy;
+
+       put_pd_read(pd);
+       put_cq_read(cq);
+
+       mutex_lock(&file->mutex);
+       list_add_tail(&obj->uevent.uobject.list, &file->ucontext->wq_list);
+       mutex_unlock(&file->mutex);
+
+       obj->uevent.uobject.live = 1;
+       up_write(&obj->uevent.uobject.mutex);
+       return 0;
+
+err_copy:
+       idr_remove_uobj(&ib_uverbs_wq_idr, &obj->uevent.uobject);
+destroy_wq:
+       ib_destroy_wq(wq);
+err_put_cq:
+       put_cq_read(cq);
+err_put_pd:
+       put_pd_read(pd);
+err_uobj:
+       put_uobj_write(&obj->uevent.uobject);
+
+       return err;
+}
+
+int ib_uverbs_ex_destroy_wq(struct ib_uverbs_file *file,
+                           struct ib_device *ib_dev,
+                           struct ib_udata *ucore,
+                           struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_destroy_wq  cmd = {};
+       struct ib_uverbs_ex_destroy_wq_resp     resp = {};
+       struct ib_wq                    *wq;
+       struct ib_uobject               *uobj;
+       struct ib_uwq_object            *obj;
+       size_t required_cmd_sz;
+       size_t required_resp_len;
+       int                             ret;
+
+       required_cmd_sz = offsetof(typeof(cmd), wq_handle) + sizeof(cmd.wq_handle);
+       required_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
+
+       if (ucore->inlen < required_cmd_sz)
+               return -EINVAL;
+
+       if (ucore->outlen < required_resp_len)
+               return -ENOSPC;
+
+       if (ucore->inlen > sizeof(cmd) &&
+           !ib_is_udata_cleared(ucore, sizeof(cmd),
+                                ucore->inlen - sizeof(cmd)))
+               return -EOPNOTSUPP;
+
+       ret = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
+       if (ret)
+               return ret;
+
+       if (cmd.comp_mask)
+               return -EOPNOTSUPP;
+
+       resp.response_length = required_resp_len;
+       uobj = idr_write_uobj(&ib_uverbs_wq_idr, cmd.wq_handle,
+                             file->ucontext);
+       if (!uobj)
+               return -EINVAL;
+
+       wq = uobj->object;
+       obj = container_of(uobj, struct ib_uwq_object, uevent.uobject);
+       ret = ib_destroy_wq(wq);
+       if (!ret)
+               uobj->live = 0;
+
+       put_uobj_write(uobj);
+       if (ret)
+               return ret;
+
+       idr_remove_uobj(&ib_uverbs_wq_idr, uobj);
+
+       mutex_lock(&file->mutex);
+       list_del(&uobj->list);
+       mutex_unlock(&file->mutex);
+
+       ib_uverbs_release_uevent(file, &obj->uevent);
+       resp.events_reported = obj->uevent.events_reported;
+       put_uobj(uobj);
+
+       ret = ib_copy_to_udata(ucore, &resp, resp.response_length);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
+                          struct ib_device *ib_dev,
+                          struct ib_udata *ucore,
+                          struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_modify_wq cmd = {};
+       struct ib_wq *wq;
+       struct ib_wq_attr wq_attr = {};
+       size_t required_cmd_sz;
+       int ret;
+
+       required_cmd_sz = offsetof(typeof(cmd), curr_wq_state) + sizeof(cmd.curr_wq_state);
+       if (ucore->inlen < required_cmd_sz)
+               return -EINVAL;
+
+       if (ucore->inlen > sizeof(cmd) &&
+           !ib_is_udata_cleared(ucore, sizeof(cmd),
+                                ucore->inlen - sizeof(cmd)))
+               return -EOPNOTSUPP;
+
+       ret = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
+       if (ret)
+               return ret;
+
+       if (!cmd.attr_mask)
+               return -EINVAL;
+
+       if (cmd.attr_mask > (IB_WQ_STATE | IB_WQ_CUR_STATE))
+               return -EINVAL;
+
+       wq = idr_read_wq(cmd.wq_handle, file->ucontext);
+       if (!wq)
+               return -EINVAL;
+
+       wq_attr.curr_wq_state = cmd.curr_wq_state;
+       wq_attr.wq_state = cmd.wq_state;
+       ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw);
+       put_wq_read(wq);
+       return ret;
+}
+
+int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
+                                     struct ib_device *ib_dev,
+                                     struct ib_udata *ucore,
+                                     struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_create_rwq_ind_table          cmd = {};
+       struct ib_uverbs_ex_create_rwq_ind_table_resp  resp = {};
+       struct ib_uobject                 *uobj;
+       int err = 0;
+       struct ib_rwq_ind_table_init_attr init_attr = {};
+       struct ib_rwq_ind_table *rwq_ind_tbl;
+       struct ib_wq    **wqs = NULL;
+       u32 *wqs_handles = NULL;
+       struct ib_wq    *wq = NULL;
+       int i, j, num_read_wqs;
+       u32 num_wq_handles;
+       u32 expected_in_size;
+       size_t required_cmd_sz_header;
+       size_t required_resp_len;
+
+       required_cmd_sz_header = offsetof(typeof(cmd), log_ind_tbl_size) + sizeof(cmd.log_ind_tbl_size);
+       required_resp_len = offsetof(typeof(resp), ind_tbl_num) + sizeof(resp.ind_tbl_num);
+
+       if (ucore->inlen < required_cmd_sz_header)
+               return -EINVAL;
+
+       if (ucore->outlen < required_resp_len)
+               return -ENOSPC;
+
+       err = ib_copy_from_udata(&cmd, ucore, required_cmd_sz_header);
+       if (err)
+               return err;
+
+       ucore->inbuf += required_cmd_sz_header;
+       ucore->inlen -= required_cmd_sz_header;
+
+       if (cmd.comp_mask)
+               return -EOPNOTSUPP;
+
+       if (cmd.log_ind_tbl_size > IB_USER_VERBS_MAX_LOG_IND_TBL_SIZE)
+               return -EINVAL;
+
+       num_wq_handles = 1 << cmd.log_ind_tbl_size;
+       expected_in_size = num_wq_handles * sizeof(__u32);
+       if (num_wq_handles == 1)
+               /* input size for wq handles is u64 aligned */
+               expected_in_size += sizeof(__u32);
+
+       if (ucore->inlen < expected_in_size)
+               return -EINVAL;
+
+       if (ucore->inlen > expected_in_size &&
+           !ib_is_udata_cleared(ucore, expected_in_size,
+                                ucore->inlen - expected_in_size))
+               return -EOPNOTSUPP;
+
+       wqs_handles = kcalloc(num_wq_handles, sizeof(*wqs_handles),
+                             GFP_KERNEL);
+       if (!wqs_handles)
+               return -ENOMEM;
+
+       err = ib_copy_from_udata(wqs_handles, ucore,
+                                num_wq_handles * sizeof(__u32));
+       if (err)
+               goto err_free;
+
+       wqs = kcalloc(num_wq_handles, sizeof(*wqs), GFP_KERNEL);
+       if (!wqs) {
+               err = -ENOMEM;
+               goto  err_free;
+       }
+
+       for (num_read_wqs = 0; num_read_wqs < num_wq_handles;
+                       num_read_wqs++) {
+               wq = idr_read_wq(wqs_handles[num_read_wqs], file->ucontext);
+               if (!wq) {
+                       err = -EINVAL;
+                       goto put_wqs;
+               }
+
+               wqs[num_read_wqs] = wq;
+       }
+
+       uobj = kmalloc(sizeof(*uobj), GFP_KERNEL);
+       if (!uobj) {
+               err = -ENOMEM;
+               goto put_wqs;
+       }
+
+       init_uobj(uobj, 0, file->ucontext, &rwq_ind_table_lock_class);
+       down_write(&uobj->mutex);
+       init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
+       init_attr.ind_tbl = wqs;
+       rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw);
+
+       if (IS_ERR(rwq_ind_tbl)) {
+               err = PTR_ERR(rwq_ind_tbl);
+               goto err_uobj;
+       }
+
+       rwq_ind_tbl->ind_tbl = wqs;
+       rwq_ind_tbl->log_ind_tbl_size = init_attr.log_ind_tbl_size;
+       rwq_ind_tbl->uobject = uobj;
+       uobj->object = rwq_ind_tbl;
+       rwq_ind_tbl->device = ib_dev;
+       atomic_set(&rwq_ind_tbl->usecnt, 0);
+
+       for (i = 0; i < num_wq_handles; i++)
+               atomic_inc(&wqs[i]->usecnt);
+
+       err = idr_add_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+       if (err)
+               goto destroy_ind_tbl;
+
+       resp.ind_tbl_handle = uobj->id;
+       resp.ind_tbl_num = rwq_ind_tbl->ind_tbl_num;
+       resp.response_length = required_resp_len;
+
+       err = ib_copy_to_udata(ucore,
+                              &resp, resp.response_length);
+       if (err)
+               goto err_copy;
+
+       kfree(wqs_handles);
+
+       for (j = 0; j < num_read_wqs; j++)
+               put_wq_read(wqs[j]);
+
+       mutex_lock(&file->mutex);
+       list_add_tail(&uobj->list, &file->ucontext->rwq_ind_tbl_list);
+       mutex_unlock(&file->mutex);
+
+       uobj->live = 1;
+
+       up_write(&uobj->mutex);
+       return 0;
+
+err_copy:
+       idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+destroy_ind_tbl:
+       ib_destroy_rwq_ind_table(rwq_ind_tbl);
+err_uobj:
+       put_uobj_write(uobj);
+put_wqs:
+       for (j = 0; j < num_read_wqs; j++)
+               put_wq_read(wqs[j]);
+err_free:
+       kfree(wqs_handles);
+       kfree(wqs);
+       return err;
+}
+
+int ib_uverbs_ex_destroy_rwq_ind_table(struct ib_uverbs_file *file,
+                                      struct ib_device *ib_dev,
+                                      struct ib_udata *ucore,
+                                      struct ib_udata *uhw)
+{
+       struct ib_uverbs_ex_destroy_rwq_ind_table       cmd = {};
+       struct ib_rwq_ind_table *rwq_ind_tbl;
+       struct ib_uobject               *uobj;
+       int                     ret;
+       struct ib_wq    **ind_tbl;
+       size_t required_cmd_sz;
+
+       required_cmd_sz = offsetof(typeof(cmd), ind_tbl_handle) + sizeof(cmd.ind_tbl_handle);
+
+       if (ucore->inlen < required_cmd_sz)
+               return -EINVAL;
+
+       if (ucore->inlen > sizeof(cmd) &&
+           !ib_is_udata_cleared(ucore, sizeof(cmd),
+                                ucore->inlen - sizeof(cmd)))
+               return -EOPNOTSUPP;
+
+       ret = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
+       if (ret)
+               return ret;
+
+       if (cmd.comp_mask)
+               return -EOPNOTSUPP;
+
+       uobj = idr_write_uobj(&ib_uverbs_rwq_ind_tbl_idr, cmd.ind_tbl_handle,
+                             file->ucontext);
+       if (!uobj)
+               return -EINVAL;
+       rwq_ind_tbl = uobj->object;
+       ind_tbl = rwq_ind_tbl->ind_tbl;
+
+       ret = ib_destroy_rwq_ind_table(rwq_ind_tbl);
+       if (!ret)
+               uobj->live = 0;
+
+       put_uobj_write(uobj);
+
+       if (ret)
+               return ret;
+
+       idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+
+       mutex_lock(&file->mutex);
+       list_del(&uobj->list);
+       mutex_unlock(&file->mutex);
+
+       put_uobj(uobj);
+       kfree(ind_tbl);
+       return ret;
+}
+
 int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file,
                             struct ib_device *ib_dev,
                             struct ib_udata *ucore,
index 31f422a..0012fa5 100644 (file)
@@ -76,6 +76,8 @@ DEFINE_IDR(ib_uverbs_qp_idr);
 DEFINE_IDR(ib_uverbs_srq_idr);
 DEFINE_IDR(ib_uverbs_xrcd_idr);
 DEFINE_IDR(ib_uverbs_rule_idr);
+DEFINE_IDR(ib_uverbs_wq_idr);
+DEFINE_IDR(ib_uverbs_rwq_ind_tbl_idr);
 
 static DEFINE_SPINLOCK(map_lock);
 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -130,6 +132,11 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,
        [IB_USER_VERBS_EX_CMD_QUERY_DEVICE]     = ib_uverbs_ex_query_device,
        [IB_USER_VERBS_EX_CMD_CREATE_CQ]        = ib_uverbs_ex_create_cq,
        [IB_USER_VERBS_EX_CMD_CREATE_QP]        = ib_uverbs_ex_create_qp,
+       [IB_USER_VERBS_EX_CMD_CREATE_WQ]        = ib_uverbs_ex_create_wq,
+       [IB_USER_VERBS_EX_CMD_MODIFY_WQ]        = ib_uverbs_ex_modify_wq,
+       [IB_USER_VERBS_EX_CMD_DESTROY_WQ]       = ib_uverbs_ex_destroy_wq,
+       [IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL] = ib_uverbs_ex_create_rwq_ind_table,
+       [IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL] = ib_uverbs_ex_destroy_rwq_ind_table,
 };
 
 static void ib_uverbs_add_one(struct ib_device *device);
@@ -265,6 +272,27 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
                kfree(uqp);
        }
 
+       list_for_each_entry_safe(uobj, tmp, &context->rwq_ind_tbl_list, list) {
+               struct ib_rwq_ind_table *rwq_ind_tbl = uobj->object;
+               struct ib_wq **ind_tbl = rwq_ind_tbl->ind_tbl;
+
+               idr_remove_uobj(&ib_uverbs_rwq_ind_tbl_idr, uobj);
+               ib_destroy_rwq_ind_table(rwq_ind_tbl);
+               kfree(ind_tbl);
+               kfree(uobj);
+       }
+
+       list_for_each_entry_safe(uobj, tmp, &context->wq_list, list) {
+               struct ib_wq *wq = uobj->object;
+               struct ib_uwq_object *uwq =
+                       container_of(uobj, struct ib_uwq_object, uevent.uobject);
+
+               idr_remove_uobj(&ib_uverbs_wq_idr, uobj);
+               ib_destroy_wq(wq);
+               ib_uverbs_release_uevent(file, &uwq->uevent);
+               kfree(uwq);
+       }
+
        list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
                struct ib_srq *srq = uobj->object;
                struct ib_uevent_object *uevent =
@@ -568,6 +596,16 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
                                &uobj->events_reported);
 }
 
+void ib_uverbs_wq_event_handler(struct ib_event *event, void *context_ptr)
+{
+       struct ib_uevent_object *uobj = container_of(event->element.wq->uobject,
+                                                 struct ib_uevent_object, uobject);
+
+       ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle,
+                               event->event, &uobj->event_list,
+                               &uobj->events_reported);
+}
+
 void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr)
 {
        struct ib_uevent_object *uobj;
@@ -931,6 +969,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
        file->async_file = NULL;
        kref_init(&file->ref);
        mutex_init(&file->mutex);
+       mutex_init(&file->cleanup_mutex);
 
        filp->private_data = file;
        kobject_get(&dev->kobj);
@@ -956,18 +995,20 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
 {
        struct ib_uverbs_file *file = filp->private_data;
        struct ib_uverbs_device *dev = file->device;
-       struct ib_ucontext *ucontext = NULL;
+
+       mutex_lock(&file->cleanup_mutex);
+       if (file->ucontext) {
+               ib_uverbs_cleanup_ucontext(file, file->ucontext);
+               file->ucontext = NULL;
+       }
+       mutex_unlock(&file->cleanup_mutex);
 
        mutex_lock(&file->device->lists_mutex);
-       ucontext = file->ucontext;
-       file->ucontext = NULL;
        if (!file->is_closed) {
                list_del(&file->list);
                file->is_closed = 1;
        }
        mutex_unlock(&file->device->lists_mutex);
-       if (ucontext)
-               ib_uverbs_cleanup_ucontext(file, ucontext);
 
        if (file->async_file)
                kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
@@ -1181,22 +1222,30 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
        mutex_lock(&uverbs_dev->lists_mutex);
        while (!list_empty(&uverbs_dev->uverbs_file_list)) {
                struct ib_ucontext *ucontext;
-
                file = list_first_entry(&uverbs_dev->uverbs_file_list,
                                        struct ib_uverbs_file, list);
                file->is_closed = 1;
-               ucontext = file->ucontext;
                list_del(&file->list);
-               file->ucontext = NULL;
                kref_get(&file->ref);
                mutex_unlock(&uverbs_dev->lists_mutex);
-               /* We must release the mutex before going ahead and calling
-                * disassociate_ucontext. disassociate_ucontext might end up
-                * indirectly calling uverbs_close, for example due to freeing
-                * the resources (e.g mmput).
-                */
+
                ib_uverbs_event_handler(&file->event_handler, &event);
+
+               mutex_lock(&file->cleanup_mutex);
+               ucontext = file->ucontext;
+               file->ucontext = NULL;
+               mutex_unlock(&file->cleanup_mutex);
+
+               /* At this point ib_uverbs_close cannot be running
+                * ib_uverbs_cleanup_ucontext
+                */
                if (ucontext) {
+                       /* We must release the mutex before going ahead and
+                        * calling disassociate_ucontext. disassociate_ucontext
+                        * might end up indirectly calling uverbs_close,
+                        * for example due to freeing the resources
+                        * (e.g mmput).
+                        */
                        ib_dev->disassociate_ucontext(ucontext);
                        ib_uverbs_cleanup_ucontext(file, ucontext);
                }
index 6298f54..f2b776e 100644 (file)
@@ -758,6 +758,12 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        struct ib_qp *qp;
        int ret;
 
+       if (qp_init_attr->rwq_ind_tbl &&
+           (qp_init_attr->recv_cq ||
+           qp_init_attr->srq || qp_init_attr->cap.max_recv_wr ||
+           qp_init_attr->cap.max_recv_sge))
+               return ERR_PTR(-EINVAL);
+
        /*
         * If the callers is using the RDMA API calculate the resources
         * needed for the RDMA READ/WRITE operations.
@@ -775,6 +781,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        qp->real_qp    = qp;
        qp->uobject    = NULL;
        qp->qp_type    = qp_init_attr->qp_type;
+       qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl;
 
        atomic_set(&qp->usecnt, 0);
        qp->mrs_used = 0;
@@ -792,7 +799,8 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
                qp->srq = NULL;
        } else {
                qp->recv_cq = qp_init_attr->recv_cq;
-               atomic_inc(&qp_init_attr->recv_cq->usecnt);
+               if (qp_init_attr->recv_cq)
+                       atomic_inc(&qp_init_attr->recv_cq->usecnt);
                qp->srq = qp_init_attr->srq;
                if (qp->srq)
                        atomic_inc(&qp_init_attr->srq->usecnt);
@@ -803,7 +811,10 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        qp->xrcd    = NULL;
 
        atomic_inc(&pd->usecnt);
-       atomic_inc(&qp_init_attr->send_cq->usecnt);
+       if (qp_init_attr->send_cq)
+               atomic_inc(&qp_init_attr->send_cq->usecnt);
+       if (qp_init_attr->rwq_ind_tbl)
+               atomic_inc(&qp->rwq_ind_tbl->usecnt);
 
        if (qp_init_attr->cap.max_rdma_ctxs) {
                ret = rdma_rw_init_mrs(qp, qp_init_attr);
@@ -814,6 +825,15 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
                }
        }
 
+       /*
+        * Note: all hw drivers guarantee that max_send_sge is lower than
+        * the device RDMA WRITE SGE limit but not all hw drivers ensure that
+        * max_send_sge <= max_sge_rd.
+        */
+       qp->max_write_sge = qp_init_attr->cap.max_send_sge;
+       qp->max_read_sge = min_t(u32, qp_init_attr->cap.max_send_sge,
+                                device->attrs.max_sge_rd);
+
        return qp;
 }
 EXPORT_SYMBOL(ib_create_qp);
@@ -1283,6 +1303,7 @@ int ib_destroy_qp(struct ib_qp *qp)
        struct ib_pd *pd;
        struct ib_cq *scq, *rcq;
        struct ib_srq *srq;
+       struct ib_rwq_ind_table *ind_tbl;
        int ret;
 
        WARN_ON_ONCE(qp->mrs_used > 0);
@@ -1297,6 +1318,7 @@ int ib_destroy_qp(struct ib_qp *qp)
        scq  = qp->send_cq;
        rcq  = qp->recv_cq;
        srq  = qp->srq;
+       ind_tbl = qp->rwq_ind_tbl;
 
        if (!qp->uobject)
                rdma_rw_cleanup_mrs(qp);
@@ -1311,6 +1333,8 @@ int ib_destroy_qp(struct ib_qp *qp)
                        atomic_dec(&rcq->usecnt);
                if (srq)
                        atomic_dec(&srq->usecnt);
+               if (ind_tbl)
+                       atomic_dec(&ind_tbl->usecnt);
        }
 
        return ret;
@@ -1558,6 +1582,150 @@ int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
 }
 EXPORT_SYMBOL(ib_dealloc_xrcd);
 
+/**
+ * ib_create_wq - Creates a WQ associated with the specified protection
+ * domain.
+ * @pd: The protection domain associated with the WQ.
+ * @wq_init_attr: A list of initial attributes required to create the
+ * WQ. If WQ creation succeeds, then the attributes are updated to
+ * the actual capabilities of the created WQ.
+ *
+ * wq_init_attr->max_wr and wq_init_attr->max_sge determine
+ * the requested size of the WQ, and set to the actual values allocated
+ * on return.
+ * If ib_create_wq() succeeds, then max_wr and max_sge will always be
+ * at least as large as the requested values.
+ */
+struct ib_wq *ib_create_wq(struct ib_pd *pd,
+                          struct ib_wq_init_attr *wq_attr)
+{
+       struct ib_wq *wq;
+
+       if (!pd->device->create_wq)
+               return ERR_PTR(-ENOSYS);
+
+       wq = pd->device->create_wq(pd, wq_attr, NULL);
+       if (!IS_ERR(wq)) {
+               wq->event_handler = wq_attr->event_handler;
+               wq->wq_context = wq_attr->wq_context;
+               wq->wq_type = wq_attr->wq_type;
+               wq->cq = wq_attr->cq;
+               wq->device = pd->device;
+               wq->pd = pd;
+               wq->uobject = NULL;
+               atomic_inc(&pd->usecnt);
+               atomic_inc(&wq_attr->cq->usecnt);
+               atomic_set(&wq->usecnt, 0);
+       }
+       return wq;
+}
+EXPORT_SYMBOL(ib_create_wq);
+
+/**
+ * ib_destroy_wq - Destroys the specified WQ.
+ * @wq: The WQ to destroy.
+ */
+int ib_destroy_wq(struct ib_wq *wq)
+{
+       int err;
+       struct ib_cq *cq = wq->cq;
+       struct ib_pd *pd = wq->pd;
+
+       if (atomic_read(&wq->usecnt))
+               return -EBUSY;
+
+       err = wq->device->destroy_wq(wq);
+       if (!err) {
+               atomic_dec(&pd->usecnt);
+               atomic_dec(&cq->usecnt);
+       }
+       return err;
+}
+EXPORT_SYMBOL(ib_destroy_wq);
+
+/**
+ * ib_modify_wq - Modifies the specified WQ.
+ * @wq: The WQ to modify.
+ * @wq_attr: On input, specifies the WQ attributes to modify.
+ * @wq_attr_mask: A bit-mask used to specify which attributes of the WQ
+ *   are being modified.
+ * On output, the current values of selected WQ attributes are returned.
+ */
+int ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
+                u32 wq_attr_mask)
+{
+       int err;
+
+       if (!wq->device->modify_wq)
+               return -ENOSYS;
+
+       err = wq->device->modify_wq(wq, wq_attr, wq_attr_mask, NULL);
+       return err;
+}
+EXPORT_SYMBOL(ib_modify_wq);
+
+/*
+ * ib_create_rwq_ind_table - Creates a RQ Indirection Table.
+ * @device: The device on which to create the rwq indirection table.
+ * @ib_rwq_ind_table_init_attr: A list of initial attributes required to
+ * create the Indirection Table.
+ *
+ * Note: The life time of ib_rwq_ind_table_init_attr->ind_tbl is not less
+ *     than the created ib_rwq_ind_table object and the caller is responsible
+ *     for its memory allocation/free.
+ */
+struct ib_rwq_ind_table *ib_create_rwq_ind_table(struct ib_device *device,
+                                                struct ib_rwq_ind_table_init_attr *init_attr)
+{
+       struct ib_rwq_ind_table *rwq_ind_table;
+       int i;
+       u32 table_size;
+
+       if (!device->create_rwq_ind_table)
+               return ERR_PTR(-ENOSYS);
+
+       table_size = (1 << init_attr->log_ind_tbl_size);
+       rwq_ind_table = device->create_rwq_ind_table(device,
+                               init_attr, NULL);
+       if (IS_ERR(rwq_ind_table))
+               return rwq_ind_table;
+
+       rwq_ind_table->ind_tbl = init_attr->ind_tbl;
+       rwq_ind_table->log_ind_tbl_size = init_attr->log_ind_tbl_size;
+       rwq_ind_table->device = device;
+       rwq_ind_table->uobject = NULL;
+       atomic_set(&rwq_ind_table->usecnt, 0);
+
+       for (i = 0; i < table_size; i++)
+               atomic_inc(&rwq_ind_table->ind_tbl[i]->usecnt);
+
+       return rwq_ind_table;
+}
+EXPORT_SYMBOL(ib_create_rwq_ind_table);
+
+/*
+ * ib_destroy_rwq_ind_table - Destroys the specified Indirection Table.
+ * @wq_ind_table: The Indirection Table to destroy.
+*/
+int ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *rwq_ind_table)
+{
+       int err, i;
+       u32 table_size = (1 << rwq_ind_table->log_ind_tbl_size);
+       struct ib_wq **ind_tbl = rwq_ind_table->ind_tbl;
+
+       if (atomic_read(&rwq_ind_table->usecnt))
+               return -EBUSY;
+
+       err = rwq_ind_table->device->destroy_rwq_ind_table(rwq_ind_table);
+       if (!err) {
+               for (i = 0; i < table_size; i++)
+                       atomic_dec(&ind_tbl[i]->usecnt);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(ib_destroy_rwq_ind_table);
+
 struct ib_flow *ib_create_flow(struct ib_qp *qp,
                               struct ib_flow_attr *flow_attr,
                               int domain)
index 3e8431b..04bbf17 100644 (file)
@@ -1396,10 +1396,10 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        state_set(&child_ep->com, CONNECTING);
        child_ep->com.tdev = tdev;
        child_ep->com.cm_id = NULL;
-       child_ep->com.local_addr.sin_family = PF_INET;
+       child_ep->com.local_addr.sin_family = AF_INET;
        child_ep->com.local_addr.sin_port = req->local_port;
        child_ep->com.local_addr.sin_addr.s_addr = req->local_ip;
-       child_ep->com.remote_addr.sin_family = PF_INET;
+       child_ep->com.remote_addr.sin_family = AF_INET;
        child_ep->com.remote_addr.sin_port = req->peer_port;
        child_ep->com.remote_addr.sin_addr.s_addr = req->peer_ip;
        get_ep(&parent_ep->com);
index bb1a839..3edb806 100644 (file)
@@ -1183,18 +1183,6 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%d\n", iwch_dev->rdev.t3cdev_p->type);
 }
 
-static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct iwch_dev *iwch_dev = container_of(dev, struct iwch_dev,
-                                                ibdev.dev);
-       struct ethtool_drvinfo info;
-       struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
-
-       PDBG("%s dev 0x%p\n", __func__, dev);
-       lldev->ethtool_ops->get_drvinfo(lldev, &info);
-       return sprintf(buf, "%s\n", info.fw_version);
-}
-
 static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
@@ -1334,13 +1322,11 @@ static int iwch_get_mib(struct ib_device *ibdev, struct rdma_hw_stats *stats,
 }
 
 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 struct device_attribute *iwch_class_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id,
 };
@@ -1362,6 +1348,18 @@ static int iwch_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_ver_str(struct ib_device *ibdev, char *str,
+                              size_t str_len)
+{
+       struct iwch_dev *iwch_dev = to_iwch_dev(ibdev);
+       struct ethtool_drvinfo info;
+       struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
+
+       PDBG("%s dev 0x%p\n", __func__, iwch_dev);
+       lldev->ethtool_ops->get_drvinfo(lldev, &info);
+       snprintf(str, str_len, "%s", info.fw_version);
+}
+
 int iwch_register_device(struct iwch_dev *dev)
 {
        int ret;
@@ -1437,6 +1435,7 @@ int iwch_register_device(struct iwch_dev *dev)
        dev->ibdev.get_hw_stats = iwch_get_mib;
        dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
        dev->ibdev.get_port_immutable = iwch_port_immutable;
+       dev->ibdev.get_dev_fw_str = get_dev_fw_ver_str;
 
        dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
        if (!dev->ibdev.iwcm)
index a3a6721..3aca7f6 100644 (file)
@@ -294,6 +294,25 @@ static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
        return;
 }
 
+static int alloc_ep_skb_list(struct sk_buff_head *ep_skb_list, int size)
+{
+       struct sk_buff *skb;
+       unsigned int i;
+       size_t len;
+
+       len = roundup(sizeof(union cpl_wr_size), 16);
+       for (i = 0; i < size; i++) {
+               skb = alloc_skb(len, GFP_KERNEL);
+               if (!skb)
+                       goto fail;
+               skb_queue_tail(ep_skb_list, skb);
+       }
+       return 0;
+fail:
+       skb_queue_purge(ep_skb_list);
+       return -ENOMEM;
+}
+
 static void *alloc_ep(int size, gfp_t gfp)
 {
        struct c4iw_ep_common *epc;
@@ -384,6 +403,8 @@ void _c4iw_free_ep(struct kref *kref)
                if (ep->mpa_skb)
                        kfree_skb(ep->mpa_skb);
        }
+       if (!skb_queue_empty(&ep->com.ep_skb_list))
+               skb_queue_purge(&ep->com.ep_skb_list);
        kfree(ep);
 }
 
@@ -620,25 +641,27 @@ static void abort_arp_failure(void *handle, struct sk_buff *skb)
        }
 }
 
-static int send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
+static int send_flowc(struct c4iw_ep *ep)
 {
-       unsigned int flowclen = 80;
        struct fw_flowc_wr *flowc;
+       struct sk_buff *skb = skb_dequeue(&ep->com.ep_skb_list);
        int i;
        u16 vlan = ep->l2t->vlan;
        int nparams;
 
+       if (WARN_ON(!skb))
+               return -ENOMEM;
+
        if (vlan == CPL_L2T_VLAN_NONE)
                nparams = 8;
        else
                nparams = 9;
 
-       skb = get_skb(skb, flowclen, GFP_KERNEL);
-       flowc = (struct fw_flowc_wr *)__skb_put(skb, flowclen);
+       flowc = (struct fw_flowc_wr *)__skb_put(skb, FLOWC_LEN);
 
        flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
                                           FW_FLOWC_WR_NPARAMS_V(nparams));
-       flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(flowclen,
+       flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(FLOWC_LEN,
                                          16)) | FW_WR_FLOWID_V(ep->hwtid));
 
        flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
@@ -679,18 +702,16 @@ static int send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
        return c4iw_ofld_send(&ep->com.dev->rdev, skb);
 }
 
-static int send_halfclose(struct c4iw_ep *ep, gfp_t gfp)
+static int send_halfclose(struct c4iw_ep *ep)
 {
        struct cpl_close_con_req *req;
-       struct sk_buff *skb;
+       struct sk_buff *skb = skb_dequeue(&ep->com.ep_skb_list);
        int wrlen = roundup(sizeof *req, 16);
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-       skb = get_skb(NULL, wrlen, gfp);
-       if (!skb) {
-               printk(KERN_ERR MOD "%s - failed to alloc skb\n", __func__);
+       if (WARN_ON(!skb))
                return -ENOMEM;
-       }
+
        set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
        t4_set_arp_err_handler(skb, NULL, arp_failure_discard);
        req = (struct cpl_close_con_req *) skb_put(skb, wrlen);
@@ -701,26 +722,24 @@ static int send_halfclose(struct c4iw_ep *ep, gfp_t gfp)
        return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
 }
 
-static int send_abort(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
+static int send_abort(struct c4iw_ep *ep)
 {
        struct cpl_abort_req *req;
        int wrlen = roundup(sizeof *req, 16);
+       struct sk_buff *req_skb = skb_dequeue(&ep->com.ep_skb_list);
 
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-       skb = get_skb(skb, wrlen, gfp);
-       if (!skb) {
-               printk(KERN_ERR MOD "%s - failed to alloc skb.\n",
-                      __func__);
+       if (WARN_ON(!req_skb))
                return -ENOMEM;
-       }
-       set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
-       t4_set_arp_err_handler(skb, ep, abort_arp_failure);
-       req = (struct cpl_abort_req *) skb_put(skb, wrlen);
+
+       set_wr_txq(req_skb, CPL_PRIORITY_DATA, ep->txq_idx);
+       t4_set_arp_err_handler(req_skb, ep, abort_arp_failure);
+       req = (struct cpl_abort_req *)skb_put(req_skb, wrlen);
        memset(req, 0, wrlen);
        INIT_TP_WR(req, ep->hwtid);
        OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid));
        req->cmd = CPL_ABORT_SEND_RST;
-       return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+       return c4iw_l2t_send(&ep->com.dev->rdev, req_skb, ep->l2t);
 }
 
 static void best_mtu(const unsigned short *mtus, unsigned short mtu,
@@ -992,9 +1011,19 @@ static int send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
 
        mpa = (struct mpa_message *)(req + 1);
        memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
-       mpa->flags = (crc_enabled ? MPA_CRC : 0) |
-                    (markers_enabled ? MPA_MARKERS : 0) |
-                    (mpa_rev_to_use == 2 ? MPA_ENHANCED_RDMA_CONN : 0);
+
+       mpa->flags = 0;
+       if (crc_enabled)
+               mpa->flags |= MPA_CRC;
+       if (markers_enabled) {
+               mpa->flags |= MPA_MARKERS;
+               ep->mpa_attr.recv_marker_enabled = 1;
+       } else {
+               ep->mpa_attr.recv_marker_enabled = 0;
+       }
+       if (mpa_rev_to_use == 2)
+               mpa->flags |= MPA_ENHANCED_RDMA_CONN;
+
        mpa->private_data_size = htons(ep->plen);
        mpa->revision = mpa_rev_to_use;
        if (mpa_rev_to_use == 1) {
@@ -1169,8 +1198,11 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
        mpa = (struct mpa_message *)(req + 1);
        memset(mpa, 0, sizeof(*mpa));
        memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
-       mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) |
-                    (markers_enabled ? MPA_MARKERS : 0);
+       mpa->flags = 0;
+       if (ep->mpa_attr.crc_enabled)
+               mpa->flags |= MPA_CRC;
+       if (ep->mpa_attr.recv_marker_enabled)
+               mpa->flags |= MPA_MARKERS;
        mpa->revision = ep->mpa_attr.version;
        mpa->private_data_size = htons(plen);
 
@@ -1248,7 +1280,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        set_bit(ACT_ESTAB, &ep->com.history);
 
        /* start MPA negotiation */
-       ret = send_flowc(ep, NULL);
+       ret = send_flowc(ep);
        if (ret)
                goto err;
        if (ep->retry_with_mpa_v1)
@@ -1555,7 +1587,6 @@ static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)
         */
        __state_set(&ep->com, FPDU_MODE);
        ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
-       ep->mpa_attr.recv_marker_enabled = markers_enabled;
        ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
        ep->mpa_attr.version = mpa->revision;
        ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED;
@@ -2004,12 +2035,17 @@ static int send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
 }
 
 /*
- * Return whether a failed active open has allocated a TID
+ * Some of the error codes above implicitly indicate that there is no TID
+ * allocated with the result of an ACT_OPEN.  We use this predicate to make
+ * that explicit.
  */
 static inline int act_open_has_tid(int status)
 {
-       return status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST &&
-              status != CPL_ERR_ARP_MISS;
+       return (status != CPL_ERR_TCAM_PARITY &&
+               status != CPL_ERR_TCAM_MISS &&
+               status != CPL_ERR_TCAM_FULL &&
+               status != CPL_ERR_CONN_EXIST_SYNRECV &&
+               status != CPL_ERR_CONN_EXIST);
 }
 
 /* Returns whether a CPL status conveys negative advice.
@@ -2130,6 +2166,7 @@ out:
 static int c4iw_reconnect(struct c4iw_ep *ep)
 {
        int err = 0;
+       int size = 0;
        struct sockaddr_in *laddr = (struct sockaddr_in *)
                                    &ep->com.cm_id->m_local_addr;
        struct sockaddr_in *raddr = (struct sockaddr_in *)
@@ -2145,6 +2182,21 @@ static int c4iw_reconnect(struct c4iw_ep *ep)
        init_timer(&ep->timer);
        c4iw_init_wr_wait(&ep->com.wr_wait);
 
+       /* When MPA revision is different on nodes, the node with MPA_rev=2
+        * tries to reconnect with MPA_rev 1 for the same EP through
+        * c4iw_reconnect(), where the same EP is assigned with new tid for
+        * further connection establishment. As we are using the same EP pointer
+        * for reconnect, few skbs are used during the previous c4iw_connect(),
+        * which leaves the EP with inadequate skbs for further
+        * c4iw_reconnect(), Further causing an assert BUG_ON() due to empty
+        * skb_list() during peer_abort(). Allocate skbs which is already used.
+        */
+       size = (CN_MAX_CON_BUF - skb_queue_len(&ep->com.ep_skb_list));
+       if (alloc_ep_skb_list(&ep->com.ep_skb_list, size)) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
        /*
         * Allocate an active TID to initiate a TCP connection.
         */
@@ -2210,6 +2262,7 @@ fail2:
         * response of 1st connect request.
         */
        connect_reply_upcall(ep, -ECONNRESET);
+fail1:
        c4iw_put_ep(&ep->com);
 out:
        return err;
@@ -2576,6 +2629,10 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
        if (peer_mss && child_ep->mtu > (peer_mss + hdrs))
                child_ep->mtu = peer_mss + hdrs;
 
+       skb_queue_head_init(&child_ep->com.ep_skb_list);
+       if (alloc_ep_skb_list(&child_ep->com.ep_skb_list, CN_MAX_CON_BUF))
+               goto fail;
+
        state_set(&child_ep->com, CONNECTING);
        child_ep->com.dev = dev;
        child_ep->com.cm_id = NULL;
@@ -2640,6 +2697,8 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
                               (const u32 *)&sin6->sin6_addr.s6_addr, 1);
        }
        goto out;
+fail:
+       c4iw_put_ep(&child_ep->com);
 reject:
        reject_cr(dev, hwtid, skb);
        if (parent_ep)
@@ -2670,7 +2729,7 @@ static int pass_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        ep->com.state = MPA_REQ_WAIT;
        start_ep_timer(ep);
        set_bit(PASS_ESTAB, &ep->com.history);
-       ret = send_flowc(ep, skb);
+       ret = send_flowc(ep);
        mutex_unlock(&ep->com.mutex);
        if (ret)
                c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
@@ -2871,10 +2930,8 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        }
        mutex_unlock(&ep->com.mutex);
 
-       rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
-       if (!rpl_skb) {
-               printk(KERN_ERR MOD "%s - cannot allocate skb!\n",
-                      __func__);
+       rpl_skb = skb_dequeue(&ep->com.ep_skb_list);
+       if (WARN_ON(!rpl_skb)) {
                release = 1;
                goto out;
        }
@@ -3011,9 +3068,9 @@ static int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)
                PDBG("%s last streaming msg ack ep %p tid %u state %u "
                     "initiator %u freeing skb\n", __func__, ep, ep->hwtid,
                     state_read(&ep->com), ep->mpa_attr.initiator ? 1 : 0);
+               mutex_lock(&ep->com.mutex);
                kfree_skb(ep->mpa_skb);
                ep->mpa_skb = NULL;
-               mutex_lock(&ep->com.mutex);
                if (test_bit(STOP_MPA_TIMER, &ep->com.flags))
                        stop_ep_timer(ep);
                mutex_unlock(&ep->com.mutex);
@@ -3025,9 +3082,9 @@ out:
 
 int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
 {
-       int err = 0;
-       int disconnect = 0;
+       int abort;
        struct c4iw_ep *ep = to_ep(cm_id);
+
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 
        mutex_lock(&ep->com.mutex);
@@ -3038,16 +3095,13 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
        }
        set_bit(ULP_REJECT, &ep->com.history);
        if (mpa_rev == 0)
-               disconnect = 2;
-       else {
-               err = send_mpa_reject(ep, pdata, pdata_len);
-               disconnect = 1;
-       }
+               abort = 1;
+       else
+               abort = send_mpa_reject(ep, pdata, pdata_len);
        mutex_unlock(&ep->com.mutex);
-       if (disconnect) {
-               stop_ep_timer(ep);
-               err = c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
-       }
+
+       stop_ep_timer(ep);
+       c4iw_ep_disconnect(ep, abort != 0, GFP_KERNEL);
        c4iw_put_ep(&ep->com);
        return 0;
 }
@@ -3248,6 +3302,13 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                err = -ENOMEM;
                goto out;
        }
+
+       skb_queue_head_init(&ep->com.ep_skb_list);
+       if (alloc_ep_skb_list(&ep->com.ep_skb_list, CN_MAX_CON_BUF)) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
        init_timer(&ep->timer);
        ep->plen = conn_param->private_data_len;
        if (ep->plen)
@@ -3266,7 +3327,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (!ep->com.qp) {
                PDBG("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);
                err = -EINVAL;
-               goto fail1;
+               goto fail2;
        }
        ref_qp(ep);
        PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn,
@@ -3279,7 +3340,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (ep->atid == -1) {
                printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __func__);
                err = -ENOMEM;
-               goto fail1;
+               goto fail2;
        }
        insert_handle(dev, &dev->atid_idr, ep, ep->atid);
 
@@ -3303,7 +3364,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                if (raddr->sin_addr.s_addr == htonl(INADDR_ANY)) {
                        err = pick_local_ipaddrs(dev, cm_id);
                        if (err)
-                               goto fail1;
+                               goto fail2;
                }
 
                /* find a route */
@@ -3323,7 +3384,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) {
                        err = pick_local_ip6addrs(dev, cm_id);
                        if (err)
-                               goto fail1;
+                               goto fail2;
                }
 
                /* find a route */
@@ -3339,14 +3400,14 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (!ep->dst) {
                printk(KERN_ERR MOD "%s - cannot find route.\n", __func__);
                err = -EHOSTUNREACH;
-               goto fail2;
+               goto fail3;
        }
 
        err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true,
                        ep->com.dev->rdev.lldi.adapter_type, cm_id->tos);
        if (err) {
                printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
-               goto fail3;
+               goto fail4;
        }
 
        PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
@@ -3362,13 +3423,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                goto out;
 
        cxgb4_l2t_release(ep->l2t);
-fail3:
+fail4:
        dst_release(ep->dst);
-fail2:
+fail3:
        remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
        cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
-fail1:
+fail2:
+       skb_queue_purge(&ep->com.ep_skb_list);
        deref_cm_id(&ep->com);
+fail1:
        c4iw_put_ep(&ep->com);
 out:
        return err;
@@ -3461,6 +3524,7 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
                err = -ENOMEM;
                goto fail1;
        }
+       skb_queue_head_init(&ep->com.ep_skb_list);
        PDBG("%s ep %p\n", __func__, ep);
        ep->com.cm_id = cm_id;
        ref_cm_id(&ep->com);
@@ -3577,11 +3641,22 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
        case MPA_REQ_RCVD:
        case MPA_REP_SENT:
        case FPDU_MODE:
+       case CONNECTING:
                close = 1;
                if (abrupt)
                        ep->com.state = ABORTING;
                else {
                        ep->com.state = CLOSING;
+
+                       /*
+                        * if we close before we see the fw4_ack() then we fix
+                        * up the timer state since we're reusing it.
+                        */
+                       if (ep->mpa_skb &&
+                           test_bit(STOP_MPA_TIMER, &ep->com.flags)) {
+                               clear_bit(STOP_MPA_TIMER, &ep->com.flags);
+                               stop_ep_timer(ep);
+                       }
                        start_ep_timer(ep);
                }
                set_bit(CLOSE_SENT, &ep->com.flags);
@@ -3611,10 +3686,10 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
                if (abrupt) {
                        set_bit(EP_DISC_ABORT, &ep->com.history);
                        close_complete_upcall(ep, -ECONNRESET);
-                       ret = send_abort(ep, NULL, gfp);
+                       ret = send_abort(ep);
                } else {
                        set_bit(EP_DISC_CLOSE, &ep->com.history);
-                       ret = send_halfclose(ep, gfp);
+                       ret = send_halfclose(ep);
                }
                if (ret) {
                        set_bit(EP_DISC_FAIL, &ep->com.history);
index b0b9557..812ab72 100644 (file)
 #include "iw_cxgb4.h"
 
 static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
-                     struct c4iw_dev_ucontext *uctx)
+                     struct c4iw_dev_ucontext *uctx, struct sk_buff *skb)
 {
        struct fw_ri_res_wr *res_wr;
        struct fw_ri_res *res;
        int wr_len;
        struct c4iw_wr_wait wr_wait;
-       struct sk_buff *skb;
        int ret;
 
        wr_len = sizeof *res_wr + sizeof *res;
-       skb = alloc_skb(wr_len, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
        set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
 
        res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
@@ -863,7 +859,9 @@ int c4iw_destroy_cq(struct ib_cq *ib_cq)
        ucontext = ib_cq->uobject ? to_c4iw_ucontext(ib_cq->uobject->context)
                                  : NULL;
        destroy_cq(&chp->rhp->rdev, &chp->cq,
-                  ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx);
+                  ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx,
+                  chp->destroy_skb);
+       chp->destroy_skb = NULL;
        kfree(chp);
        return 0;
 }
@@ -879,7 +877,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
        struct c4iw_cq *chp;
        struct c4iw_create_cq_resp uresp;
        struct c4iw_ucontext *ucontext = NULL;
-       int ret;
+       int ret, wr_len;
        size_t memsize, hwentries;
        struct c4iw_mm_entry *mm, *mm2;
 
@@ -896,6 +894,13 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
        if (!chp)
                return ERR_PTR(-ENOMEM);
 
+       wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res);
+       chp->destroy_skb = alloc_skb(wr_len, GFP_KERNEL);
+       if (!chp->destroy_skb) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
        if (ib_context)
                ucontext = to_c4iw_ucontext(ib_context);
 
@@ -936,7 +941,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
        ret = create_cq(&rhp->rdev, &chp->cq,
                        ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
        if (ret)
-               goto err1;
+               goto err2;
 
        chp->rhp = rhp;
        chp->cq.size--;                         /* status page */
@@ -947,15 +952,15 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
        init_waitqueue_head(&chp->wait);
        ret = insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid);
        if (ret)
-               goto err2;
+               goto err3;
 
        if (ucontext) {
                mm = kmalloc(sizeof *mm, GFP_KERNEL);
                if (!mm)
-                       goto err3;
+                       goto err4;
                mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
                if (!mm2)
-                       goto err4;
+                       goto err5;
 
                uresp.qid_mask = rhp->rdev.cqmask;
                uresp.cqid = chp->cq.cqid;
@@ -970,7 +975,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
                ret = ib_copy_to_udata(udata, &uresp,
                                       sizeof(uresp) - sizeof(uresp.reserved));
                if (ret)
-                       goto err5;
+                       goto err6;
 
                mm->key = uresp.key;
                mm->addr = virt_to_phys(chp->cq.queue);
@@ -986,15 +991,18 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
             __func__, chp->cq.cqid, chp, chp->cq.size,
             chp->cq.memsize, (unsigned long long) chp->cq.dma_addr);
        return &chp->ibcq;
-err5:
+err6:
        kfree(mm2);
-err4:
+err5:
        kfree(mm);
-err3:
+err4:
        remove_handle(rhp, &rhp->cqidr, chp->cq.cqid);
-err2:
+err3:
        destroy_cq(&chp->rhp->rdev, &chp->cq,
-                  ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+                  ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
+                  chp->destroy_skb);
+err2:
+       kfree_skb(chp->destroy_skb);
 err1:
        kfree(chp);
        return ERR_PTR(ret);
index ae2e8b2..071d733 100644 (file)
@@ -317,7 +317,7 @@ static int qp_open(struct inode *inode, struct file *file)
        idr_for_each(&qpd->devp->qpidr, count_idrs, &count);
        spin_unlock_irq(&qpd->devp->lock);
 
-       qpd->bufsize = count * 128;
+       qpd->bufsize = count * 180;
        qpd->buf = vmalloc(qpd->bufsize);
        if (!qpd->buf) {
                kfree(qpd);
index f6f34a7..aa47e0a 100644 (file)
@@ -384,6 +384,7 @@ struct c4iw_mr {
        struct ib_mr ibmr;
        struct ib_umem *umem;
        struct c4iw_dev *rhp;
+       struct sk_buff *dereg_skb;
        u64 kva;
        struct tpt_attributes attr;
        u64 *mpl;
@@ -400,6 +401,7 @@ static inline struct c4iw_mr *to_c4iw_mr(struct ib_mr *ibmr)
 struct c4iw_mw {
        struct ib_mw ibmw;
        struct c4iw_dev *rhp;
+       struct sk_buff *dereg_skb;
        u64 kva;
        struct tpt_attributes attr;
 };
@@ -412,6 +414,7 @@ static inline struct c4iw_mw *to_c4iw_mw(struct ib_mw *ibmw)
 struct c4iw_cq {
        struct ib_cq ibcq;
        struct c4iw_dev *rhp;
+       struct sk_buff *destroy_skb;
        struct t4_cq cq;
        spinlock_t lock;
        spinlock_t comp_handler_lock;
@@ -472,7 +475,7 @@ struct c4iw_qp {
        struct t4_wq wq;
        spinlock_t lock;
        struct mutex mutex;
-       atomic_t refcnt;
+       struct kref kref;
        wait_queue_head_t wait;
        struct timer_list timer;
        int sq_sig_all;
@@ -789,10 +792,29 @@ enum c4iw_ep_history {
        CM_ID_DEREFED           = 28,
 };
 
+enum conn_pre_alloc_buffers {
+       CN_ABORT_REQ_BUF,
+       CN_ABORT_RPL_BUF,
+       CN_CLOSE_CON_REQ_BUF,
+       CN_DESTROY_BUF,
+       CN_FLOWC_BUF,
+       CN_MAX_CON_BUF
+};
+
+#define FLOWC_LEN 80
+union cpl_wr_size {
+       struct cpl_abort_req abrt_req;
+       struct cpl_abort_rpl abrt_rpl;
+       struct fw_ri_wr ri_req;
+       struct cpl_close_con_req close_req;
+       char flowc_buf[FLOWC_LEN];
+};
+
 struct c4iw_ep_common {
        struct iw_cm_id *cm_id;
        struct c4iw_qp *qp;
        struct c4iw_dev *dev;
+       struct sk_buff_head ep_skb_list;
        enum c4iw_ep_state state;
        struct kref kref;
        struct mutex mutex;
index 55d0651..0b91b0f 100644 (file)
@@ -59,9 +59,9 @@ static int mr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
 }
 
 static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
-                                      u32 len, dma_addr_t data, int wait)
+                                      u32 len, dma_addr_t data,
+                                      int wait, struct sk_buff *skb)
 {
-       struct sk_buff *skb;
        struct ulp_mem_io *req;
        struct ulptx_sgl *sgl;
        u8 wr_len;
@@ -74,9 +74,11 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
                c4iw_init_wr_wait(&wr_wait);
        wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
 
-       skb = alloc_skb(wr_len, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
+       if (!skb) {
+               skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+               if (!skb)
+                       return -ENOMEM;
+       }
        set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
 
        req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
@@ -108,9 +110,8 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
 }
 
 static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
-                                 void *data)
+                                 void *data, struct sk_buff *skb)
 {
-       struct sk_buff *skb;
        struct ulp_mem_io *req;
        struct ulptx_idata *sc;
        u8 wr_len, *to_dp, *from_dp;
@@ -134,9 +135,11 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
                wr_len = roundup(sizeof *req + sizeof *sc +
                                 roundup(copy_len, T4_ULPTX_MIN_IO), 16);
 
-               skb = alloc_skb(wr_len, GFP_KERNEL);
-               if (!skb)
-                       return -ENOMEM;
+               if (!skb) {
+                       skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+                       if (!skb)
+                               return -ENOMEM;
+               }
                set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
 
                req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
@@ -173,6 +176,7 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
                        memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO -
                               (copy_len % T4_ULPTX_MIN_IO));
                ret = c4iw_ofld_send(rdev, skb);
+               skb = NULL;
                if (ret)
                        return ret;
                len -= C4IW_MAX_INLINE_SIZE;
@@ -182,7 +186,8 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
        return ret;
 }
 
-static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
+static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
+                              void *data, struct sk_buff *skb)
 {
        u32 remain = len;
        u32 dmalen;
@@ -205,7 +210,7 @@ static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *
                        dmalen = T4_ULPTX_MAX_DMA;
                remain -= dmalen;
                ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr,
-                                                !remain);
+                                                !remain, skb);
                if (ret)
                        goto out;
                addr += dmalen >> 5;
@@ -213,7 +218,7 @@ static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *
                daddr += dmalen;
        }
        if (remain)
-               ret = _c4iw_write_mem_inline(rdev, addr, remain, data);
+               ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb);
 out:
        dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE);
        return ret;
@@ -224,23 +229,25 @@ out:
  * If data is NULL, clear len byte of memory to zero.
  */
 static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
-                            void *data)
+                            void *data, struct sk_buff *skb)
 {
        if (is_t5(rdev->lldi.adapter_type) && use_dsgl) {
                if (len > inline_threshold) {
-                       if (_c4iw_write_mem_dma(rdev, addr, len, data)) {
+                       if (_c4iw_write_mem_dma(rdev, addr, len, data, skb)) {
                                printk_ratelimited(KERN_WARNING
                                                   "%s: dma map"
                                                   " failure (non fatal)\n",
                                                   pci_name(rdev->lldi.pdev));
                                return _c4iw_write_mem_inline(rdev, addr, len,
-                                                             data);
-                       } else
+                                                             data, skb);
+                       } else {
                                return 0;
+                       }
                } else
-                       return _c4iw_write_mem_inline(rdev, addr, len, data);
+                       return _c4iw_write_mem_inline(rdev, addr,
+                                                     len, data, skb);
        } else
-               return _c4iw_write_mem_inline(rdev, addr, len, data);
+               return _c4iw_write_mem_inline(rdev, addr, len, data, skb);
 }
 
 /*
@@ -253,7 +260,8 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
                           u32 *stag, u8 stag_state, u32 pdid,
                           enum fw_ri_stag_type type, enum fw_ri_mem_perms perm,
                           int bind_enabled, u32 zbva, u64 to,
-                          u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr)
+                          u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr,
+                          struct sk_buff *skb)
 {
        int err;
        struct fw_ri_tpte tpt;
@@ -307,7 +315,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
        }
        err = write_adapter_mem(rdev, stag_idx +
                                (rdev->lldi.vr->stag.start >> 5),
-                               sizeof(tpt), &tpt);
+                               sizeof(tpt), &tpt, skb);
 
        if (reset_tpt_entry) {
                c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
@@ -327,28 +335,29 @@ static int write_pbl(struct c4iw_rdev *rdev, __be64 *pbl,
             __func__, pbl_addr, rdev->lldi.vr->pbl.start,
             pbl_size);
 
-       err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl);
+       err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL);
        return err;
 }
 
 static int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size,
-                    u32 pbl_addr)
+                    u32 pbl_addr, struct sk_buff *skb)
 {
        return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0,
-                              pbl_size, pbl_addr);
+                              pbl_size, pbl_addr, skb);
 }
 
 static int allocate_window(struct c4iw_rdev *rdev, u32 * stag, u32 pdid)
 {
        *stag = T4_STAG_UNSET;
        return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_MW, 0, 0, 0,
-                              0UL, 0, 0, 0, 0);
+                              0UL, 0, 0, 0, 0, NULL);
 }
 
-static int deallocate_window(struct c4iw_rdev *rdev, u32 stag)
+static int deallocate_window(struct c4iw_rdev *rdev, u32 stag,
+                            struct sk_buff *skb)
 {
        return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 0,
-                              0);
+                              0, skb);
 }
 
 static int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
@@ -356,7 +365,7 @@ static int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
 {
        *stag = T4_STAG_UNSET;
        return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0,
-                              0UL, 0, 0, pbl_size, pbl_addr);
+                              0UL, 0, 0, pbl_size, pbl_addr, NULL);
 }
 
 static int finish_mem_reg(struct c4iw_mr *mhp, u32 stag)
@@ -383,14 +392,16 @@ static int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
                              mhp->attr.mw_bind_enable, mhp->attr.zbva,
                              mhp->attr.va_fbo, mhp->attr.len ?
                              mhp->attr.len : -1, shift - 12,
-                             mhp->attr.pbl_size, mhp->attr.pbl_addr);
+                             mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL);
        if (ret)
                return ret;
 
        ret = finish_mem_reg(mhp, stag);
-       if (ret)
+       if (ret) {
                dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
-                      mhp->attr.pbl_addr);
+                         mhp->attr.pbl_addr, mhp->dereg_skb);
+               mhp->dereg_skb = NULL;
+       }
        return ret;
 }
 
@@ -423,6 +434,12 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
        if (!mhp)
                return ERR_PTR(-ENOMEM);
 
+       mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+       if (!mhp->dereg_skb) {
+               ret = -ENOMEM;
+               goto err0;
+       }
+
        mhp->rhp = rhp;
        mhp->attr.pdid = php->pdid;
        mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
@@ -435,7 +452,8 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
 
        ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
                              FW_RI_STAG_NSMR, mhp->attr.perms,
-                             mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0);
+                             mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
+                             NULL);
        if (ret)
                goto err1;
 
@@ -445,8 +463,10 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
        return &mhp->ibmr;
 err2:
        dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
-                 mhp->attr.pbl_addr);
+                 mhp->attr.pbl_addr, mhp->dereg_skb);
 err1:
+       kfree_skb(mhp->dereg_skb);
+err0:
        kfree(mhp);
        return ERR_PTR(ret);
 }
@@ -481,11 +501,18 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
        if (!mhp)
                return ERR_PTR(-ENOMEM);
 
+       mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+       if (!mhp->dereg_skb) {
+               kfree(mhp);
+               return ERR_PTR(-ENOMEM);
+       }
+
        mhp->rhp = rhp;
 
        mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
        if (IS_ERR(mhp->umem)) {
                err = PTR_ERR(mhp->umem);
+               kfree_skb(mhp->dereg_skb);
                kfree(mhp);
                return ERR_PTR(err);
        }
@@ -550,6 +577,7 @@ err_pbl:
 
 err:
        ib_umem_release(mhp->umem);
+       kfree_skb(mhp->dereg_skb);
        kfree(mhp);
        return ERR_PTR(err);
 }
@@ -572,11 +600,16 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
        mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
        if (!mhp)
                return ERR_PTR(-ENOMEM);
-       ret = allocate_window(&rhp->rdev, &stag, php->pdid);
-       if (ret) {
-               kfree(mhp);
-               return ERR_PTR(ret);
+
+       mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
+       if (!mhp->dereg_skb) {
+               ret = -ENOMEM;
+               goto free_mhp;
        }
+
+       ret = allocate_window(&rhp->rdev, &stag, php->pdid);
+       if (ret)
+               goto free_skb;
        mhp->rhp = rhp;
        mhp->attr.pdid = php->pdid;
        mhp->attr.type = FW_RI_STAG_MW;
@@ -584,12 +617,19 @@ struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type,
        mmid = (stag) >> 8;
        mhp->ibmw.rkey = stag;
        if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) {
-               deallocate_window(&rhp->rdev, mhp->attr.stag);
-               kfree(mhp);
-               return ERR_PTR(-ENOMEM);
+               ret = -ENOMEM;
+               goto dealloc_win;
        }
        PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
        return &(mhp->ibmw);
+
+dealloc_win:
+       deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb);
+free_skb:
+       kfree_skb(mhp->dereg_skb);
+free_mhp:
+       kfree(mhp);
+       return ERR_PTR(ret);
 }
 
 int c4iw_dealloc_mw(struct ib_mw *mw)
@@ -602,7 +642,8 @@ int c4iw_dealloc_mw(struct ib_mw *mw)
        rhp = mhp->rhp;
        mmid = (mw->rkey) >> 8;
        remove_handle(rhp, &rhp->mmidr, mmid);
-       deallocate_window(&rhp->rdev, mhp->attr.stag);
+       deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb);
+       kfree_skb(mhp->dereg_skb);
        kfree(mhp);
        PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __func__, mw, mmid, mhp);
        return 0;
@@ -666,7 +707,7 @@ struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd,
        return &(mhp->ibmr);
 err3:
        dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
-                      mhp->attr.pbl_addr);
+                 mhp->attr.pbl_addr, mhp->dereg_skb);
 err2:
        c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
                              mhp->attr.pbl_size << 3);
@@ -717,7 +758,7 @@ int c4iw_dereg_mr(struct ib_mr *ib_mr)
                dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
                                  mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
        dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
-                      mhp->attr.pbl_addr);
+                 mhp->attr.pbl_addr, mhp->dereg_skb);
        if (mhp->attr.pbl_size)
                c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
                                  mhp->attr.pbl_size << 3);
index dd8a86b..df127ce 100644 (file)
@@ -409,20 +409,6 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
                       CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type));
 }
 
-static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
-                                                ibdev.dev);
-       PDBG("%s dev 0x%p\n", __func__, dev);
-
-       return sprintf(buf, "%u.%u.%u.%u\n",
-                       FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers),
-                       FW_HDR_FW_VER_MINOR_G(c4iw_dev->rdev.lldi.fw_vers),
-                       FW_HDR_FW_VER_MICRO_G(c4iw_dev->rdev.lldi.fw_vers),
-                       FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers));
-}
-
 static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
@@ -502,13 +488,11 @@ static int c4iw_get_mib(struct ib_device *ibdev,
 }
 
 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 struct device_attribute *c4iw_class_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id,
 };
@@ -530,6 +514,20 @@ static int c4iw_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_str(struct ib_device *dev, char *str,
+                          size_t str_len)
+{
+       struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
+                                                ibdev);
+       PDBG("%s dev 0x%p\n", __func__, dev);
+
+       snprintf(str, str_len, "%u.%u.%u.%u",
+                FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers),
+                FW_HDR_FW_VER_MINOR_G(c4iw_dev->rdev.lldi.fw_vers),
+                FW_HDR_FW_VER_MICRO_G(c4iw_dev->rdev.lldi.fw_vers),
+                FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers));
+}
+
 int c4iw_register_device(struct c4iw_dev *dev)
 {
        int ret;
@@ -605,6 +603,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
        dev->ibdev.get_hw_stats = c4iw_get_mib;
        dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
        dev->ibdev.get_port_immutable = c4iw_port_immutable;
+       dev->ibdev.get_dev_fw_str = get_dev_fw_str;
        dev->ibdev.drain_sq = c4iw_drain_sq;
        dev->ibdev.drain_rq = c4iw_drain_rq;
 
index e8993e4..edb1172 100644 (file)
@@ -683,17 +683,25 @@ static int build_inv_stag(union t4_wr *wqe, struct ib_send_wr *wr,
        return 0;
 }
 
+void _free_qp(struct kref *kref)
+{
+       struct c4iw_qp *qhp;
+
+       qhp = container_of(kref, struct c4iw_qp, kref);
+       PDBG("%s qhp %p\n", __func__, qhp);
+       kfree(qhp);
+}
+
 void c4iw_qp_add_ref(struct ib_qp *qp)
 {
        PDBG("%s ib_qp %p\n", __func__, qp);
-       atomic_inc(&(to_c4iw_qp(qp)->refcnt));
+       kref_get(&to_c4iw_qp(qp)->kref);
 }
 
 void c4iw_qp_rem_ref(struct ib_qp *qp)
 {
        PDBG("%s ib_qp %p\n", __func__, qp);
-       if (atomic_dec_and_test(&(to_c4iw_qp(qp)->refcnt)))
-               wake_up(&(to_c4iw_qp(qp)->wait));
+       kref_put(&to_c4iw_qp(qp)->kref, _free_qp);
 }
 
 static void add_to_fc_list(struct list_head *head, struct list_head *entry)
@@ -1081,9 +1089,10 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
        PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
             qhp->ep->hwtid);
 
-       skb = alloc_skb(sizeof *wqe, gfp);
-       if (!skb)
+       skb = skb_dequeue(&qhp->ep->com.ep_skb_list);
+       if (WARN_ON(!skb))
                return;
+
        set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
 
        wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
@@ -1202,9 +1211,10 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
             ep->hwtid);
 
-       skb = alloc_skb(sizeof *wqe, GFP_KERNEL);
-       if (!skb)
+       skb = skb_dequeue(&ep->com.ep_skb_list);
+       if (WARN_ON(!skb))
                return -ENOMEM;
+
        set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
 
        wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
@@ -1592,8 +1602,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
        wait_event(qhp->wait, !qhp->ep);
 
        remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
-       atomic_dec(&qhp->refcnt);
-       wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
 
        spin_lock_irq(&rhp->lock);
        if (!list_empty(&qhp->db_fc_entry))
@@ -1606,8 +1614,9 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
        destroy_qp(&rhp->rdev, &qhp->wq,
                   ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
 
+       c4iw_qp_rem_ref(ib_qp);
+
        PDBG("%s ib_qp %p qpid 0x%0x\n", __func__, ib_qp, qhp->wq.sq.qid);
-       kfree(qhp);
        return 0;
 }
 
@@ -1704,7 +1713,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        init_completion(&qhp->rq_drained);
        mutex_init(&qhp->mutex);
        init_waitqueue_head(&qhp->wait);
-       atomic_set(&qhp->refcnt, 1);
+       kref_init(&qhp->kref);
 
        ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
        if (ret)
@@ -1896,12 +1905,20 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        return 0;
 }
 
+static void move_qp_to_err(struct c4iw_qp *qp)
+{
+       struct c4iw_qp_attributes attrs = { .next_state = C4IW_QP_STATE_ERROR };
+
+       (void)c4iw_modify_qp(qp->rhp, qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+}
+
 void c4iw_drain_sq(struct ib_qp *ibqp)
 {
        struct c4iw_qp *qp = to_c4iw_qp(ibqp);
        unsigned long flag;
        bool need_to_wait;
 
+       move_qp_to_err(qp);
        spin_lock_irqsave(&qp->lock, flag);
        need_to_wait = !t4_sq_empty(&qp->wq);
        spin_unlock_irqrestore(&qp->lock, flag);
@@ -1916,6 +1933,7 @@ void c4iw_drain_rq(struct ib_qp *ibqp)
        unsigned long flag;
        bool need_to_wait;
 
+       move_qp_to_err(qp);
        spin_lock_irqsave(&qp->lock, flag);
        need_to_wait = !t4_rq_empty(&qp->wq);
        spin_unlock_irqrestore(&qp->lock, flag);
index a925fb0..f6ea088 100644 (file)
@@ -1,9 +1,9 @@
 config INFINIBAND_HFI1
        tristate "Intel OPA Gen1 support"
-       depends on X86_64 && INFINIBAND_RDMAVT
+       depends on X86_64 && INFINIBAND_RDMAVT && I2C
        select MMU_NOTIFIER
        select CRC32
-       default m
+       select I2C_ALGOBIT
        ---help---
        This is a low-level driver for Intel OPA Gen1 adapter.
 config HFI1_DEBUG_SDMA_ORDER
index 9b5382c..0cf97a0 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o
 hfi1-y := affinity.o chip.o device.o driver.o efivar.o \
        eprom.o file_ops.o firmware.o \
        init.o intr.o mad.o mmu_rb.o pcie.o pio.o pio_copy.o platform.o \
-       qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o twsi.o \
+       qp.o qsfp.o rc.o ruc.o sdma.o sysfs.o trace.o \
        uc.o ud.o user_exp_rcv.o user_pages.o user_sdma.o verbs.o \
        verbs_txreq.o
 hfi1-$(CONFIG_DEBUG_FS) += debugfs.o
index 14d7eeb..79575ee 100644 (file)
 #include <linux/topology.h>
 #include <linux/cpumask.h>
 #include <linux/module.h>
+#include <linux/cpumask.h>
 
 #include "hfi.h"
 #include "affinity.h"
 #include "sdma.h"
 #include "trace.h"
 
+struct hfi1_affinity_node_list node_affinity = {
+       .list = LIST_HEAD_INIT(node_affinity.list),
+       .lock = __SPIN_LOCK_UNLOCKED(&node_affinity.lock),
+};
+
 /* Name of IRQ types, indexed by enum irq_type */
 static const char * const irq_type_names[] = {
        "SDMA",
@@ -61,6 +67,9 @@ static const char * const irq_type_names[] = {
        "OTHER",
 };
 
+/* Per NUMA node count of HFI devices */
+static unsigned int *hfi1_per_node_cntr;
+
 static inline void init_cpu_mask_set(struct cpu_mask_set *set)
 {
        cpumask_clear(&set->mask);
@@ -69,47 +78,136 @@ static inline void init_cpu_mask_set(struct cpu_mask_set *set)
 }
 
 /* Initialize non-HT cpu cores mask */
-int init_real_cpu_mask(struct hfi1_devdata *dd)
+void init_real_cpu_mask(void)
 {
-       struct hfi1_affinity *info;
        int possible, curr_cpu, i, ht;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       cpumask_clear(&info->real_cpu_mask);
+       cpumask_clear(&node_affinity.real_cpu_mask);
 
        /* Start with cpu online mask as the real cpu mask */
-       cpumask_copy(&info->real_cpu_mask, cpu_online_mask);
+       cpumask_copy(&node_affinity.real_cpu_mask, cpu_online_mask);
 
        /*
         * Remove HT cores from the real cpu mask.  Do this in two steps below.
         */
-       possible = cpumask_weight(&info->real_cpu_mask);
+       possible = cpumask_weight(&node_affinity.real_cpu_mask);
        ht = cpumask_weight(topology_sibling_cpumask(
-                                       cpumask_first(&info->real_cpu_mask)));
+                               cpumask_first(&node_affinity.real_cpu_mask)));
        /*
         * Step 1.  Skip over the first N HT siblings and use them as the
         * "real" cores.  Assumes that HT cores are not enumerated in
         * succession (except in the single core case).
         */
-       curr_cpu = cpumask_first(&info->real_cpu_mask);
+       curr_cpu = cpumask_first(&node_affinity.real_cpu_mask);
        for (i = 0; i < possible / ht; i++)
-               curr_cpu = cpumask_next(curr_cpu, &info->real_cpu_mask);
+               curr_cpu = cpumask_next(curr_cpu, &node_affinity.real_cpu_mask);
        /*
         * Step 2.  Remove the remaining HT siblings.  Use cpumask_next() to
         * skip any gaps.
         */
        for (; i < possible; i++) {
-               cpumask_clear_cpu(curr_cpu, &info->real_cpu_mask);
-               curr_cpu = cpumask_next(curr_cpu, &info->real_cpu_mask);
+               cpumask_clear_cpu(curr_cpu, &node_affinity.real_cpu_mask);
+               curr_cpu = cpumask_next(curr_cpu, &node_affinity.real_cpu_mask);
+       }
+}
+
+int node_affinity_init(void)
+{
+       int node;
+       struct pci_dev *dev = NULL;
+       const struct pci_device_id *ids = hfi1_pci_tbl;
+
+       cpumask_clear(&node_affinity.proc.used);
+       cpumask_copy(&node_affinity.proc.mask, cpu_online_mask);
+
+       node_affinity.proc.gen = 0;
+       node_affinity.num_core_siblings =
+                               cpumask_weight(topology_sibling_cpumask(
+                                       cpumask_first(&node_affinity.proc.mask)
+                                       ));
+       node_affinity.num_online_nodes = num_online_nodes();
+       node_affinity.num_online_cpus = num_online_cpus();
+
+       /*
+        * The real cpu mask is part of the affinity struct but it has to be
+        * initialized early. It is needed to calculate the number of user
+        * contexts in set_up_context_variables().
+        */
+       init_real_cpu_mask();
+
+       hfi1_per_node_cntr = kcalloc(num_possible_nodes(),
+                                    sizeof(*hfi1_per_node_cntr), GFP_KERNEL);
+       if (!hfi1_per_node_cntr)
+               return -ENOMEM;
+
+       while (ids->vendor) {
+               dev = NULL;
+               while ((dev = pci_get_device(ids->vendor, ids->device, dev))) {
+                       node = pcibus_to_node(dev->bus);
+                       if (node < 0)
+                               node = numa_node_id();
+
+                       hfi1_per_node_cntr[node]++;
+               }
+               ids++;
        }
 
-       dd->affinity = info;
        return 0;
 }
 
+void node_affinity_destroy(void)
+{
+       struct list_head *pos, *q;
+       struct hfi1_affinity_node *entry;
+
+       spin_lock(&node_affinity.lock);
+       list_for_each_safe(pos, q, &node_affinity.list) {
+               entry = list_entry(pos, struct hfi1_affinity_node,
+                                  list);
+               list_del(pos);
+               kfree(entry);
+       }
+       spin_unlock(&node_affinity.lock);
+       kfree(hfi1_per_node_cntr);
+}
+
+static struct hfi1_affinity_node *node_affinity_allocate(int node)
+{
+       struct hfi1_affinity_node *entry;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return NULL;
+       entry->node = node;
+       INIT_LIST_HEAD(&entry->list);
+
+       return entry;
+}
+
+/*
+ * It appends an entry to the list.
+ * It *must* be called with node_affinity.lock held.
+ */
+static void node_affinity_add_tail(struct hfi1_affinity_node *entry)
+{
+       list_add_tail(&entry->list, &node_affinity.list);
+}
+
+/* It must be called with node_affinity.lock held */
+static struct hfi1_affinity_node *node_affinity_lookup(int node)
+{
+       struct list_head *pos;
+       struct hfi1_affinity_node *entry;
+
+       list_for_each(pos, &node_affinity.list) {
+               entry = list_entry(pos, struct hfi1_affinity_node, list);
+               if (entry->node == node)
+                       return entry;
+       }
+
+       return NULL;
+}
+
 /*
  * Interrupt affinity.
  *
@@ -121,10 +219,10 @@ int init_real_cpu_mask(struct hfi1_devdata *dd)
  * to the node relative 1 as necessary.
  *
  */
-void hfi1_dev_affinity_init(struct hfi1_devdata *dd)
+int hfi1_dev_affinity_init(struct hfi1_devdata *dd)
 {
        int node = pcibus_to_node(dd->pcidev->bus);
-       struct hfi1_affinity *info = dd->affinity;
+       struct hfi1_affinity_node *entry;
        const struct cpumask *local_mask;
        int curr_cpu, possible, i;
 
@@ -132,56 +230,93 @@ void hfi1_dev_affinity_init(struct hfi1_devdata *dd)
                node = numa_node_id();
        dd->node = node;
 
-       spin_lock_init(&info->lock);
-
-       init_cpu_mask_set(&info->def_intr);
-       init_cpu_mask_set(&info->rcv_intr);
-       init_cpu_mask_set(&info->proc);
-
        local_mask = cpumask_of_node(dd->node);
        if (cpumask_first(local_mask) >= nr_cpu_ids)
                local_mask = topology_core_cpumask(0);
-       /* Use the "real" cpu mask of this node as the default */
-       cpumask_and(&info->def_intr.mask, &info->real_cpu_mask, local_mask);
-
-       /*  fill in the receive list */
-       possible = cpumask_weight(&info->def_intr.mask);
-       curr_cpu = cpumask_first(&info->def_intr.mask);
-       if (possible == 1) {
-               /*  only one CPU, everyone will use it */
-               cpumask_set_cpu(curr_cpu, &info->rcv_intr.mask);
-       } else {
-               /*
-                * Retain the first CPU in the default list for the control
-                * context.
-                */
-               curr_cpu = cpumask_next(curr_cpu, &info->def_intr.mask);
-               /*
-                * Remove the remaining kernel receive queues from
-                * the default list and add them to the receive list.
-                */
-               for (i = 0; i < dd->n_krcv_queues - 1; i++) {
-                       cpumask_clear_cpu(curr_cpu, &info->def_intr.mask);
-                       cpumask_set_cpu(curr_cpu, &info->rcv_intr.mask);
-                       curr_cpu = cpumask_next(curr_cpu, &info->def_intr.mask);
-                       if (curr_cpu >= nr_cpu_ids)
-                               break;
+
+       spin_lock(&node_affinity.lock);
+       entry = node_affinity_lookup(dd->node);
+       spin_unlock(&node_affinity.lock);
+
+       /*
+        * If this is the first time this NUMA node's affinity is used,
+        * create an entry in the global affinity structure and initialize it.
+        */
+       if (!entry) {
+               entry = node_affinity_allocate(node);
+               if (!entry) {
+                       dd_dev_err(dd,
+                                  "Unable to allocate global affinity node\n");
+                       return -ENOMEM;
                }
-       }
+               init_cpu_mask_set(&entry->def_intr);
+               init_cpu_mask_set(&entry->rcv_intr);
+               cpumask_clear(&entry->general_intr_mask);
+               /* Use the "real" cpu mask of this node as the default */
+               cpumask_and(&entry->def_intr.mask, &node_affinity.real_cpu_mask,
+                           local_mask);
+
+               /* fill in the receive list */
+               possible = cpumask_weight(&entry->def_intr.mask);
+               curr_cpu = cpumask_first(&entry->def_intr.mask);
+
+               if (possible == 1) {
+                       /* only one CPU, everyone will use it */
+                       cpumask_set_cpu(curr_cpu, &entry->rcv_intr.mask);
+                       cpumask_set_cpu(curr_cpu, &entry->general_intr_mask);
+               } else {
+                       /*
+                        * The general/control context will be the first CPU in
+                        * the default list, so it is removed from the default
+                        * list and added to the general interrupt list.
+                        */
+                       cpumask_clear_cpu(curr_cpu, &entry->def_intr.mask);
+                       cpumask_set_cpu(curr_cpu, &entry->general_intr_mask);
+                       curr_cpu = cpumask_next(curr_cpu,
+                                               &entry->def_intr.mask);
 
-       cpumask_copy(&info->proc.mask, cpu_online_mask);
-}
+                       /*
+                        * Remove the remaining kernel receive queues from
+                        * the default list and add them to the receive list.
+                        */
+                       for (i = 0;
+                            i < (dd->n_krcv_queues - 1) *
+                                 hfi1_per_node_cntr[dd->node];
+                            i++) {
+                               cpumask_clear_cpu(curr_cpu,
+                                                 &entry->def_intr.mask);
+                               cpumask_set_cpu(curr_cpu,
+                                               &entry->rcv_intr.mask);
+                               curr_cpu = cpumask_next(curr_cpu,
+                                                       &entry->def_intr.mask);
+                               if (curr_cpu >= nr_cpu_ids)
+                                       break;
+                       }
 
-void hfi1_dev_affinity_free(struct hfi1_devdata *dd)
-{
-       kfree(dd->affinity);
+                       /*
+                        * If there ends up being 0 CPU cores leftover for SDMA
+                        * engines, use the same CPU cores as general/control
+                        * context.
+                        */
+                       if (cpumask_weight(&entry->def_intr.mask) == 0)
+                               cpumask_copy(&entry->def_intr.mask,
+                                            &entry->general_intr_mask);
+               }
+
+               spin_lock(&node_affinity.lock);
+               node_affinity_add_tail(entry);
+               spin_unlock(&node_affinity.lock);
+       }
+
+       return 0;
 }
 
 int hfi1_get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix)
 {
        int ret;
        cpumask_var_t diff;
-       struct cpu_mask_set *set;
+       struct hfi1_affinity_node *entry;
+       struct cpu_mask_set *set = NULL;
        struct sdma_engine *sde = NULL;
        struct hfi1_ctxtdata *rcd = NULL;
        char extra[64];
@@ -194,22 +329,25 @@ int hfi1_get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix)
        if (!ret)
                return -ENOMEM;
 
+       spin_lock(&node_affinity.lock);
+       entry = node_affinity_lookup(dd->node);
+       spin_unlock(&node_affinity.lock);
+
        switch (msix->type) {
        case IRQ_SDMA:
                sde = (struct sdma_engine *)msix->arg;
                scnprintf(extra, 64, "engine %u", sde->this_idx);
-               /* fall through */
+               set = &entry->def_intr;
+               break;
        case IRQ_GENERAL:
-               set = &dd->affinity->def_intr;
+               cpu = cpumask_first(&entry->general_intr_mask);
                break;
        case IRQ_RCVCTXT:
                rcd = (struct hfi1_ctxtdata *)msix->arg;
-               if (rcd->ctxt == HFI1_CTRL_CTXT) {
-                       set = &dd->affinity->def_intr;
-                       cpu = cpumask_first(&set->mask);
-               } else {
-                       set = &dd->affinity->rcv_intr;
-               }
+               if (rcd->ctxt == HFI1_CTRL_CTXT)
+                       cpu = cpumask_first(&entry->general_intr_mask);
+               else
+                       set = &entry->rcv_intr;
                scnprintf(extra, 64, "ctxt %u", rcd->ctxt);
                break;
        default:
@@ -218,12 +356,12 @@ int hfi1_get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix)
        }
 
        /*
-        * The control receive context is placed on a particular CPU, which
-        * is set above.  Skip accounting for it.  Everything else finds its
-        * CPU here.
+        * The general and control contexts are placed on a particular
+        * CPU, which is set above. Skip accounting for it. Everything else
+        * finds its CPU here.
         */
-       if (cpu == -1) {
-               spin_lock(&dd->affinity->lock);
+       if (cpu == -1 && set) {
+               spin_lock(&node_affinity.lock);
                if (cpumask_equal(&set->mask, &set->used)) {
                        /*
                         * We've used up all the CPUs, bump up the generation
@@ -235,7 +373,7 @@ int hfi1_get_irq_affinity(struct hfi1_devdata *dd, struct hfi1_msix_entry *msix)
                cpumask_andnot(diff, &set->mask, &set->used);
                cpu = cpumask_first(diff);
                cpumask_set_cpu(cpu, &set->used);
-               spin_unlock(&dd->affinity->lock);
+               spin_unlock(&node_affinity.lock);
        }
 
        switch (msix->type) {
@@ -263,43 +401,84 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *dd,
 {
        struct cpu_mask_set *set = NULL;
        struct hfi1_ctxtdata *rcd;
+       struct hfi1_affinity_node *entry;
+
+       spin_lock(&node_affinity.lock);
+       entry = node_affinity_lookup(dd->node);
+       spin_unlock(&node_affinity.lock);
 
        switch (msix->type) {
        case IRQ_SDMA:
+               set = &entry->def_intr;
+               break;
        case IRQ_GENERAL:
-               set = &dd->affinity->def_intr;
+               /* Don't do accounting for general contexts */
                break;
        case IRQ_RCVCTXT:
                rcd = (struct hfi1_ctxtdata *)msix->arg;
-               /* only do accounting for non control contexts */
+               /* Don't do accounting for control contexts */
                if (rcd->ctxt != HFI1_CTRL_CTXT)
-                       set = &dd->affinity->rcv_intr;
+                       set = &entry->rcv_intr;
                break;
        default:
                return;
        }
 
        if (set) {
-               spin_lock(&dd->affinity->lock);
+               spin_lock(&node_affinity.lock);
                cpumask_andnot(&set->used, &set->used, &msix->mask);
                if (cpumask_empty(&set->used) && set->gen) {
                        set->gen--;
                        cpumask_copy(&set->used, &set->mask);
                }
-               spin_unlock(&dd->affinity->lock);
+               spin_unlock(&node_affinity.lock);
        }
 
        irq_set_affinity_hint(msix->msix.vector, NULL);
        cpumask_clear(&msix->mask);
 }
 
-int hfi1_get_proc_affinity(struct hfi1_devdata *dd, int node)
+/* This should be called with node_affinity.lock held */
+static void find_hw_thread_mask(uint hw_thread_no, cpumask_var_t hw_thread_mask,
+                               struct hfi1_affinity_node_list *affinity)
 {
-       int cpu = -1, ret;
-       cpumask_var_t diff, mask, intrs;
+       int possible, curr_cpu, i;
+       uint num_cores_per_socket = node_affinity.num_online_cpus /
+                                       affinity->num_core_siblings /
+                                               node_affinity.num_online_nodes;
+
+       cpumask_copy(hw_thread_mask, &affinity->proc.mask);
+       if (affinity->num_core_siblings > 0) {
+               /* Removing other siblings not needed for now */
+               possible = cpumask_weight(hw_thread_mask);
+               curr_cpu = cpumask_first(hw_thread_mask);
+               for (i = 0;
+                    i < num_cores_per_socket * node_affinity.num_online_nodes;
+                    i++)
+                       curr_cpu = cpumask_next(curr_cpu, hw_thread_mask);
+
+               for (; i < possible; i++) {
+                       cpumask_clear_cpu(curr_cpu, hw_thread_mask);
+                       curr_cpu = cpumask_next(curr_cpu, hw_thread_mask);
+               }
+
+               /* Identifying correct HW threads within physical cores */
+               cpumask_shift_left(hw_thread_mask, hw_thread_mask,
+                                  num_cores_per_socket *
+                                  node_affinity.num_online_nodes *
+                                  hw_thread_no);
+       }
+}
+
+int hfi1_get_proc_affinity(int node)
+{
+       int cpu = -1, ret, i;
+       struct hfi1_affinity_node *entry;
+       cpumask_var_t diff, hw_thread_mask, available_mask, intrs_mask;
        const struct cpumask *node_mask,
                *proc_mask = tsk_cpus_allowed(current);
-       struct cpu_mask_set *set = &dd->affinity->proc;
+       struct hfi1_affinity_node_list *affinity = &node_affinity;
+       struct cpu_mask_set *set = &affinity->proc;
 
        /*
         * check whether process/context affinity has already
@@ -325,22 +504,41 @@ int hfi1_get_proc_affinity(struct hfi1_devdata *dd, int node)
 
        /*
         * The process does not have a preset CPU affinity so find one to
-        * recommend. We prefer CPUs on the same NUMA as the device.
+        * recommend using the following algorithm:
+        *
+        * For each user process that is opening a context on HFI Y:
+        *  a) If all cores are filled, reinitialize the bitmask
+        *  b) Fill real cores first, then HT cores (First set of HT
+        *     cores on all physical cores, then second set of HT core,
+        *     and, so on) in the following order:
+        *
+        *     1. Same NUMA node as HFI Y and not running an IRQ
+        *        handler
+        *     2. Same NUMA node as HFI Y and running an IRQ handler
+        *     3. Different NUMA node to HFI Y and not running an IRQ
+        *        handler
+        *     4. Different NUMA node to HFI Y and running an IRQ
+        *        handler
+        *  c) Mark core as filled in the bitmask. As user processes are
+        *     done, clear cores from the bitmask.
         */
 
        ret = zalloc_cpumask_var(&diff, GFP_KERNEL);
        if (!ret)
                goto done;
-       ret = zalloc_cpumask_var(&mask, GFP_KERNEL);
+       ret = zalloc_cpumask_var(&hw_thread_mask, GFP_KERNEL);
        if (!ret)
                goto free_diff;
-       ret = zalloc_cpumask_var(&intrs, GFP_KERNEL);
+       ret = zalloc_cpumask_var(&available_mask, GFP_KERNEL);
+       if (!ret)
+               goto free_hw_thread_mask;
+       ret = zalloc_cpumask_var(&intrs_mask, GFP_KERNEL);
        if (!ret)
-               goto free_mask;
+               goto free_available_mask;
 
-       spin_lock(&dd->affinity->lock);
+       spin_lock(&affinity->lock);
        /*
-        * If we've used all available CPUs, clear the mask and start
+        * If we've used all available HW threads, clear the mask and start
         * overloading.
         */
        if (cpumask_equal(&set->mask, &set->used)) {
@@ -348,81 +546,198 @@ int hfi1_get_proc_affinity(struct hfi1_devdata *dd, int node)
                cpumask_clear(&set->used);
        }
 
-       /* CPUs used by interrupt handlers */
-       cpumask_copy(intrs, (dd->affinity->def_intr.gen ?
-                            &dd->affinity->def_intr.mask :
-                            &dd->affinity->def_intr.used));
-       cpumask_or(intrs, intrs, (dd->affinity->rcv_intr.gen ?
-                                 &dd->affinity->rcv_intr.mask :
-                                 &dd->affinity->rcv_intr.used));
+       /*
+        * If NUMA node has CPUs used by interrupt handlers, include them in the
+        * interrupt handler mask.
+        */
+       entry = node_affinity_lookup(node);
+       if (entry) {
+               cpumask_copy(intrs_mask, (entry->def_intr.gen ?
+                                         &entry->def_intr.mask :
+                                         &entry->def_intr.used));
+               cpumask_or(intrs_mask, intrs_mask, (entry->rcv_intr.gen ?
+                                                   &entry->rcv_intr.mask :
+                                                   &entry->rcv_intr.used));
+               cpumask_or(intrs_mask, intrs_mask, &entry->general_intr_mask);
+       }
        hfi1_cdbg(PROC, "CPUs used by interrupts: %*pbl",
-                 cpumask_pr_args(intrs));
+                 cpumask_pr_args(intrs_mask));
+
+       cpumask_copy(hw_thread_mask, &set->mask);
 
        /*
-        * If we don't have a NUMA node requested, preference is towards
-        * device NUMA node
+        * If HT cores are enabled, identify which HW threads within the
+        * physical cores should be used.
         */
-       if (node == -1)
-               node = dd->node;
+       if (affinity->num_core_siblings > 0) {
+               for (i = 0; i < affinity->num_core_siblings; i++) {
+                       find_hw_thread_mask(i, hw_thread_mask, affinity);
+
+                       /*
+                        * If there's at least one available core for this HW
+                        * thread number, stop looking for a core.
+                        *
+                        * diff will always be not empty at least once in this
+                        * loop as the used mask gets reset when
+                        * (set->mask == set->used) before this loop.
+                        */
+                       cpumask_andnot(diff, hw_thread_mask, &set->used);
+                       if (!cpumask_empty(diff))
+                               break;
+               }
+       }
+       hfi1_cdbg(PROC, "Same available HW thread on all physical CPUs: %*pbl",
+                 cpumask_pr_args(hw_thread_mask));
+
        node_mask = cpumask_of_node(node);
-       hfi1_cdbg(PROC, "device on NUMA %u, CPUs %*pbl", node,
+       hfi1_cdbg(PROC, "Device on NUMA %u, CPUs %*pbl", node,
                  cpumask_pr_args(node_mask));
 
-       /* diff will hold all unused cpus */
-       cpumask_andnot(diff, &set->mask, &set->used);
-       hfi1_cdbg(PROC, "unused CPUs (all) %*pbl", cpumask_pr_args(diff));
-
-       /* get cpumask of available CPUs on preferred NUMA */
-       cpumask_and(mask, diff, node_mask);
-       hfi1_cdbg(PROC, "available cpus on NUMA %*pbl", cpumask_pr_args(mask));
+       /* Get cpumask of available CPUs on preferred NUMA */
+       cpumask_and(available_mask, hw_thread_mask, node_mask);
+       cpumask_andnot(available_mask, available_mask, &set->used);
+       hfi1_cdbg(PROC, "Available CPUs on NUMA %u: %*pbl", node,
+                 cpumask_pr_args(available_mask));
 
        /*
         * At first, we don't want to place processes on the same
-        * CPUs as interrupt handlers.
+        * CPUs as interrupt handlers. Then, CPUs running interrupt
+        * handlers are used.
+        *
+        * 1) If diff is not empty, then there are CPUs not running
+        *    non-interrupt handlers available, so diff gets copied
+        *    over to available_mask.
+        * 2) If diff is empty, then all CPUs not running interrupt
+        *    handlers are taken, so available_mask contains all
+        *    available CPUs running interrupt handlers.
+        * 3) If available_mask is empty, then all CPUs on the
+        *    preferred NUMA node are taken, so other NUMA nodes are
+        *    used for process assignments using the same method as
+        *    the preferred NUMA node.
         */
-       cpumask_andnot(diff, mask, intrs);
+       cpumask_andnot(diff, available_mask, intrs_mask);
        if (!cpumask_empty(diff))
-               cpumask_copy(mask, diff);
+               cpumask_copy(available_mask, diff);
 
-       /*
-        * if we don't have a cpu on the preferred NUMA, get
-        * the list of the remaining available CPUs
-        */
-       if (cpumask_empty(mask)) {
-               cpumask_andnot(diff, &set->mask, &set->used);
-               cpumask_andnot(mask, diff, node_mask);
+       /* If we don't have CPUs on the preferred node, use other NUMA nodes */
+       if (cpumask_empty(available_mask)) {
+               cpumask_andnot(available_mask, hw_thread_mask, &set->used);
+               /* Excluding preferred NUMA cores */
+               cpumask_andnot(available_mask, available_mask, node_mask);
+               hfi1_cdbg(PROC,
+                         "Preferred NUMA node cores are taken, cores available in other NUMA nodes: %*pbl",
+                         cpumask_pr_args(available_mask));
+
+               /*
+                * At first, we don't want to place processes on the same
+                * CPUs as interrupt handlers.
+                */
+               cpumask_andnot(diff, available_mask, intrs_mask);
+               if (!cpumask_empty(diff))
+                       cpumask_copy(available_mask, diff);
        }
-       hfi1_cdbg(PROC, "possible CPUs for process %*pbl",
-                 cpumask_pr_args(mask));
+       hfi1_cdbg(PROC, "Possible CPUs for process: %*pbl",
+                 cpumask_pr_args(available_mask));
 
-       cpu = cpumask_first(mask);
+       cpu = cpumask_first(available_mask);
        if (cpu >= nr_cpu_ids) /* empty */
                cpu = -1;
        else
                cpumask_set_cpu(cpu, &set->used);
-       spin_unlock(&dd->affinity->lock);
-
-       free_cpumask_var(intrs);
-free_mask:
-       free_cpumask_var(mask);
+       spin_unlock(&affinity->lock);
+       hfi1_cdbg(PROC, "Process assigned to CPU %d", cpu);
+
+       free_cpumask_var(intrs_mask);
+free_available_mask:
+       free_cpumask_var(available_mask);
+free_hw_thread_mask:
+       free_cpumask_var(hw_thread_mask);
 free_diff:
        free_cpumask_var(diff);
 done:
        return cpu;
 }
 
-void hfi1_put_proc_affinity(struct hfi1_devdata *dd, int cpu)
+void hfi1_put_proc_affinity(int cpu)
 {
-       struct cpu_mask_set *set = &dd->affinity->proc;
+       struct hfi1_affinity_node_list *affinity = &node_affinity;
+       struct cpu_mask_set *set = &affinity->proc;
 
        if (cpu < 0)
                return;
-       spin_lock(&dd->affinity->lock);
+       spin_lock(&affinity->lock);
        cpumask_clear_cpu(cpu, &set->used);
+       hfi1_cdbg(PROC, "Returning CPU %d for future process assignment", cpu);
        if (cpumask_empty(&set->used) && set->gen) {
                set->gen--;
                cpumask_copy(&set->used, &set->mask);
        }
-       spin_unlock(&dd->affinity->lock);
+       spin_unlock(&affinity->lock);
 }
 
+/* Prevents concurrent reads and writes of the sdma_affinity attrib */
+static DEFINE_MUTEX(sdma_affinity_mutex);
+
+int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf,
+                          size_t count)
+{
+       struct hfi1_affinity_node *entry;
+       struct cpumask mask;
+       int ret, i;
+
+       spin_lock(&node_affinity.lock);
+       entry = node_affinity_lookup(dd->node);
+       spin_unlock(&node_affinity.lock);
+
+       if (!entry)
+               return -EINVAL;
+
+       ret = cpulist_parse(buf, &mask);
+       if (ret)
+               return ret;
+
+       if (!cpumask_subset(&mask, cpu_online_mask) || cpumask_empty(&mask)) {
+               dd_dev_warn(dd, "Invalid CPU mask\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&sdma_affinity_mutex);
+       /* reset the SDMA interrupt affinity details */
+       init_cpu_mask_set(&entry->def_intr);
+       cpumask_copy(&entry->def_intr.mask, &mask);
+       /*
+        * Reassign the affinity for each SDMA interrupt.
+        */
+       for (i = 0; i < dd->num_msix_entries; i++) {
+               struct hfi1_msix_entry *msix;
+
+               msix = &dd->msix_entries[i];
+               if (msix->type != IRQ_SDMA)
+                       continue;
+
+               ret = hfi1_get_irq_affinity(dd, msix);
+
+               if (ret)
+                       break;
+       }
+
+       mutex_unlock(&sdma_affinity_mutex);
+       return ret ? ret : strnlen(buf, PAGE_SIZE);
+}
+
+int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf)
+{
+       struct hfi1_affinity_node *entry;
+
+       spin_lock(&node_affinity.lock);
+       entry = node_affinity_lookup(dd->node);
+       spin_unlock(&node_affinity.lock);
+
+       if (!entry)
+               return -EINVAL;
+
+       mutex_lock(&sdma_affinity_mutex);
+       cpumap_print_to_pagebuf(true, buf, &entry->def_intr.mask);
+       mutex_unlock(&sdma_affinity_mutex);
+       return strnlen(buf, PAGE_SIZE);
+}
index 20f52fe..8879cf7 100644 (file)
@@ -73,7 +73,6 @@ struct cpu_mask_set {
 struct hfi1_affinity {
        struct cpu_mask_set def_intr;
        struct cpu_mask_set rcv_intr;
-       struct cpu_mask_set proc;
        struct cpumask real_cpu_mask;
        /* spin lock to protect affinity struct */
        spinlock_t lock;
@@ -82,11 +81,9 @@ struct hfi1_affinity {
 struct hfi1_msix_entry;
 
 /* Initialize non-HT cpu cores mask */
-int init_real_cpu_mask(struct hfi1_devdata *);
+void init_real_cpu_mask(void);
 /* Initialize driver affinity data */
-void hfi1_dev_affinity_init(struct hfi1_devdata *);
-/* Free driver affinity data */
-void hfi1_dev_affinity_free(struct hfi1_devdata *);
+int hfi1_dev_affinity_init(struct hfi1_devdata *);
 /*
  * Set IRQ affinity to a CPU. The function will determine the
  * CPU and set the affinity to it.
@@ -101,8 +98,35 @@ void hfi1_put_irq_affinity(struct hfi1_devdata *, struct hfi1_msix_entry *);
  * Determine a CPU affinity for a user process, if the process does not
  * have an affinity set yet.
  */
-int hfi1_get_proc_affinity(struct hfi1_devdata *, int);
+int hfi1_get_proc_affinity(int);
 /* Release a CPU used by a user process. */
-void hfi1_put_proc_affinity(struct hfi1_devdata *, int);
+void hfi1_put_proc_affinity(int);
+
+int hfi1_get_sdma_affinity(struct hfi1_devdata *dd, char *buf);
+int hfi1_set_sdma_affinity(struct hfi1_devdata *dd, const char *buf,
+                          size_t count);
+
+struct hfi1_affinity_node {
+       int node;
+       struct cpu_mask_set def_intr;
+       struct cpu_mask_set rcv_intr;
+       struct cpumask general_intr_mask;
+       struct list_head list;
+};
+
+struct hfi1_affinity_node_list {
+       struct list_head list;
+       struct cpumask real_cpu_mask;
+       struct cpu_mask_set proc;
+       int num_core_siblings;
+       int num_online_nodes;
+       int num_online_cpus;
+       /* protect affinity node list */
+       spinlock_t lock;
+};
+
+int node_affinity_init(void);
+void node_affinity_destroy(void);
+extern struct hfi1_affinity_node_list node_affinity;
 
 #endif /* _HFI1_AFFINITY_H */
index dad4d0e..b32638d 100644 (file)
@@ -63,6 +63,7 @@
 #include "efivar.h"
 #include "platform.h"
 #include "aspm.h"
+#include "affinity.h"
 
 #define NUM_IB_PORTS 1
 
@@ -121,6 +122,7 @@ struct flag_table {
 #define SEC_SC_HALTED          0x4     /* per-context only */
 #define SEC_SPC_FREEZE         0x8     /* per-HFI only */
 
+#define DEFAULT_KRCVQS           2
 #define MIN_KERNEL_KCTXTS         2
 #define FIRST_KERNEL_KCTXT        1
 /* sizes for both the QP and RSM map tables */
@@ -238,6 +240,9 @@ struct flag_table {
 /* all CceStatus sub-block RXE pause bits */
 #define ALL_RXE_PAUSE CCE_STATUS_RXE_PAUSED_SMASK
 
+#define CNTR_MAX 0xFFFFFFFFFFFFFFFFULL
+#define CNTR_32BIT_MAX 0x00000000FFFFFFFF
+
 /*
  * CCE Error flags.
  */
@@ -3947,6 +3952,28 @@ static u64 access_sdma_wrong_dw_err_cnt(const struct cntr_entry *entry,
        return dd->sw_send_dma_eng_err_status_cnt[0];
 }
 
+static u64 access_dc_rcv_err_cnt(const struct cntr_entry *entry,
+                                void *context, int vl, int mode,
+                                u64 data)
+{
+       struct hfi1_devdata *dd = (struct hfi1_devdata *)context;
+
+       u64 val = 0;
+       u64 csr = entry->csr;
+
+       val = read_write_csr(dd, csr, mode, data);
+       if (mode == CNTR_MODE_R) {
+               val = val > CNTR_MAX - dd->sw_rcv_bypass_packet_errors ?
+                       CNTR_MAX : val + dd->sw_rcv_bypass_packet_errors;
+       } else if (mode == CNTR_MODE_W) {
+               dd->sw_rcv_bypass_packet_errors = 0;
+       } else {
+               dd_dev_err(dd, "Invalid cntr register access mode");
+               return 0;
+       }
+       return val;
+}
+
 #define def_access_sw_cpu(cntr) \
 static u64 access_sw_cpu_##cntr(const struct cntr_entry *entry,                      \
                              void *context, int vl, int mode, u64 data)      \
@@ -4020,7 +4047,8 @@ static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = {
                        CCE_SEND_CREDIT_INT_CNT, CNTR_NORMAL),
 [C_DC_UNC_ERR] = DC_PERF_CNTR(DcUnctblErr, DCC_ERR_UNCORRECTABLE_CNT,
                              CNTR_SYNTH),
-[C_DC_RCV_ERR] = DC_PERF_CNTR(DcRecvErr, DCC_ERR_PORTRCV_ERR_CNT, CNTR_SYNTH),
+[C_DC_RCV_ERR] = CNTR_ELEM("DcRecvErr", DCC_ERR_PORTRCV_ERR_CNT, 0, CNTR_SYNTH,
+                           access_dc_rcv_err_cnt),
 [C_DC_FM_CFG_ERR] = DC_PERF_CNTR(DcFmCfgErr, DCC_ERR_FMCONFIG_ERR_CNT,
                                 CNTR_SYNTH),
 [C_DC_RMT_PHY_ERR] = DC_PERF_CNTR(DcRmtPhyErr, DCC_ERR_RCVREMOTE_PHY_ERR_CNT,
@@ -8798,30 +8826,6 @@ static int write_tx_settings(struct hfi1_devdata *dd,
        return load_8051_config(dd, TX_SETTINGS, GENERAL_CONFIG, frame);
 }
 
-static void check_fabric_firmware_versions(struct hfi1_devdata *dd)
-{
-       u32 frame, version, prod_id;
-       int ret, lane;
-
-       /* 4 lanes */
-       for (lane = 0; lane < 4; lane++) {
-               ret = read_8051_config(dd, SPICO_FW_VERSION, lane, &frame);
-               if (ret) {
-                       dd_dev_err(dd,
-                                  "Unable to read lane %d firmware details\n",
-                                  lane);
-                       continue;
-               }
-               version = (frame >> SPICO_ROM_VERSION_SHIFT)
-                                       & SPICO_ROM_VERSION_MASK;
-               prod_id = (frame >> SPICO_ROM_PROD_ID_SHIFT)
-                                       & SPICO_ROM_PROD_ID_MASK;
-               dd_dev_info(dd,
-                           "Lane %d firmware: version 0x%04x, prod_id 0x%04x\n",
-                           lane, version, prod_id);
-       }
-}
-
 /*
  * Read an idle LCB message.
  *
@@ -9187,17 +9191,24 @@ static void wait_for_qsfp_init(struct hfi1_pportdata *ppd)
        unsigned long timeout;
 
        /*
-        * Check for QSFP interrupt for t_init (SFF 8679)
+        * Some QSFP cables have a quirk that asserts the IntN line as a side
+        * effect of power up on plug-in. We ignore this false positive
+        * interrupt until the module has finished powering up by waiting for
+        * a minimum timeout of the module inrush initialization time of
+        * 500 ms (SFF 8679 Table 5-6) to ensure the voltage rails in the
+        * module have stabilized.
+        */
+       msleep(500);
+
+       /*
+        * Check for QSFP interrupt for t_init (SFF 8679 Table 8-1)
         */
        timeout = jiffies + msecs_to_jiffies(2000);
        while (1) {
                mask = read_csr(dd, dd->hfi1_id ?
                                ASIC_QSFP2_IN : ASIC_QSFP1_IN);
-               if (!(mask & QSFP_HFI0_INT_N)) {
-                       write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_CLEAR :
-                                 ASIC_QSFP1_CLEAR, QSFP_HFI0_INT_N);
+               if (!(mask & QSFP_HFI0_INT_N))
                        break;
-               }
                if (time_after(jiffies, timeout)) {
                        dd_dev_info(dd, "%s: No IntN detected, reset complete\n",
                                    __func__);
@@ -9213,10 +9224,17 @@ static void set_qsfp_int_n(struct hfi1_pportdata *ppd, u8 enable)
        u64 mask;
 
        mask = read_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK);
-       if (enable)
+       if (enable) {
+               /*
+                * Clear the status register to avoid an immediate interrupt
+                * when we re-enable the IntN pin
+                */
+               write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_CLEAR : ASIC_QSFP1_CLEAR,
+                         QSFP_HFI0_INT_N);
                mask |= (u64)QSFP_HFI0_INT_N;
-       else
+       } else {
                mask &= ~(u64)QSFP_HFI0_INT_N;
+       }
        write_csr(dd, dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, mask);
 }
 
@@ -9630,14 +9648,6 @@ void hfi1_clear_tids(struct hfi1_ctxtdata *rcd)
                hfi1_put_tid(dd, i, PT_INVALID, 0, 0);
 }
 
-int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd,
-                       struct hfi1_ctxt_info *kinfo)
-{
-       kinfo->runtime_flags = (HFI1_MISC_GET() << HFI1_CAP_USER_SHIFT) |
-               HFI1_CAP_UGET(MASK) | HFI1_CAP_KGET(K2U);
-       return 0;
-}
-
 struct hfi1_message_header *hfi1_get_msgheader(
                                struct hfi1_devdata *dd, __le32 *rhf_addr)
 {
@@ -9890,6 +9900,131 @@ static int wait_phy_linkstate(struct hfi1_devdata *dd, u32 state, u32 msecs)
        return 0;
 }
 
+static const char *state_completed_string(u32 completed)
+{
+       static const char * const state_completed[] = {
+               "EstablishComm",
+               "OptimizeEQ",
+               "VerifyCap"
+       };
+
+       if (completed < ARRAY_SIZE(state_completed))
+               return state_completed[completed];
+
+       return "unknown";
+}
+
+static const char all_lanes_dead_timeout_expired[] =
+       "All lanes were inactive – was the interconnect media removed?";
+static const char tx_out_of_policy[] =
+       "Passing lanes on local port do not meet the local link width policy";
+static const char no_state_complete[] =
+       "State timeout occurred before link partner completed the state";
+static const char * const state_complete_reasons[] = {
+       [0x00] = "Reason unknown",
+       [0x01] = "Link was halted by driver, refer to LinkDownReason",
+       [0x02] = "Link partner reported failure",
+       [0x10] = "Unable to achieve frame sync on any lane",
+       [0x11] =
+         "Unable to find a common bit rate with the link partner",
+       [0x12] =
+         "Unable to achieve frame sync on sufficient lanes to meet the local link width policy",
+       [0x13] =
+         "Unable to identify preset equalization on sufficient lanes to meet the local link width policy",
+       [0x14] = no_state_complete,
+       [0x15] =
+         "State timeout occurred before link partner identified equalization presets",
+       [0x16] =
+         "Link partner completed the EstablishComm state, but the passing lanes do not meet the local link width policy",
+       [0x17] = tx_out_of_policy,
+       [0x20] = all_lanes_dead_timeout_expired,
+       [0x21] =
+         "Unable to achieve acceptable BER on sufficient lanes to meet the local link width policy",
+       [0x22] = no_state_complete,
+       [0x23] =
+         "Link partner completed the OptimizeEq state, but the passing lanes do not meet the local link width policy",
+       [0x24] = tx_out_of_policy,
+       [0x30] = all_lanes_dead_timeout_expired,
+       [0x31] =
+         "State timeout occurred waiting for host to process received frames",
+       [0x32] = no_state_complete,
+       [0x33] =
+         "Link partner completed the VerifyCap state, but the passing lanes do not meet the local link width policy",
+       [0x34] = tx_out_of_policy,
+};
+
+static const char *state_complete_reason_code_string(struct hfi1_pportdata *ppd,
+                                                    u32 code)
+{
+       const char *str = NULL;
+
+       if (code < ARRAY_SIZE(state_complete_reasons))
+               str = state_complete_reasons[code];
+
+       if (str)
+               return str;
+       return "Reserved";
+}
+
+/* describe the given last state complete frame */
+static void decode_state_complete(struct hfi1_pportdata *ppd, u32 frame,
+                                 const char *prefix)
+{
+       struct hfi1_devdata *dd = ppd->dd;
+       u32 success;
+       u32 state;
+       u32 reason;
+       u32 lanes;
+
+       /*
+        * Decode frame:
+        *  [ 0: 0] - success
+        *  [ 3: 1] - state
+        *  [ 7: 4] - next state timeout
+        *  [15: 8] - reason code
+        *  [31:16] - lanes
+        */
+       success = frame & 0x1;
+       state = (frame >> 1) & 0x7;
+       reason = (frame >> 8) & 0xff;
+       lanes = (frame >> 16) & 0xffff;
+
+       dd_dev_err(dd, "Last %s LNI state complete frame 0x%08x:\n",
+                  prefix, frame);
+       dd_dev_err(dd, "    last reported state state: %s (0x%x)\n",
+                  state_completed_string(state), state);
+       dd_dev_err(dd, "    state successfully completed: %s\n",
+                  success ? "yes" : "no");
+       dd_dev_err(dd, "    fail reason 0x%x: %s\n",
+                  reason, state_complete_reason_code_string(ppd, reason));
+       dd_dev_err(dd, "    passing lane mask: 0x%x", lanes);
+}
+
+/*
+ * Read the last state complete frames and explain them.  This routine
+ * expects to be called if the link went down during link negotiation
+ * and initialization (LNI).  That is, anywhere between polling and link up.
+ */
+static void check_lni_states(struct hfi1_pportdata *ppd)
+{
+       u32 last_local_state;
+       u32 last_remote_state;
+
+       read_last_local_state(ppd->dd, &last_local_state);
+       read_last_remote_state(ppd->dd, &last_remote_state);
+
+       /*
+        * Don't report anything if there is nothing to report.  A value of
+        * 0 means the link was taken down while polling and there was no
+        * training in-process.
+        */
+       if (last_local_state == 0 && last_remote_state == 0)
+               return;
+
+       decode_state_complete(ppd, last_local_state, "transmitted");
+       decode_state_complete(ppd, last_remote_state, "received");
+}
+
 /*
  * Helper for set_link_state().  Do not call except from that routine.
  * Expects ppd->hls_mutex to be held.
@@ -9902,8 +10037,6 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
 {
        struct hfi1_devdata *dd = ppd->dd;
        u32 pstate, previous_state;
-       u32 last_local_state;
-       u32 last_remote_state;
        int ret;
        int do_transition;
        int do_wait;
@@ -10003,12 +10136,7 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
        } else if (previous_state
                        & (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) {
                /* went down while attempting link up */
-               /* byte 1 of last_*_state is the failure reason */
-               read_last_local_state(dd, &last_local_state);
-               read_last_remote_state(dd, &last_remote_state);
-               dd_dev_err(dd,
-                          "LNI failure last states: local 0x%08x, remote 0x%08x\n",
-                          last_local_state, last_remote_state);
+               check_lni_states(ppd);
        }
 
        /* the active link width (downgrade) is 0 on link down */
@@ -11668,9 +11796,6 @@ static void free_cntrs(struct hfi1_devdata *dd)
        dd->cntrnames = NULL;
 }
 
-#define CNTR_MAX 0xFFFFFFFFFFFFFFFFULL
-#define CNTR_32BIT_MAX 0x00000000FFFFFFFF
-
 static u64 read_dev_port_cntr(struct hfi1_devdata *dd, struct cntr_entry *entry,
                              u64 *psval, void *context, int vl)
 {
@@ -12325,37 +12450,6 @@ u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd)
        return ib_pstate;
 }
 
-/*
- * Read/modify/write ASIC_QSFP register bits as selected by mask
- * data: 0 or 1 in the positions depending on what needs to be written
- * dir: 0 for read, 1 for write
- * mask: select by setting
- *      I2CCLK  (bit 0)
- *      I2CDATA (bit 1)
- */
-u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir,
-                 u32 mask)
-{
-       u64 qsfp_oe, target_oe;
-
-       target_oe = target ? ASIC_QSFP2_OE : ASIC_QSFP1_OE;
-       if (mask) {
-               /* We are writing register bits, so lock access */
-               dir &= mask;
-               data &= mask;
-
-               qsfp_oe = read_csr(dd, target_oe);
-               qsfp_oe = (qsfp_oe & ~(u64)mask) | (u64)dir;
-               write_csr(dd, target_oe, qsfp_oe);
-       }
-       /* We are exclusively reading bits here, but it is unlikely
-        * we'll get valid data when we set the direction of the pin
-        * in the same call, so read should call this function again
-        * to get valid data
-        */
-       return read_csr(dd, target ? ASIC_QSFP2_IN : ASIC_QSFP1_IN);
-}
-
 #define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \
 (r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK)
 
@@ -12780,7 +12874,6 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
 
        /*
         * Kernel receive contexts:
-        * - min of 2 or 1 context/numa (excluding control context)
         * - Context 0 - control context (VL15/multicast/error)
         * - Context 1 - first kernel context
         * - Context 2 - second kernel context
@@ -12794,9 +12887,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
                 */
                num_kernel_contexts = n_krcvqs + 1;
        else
-               num_kernel_contexts = num_online_nodes() + 1;
-       num_kernel_contexts =
-               max_t(int, MIN_KERNEL_KCTXTS, num_kernel_contexts);
+               num_kernel_contexts = DEFAULT_KRCVQS + 1;
        /*
         * Every kernel receive context needs an ACK send context.
         * one send context is allocated for each VL{0-7} and VL15
@@ -12815,7 +12906,7 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
         */
        if (num_user_contexts < 0)
                num_user_contexts =
-                       cpumask_weight(&dd->affinity->real_cpu_mask);
+                       cpumask_weight(&node_affinity.real_cpu_mask);
 
        total_contexts = num_kernel_contexts + num_user_contexts;
 
@@ -14141,6 +14232,11 @@ static int init_asic_data(struct hfi1_devdata *dd)
        }
        dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */
        spin_unlock_irqrestore(&hfi1_devs_lock, flags);
+
+       /* first one through - set up i2c devices */
+       if (!peer)
+               ret = set_up_i2c(dd, dd->asic_data);
+
        return ret;
 }
 
@@ -14445,19 +14541,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
                 (dd->revision >> CCE_REVISION_SW_SHIFT)
                    & CCE_REVISION_SW_MASK);
 
-       /*
-        * The real cpu mask is part of the affinity struct but has to be
-        * initialized earlier than the rest of the affinity struct because it
-        * is needed to calculate the number of user contexts in
-        * set_up_context_variables(). However, hfi1_dev_affinity_init(),
-        * which initializes the rest of the affinity struct members,
-        * depends on set_up_context_variables() for the number of kernel
-        * contexts, so it cannot be called before set_up_context_variables().
-        */
-       ret = init_real_cpu_mask(dd);
-       if (ret)
-               goto bail_cleanup;
-
        ret = set_up_context_variables(dd);
        if (ret)
                goto bail_cleanup;
@@ -14471,7 +14554,9 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
        /* set up KDETH QP prefix in both RX and TX CSRs */
        init_kdeth_qp(dd);
 
-       hfi1_dev_affinity_init(dd);
+       ret = hfi1_dev_affinity_init(dd);
+       if (ret)
+               goto bail_cleanup;
 
        /* send contexts must be set up before receive contexts */
        ret = init_send_contexts(dd);
@@ -14508,8 +14593,14 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
        /* set up LCB access - must be after set_up_interrupts() */
        init_lcb_access(dd);
 
+       /*
+        * Serial number is created from the base guid:
+        * [27:24] = base guid [38:35]
+        * [23: 0] = base guid [23: 0]
+        */
        snprintf(dd->serial, SERIAL_MAX, "0x%08llx\n",
-                dd->base_guid & 0xFFFFFF);
+                (dd->base_guid & 0xFFFFFF) |
+                    ((dd->base_guid >> 11) & 0xF000000));
 
        dd->oui1 = dd->base_guid >> 56 & 0xFF;
        dd->oui2 = dd->base_guid >> 48 & 0xFF;
@@ -14518,7 +14609,6 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
        ret = load_firmware(dd); /* asymmetric with dispose_firmware() */
        if (ret)
                goto bail_clear_intr;
-       check_fabric_firmware_versions(dd);
 
        thermal_init(dd);
 
index 66a3279..ed11107 100644 (file)
@@ -640,6 +640,7 @@ extern uint platform_config_load;
 /* SBus commands */
 #define RESET_SBUS_RECEIVER 0x20
 #define WRITE_SBUS_RECEIVER 0x21
+#define READ_SBUS_RECEIVER  0x22
 void sbus_request(struct hfi1_devdata *dd,
                  u8 receiver_addr, u8 data_addr, u8 command, u32 data_in);
 int sbus_request_slow(struct hfi1_devdata *dd,
@@ -1336,10 +1337,6 @@ void hfi1_start_cleanup(struct hfi1_devdata *dd);
 void hfi1_clear_tids(struct hfi1_ctxtdata *rcd);
 struct hfi1_message_header *hfi1_get_msgheader(
                                struct hfi1_devdata *dd, __le32 *rhf_addr);
-int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd,
-                       struct hfi1_ctxt_info *kinfo);
-u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir,
-                 u32 mask);
 int hfi1_init_ctxt(struct send_context *sc);
 void hfi1_put_tid(struct hfi1_devdata *dd, u32 index,
                  u32 type, unsigned long pa, u16 order);
index 8744de6..5b99938 100644 (file)
 #define ASIC_STS_SBUS_RESULT (ASIC + 0x000000000010)
 #define ASIC_STS_SBUS_RESULT_DONE_SMASK 0x1ull
 #define ASIC_STS_SBUS_RESULT_RCV_DATA_VALID_SMASK 0x2ull
+#define ASIC_STS_SBUS_RESULT_RESULT_CODE_SHIFT 2
+#define ASIC_STS_SBUS_RESULT_RESULT_CODE_MASK 0x7ull
+#define ASIC_STS_SBUS_RESULT_DATA_OUT_SHIFT 32
+#define ASIC_STS_SBUS_RESULT_DATA_OUT_MASK 0xFFFFFFFFull
 #define ASIC_STS_THERM (ASIC + 0x000000000058)
 #define ASIC_STS_THERM_CRIT_TEMP_MASK 0x7FFull
 #define ASIC_STS_THERM_CRIT_TEMP_SHIFT 18
index c75b0ae..8246dc7 100644 (file)
@@ -392,9 +392,7 @@ static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd,
                        u16 rlid;
                        u8 svc_type, sl, sc5;
 
-                       sc5  = (be16_to_cpu(rhdr->lrh[0]) >> 12) & 0xf;
-                       if (rhf_dc_info(packet->rhf))
-                               sc5 |= 0x10;
+                       sc5 = hdr2sc(rhdr, packet->rhf);
                        sl = ibp->sc_to_sl[sc5];
 
                        lqpn = be32_to_cpu(bth[1]) & RVT_QPN_MASK;
@@ -450,14 +448,20 @@ static inline void init_packet(struct hfi1_ctxtdata *rcd,
        packet->rcv_flags = 0;
 }
 
-static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr,
-                       struct hfi1_other_headers *ohdr,
-                       u64 rhf, u32 bth1, struct ib_grh *grh)
+void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
+                              bool do_cnp)
 {
        struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
-       u32 rqpn = 0;
-       u16 rlid;
-       u8 sc5, svc_type;
+       struct hfi1_ib_header *hdr = pkt->hdr;
+       struct hfi1_other_headers *ohdr = pkt->ohdr;
+       struct ib_grh *grh = NULL;
+       u32 rqpn = 0, bth1;
+       u16 rlid, dlid = be16_to_cpu(hdr->lrh[1]);
+       u8 sc, svc_type;
+       bool is_mcast = false;
+
+       if (pkt->rcv_flags & HFI1_HAS_GRH)
+               grh = &hdr->u.l.grh;
 
        switch (qp->ibqp.qp_type) {
        case IB_QPT_SMI:
@@ -466,6 +470,8 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr,
                rlid = be16_to_cpu(hdr->lrh[3]);
                rqpn = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK;
                svc_type = IB_CC_SVCTYPE_UD;
+               is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
+                       (dlid != be16_to_cpu(IB_LID_PERMISSIVE));
                break;
        case IB_QPT_UC:
                rlid = qp->remote_ah_attr.dlid;
@@ -481,24 +487,23 @@ static void process_ecn(struct rvt_qp *qp, struct hfi1_ib_header *hdr,
                return;
        }
 
-       sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf;
-       if (rhf_dc_info(rhf))
-               sc5 |= 0x10;
+       sc = hdr2sc((struct hfi1_message_header *)hdr, pkt->rhf);
 
-       if (bth1 & HFI1_FECN_SMASK) {
+       bth1 = be32_to_cpu(ohdr->bth[1]);
+       if (do_cnp && (bth1 & HFI1_FECN_SMASK)) {
                u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]);
-               u16 dlid = be16_to_cpu(hdr->lrh[1]);
 
-               return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc5, grh);
+               return_cnp(ibp, qp, rqpn, pkey, dlid, rlid, sc, grh);
        }
 
-       if (bth1 & HFI1_BECN_SMASK) {
+       if (!is_mcast && (bth1 & HFI1_BECN_SMASK)) {
                struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
                u32 lqpn = bth1 & RVT_QPN_MASK;
-               u8 sl = ibp->sc_to_sl[sc5];
+               u8 sl = ibp->sc_to_sl[sc];
 
                process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type);
        }
+
 }
 
 struct ps_mdata {
@@ -596,7 +601,6 @@ static void __prescan_rxq(struct hfi1_packet *packet)
                struct rvt_qp *qp;
                struct hfi1_ib_header *hdr;
                struct hfi1_other_headers *ohdr;
-               struct ib_grh *grh = NULL;
                struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
                u64 rhf = rhf_to_cpu(rhf_addr);
                u32 etype = rhf_rcv_type(rhf), qpn, bth1;
@@ -616,14 +620,13 @@ static void __prescan_rxq(struct hfi1_packet *packet)
                        hfi1_get_msgheader(dd, rhf_addr);
                lnh = be16_to_cpu(hdr->lrh[0]) & 3;
 
-               if (lnh == HFI1_LRH_BTH) {
+               if (lnh == HFI1_LRH_BTH)
                        ohdr = &hdr->u.oth;
-               } else if (lnh == HFI1_LRH_GRH) {
+               else if (lnh == HFI1_LRH_GRH)
                        ohdr = &hdr->u.l.oth;
-                       grh = &hdr->u.l.grh;
-               } else {
+               else
                        goto next; /* just in case */
-               }
+
                bth1 = be32_to_cpu(ohdr->bth[1]);
                is_ecn = !!(bth1 & (HFI1_FECN_SMASK | HFI1_BECN_SMASK));
 
@@ -639,7 +642,7 @@ static void __prescan_rxq(struct hfi1_packet *packet)
                        goto next;
                }
 
-               process_ecn(qp, hdr, ohdr, rhf, bth1, grh);
+               process_ecn(qp, packet, true);
                rcu_read_unlock();
 
                /* turn off BECN, FECN */
@@ -1362,6 +1365,7 @@ int process_receive_bypass(struct hfi1_packet *packet)
 
        dd_dev_err(packet->rcd->dd,
                   "Bypass packets are not supported in normal operation. Dropping\n");
+       incr_cntr64(&packet->rcd->dd->sw_rcv_bypass_packet_errors);
        return RHF_RCV_CONTINUE;
 }
 
index c702a00..1ecbec1 100644 (file)
@@ -168,6 +168,7 @@ static inline int is_valid_mmap(u64 token)
 
 static int hfi1_file_open(struct inode *inode, struct file *fp)
 {
+       struct hfi1_filedata *fd;
        struct hfi1_devdata *dd = container_of(inode->i_cdev,
                                               struct hfi1_devdata,
                                               user_cdev);
@@ -176,10 +177,17 @@ static int hfi1_file_open(struct inode *inode, struct file *fp)
        kobject_get(&dd->kobj);
 
        /* The real work is performed later in assign_ctxt() */
-       fp->private_data = kzalloc(sizeof(struct hfi1_filedata), GFP_KERNEL);
-       if (fp->private_data) /* no cpu affinity by default */
-               ((struct hfi1_filedata *)fp->private_data)->rec_cpu_num = -1;
-       return fp->private_data ? 0 : -ENOMEM;
+
+       fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+
+       if (fd) {
+               fd->rec_cpu_num = -1; /* no cpu affinity by default */
+               fd->mm = current->mm;
+       }
+
+       fp->private_data = fd;
+
+       return fd ? 0 : -ENOMEM;
 }
 
 static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
@@ -228,7 +236,7 @@ static long hfi1_file_ioctl(struct file *fp, unsigned int cmd,
                                    sizeof(struct hfi1_base_info));
                break;
        case HFI1_IOCTL_CREDIT_UPD:
-               if (uctxt && uctxt->sc)
+               if (uctxt)
                        sc_return_credits(uctxt->sc);
                break;
 
@@ -392,41 +400,38 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
        struct hfi1_filedata *fd = kiocb->ki_filp->private_data;
        struct hfi1_user_sdma_pkt_q *pq = fd->pq;
        struct hfi1_user_sdma_comp_q *cq = fd->cq;
-       int ret = 0, done = 0, reqs = 0;
+       int done = 0, reqs = 0;
        unsigned long dim = from->nr_segs;
 
-       if (!cq || !pq) {
-               ret = -EIO;
-               goto done;
-       }
+       if (!cq || !pq)
+               return -EIO;
 
-       if (!iter_is_iovec(from) || !dim) {
-               ret = -EINVAL;
-               goto done;
-       }
+       if (!iter_is_iovec(from) || !dim)
+               return -EINVAL;
 
        hfi1_cdbg(SDMA, "SDMA request from %u:%u (%lu)",
                  fd->uctxt->ctxt, fd->subctxt, dim);
 
-       if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) {
-               ret = -ENOSPC;
-               goto done;
-       }
+       if (atomic_read(&pq->n_reqs) == pq->n_max_reqs)
+               return -ENOSPC;
 
        while (dim) {
+               int ret;
                unsigned long count = 0;
 
                ret = hfi1_user_sdma_process_request(
                        kiocb->ki_filp, (struct iovec *)(from->iov + done),
                        dim, &count);
-               if (ret)
-                       goto done;
+               if (ret) {
+                       reqs = ret;
+                       break;
+               }
                dim -= count;
                done += count;
                reqs++;
        }
-done:
-       return ret ? ret : reqs;
+
+       return reqs;
 }
 
 static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
@@ -718,7 +723,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
        hfi1_user_sdma_free_queues(fdata);
 
        /* release the cpu */
-       hfi1_put_proc_affinity(dd, fdata->rec_cpu_num);
+       hfi1_put_proc_affinity(fdata->rec_cpu_num);
 
        /*
         * Clear any left over, unhandled events so the next process that
@@ -730,7 +735,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
 
        if (--uctxt->cnt) {
                uctxt->active_slaves &= ~(1 << fdata->subctxt);
-               uctxt->subpid[fdata->subctxt] = 0;
                mutex_unlock(&hfi1_mutex);
                goto done;
        }
@@ -756,7 +760,6 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
        write_kctxt_csr(dd, uctxt->sc->hw_context, SEND_CTXT_CHECK_ENABLE,
                        hfi1_pkt_default_send_ctxt_mask(dd, uctxt->sc->type));
        sc_disable(uctxt->sc);
-       uctxt->pid = 0;
        spin_unlock_irqrestore(&dd->uctxt_lock, flags);
 
        dd->rcd[uctxt->ctxt] = NULL;
@@ -818,9 +821,10 @@ static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo)
                ret = find_shared_ctxt(fp, uinfo);
                if (ret < 0)
                        goto done_unlock;
-               if (ret)
-                       fd->rec_cpu_num = hfi1_get_proc_affinity(
-                               fd->uctxt->dd, fd->uctxt->numa_id);
+               if (ret) {
+                       fd->rec_cpu_num =
+                               hfi1_get_proc_affinity(fd->uctxt->numa_id);
+               }
        }
 
        /*
@@ -895,7 +899,6 @@ static int find_shared_ctxt(struct file *fp,
                        }
                        fd->uctxt = uctxt;
                        fd->subctxt  = uctxt->cnt++;
-                       uctxt->subpid[fd->subctxt] = current->pid;
                        uctxt->active_slaves |= 1 << fd->subctxt;
                        ret = 1;
                        goto done;
@@ -932,7 +935,11 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
        if (ctxt == dd->num_rcv_contexts)
                return -EBUSY;
 
-       fd->rec_cpu_num = hfi1_get_proc_affinity(dd, -1);
+       /*
+        * If we don't have a NUMA node requested, preference is towards
+        * device NUMA node.
+        */
+       fd->rec_cpu_num = hfi1_get_proc_affinity(dd->node);
        if (fd->rec_cpu_num != -1)
                numa = cpu_to_node(fd->rec_cpu_num);
        else
@@ -976,8 +983,7 @@ static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd,
                        return ret;
        }
        uctxt->userversion = uinfo->userversion;
-       uctxt->pid = current->pid;
-       uctxt->flags = HFI1_CAP_UGET(MASK);
+       uctxt->flags = hfi1_cap_mask; /* save current flag state */
        init_waitqueue_head(&uctxt->wait);
        strlcpy(uctxt->comm, current->comm, sizeof(uctxt->comm));
        memcpy(uctxt->uuid, uinfo->uuid, sizeof(uctxt->uuid));
@@ -1080,18 +1086,18 @@ static int user_init(struct file *fp)
        hfi1_set_ctxt_jkey(uctxt->dd, uctxt->ctxt, uctxt->jkey);
 
        rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB;
-       if (HFI1_CAP_KGET_MASK(uctxt->flags, HDRSUPP))
+       if (HFI1_CAP_UGET_MASK(uctxt->flags, HDRSUPP))
                rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB;
        /*
         * Ignore the bit in the flags for now until proper
         * support for multiple packet per rcv array entry is
         * added.
         */
-       if (!HFI1_CAP_KGET_MASK(uctxt->flags, MULTI_PKT_EGR))
+       if (!HFI1_CAP_UGET_MASK(uctxt->flags, MULTI_PKT_EGR))
                rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB;
-       if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_EGR_FULL))
+       if (HFI1_CAP_UGET_MASK(uctxt->flags, NODROP_EGR_FULL))
                rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB;
-       if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_RHQ_FULL))
+       if (HFI1_CAP_UGET_MASK(uctxt->flags, NODROP_RHQ_FULL))
                rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB;
        /*
         * The RcvCtxtCtrl.TailUpd bit has to be explicitly written.
@@ -1099,7 +1105,7 @@ static int user_init(struct file *fp)
         * uses of the chip or ctxt. Therefore, add the rcvctrl op
         * for both cases.
         */
-       if (HFI1_CAP_KGET_MASK(uctxt->flags, DMA_RTAIL))
+       if (HFI1_CAP_UGET_MASK(uctxt->flags, DMA_RTAIL))
                rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB;
        else
                rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_DIS;
@@ -1122,9 +1128,14 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
        int ret = 0;
 
        memset(&cinfo, 0, sizeof(cinfo));
-       ret = hfi1_get_base_kinfo(uctxt, &cinfo);
-       if (ret < 0)
-               goto done;
+       cinfo.runtime_flags = (((uctxt->flags >> HFI1_CAP_MISC_SHIFT) &
+                               HFI1_CAP_MISC_MASK) << HFI1_CAP_USER_SHIFT) |
+                       HFI1_CAP_UGET_MASK(uctxt->flags, MASK) |
+                       HFI1_CAP_KGET_MASK(uctxt->flags, K2U);
+       /* adjust flag if this fd is not able to cache */
+       if (!fd->handler)
+               cinfo.runtime_flags |= HFI1_CAP_TID_UNMAP; /* no caching */
+
        cinfo.num_active = hfi1_count_active_units();
        cinfo.unit = uctxt->dd->unit;
        cinfo.ctxt = uctxt->ctxt;
@@ -1146,7 +1157,7 @@ static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len)
        trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, fd->subctxt, cinfo);
        if (copy_to_user(ubase, &cinfo, sizeof(cinfo)))
                ret = -EFAULT;
-done:
+
        return ret;
 }
 
index ed680fd..13db8eb 100644 (file)
@@ -206,6 +206,9 @@ static const struct firmware *platform_config;
 /* the number of fabric SerDes on the SBus */
 #define NUM_FABRIC_SERDES 4
 
+/* ASIC_STS_SBUS_RESULT.RESULT_CODE value */
+#define SBUS_READ_COMPLETE 0x4
+
 /* SBus fabric SerDes addresses, one set per HFI */
 static const u8 fabric_serdes_addrs[2][NUM_FABRIC_SERDES] = {
        { 0x01, 0x02, 0x03, 0x04 },
@@ -240,6 +243,7 @@ static const u8 all_pcie_serdes_broadcast = 0xe0;
 static void dispose_one_firmware(struct firmware_details *fdet);
 static int load_fabric_serdes_firmware(struct hfi1_devdata *dd,
                                       struct firmware_details *fdet);
+static void dump_fw_version(struct hfi1_devdata *dd);
 
 /*
  * Read a single 64-bit value from 8051 data memory.
@@ -1078,6 +1082,44 @@ void sbus_request(struct hfi1_devdata *dd,
                   ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT));
 }
 
+/*
+ * Read a value from the SBus.
+ *
+ * Requires the caller to be in fast mode
+ */
+static u32 sbus_read(struct hfi1_devdata *dd, u8 receiver_addr, u8 data_addr,
+                    u32 data_in)
+{
+       u64 reg;
+       int retries;
+       int success = 0;
+       u32 result = 0;
+       u32 result_code = 0;
+
+       sbus_request(dd, receiver_addr, data_addr, READ_SBUS_RECEIVER, data_in);
+
+       for (retries = 0; retries < 100; retries++) {
+               usleep_range(1000, 1200); /* arbitrary */
+               reg = read_csr(dd, ASIC_STS_SBUS_RESULT);
+               result_code = (reg >> ASIC_STS_SBUS_RESULT_RESULT_CODE_SHIFT)
+                               & ASIC_STS_SBUS_RESULT_RESULT_CODE_MASK;
+               if (result_code != SBUS_READ_COMPLETE)
+                       continue;
+
+               success = 1;
+               result = (reg >> ASIC_STS_SBUS_RESULT_DATA_OUT_SHIFT)
+                          & ASIC_STS_SBUS_RESULT_DATA_OUT_MASK;
+               break;
+       }
+
+       if (!success) {
+               dd_dev_err(dd, "%s: read failed, result code 0x%x\n", __func__,
+                          result_code);
+       }
+
+       return result;
+}
+
 /*
  * Turn off the SBus and fabric serdes spicos.
  *
@@ -1636,6 +1678,7 @@ int load_firmware(struct hfi1_devdata *dd)
                        return ret;
        }
 
+       dump_fw_version(dd);
        return 0;
 }
 
@@ -2054,3 +2097,85 @@ void read_guid(struct hfi1_devdata *dd)
        dd_dev_info(dd, "GUID %llx",
                    (unsigned long long)dd->base_guid);
 }
+
+/* read and display firmware version info */
+static void dump_fw_version(struct hfi1_devdata *dd)
+{
+       u32 pcie_vers[NUM_PCIE_SERDES];
+       u32 fabric_vers[NUM_FABRIC_SERDES];
+       u32 sbus_vers;
+       int i;
+       int all_same;
+       int ret;
+       u8 rcv_addr;
+
+       ret = acquire_chip_resource(dd, CR_SBUS, SBUS_TIMEOUT);
+       if (ret) {
+               dd_dev_err(dd, "Unable to acquire SBus to read firmware versions\n");
+               return;
+       }
+
+       /* set fast mode */
+       set_sbus_fast_mode(dd);
+
+       /* read version for SBus Master */
+       sbus_request(dd, SBUS_MASTER_BROADCAST, 0x02, WRITE_SBUS_RECEIVER, 0);
+       sbus_request(dd, SBUS_MASTER_BROADCAST, 0x07, WRITE_SBUS_RECEIVER, 0x1);
+       /* wait for interrupt to be processed */
+       usleep_range(10000, 11000);
+       sbus_vers = sbus_read(dd, SBUS_MASTER_BROADCAST, 0x08, 0x1);
+       dd_dev_info(dd, "SBus Master firmware version 0x%08x\n", sbus_vers);
+
+       /* read version for PCIe SerDes */
+       all_same = 1;
+       pcie_vers[0] = 0;
+       for (i = 0; i < NUM_PCIE_SERDES; i++) {
+               rcv_addr = pcie_serdes_addrs[dd->hfi1_id][i];
+               sbus_request(dd, rcv_addr, 0x03, WRITE_SBUS_RECEIVER, 0);
+               /* wait for interrupt to be processed */
+               usleep_range(10000, 11000);
+               pcie_vers[i] = sbus_read(dd, rcv_addr, 0x04, 0x0);
+               if (i > 0 && pcie_vers[0] != pcie_vers[i])
+                       all_same = 0;
+       }
+
+       if (all_same) {
+               dd_dev_info(dd, "PCIe SerDes firmware version 0x%x\n",
+                           pcie_vers[0]);
+       } else {
+               dd_dev_warn(dd, "PCIe SerDes do not have the same firmware version\n");
+               for (i = 0; i < NUM_PCIE_SERDES; i++) {
+                       dd_dev_info(dd,
+                                   "PCIe SerDes lane %d firmware version 0x%x\n",
+                                   i, pcie_vers[i]);
+               }
+       }
+
+       /* read version for fabric SerDes */
+       all_same = 1;
+       fabric_vers[0] = 0;
+       for (i = 0; i < NUM_FABRIC_SERDES; i++) {
+               rcv_addr = fabric_serdes_addrs[dd->hfi1_id][i];
+               sbus_request(dd, rcv_addr, 0x03, WRITE_SBUS_RECEIVER, 0);
+               /* wait for interrupt to be processed */
+               usleep_range(10000, 11000);
+               fabric_vers[i] = sbus_read(dd, rcv_addr, 0x04, 0x0);
+               if (i > 0 && fabric_vers[0] != fabric_vers[i])
+                       all_same = 0;
+       }
+
+       if (all_same) {
+               dd_dev_info(dd, "Fabric SerDes firmware version 0x%x\n",
+                           fabric_vers[0]);
+       } else {
+               dd_dev_warn(dd, "Fabric SerDes do not have the same firmware version\n");
+               for (i = 0; i < NUM_FABRIC_SERDES; i++) {
+                       dd_dev_info(dd,
+                                   "Fabric SerDes lane %d firmware version 0x%x\n",
+                                   i, fabric_vers[i]);
+               }
+       }
+
+       clear_sbus_fast_mode(dd);
+       release_chip_resource(dd, CR_SBUS);
+}
index 4417a0f..1000e0f 100644 (file)
@@ -62,6 +62,8 @@
 #include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 #include <rdma/rdma_vt.h>
 
 #include "chip_registers.h"
@@ -253,7 +255,7 @@ struct hfi1_ctxtdata {
        /* chip offset of PIO buffers for this ctxt */
        u32 piobufs;
        /* per-context configuration flags */
-       u32 flags;
+       unsigned long flags;
        /* per-context event flags for fileops/intr communication */
        unsigned long event_flags;
        /* WAIT_RCV that timed out, no interrupt */
@@ -268,9 +270,6 @@ struct hfi1_ctxtdata {
        u32 urgent;
        /* saved total number of polled urgent packets for poll edge trigger */
        u32 urgent_poll;
-       /* pid of process using this ctxt */
-       pid_t pid;
-       pid_t subpid[HFI1_MAX_SHARED_CTXTS];
        /* same size as task_struct .comm[], command that opened context */
        char comm[TASK_COMM_LEN];
        /* so file ops can get at unit */
@@ -366,11 +365,6 @@ struct hfi1_packet {
        u8 etype;
 };
 
-static inline bool has_sc4_bit(struct hfi1_packet *p)
-{
-       return !!rhf_dc_info(p->rhf);
-}
-
 /*
  * Private data for snoop/capture support.
  */
@@ -805,10 +799,19 @@ struct hfi1_temp {
        u8 triggers;      /* temperature triggers */
 };
 
+struct hfi1_i2c_bus {
+       struct hfi1_devdata *controlling_dd; /* current controlling device */
+       struct i2c_adapter adapter;     /* bus details */
+       struct i2c_algo_bit_data algo;  /* bus algorithm details */
+       int num;                        /* bus number, 0 or 1 */
+};
+
 /* common data between shared ASIC HFIs */
 struct hfi1_asic_data {
        struct hfi1_devdata *dds[2];    /* back pointers */
        struct mutex asic_resource_mutex;
+       struct hfi1_i2c_bus *i2c_bus0;
+       struct hfi1_i2c_bus *i2c_bus1;
 };
 
 /* device data struct now contains only "general per-device" info.
@@ -1128,7 +1131,8 @@ struct hfi1_devdata {
                NUM_SEND_DMA_ENG_ERR_STATUS_COUNTERS];
        /* Software counter that aggregates all cce_err_status errors */
        u64 sw_cce_err_status_aggregate;
-
+       /* Software counter that aggregates all bypass packet rcv errors */
+       u64 sw_rcv_bypass_packet_errors;
        /* receive interrupt functions */
        rhf_rcv_function_ptr *rhf_rcv_function_map;
        rhf_rcv_function_ptr normal_rhf_rcv_functions[8];
@@ -1174,6 +1178,8 @@ struct hfi1_devdata {
 
 /* 8051 firmware version helper */
 #define dc8051_ver(a, b) ((a) << 8 | (b))
+#define dc8051_ver_maj(a) ((a & 0xff00) >> 8)
+#define dc8051_ver_min(a)  (a & 0x00ff)
 
 /* f_put_tid types */
 #define PT_EXPECTED 0
@@ -1182,6 +1188,7 @@ struct hfi1_devdata {
 
 struct tid_rb_node;
 struct mmu_rb_node;
+struct mmu_rb_handler;
 
 /* Private data for file operations */
 struct hfi1_filedata {
@@ -1192,7 +1199,7 @@ struct hfi1_filedata {
        /* for cpu affinity; -1 if none */
        int rec_cpu_num;
        u32 tid_n_pinned;
-       struct rb_root tid_rb_root;
+       struct mmu_rb_handler *handler;
        struct tid_rb_node **entry_to_rb;
        spinlock_t tid_lock; /* protect tid_[limit,used] counters */
        u32 tid_limit;
@@ -1201,6 +1208,7 @@ struct hfi1_filedata {
        u32 invalid_tid_idx;
        /* protect invalid_tids array and invalid_tid_idx */
        spinlock_t invalid_lock;
+       struct mm_struct *mm;
 };
 
 extern struct list_head hfi1_dev_list;
@@ -1234,6 +1242,8 @@ int handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *, int);
 int handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *, int);
 void set_all_slowpath(struct hfi1_devdata *dd);
 
+extern const struct pci_device_id hfi1_pci_tbl[];
+
 /* receive packet handler dispositions */
 #define RCV_PKT_OK      0x0 /* keep going */
 #define RCV_PKT_LIMIT   0x1 /* stop, hit limit, start thread */
@@ -1259,7 +1269,7 @@ void receive_interrupt_work(struct work_struct *work);
 static inline int hdr2sc(struct hfi1_message_header *hdr, u64 rhf)
 {
        return ((be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf) |
-              ((!!(rhf & RHF_DC_INFO_SMASK)) << 4);
+              ((!!(rhf_dc_info(rhf))) << 4);
 }
 
 static inline u16 generate_jkey(kuid_t uid)
@@ -1569,6 +1579,22 @@ static inline struct hfi1_ibport *to_iport(struct ib_device *ibdev, u8 port)
        return &dd->pport[pidx].ibport_data;
 }
 
+void hfi1_process_ecn_slowpath(struct rvt_qp *qp, struct hfi1_packet *pkt,
+                              bool do_cnp);
+static inline bool process_ecn(struct rvt_qp *qp, struct hfi1_packet *pkt,
+                              bool do_cnp)
+{
+       struct hfi1_other_headers *ohdr = pkt->ohdr;
+       u32 bth1;
+
+       bth1 = be32_to_cpu(ohdr->bth[1]);
+       if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) {
+               hfi1_process_ecn_slowpath(qp, pkt, do_cnp);
+               return bth1 & HFI1_FECN_SMASK;
+       }
+       return false;
+}
+
 /*
  * Return the indexed PKEY from the port PKEY table.
  */
@@ -1586,14 +1612,23 @@ static inline u16 hfi1_get_pkey(struct hfi1_ibport *ibp, unsigned index)
 }
 
 /*
- * Readers of cc_state must call get_cc_state() under rcu_read_lock().
- * Writers of cc_state must call get_cc_state() under cc_state_lock.
+ * Called by readers of cc_state only, must call under rcu_read_lock().
  */
 static inline struct cc_state *get_cc_state(struct hfi1_pportdata *ppd)
 {
        return rcu_dereference(ppd->cc_state);
 }
 
+/*
+ * Called by writers of cc_state only,  must call under cc_state_lock.
+ */
+static inline
+struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd)
+{
+       return rcu_dereference_protected(ppd->cc_state,
+                                        lockdep_is_held(&ppd->cc_state_lock));
+}
+
 /*
  * values for dd->flags (_device_ related flags)
  */
@@ -1669,9 +1704,12 @@ void shutdown_led_override(struct hfi1_pportdata *ppd);
  */
 #define DEFAULT_RCVHDR_ENTSIZE 32
 
-bool hfi1_can_pin_pages(struct hfi1_devdata *, u32, u32);
-int hfi1_acquire_user_pages(unsigned long, size_t, bool, struct page **);
-void hfi1_release_user_pages(struct mm_struct *, struct page **, size_t, bool);
+bool hfi1_can_pin_pages(struct hfi1_devdata *dd, struct mm_struct *mm,
+                       u32 nlocked, u32 npages);
+int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr,
+                           size_t npages, bool writable, struct page **pages);
+void hfi1_release_user_pages(struct mm_struct *mm, struct page **p,
+                            size_t npages, bool dirty);
 
 static inline void clear_rcvhdrtail(const struct hfi1_ctxtdata *rcd)
 {
@@ -1947,4 +1985,55 @@ static inline u32 qsfp_resource(struct hfi1_devdata *dd)
 
 int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp);
 
+#define DD_DEV_ENTRY(dd)       __string(dev, dev_name(&(dd)->pcidev->dev))
+#define DD_DEV_ASSIGN(dd)      __assign_str(dev, dev_name(&(dd)->pcidev->dev))
+
+#define packettype_name(etype) { RHF_RCV_TYPE_##etype, #etype }
+#define show_packettype(etype)                  \
+__print_symbolic(etype,                         \
+       packettype_name(EXPECTED),              \
+       packettype_name(EAGER),                 \
+       packettype_name(IB),                    \
+       packettype_name(ERROR),                 \
+       packettype_name(BYPASS))
+
+#define ib_opcode_name(opcode) { IB_OPCODE_##opcode, #opcode  }
+#define show_ib_opcode(opcode)                             \
+__print_symbolic(opcode,                                   \
+       ib_opcode_name(RC_SEND_FIRST),                     \
+       ib_opcode_name(RC_SEND_MIDDLE),                    \
+       ib_opcode_name(RC_SEND_LAST),                      \
+       ib_opcode_name(RC_SEND_LAST_WITH_IMMEDIATE),       \
+       ib_opcode_name(RC_SEND_ONLY),                      \
+       ib_opcode_name(RC_SEND_ONLY_WITH_IMMEDIATE),       \
+       ib_opcode_name(RC_RDMA_WRITE_FIRST),               \
+       ib_opcode_name(RC_RDMA_WRITE_MIDDLE),              \
+       ib_opcode_name(RC_RDMA_WRITE_LAST),                \
+       ib_opcode_name(RC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
+       ib_opcode_name(RC_RDMA_WRITE_ONLY),                \
+       ib_opcode_name(RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
+       ib_opcode_name(RC_RDMA_READ_REQUEST),              \
+       ib_opcode_name(RC_RDMA_READ_RESPONSE_FIRST),       \
+       ib_opcode_name(RC_RDMA_READ_RESPONSE_MIDDLE),      \
+       ib_opcode_name(RC_RDMA_READ_RESPONSE_LAST),        \
+       ib_opcode_name(RC_RDMA_READ_RESPONSE_ONLY),        \
+       ib_opcode_name(RC_ACKNOWLEDGE),                    \
+       ib_opcode_name(RC_ATOMIC_ACKNOWLEDGE),             \
+       ib_opcode_name(RC_COMPARE_SWAP),                   \
+       ib_opcode_name(RC_FETCH_ADD),                      \
+       ib_opcode_name(UC_SEND_FIRST),                     \
+       ib_opcode_name(UC_SEND_MIDDLE),                    \
+       ib_opcode_name(UC_SEND_LAST),                      \
+       ib_opcode_name(UC_SEND_LAST_WITH_IMMEDIATE),       \
+       ib_opcode_name(UC_SEND_ONLY),                      \
+       ib_opcode_name(UC_SEND_ONLY_WITH_IMMEDIATE),       \
+       ib_opcode_name(UC_RDMA_WRITE_FIRST),               \
+       ib_opcode_name(UC_RDMA_WRITE_MIDDLE),              \
+       ib_opcode_name(UC_RDMA_WRITE_LAST),                \
+       ib_opcode_name(UC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
+       ib_opcode_name(UC_RDMA_WRITE_ONLY),                \
+       ib_opcode_name(UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
+       ib_opcode_name(UD_SEND_ONLY),                      \
+       ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE),       \
+       ib_opcode_name(CNP))
 #endif                          /* _HFI1_KERNEL_H */
index eed971c..a358d23 100644 (file)
@@ -64,6 +64,7 @@
 #include "debugfs.h"
 #include "verbs.h"
 #include "aspm.h"
+#include "affinity.h"
 
 #undef pr_fmt
 #define pr_fmt(fmt) DRIVER_NAME ": " fmt
@@ -474,8 +475,9 @@ static enum hrtimer_restart cca_timer_fn(struct hrtimer *t)
 void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
                         struct hfi1_devdata *dd, u8 hw_pidx, u8 port)
 {
-       int i, size;
+       int i;
        uint default_pkey_idx;
+       struct cc_state *cc_state;
 
        ppd->dd = dd;
        ppd->hw_pidx = hw_pidx;
@@ -526,9 +528,9 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
 
        spin_lock_init(&ppd->cc_state_lock);
        spin_lock_init(&ppd->cc_log_lock);
-       size = sizeof(struct cc_state);
-       RCU_INIT_POINTER(ppd->cc_state, kzalloc(size, GFP_KERNEL));
-       if (!rcu_dereference(ppd->cc_state))
+       cc_state = kzalloc(sizeof(*cc_state), GFP_KERNEL);
+       RCU_INIT_POINTER(ppd->cc_state, cc_state);
+       if (!cc_state)
                goto bail;
        return;
 
@@ -972,39 +974,49 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
 
 /*
  * Release our hold on the shared asic data.  If we are the last one,
- * free the structure.  Must be holding hfi1_devs_lock.
+ * return the structure to be finalized outside the lock.  Must be
+ * holding hfi1_devs_lock.
  */
-static void release_asic_data(struct hfi1_devdata *dd)
+static struct hfi1_asic_data *release_asic_data(struct hfi1_devdata *dd)
 {
+       struct hfi1_asic_data *ad;
        int other;
 
        if (!dd->asic_data)
-               return;
+               return NULL;
        dd->asic_data->dds[dd->hfi1_id] = NULL;
        other = dd->hfi1_id ? 0 : 1;
-       if (!dd->asic_data->dds[other]) {
-               /* we are the last holder, free it */
-               kfree(dd->asic_data);
-       }
+       ad = dd->asic_data;
        dd->asic_data = NULL;
+       /* return NULL if the other dd still has a link */
+       return ad->dds[other] ? NULL : ad;
+}
+
+static void finalize_asic_data(struct hfi1_devdata *dd,
+                              struct hfi1_asic_data *ad)
+{
+       clean_up_i2c(dd, ad);
+       kfree(ad);
 }
 
 static void __hfi1_free_devdata(struct kobject *kobj)
 {
        struct hfi1_devdata *dd =
                container_of(kobj, struct hfi1_devdata, kobj);
+       struct hfi1_asic_data *ad;
        unsigned long flags;
 
        spin_lock_irqsave(&hfi1_devs_lock, flags);
        idr_remove(&hfi1_unit_table, dd->unit);
        list_del(&dd->list);
-       release_asic_data(dd);
+       ad = release_asic_data(dd);
        spin_unlock_irqrestore(&hfi1_devs_lock, flags);
+       if (ad)
+               finalize_asic_data(dd, ad);
        free_platform_config(dd);
        rcu_barrier(); /* wait for rcu callbacks to complete */
        free_percpu(dd->int_counter);
        free_percpu(dd->rcv_limit);
-       hfi1_dev_affinity_free(dd);
        free_percpu(dd->send_schedule);
        rvt_dealloc_device(&dd->verbs_dev.rdi);
 }
@@ -1162,7 +1174,7 @@ static int init_one(struct pci_dev *, const struct pci_device_id *);
 #define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: "
 #define PFX DRIVER_NAME ": "
 
-static const struct pci_device_id hfi1_pci_tbl[] = {
+const struct pci_device_id hfi1_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL1) },
        { 0, }
@@ -1198,6 +1210,10 @@ static int __init hfi1_mod_init(void)
        if (ret)
                goto bail;
 
+       ret = node_affinity_init();
+       if (ret)
+               goto bail;
+
        /* validate max MTU before any devices start */
        if (!valid_opa_max_mtu(hfi1_max_mtu)) {
                pr_err("Invalid max_mtu 0x%x, using 0x%x instead\n",
@@ -1278,6 +1294,7 @@ module_init(hfi1_mod_init);
 static void __exit hfi1_mod_cleanup(void)
 {
        pci_unregister_driver(&hfi1_pci_driver);
+       node_affinity_destroy();
        hfi1_wss_exit();
        hfi1_dbg_exit();
        hfi1_cpulist_count = 0;
@@ -1311,7 +1328,7 @@ static void cleanup_device_data(struct hfi1_devdata *dd)
                        hrtimer_cancel(&ppd->cca_timer[i].hrtimer);
 
                spin_lock(&ppd->cc_state_lock);
-               cc_state = get_cc_state(ppd);
+               cc_state = get_cc_state_protected(ppd);
                RCU_INIT_POINTER(ppd->cc_state, NULL);
                spin_unlock(&ppd->cc_state_lock);
 
@@ -1760,8 +1777,8 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd)
 
        hfi1_cdbg(PROC,
                  "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n",
-                 rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size,
-                 rcd->egrbufs.size);
+                 rcd->ctxt, rcd->egrbufs.alloced,
+                 rcd->egrbufs.rcvtid_size / 1024, rcd->egrbufs.size / 1024);
 
        /*
         * Set the contexts rcv array head update threshold to the closest
index fca07a1..1263abe 100644 (file)
@@ -588,7 +588,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
 
        pi->port_phys_conf = (ppd->port_type & 0xf);
 
-#if PI_LED_ENABLE_SUP
        pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4;
        pi->port_states.ledenable_offlinereason |=
                ppd->is_sm_config_started << 5;
@@ -602,11 +601,6 @@ static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data,
        pi->port_states.ledenable_offlinereason |= is_beaconing_active << 6;
        pi->port_states.ledenable_offlinereason |=
                ppd->offline_disabled_reason;
-#else
-       pi->port_states.offline_reason = ppd->neighbor_normal << 4;
-       pi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
-       pi->port_states.offline_reason |= ppd->offline_disabled_reason;
-#endif /* PI_LED_ENABLE_SUP */
 
        pi->port_states.portphysstate_portstate =
                (hfi1_ibphys_portstate(ppd) << 4) | state;
@@ -1752,17 +1746,11 @@ static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data,
        if (start_of_sm_config && (lstate == IB_PORT_INIT))
                ppd->is_sm_config_started = 1;
 
-#if PI_LED_ENABLE_SUP
        psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4;
        psi->port_states.ledenable_offlinereason |=
                ppd->is_sm_config_started << 5;
        psi->port_states.ledenable_offlinereason |=
                ppd->offline_disabled_reason;
-#else
-       psi->port_states.offline_reason = ppd->neighbor_normal << 4;
-       psi->port_states.offline_reason |= ppd->is_sm_config_started << 5;
-       psi->port_states.offline_reason |= ppd->offline_disabled_reason;
-#endif /* PI_LED_ENABLE_SUP */
 
        psi->port_states.portphysstate_portstate =
                (hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf);
@@ -2430,14 +2418,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
        rsp->port_rcv_remote_physical_errors =
                cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR,
                                          CNTR_INVALID_VL));
-       tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL);
-       tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL);
-       if (tmp2 < tmp) {
-               /* overflow/wrapped */
-               rsp->local_link_integrity_errors = cpu_to_be64(~0);
-       } else {
-               rsp->local_link_integrity_errors = cpu_to_be64(tmp2);
-       }
+       rsp->local_link_integrity_errors =
+               cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY,
+                                         CNTR_INVALID_VL));
        tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL);
        tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT,
                                   CNTR_INVALID_VL);
@@ -2499,6 +2482,9 @@ static int pma_get_opa_portstatus(struct opa_pma_mad *pmp,
                        cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL,
                                                  idx_from_vl(vl)));
 
+               rsp->vls[vfi].port_vl_xmit_discards =
+                       cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
+                                                  idx_from_vl(vl)));
                vlinfo++;
                vfi++;
        }
@@ -2529,9 +2515,8 @@ static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port,
        error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR,
                                               CNTR_INVALID_VL);
        /* local link integrity must be right-shifted by the lli resolution */
-       tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL);
-       tmp += read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL);
-       error_counter_summary += (tmp >> res_lli);
+       error_counter_summary += (read_dev_cntr(dd, C_DC_RX_REPLAY,
+                                               CNTR_INVALID_VL) >> res_lli);
        /* link error recovery must b right-shifted by the ler resolution */
        tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL);
        tmp += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL);
@@ -2800,14 +2785,9 @@ static void pma_get_opa_port_ectrs(struct ib_device *ibdev,
        rsp->port_rcv_constraint_errors =
                cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR,
                                           CNTR_INVALID_VL));
-       tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL);
-       tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL);
-       if (tmp2 < tmp) {
-               /* overflow/wrapped */
-               rsp->local_link_integrity_errors = cpu_to_be64(~0);
-       } else {
-               rsp->local_link_integrity_errors = cpu_to_be64(tmp2);
-       }
+       rsp->local_link_integrity_errors =
+               cpu_to_be64(read_dev_cntr(dd, C_DC_RX_REPLAY,
+                                         CNTR_INVALID_VL));
        rsp->excessive_buffer_overruns =
                cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL));
 }
@@ -2883,14 +2863,17 @@ static int pma_get_opa_porterrors(struct opa_pma_mad *pmp,
        tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL);
 
        rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff;
-
+       rsp->port_rcv_errors =
+               cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL));
        vlinfo = &rsp->vls[0];
        vfi = 0;
        vl_select_mask = be32_to_cpu(req->vl_select_mask);
        for_each_set_bit(vl, (unsigned long *)&(vl_select_mask),
                         8 * sizeof(req->vl_select_mask)) {
                memset(vlinfo, 0, sizeof(*vlinfo));
-               /* vlinfo->vls[vfi].port_vl_xmit_discards ??? */
+               rsp->vls[vfi].port_vl_xmit_discards =
+                       cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
+                                                  idx_from_vl(vl)));
                vlinfo += 1;
                vfi++;
        }
@@ -3162,10 +3145,8 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp,
        if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS)
                write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0);
 
-       if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS) {
-               write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0);
+       if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS)
                write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0);
-       }
 
        if (counter_select & CS_LINK_ERROR_RECOVERY) {
                write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0);
@@ -3223,7 +3204,9 @@ static int pma_set_opa_portstatus(struct opa_pma_mad *pmp,
                /* if (counter_select & CS_PORT_MARK_FECN)
                 *     write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0);
                 */
-               /* port_vl_xmit_discards ??? */
+               if (counter_select & C_SW_XMIT_DSCD_VL)
+                       write_port_cntr(ppd, C_SW_XMIT_DSCD_VL,
+                                       idx_from_vl(vl), 0);
        }
 
        if (resp_len)
@@ -3392,7 +3375,7 @@ static void apply_cc_state(struct hfi1_pportdata *ppd)
         */
        spin_lock(&ppd->cc_state_lock);
 
-       old_cc_state = get_cc_state(ppd);
+       old_cc_state = get_cc_state_protected(ppd);
        if (!old_cc_state) {
                /* never active, or shutting down */
                spin_unlock(&ppd->cc_state_lock);
@@ -3960,7 +3943,6 @@ void clear_linkup_counters(struct hfi1_devdata *dd)
        write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0);
        write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0);
        /* LocalLinkIntegrityErrors */
-       write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0);
        write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0);
        /* ExcessiveBufferOverruns */
        write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0);
index 8b734aa..5aa3fd1 100644 (file)
 #define _HFI1_MAD_H
 
 #include <rdma/ib_pma.h>
-#define USE_PI_LED_ENABLE      1 /*
-                                  * use led enabled bit in struct
-                                  * opa_port_states, if available
-                                  */
 #include <rdma/opa_smi.h>
 #include <rdma/opa_port_info.h>
-#ifndef PI_LED_ENABLE_SUP
-#define PI_LED_ENABLE_SUP 0
-#endif
 #include "opa_compat.h"
 
 /*
index b7a80aa..7ad3089 100644 (file)
 #include "trace.h"
 
 struct mmu_rb_handler {
-       struct list_head list;
        struct mmu_notifier mn;
-       struct rb_root *root;
+       struct rb_root root;
+       void *ops_arg;
        spinlock_t lock;        /* protect the RB tree */
        struct mmu_rb_ops *ops;
+       struct mm_struct *mm;
+       struct list_head lru_list;
+       struct work_struct del_work;
+       struct list_head del_list;
+       struct workqueue_struct *wq;
 };
 
-static LIST_HEAD(mmu_rb_handlers);
-static DEFINE_SPINLOCK(mmu_rb_lock); /* protect mmu_rb_handlers list */
-
 static unsigned long mmu_node_start(struct mmu_rb_node *);
 static unsigned long mmu_node_last(struct mmu_rb_node *);
-static struct mmu_rb_handler *find_mmu_handler(struct rb_root *);
 static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *,
                                     unsigned long);
 static inline void mmu_notifier_range_start(struct mmu_notifier *,
@@ -76,6 +77,9 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *,
                                        unsigned long, unsigned long);
 static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *,
                                           unsigned long, unsigned long);
+static void do_remove(struct mmu_rb_handler *handler,
+                     struct list_head *del_list);
+static void handle_remove(struct work_struct *work);
 
 static struct mmu_notifier_ops mn_opts = {
        .invalidate_page = mmu_notifier_page,
@@ -95,73 +99,79 @@ static unsigned long mmu_node_last(struct mmu_rb_node *node)
        return PAGE_ALIGN(node->addr + node->len) - 1;
 }
 
-int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
+int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm,
+                        struct mmu_rb_ops *ops,
+                        struct workqueue_struct *wq,
+                        struct mmu_rb_handler **handler)
 {
        struct mmu_rb_handler *handlr;
-
-       if (!ops->invalidate)
-               return -EINVAL;
+       int ret;
 
        handlr = kmalloc(sizeof(*handlr), GFP_KERNEL);
        if (!handlr)
                return -ENOMEM;
 
-       handlr->root = root;
+       handlr->root = RB_ROOT;
        handlr->ops = ops;
+       handlr->ops_arg = ops_arg;
        INIT_HLIST_NODE(&handlr->mn.hlist);
        spin_lock_init(&handlr->lock);
        handlr->mn.ops = &mn_opts;
-       spin_lock(&mmu_rb_lock);
-       list_add_tail_rcu(&handlr->list, &mmu_rb_handlers);
-       spin_unlock(&mmu_rb_lock);
+       handlr->mm = mm;
+       INIT_WORK(&handlr->del_work, handle_remove);
+       INIT_LIST_HEAD(&handlr->del_list);
+       INIT_LIST_HEAD(&handlr->lru_list);
+       handlr->wq = wq;
+
+       ret = mmu_notifier_register(&handlr->mn, handlr->mm);
+       if (ret) {
+               kfree(handlr);
+               return ret;
+       }
 
-       return mmu_notifier_register(&handlr->mn, current->mm);
+       *handler = handlr;
+       return 0;
 }
 
-void hfi1_mmu_rb_unregister(struct rb_root *root)
+void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler)
 {
-       struct mmu_rb_handler *handler = find_mmu_handler(root);
+       struct mmu_rb_node *rbnode;
+       struct rb_node *node;
        unsigned long flags;
-
-       if (!handler)
-               return;
+       struct list_head del_list;
 
        /* Unregister first so we don't get any more notifications. */
-       if (current->mm)
-               mmu_notifier_unregister(&handler->mn, current->mm);
+       mmu_notifier_unregister(&handler->mn, handler->mm);
 
-       spin_lock(&mmu_rb_lock);
-       list_del_rcu(&handler->list);
-       spin_unlock(&mmu_rb_lock);
-       synchronize_rcu();
+       /*
+        * Make sure the wq delete handler is finished running.  It will not
+        * be triggered once the mmu notifiers are unregistered above.
+        */
+       flush_work(&handler->del_work);
+
+       INIT_LIST_HEAD(&del_list);
 
        spin_lock_irqsave(&handler->lock, flags);
-       if (!RB_EMPTY_ROOT(root)) {
-               struct rb_node *node;
-               struct mmu_rb_node *rbnode;
-
-               while ((node = rb_first(root))) {
-                       rbnode = rb_entry(node, struct mmu_rb_node, node);
-                       rb_erase(node, root);
-                       if (handler->ops->remove)
-                               handler->ops->remove(root, rbnode, NULL);
-               }
+       while ((node = rb_first(&handler->root))) {
+               rbnode = rb_entry(node, struct mmu_rb_node, node);
+               rb_erase(node, &handler->root);
+               /* move from LRU list to delete list */
+               list_move(&rbnode->list, &del_list);
        }
        spin_unlock_irqrestore(&handler->lock, flags);
 
+       do_remove(handler, &del_list);
+
        kfree(handler);
 }
 
-int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
+int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler,
+                      struct mmu_rb_node *mnode)
 {
-       struct mmu_rb_handler *handler = find_mmu_handler(root);
        struct mmu_rb_node *node;
        unsigned long flags;
        int ret = 0;
 
-       if (!handler)
-               return -EINVAL;
-
        spin_lock_irqsave(&handler->lock, flags);
        hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr,
                  mnode->len);
@@ -170,12 +180,13 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
                ret = -EINVAL;
                goto unlock;
        }
-       __mmu_int_rb_insert(mnode, root);
+       __mmu_int_rb_insert(mnode, &handler->root);
+       list_add(&mnode->list, &handler->lru_list);
 
-       if (handler->ops->insert) {
-               ret = handler->ops->insert(root, mnode);
-               if (ret)
-                       __mmu_int_rb_remove(mnode, root);
+       ret = handler->ops->insert(handler->ops_arg, mnode);
+       if (ret) {
+               __mmu_int_rb_remove(mnode, &handler->root);
+               list_del(&mnode->list); /* remove from LRU list */
        }
 unlock:
        spin_unlock_irqrestore(&handler->lock, flags);
@@ -191,10 +202,10 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
 
        hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len);
        if (!handler->ops->filter) {
-               node = __mmu_int_rb_iter_first(handler->root, addr,
+               node = __mmu_int_rb_iter_first(&handler->root, addr,
                                               (addr + len) - 1);
        } else {
-               for (node = __mmu_int_rb_iter_first(handler->root, addr,
+               for (node = __mmu_int_rb_iter_first(&handler->root, addr,
                                                    (addr + len) - 1);
                     node;
                     node = __mmu_int_rb_iter_next(node, addr,
@@ -206,82 +217,72 @@ static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler,
        return node;
 }
 
-/* Caller must *not* hold handler lock. */
-static void __mmu_rb_remove(struct mmu_rb_handler *handler,
-                           struct mmu_rb_node *node, struct mm_struct *mm)
-{
-       unsigned long flags;
-
-       /* Validity of handler and node pointers has been checked by caller. */
-       hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr,
-                 node->len);
-       spin_lock_irqsave(&handler->lock, flags);
-       __mmu_int_rb_remove(node, handler->root);
-       spin_unlock_irqrestore(&handler->lock, flags);
-
-       if (handler->ops->remove)
-               handler->ops->remove(handler->root, node, mm);
-}
-
-struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
-                                      unsigned long len)
+struct mmu_rb_node *hfi1_mmu_rb_extract(struct mmu_rb_handler *handler,
+                                       unsigned long addr, unsigned long len)
 {
-       struct mmu_rb_handler *handler = find_mmu_handler(root);
        struct mmu_rb_node *node;
        unsigned long flags;
 
-       if (!handler)
-               return ERR_PTR(-EINVAL);
-
        spin_lock_irqsave(&handler->lock, flags);
        node = __mmu_rb_search(handler, addr, len);
+       if (node) {
+               __mmu_int_rb_remove(node, &handler->root);
+               list_del(&node->list); /* remove from LRU list */
+       }
        spin_unlock_irqrestore(&handler->lock, flags);
 
        return node;
 }
 
-struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *root,
-                                       unsigned long addr, unsigned long len)
+void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg)
 {
-       struct mmu_rb_handler *handler = find_mmu_handler(root);
-       struct mmu_rb_node *node;
+       struct mmu_rb_node *rbnode, *ptr;
+       struct list_head del_list;
        unsigned long flags;
+       bool stop = false;
 
-       if (!handler)
-               return ERR_PTR(-EINVAL);
+       INIT_LIST_HEAD(&del_list);
 
        spin_lock_irqsave(&handler->lock, flags);
-       node = __mmu_rb_search(handler, addr, len);
-       if (node)
-               __mmu_int_rb_remove(node, handler->root);
+       list_for_each_entry_safe_reverse(rbnode, ptr, &handler->lru_list,
+                                        list) {
+               if (handler->ops->evict(handler->ops_arg, rbnode, evict_arg,
+                                       &stop)) {
+                       __mmu_int_rb_remove(rbnode, &handler->root);
+                       /* move from LRU list to delete list */
+                       list_move(&rbnode->list, &del_list);
+               }
+               if (stop)
+                       break;
+       }
        spin_unlock_irqrestore(&handler->lock, flags);
 
-       return node;
+       while (!list_empty(&del_list)) {
+               rbnode = list_first_entry(&del_list, struct mmu_rb_node, list);
+               list_del(&rbnode->list);
+               handler->ops->remove(handler->ops_arg, rbnode);
+       }
 }
 
-void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node)
+/*
+ * It is up to the caller to ensure that this function does not race with the
+ * mmu invalidate notifier which may be calling the users remove callback on
+ * 'node'.
+ */
+void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler,
+                       struct mmu_rb_node *node)
 {
-       struct mmu_rb_handler *handler = find_mmu_handler(root);
-
-       if (!handler || !node)
-               return;
-
-       __mmu_rb_remove(handler, node, NULL);
-}
+       unsigned long flags;
 
-static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root)
-{
-       struct mmu_rb_handler *handler;
+       /* Validity of handler and node pointers has been checked by caller. */
+       hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr,
+                 node->len);
+       spin_lock_irqsave(&handler->lock, flags);
+       __mmu_int_rb_remove(node, &handler->root);
+       list_del(&node->list); /* remove from LRU list */
+       spin_unlock_irqrestore(&handler->lock, flags);
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(handler, &mmu_rb_handlers, list) {
-               if (handler->root == root)
-                       goto unlock;
-       }
-       handler = NULL;
-unlock:
-       rcu_read_unlock();
-       return handler;
+       handler->ops->remove(handler->ops_arg, node);
 }
 
 static inline void mmu_notifier_page(struct mmu_notifier *mn,
@@ -304,9 +305,10 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
 {
        struct mmu_rb_handler *handler =
                container_of(mn, struct mmu_rb_handler, mn);
-       struct rb_root *root = handler->root;
+       struct rb_root *root = &handler->root;
        struct mmu_rb_node *node, *ptr = NULL;
        unsigned long flags;
+       bool added = false;
 
        spin_lock_irqsave(&handler->lock, flags);
        for (node = __mmu_int_rb_iter_first(root, start, end - 1);
@@ -315,11 +317,53 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
                ptr = __mmu_int_rb_iter_next(node, start, end - 1);
                hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u",
                          node->addr, node->len);
-               if (handler->ops->invalidate(root, node)) {
+               if (handler->ops->invalidate(handler->ops_arg, node)) {
                        __mmu_int_rb_remove(node, root);
-                       if (handler->ops->remove)
-                               handler->ops->remove(root, node, mm);
+                       /* move from LRU list to delete list */
+                       list_move(&node->list, &handler->del_list);
+                       added = true;
                }
        }
        spin_unlock_irqrestore(&handler->lock, flags);
+
+       if (added)
+               queue_work(handler->wq, &handler->del_work);
+}
+
+/*
+ * Call the remove function for the given handler and the list.  This
+ * is expected to be called with a delete list extracted from handler.
+ * The caller should not be holding the handler lock.
+ */
+static void do_remove(struct mmu_rb_handler *handler,
+                     struct list_head *del_list)
+{
+       struct mmu_rb_node *node;
+
+       while (!list_empty(del_list)) {
+               node = list_first_entry(del_list, struct mmu_rb_node, list);
+               list_del(&node->list);
+               handler->ops->remove(handler->ops_arg, node);
+       }
+}
+
+/*
+ * Work queue function to remove all nodes that have been queued up to
+ * be removed.  The key feature is that mm->mmap_sem is not being held
+ * and the remove callback can sleep while taking it, if needed.
+ */
+static void handle_remove(struct work_struct *work)
+{
+       struct mmu_rb_handler *handler = container_of(work,
+                                               struct mmu_rb_handler,
+                                               del_work);
+       struct list_head del_list;
+       unsigned long flags;
+
+       /* remove anything that is queued to get removed */
+       spin_lock_irqsave(&handler->lock, flags);
+       list_replace_init(&handler->del_list, &del_list);
+       spin_unlock_irqrestore(&handler->lock, flags);
+
+       do_remove(handler, &del_list);
 }
index 7a57b9c..754f6eb 100644 (file)
@@ -54,23 +54,34 @@ struct mmu_rb_node {
        unsigned long len;
        unsigned long __last;
        struct rb_node node;
+       struct list_head list;
 };
 
+/*
+ * NOTE: filter, insert, invalidate, and evict must not sleep.  Only remove is
+ * allowed to sleep.
+ */
 struct mmu_rb_ops {
-       bool (*filter)(struct mmu_rb_node *, unsigned long, unsigned long);
-       int (*insert)(struct rb_root *, struct mmu_rb_node *);
-       void (*remove)(struct rb_root *, struct mmu_rb_node *,
-                      struct mm_struct *);
-       int (*invalidate)(struct rb_root *, struct mmu_rb_node *);
+       bool (*filter)(struct mmu_rb_node *node, unsigned long addr,
+                      unsigned long len);
+       int (*insert)(void *ops_arg, struct mmu_rb_node *mnode);
+       void (*remove)(void *ops_arg, struct mmu_rb_node *mnode);
+       int (*invalidate)(void *ops_arg, struct mmu_rb_node *node);
+       int (*evict)(void *ops_arg, struct mmu_rb_node *mnode,
+                    void *evict_arg, bool *stop);
 };
 
-int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops);
-void hfi1_mmu_rb_unregister(struct rb_root *);
-int hfi1_mmu_rb_insert(struct rb_root *, struct mmu_rb_node *);
-void hfi1_mmu_rb_remove(struct rb_root *, struct mmu_rb_node *);
-struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *, unsigned long,
-                                      unsigned long);
-struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *, unsigned long,
-                                       unsigned long);
+int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm,
+                        struct mmu_rb_ops *ops,
+                        struct workqueue_struct *wq,
+                        struct mmu_rb_handler **handler);
+void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler);
+int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler,
+                      struct mmu_rb_node *mnode);
+void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg);
+void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler,
+                       struct mmu_rb_node *mnode);
+struct mmu_rb_node *hfi1_mmu_rb_extract(struct mmu_rb_handler *handler,
+                                       unsigned long addr, unsigned long len);
 
 #endif /* _HFI1_MMU_RB_H */
index 0bac21e..89c68da 100644 (file)
@@ -679,6 +679,10 @@ static uint pcie_pset = UNSET_PSET;
 module_param(pcie_pset, uint, S_IRUGO);
 MODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10");
 
+static uint pcie_ctle = 1; /* discrete on, integrated off */
+module_param(pcie_ctle, uint, S_IRUGO);
+MODULE_PARM_DESC(pcie_ctle, "PCIe static CTLE mode, bit 0 - discrete on/off, bit 1 - integrated on/off");
+
 /* equalization columns */
 #define PREC 0
 #define ATTN 1
@@ -716,6 +720,36 @@ static const u8 integrated_preliminary_eq[11][3] = {
        {  0x00,  0x1e,  0x0a },        /* p10 */
 };
 
+static const u8 discrete_ctle_tunings[11][4] = {
+       /* DC     LF     HF     BW */
+       {  0x48,  0x0b,  0x04,  0x04 }, /* p0 */
+       {  0x60,  0x05,  0x0f,  0x0a }, /* p1 */
+       {  0x50,  0x09,  0x06,  0x06 }, /* p2 */
+       {  0x68,  0x05,  0x0f,  0x0a }, /* p3 */
+       {  0x80,  0x05,  0x0f,  0x0a }, /* p4 */
+       {  0x70,  0x05,  0x0f,  0x0a }, /* p5 */
+       {  0x68,  0x05,  0x0f,  0x0a }, /* p6 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p7 */
+       {  0x48,  0x09,  0x06,  0x06 }, /* p8 */
+       {  0x60,  0x05,  0x0f,  0x0a }, /* p9 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p10 */
+};
+
+static const u8 integrated_ctle_tunings[11][4] = {
+       /* DC     LF     HF     BW */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p0 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p1 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p2 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p3 */
+       {  0x58,  0x0a,  0x05,  0x05 }, /* p4 */
+       {  0x48,  0x0a,  0x05,  0x05 }, /* p5 */
+       {  0x40,  0x0a,  0x05,  0x05 }, /* p6 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p7 */
+       {  0x38,  0x0f,  0x00,  0x00 }, /* p8 */
+       {  0x38,  0x09,  0x06,  0x06 }, /* p9 */
+       {  0x38,  0x0e,  0x01,  0x01 }, /* p10 */
+};
+
 /* helper to format the value to write to hardware */
 #define eq_value(pre, curr, post) \
        ((((u32)(pre)) << \
@@ -951,11 +985,14 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
        u32 status, err;
        int ret;
        int do_retry, retry_count = 0;
+       int intnum = 0;
        uint default_pset;
        u16 target_vector, target_speed;
        u16 lnkctl2, vendor;
        u8 div;
        const u8 (*eq)[3];
+       const u8 (*ctle_tunings)[4];
+       uint static_ctle_mode;
        int return_error = 0;
 
        /* PCIe Gen3 is for the ASIC only */
@@ -1089,6 +1126,9 @@ retry:
                div = 3;
                eq = discrete_preliminary_eq;
                default_pset = DEFAULT_DISCRETE_PSET;
+               ctle_tunings = discrete_ctle_tunings;
+               /* bit 0 - discrete on/off */
+               static_ctle_mode = pcie_ctle & 0x1;
        } else {
                /* 400mV, FS=29, LF = 9 */
                fs = 29;
@@ -1096,6 +1136,9 @@ retry:
                div = 1;
                eq = integrated_preliminary_eq;
                default_pset = DEFAULT_MCP_PSET;
+               ctle_tunings = integrated_ctle_tunings;
+               /* bit 1 - integrated on/off */
+               static_ctle_mode = (pcie_ctle >> 1) & 0x1;
        }
        pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL101,
                               (fs <<
@@ -1135,16 +1178,33 @@ retry:
         * step 5c: Program gasket interrupts
         */
        /* set the Rx Bit Rate to REFCLK ratio */
-       write_gasket_interrupt(dd, 0, 0x0006, 0x0050);
+       write_gasket_interrupt(dd, intnum++, 0x0006, 0x0050);
        /* disable pCal for PCIe Gen3 RX equalization */
-       write_gasket_interrupt(dd, 1, 0x0026, 0x5b01);
+       /* select adaptive or static CTLE */
+       write_gasket_interrupt(dd, intnum++, 0x0026,
+                              0x5b01 | (static_ctle_mode << 3));
        /*
         * Enable iCal for PCIe Gen3 RX equalization, and set which
         * evaluation of RX_EQ_EVAL will launch the iCal procedure.
         */
-       write_gasket_interrupt(dd, 2, 0x0026, 0x5202);
+       write_gasket_interrupt(dd, intnum++, 0x0026, 0x5202);
+
+       if (static_ctle_mode) {
+               /* apply static CTLE tunings */
+               u8 pcie_dc, pcie_lf, pcie_hf, pcie_bw;
+
+               pcie_dc = ctle_tunings[pcie_pset][0];
+               pcie_lf = ctle_tunings[pcie_pset][1];
+               pcie_hf = ctle_tunings[pcie_pset][2];
+               pcie_bw = ctle_tunings[pcie_pset][3];
+               write_gasket_interrupt(dd, intnum++, 0x0026, 0x0200 | pcie_dc);
+               write_gasket_interrupt(dd, intnum++, 0x0026, 0x0100 | pcie_lf);
+               write_gasket_interrupt(dd, intnum++, 0x0026, 0x0000 | pcie_hf);
+               write_gasket_interrupt(dd, intnum++, 0x0026, 0x5500 | pcie_bw);
+       }
+
        /* terminate list */
-       write_gasket_interrupt(dd, 3, 0x0000, 0x0000);
+       write_gasket_interrupt(dd, intnum++, 0x0000, 0x0000);
 
        /*
         * step 5d: program XMT margin
index d402245..ac1bf4a 100644 (file)
@@ -1952,13 +1952,17 @@ int init_pervl_scs(struct hfi1_devdata *dd)
        dd->vld[15].sc = sc_alloc(dd, SC_VL15,
                                  dd->rcd[0]->rcvhdrqentsize, dd->node);
        if (!dd->vld[15].sc)
-               goto nomem;
+               return -ENOMEM;
+
        hfi1_init_ctxt(dd->vld[15].sc);
        dd->vld[15].mtu = enum_to_mtu(OPA_MTU_2048);
 
-       dd->kernel_send_context = kmalloc_node(dd->num_send_contexts *
+       dd->kernel_send_context = kzalloc_node(dd->num_send_contexts *
                                        sizeof(struct send_context *),
                                        GFP_KERNEL, dd->node);
+       if (!dd->kernel_send_context)
+               goto freesc15;
+
        dd->kernel_send_context[0] = dd->vld[15].sc;
 
        for (i = 0; i < num_vls; i++) {
@@ -2010,12 +2014,21 @@ int init_pervl_scs(struct hfi1_devdata *dd)
        if (pio_map_init(dd, ppd->port - 1, num_vls, NULL))
                goto nomem;
        return 0;
+
 nomem:
-       sc_free(dd->vld[15].sc);
-       for (i = 0; i < num_vls; i++)
+       for (i = 0; i < num_vls; i++) {
                sc_free(dd->vld[i].sc);
+               dd->vld[i].sc = NULL;
+       }
+
        for (i = num_vls; i < INIT_SC_PER_VL * num_vls; i++)
                sc_free(dd->kernel_send_context[i + 1]);
+
+       kfree(dd->kernel_send_context);
+       dd->kernel_send_context = NULL;
+
+freesc15:
+       sc_free(dd->vld[15].sc);
        return -ENOMEM;
 }
 
index 03df932..965c8ae 100644 (file)
@@ -537,20 +537,6 @@ static void apply_tunings(
        u8 precur = 0, attn = 0, postcur = 0, external_device_config = 0;
        u8 *cache = ppd->qsfp_info.cache;
 
-       /* Enable external device config if channel is limiting active */
-       read_8051_config(ppd->dd, LINK_OPTIMIZATION_SETTINGS,
-                        GENERAL_CONFIG, &config_data);
-       config_data &= ~(0xff << ENABLE_EXT_DEV_CONFIG_SHIFT);
-       config_data |= ((u32)limiting_active << ENABLE_EXT_DEV_CONFIG_SHIFT);
-       ret = load_8051_config(ppd->dd, LINK_OPTIMIZATION_SETTINGS,
-                              GENERAL_CONFIG, config_data);
-       if (ret != HCMD_SUCCESS)
-               dd_dev_err(
-                       ppd->dd,
-                       "%s: Failed to set enable external device config\n",
-                       __func__);
-
-       config_data = 0; /* re-init  */
        /* Pass tuning method to 8051 */
        read_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG,
                         &config_data);
@@ -638,9 +624,13 @@ static int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset,
        if (ret)
                return ret;
 
+       /*
+        * We'll change the QSFP memory contents from here on out, thus we set a
+        * flag here to remind ourselves to reset the QSFP module. This prevents
+        * reuse of stale settings established in our previous pass through.
+        */
        if (ppd->qsfp_info.reset_needed) {
                reset_qsfp(ppd);
-               ppd->qsfp_info.reset_needed = 0;
                refresh_qsfp_cache(ppd, &ppd->qsfp_info);
        } else {
                ppd->qsfp_info.reset_needed = 1;
index 1a942ff..a5aa351 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/seq_file.h>
 #include <rdma/rdma_vt.h>
 #include <rdma/rdmavt_qp.h>
+#include <rdma/ib_verbs.h>
 
 #include "hfi.h"
 #include "qp.h"
@@ -115,6 +116,66 @@ static const u16 credit_table[31] = {
        32768                   /* 1E */
 };
 
+const struct rvt_operation_params hfi1_post_parms[RVT_OPERATION_MAX] = {
+[IB_WR_RDMA_WRITE] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_RDMA_READ] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC,
+},
+
+[IB_WR_ATOMIC_CMP_AND_SWP] = {
+       .length = sizeof(struct ib_atomic_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
+},
+
+[IB_WR_ATOMIC_FETCH_AND_ADD] = {
+       .length = sizeof(struct ib_atomic_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
+},
+
+[IB_WR_RDMA_WRITE_WITH_IMM] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_SEND] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
+                      BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_SEND_WITH_IMM] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
+                      BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_REG_MR] = {
+       .length = sizeof(struct ib_reg_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_LOCAL,
+},
+
+[IB_WR_LOCAL_INV] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_LOCAL,
+},
+
+[IB_WR_SEND_WITH_INV] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+},
+
+};
+
 static void flush_tx_list(struct rvt_qp *qp)
 {
        struct hfi1_qp_priv *priv = qp->priv;
@@ -745,8 +806,9 @@ void *qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp,
 
        priv->owner = qp;
 
-       priv->s_hdr = kzalloc_node(sizeof(*priv->s_hdr), gfp, rdi->dparms.node);
-       if (!priv->s_hdr) {
+       priv->s_ahg = kzalloc_node(sizeof(*priv->s_ahg), gfp,
+                                  rdi->dparms.node);
+       if (!priv->s_ahg) {
                kfree(priv);
                return ERR_PTR(-ENOMEM);
        }
@@ -759,7 +821,7 @@ void qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp)
 {
        struct hfi1_qp_priv *priv = qp->priv;
 
-       kfree(priv->s_hdr);
+       kfree(priv->s_ahg);
        kfree(priv);
 }
 
index e7bc8d6..587d84d 100644 (file)
@@ -54,6 +54,8 @@
 
 extern unsigned int hfi1_qp_table_size;
 
+extern const struct rvt_operation_params hfi1_post_parms[];
+
 /*
  * free_ahg - clear ahg from QP
  */
@@ -61,7 +63,7 @@ static inline void clear_ahg(struct rvt_qp *qp)
 {
        struct hfi1_qp_priv *priv = qp->priv;
 
-       priv->s_hdr->ahgcount = 0;
+       priv->s_ahg->ahgcount = 0;
        qp->s_flags &= ~(RVT_S_AHG_VALID | RVT_S_AHG_CLEAR);
        if (priv->s_sde && qp->s_ahgidx >= 0)
                sdma_ahg_free(priv->s_sde, qp->s_ahgidx);
index 9fb5616..a207717 100644 (file)
 #include <linux/vmalloc.h>
 
 #include "hfi.h"
-#include "twsi.h"
+
+/* for the given bus number, return the CSR for reading an i2c line */
+static inline u32 i2c_in_csr(u32 bus_num)
+{
+       return bus_num ? ASIC_QSFP2_IN : ASIC_QSFP1_IN;
+}
+
+/* for the given bus number, return the CSR for writing an i2c line */
+static inline u32 i2c_oe_csr(u32 bus_num)
+{
+       return bus_num ? ASIC_QSFP2_OE : ASIC_QSFP1_OE;
+}
+
+static void hfi1_setsda(void *data, int state)
+{
+       struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
+       struct hfi1_devdata *dd = bus->controlling_dd;
+       u64 reg;
+       u32 target_oe;
+
+       target_oe = i2c_oe_csr(bus->num);
+       reg = read_csr(dd, target_oe);
+       /*
+        * The OE bit value is inverted and connected to the pin.  When
+        * OE is 0 the pin is left to be pulled up, when the OE is 1
+        * the pin is driven low.  This matches the "open drain" or "open
+        * collector" convention.
+        */
+       if (state)
+               reg &= ~QSFP_HFI0_I2CDAT;
+       else
+               reg |= QSFP_HFI0_I2CDAT;
+       write_csr(dd, target_oe, reg);
+       /* do a read to force the write into the chip */
+       (void)read_csr(dd, target_oe);
+}
+
+static void hfi1_setscl(void *data, int state)
+{
+       struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
+       struct hfi1_devdata *dd = bus->controlling_dd;
+       u64 reg;
+       u32 target_oe;
+
+       target_oe = i2c_oe_csr(bus->num);
+       reg = read_csr(dd, target_oe);
+       /*
+        * The OE bit value is inverted and connected to the pin.  When
+        * OE is 0 the pin is left to be pulled up, when the OE is 1
+        * the pin is driven low.  This matches the "open drain" or "open
+        * collector" convention.
+        */
+       if (state)
+               reg &= ~QSFP_HFI0_I2CCLK;
+       else
+               reg |= QSFP_HFI0_I2CCLK;
+       write_csr(dd, target_oe, reg);
+       /* do a read to force the write into the chip */
+       (void)read_csr(dd, target_oe);
+}
+
+static int hfi1_getsda(void *data)
+{
+       struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
+       u64 reg;
+       u32 target_in;
+
+       hfi1_setsda(data, 1);   /* clear OE so we do not pull line down */
+       udelay(2);              /* 1us pull up + 250ns hold */
+
+       target_in = i2c_in_csr(bus->num);
+       reg = read_csr(bus->controlling_dd, target_in);
+       return !!(reg & QSFP_HFI0_I2CDAT);
+}
+
+static int hfi1_getscl(void *data)
+{
+       struct hfi1_i2c_bus *bus = (struct hfi1_i2c_bus *)data;
+       u64 reg;
+       u32 target_in;
+
+       hfi1_setscl(data, 1);   /* clear OE so we do not pull line down */
+       udelay(2);              /* 1us pull up + 250ns hold */
+
+       target_in = i2c_in_csr(bus->num);
+       reg = read_csr(bus->controlling_dd, target_in);
+       return !!(reg & QSFP_HFI0_I2CCLK);
+}
 
 /*
- * QSFP support for hfi driver, using "Two Wire Serial Interface" driver
- * in twsi.c
+ * Allocate and initialize the given i2c bus number.
+ * Returns NULL on failure.
  */
-#define I2C_MAX_RETRY 4
+static struct hfi1_i2c_bus *init_i2c_bus(struct hfi1_devdata *dd,
+                                        struct hfi1_asic_data *ad, int num)
+{
+       struct hfi1_i2c_bus *bus;
+       int ret;
+
+       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+       if (!bus)
+               return NULL;
+
+       bus->controlling_dd = dd;
+       bus->num = num; /* our bus number */
+
+       bus->algo.setsda = hfi1_setsda;
+       bus->algo.setscl = hfi1_setscl;
+       bus->algo.getsda = hfi1_getsda;
+       bus->algo.getscl = hfi1_getscl;
+       bus->algo.udelay = 5;
+       bus->algo.timeout = usecs_to_jiffies(50);
+       bus->algo.data = bus;
+
+       bus->adapter.owner = THIS_MODULE;
+       bus->adapter.algo_data = &bus->algo;
+       bus->adapter.dev.parent = &dd->pcidev->dev;
+       snprintf(bus->adapter.name, sizeof(bus->adapter.name),
+                "hfi1_i2c%d", num);
+
+       ret = i2c_bit_add_bus(&bus->adapter);
+       if (ret) {
+               dd_dev_info(dd, "%s: unable to add i2c bus %d, err %d\n",
+                           __func__, num, ret);
+               kfree(bus);
+               return NULL;
+       }
+
+       return bus;
+}
 
 /*
- * Raw i2c write.  No set-up or lock checking.
+ * Initialize i2c buses.
+ * Return 0 on success, -errno on error.
  */
-static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
-                      int offset, void *bp, int len)
+int set_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
 {
-       struct hfi1_devdata *dd = ppd->dd;
-       int ret, cnt;
-       u8 *buff = bp;
+       ad->i2c_bus0 = init_i2c_bus(dd, ad, 0);
+       ad->i2c_bus1 = init_i2c_bus(dd, ad, 1);
+       if (!ad->i2c_bus0 || !ad->i2c_bus1)
+               return -ENOMEM;
+       return 0;
+};
 
-       cnt = 0;
-       while (cnt < len) {
-               int wlen = len - cnt;
+static void clean_i2c_bus(struct hfi1_i2c_bus *bus)
+{
+       if (bus) {
+               i2c_del_adapter(&bus->adapter);
+               kfree(bus);
+       }
+}
 
-               ret = hfi1_twsi_blk_wr(dd, target, i2c_addr, offset,
-                                      buff + cnt, wlen);
-               if (ret) {
-                       /* hfi1_twsi_blk_wr() 1 for error, else 0 */
-                       return -EIO;
-               }
-               offset += wlen;
-               cnt += wlen;
+void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad)
+{
+       clean_i2c_bus(ad->i2c_bus0);
+       ad->i2c_bus0 = NULL;
+       clean_i2c_bus(ad->i2c_bus1);
+       ad->i2c_bus1 = NULL;
+}
+
+static int i2c_bus_write(struct hfi1_devdata *dd, struct hfi1_i2c_bus *i2c,
+                        u8 slave_addr, int offset, int offset_size,
+                        u8 *data, u16 len)
+{
+       int ret;
+       int num_msgs;
+       u8 offset_bytes[2];
+       struct i2c_msg msgs[2];
+
+       switch (offset_size) {
+       case 0:
+               num_msgs = 1;
+               msgs[0].addr = slave_addr;
+               msgs[0].flags = 0;
+               msgs[0].len = len;
+               msgs[0].buf = data;
+               break;
+       case 2:
+               offset_bytes[1] = (offset >> 8) & 0xff;
+               /* fall through */
+       case 1:
+               num_msgs = 2;
+               offset_bytes[0] = offset & 0xff;
+
+               msgs[0].addr = slave_addr;
+               msgs[0].flags = 0;
+               msgs[0].len = offset_size;
+               msgs[0].buf = offset_bytes;
+
+               msgs[1].addr = slave_addr;
+               msgs[1].flags = I2C_M_NOSTART,
+               msgs[1].len = len;
+               msgs[1].buf = data;
+               break;
+       default:
+               return -EINVAL;
        }
 
-       /* Must wait min 20us between qsfp i2c transactions */
-       udelay(20);
+       i2c->controlling_dd = dd;
+       ret = i2c_transfer(&i2c->adapter, msgs, num_msgs);
+       if (ret != num_msgs) {
+               dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; write failed, ret %d\n",
+                          __func__, i2c->num, slave_addr, offset, len, ret);
+               return ret < 0 ? ret : -EIO;
+       }
+       return 0;
+}
+
+static int i2c_bus_read(struct hfi1_devdata *dd, struct hfi1_i2c_bus *bus,
+                       u8 slave_addr, int offset, int offset_size,
+                       u8 *data, u16 len)
+{
+       int ret;
+       int num_msgs;
+       u8 offset_bytes[2];
+       struct i2c_msg msgs[2];
+
+       switch (offset_size) {
+       case 0:
+               num_msgs = 1;
+               msgs[0].addr = slave_addr;
+               msgs[0].flags = I2C_M_RD;
+               msgs[0].len = len;
+               msgs[0].buf = data;
+               break;
+       case 2:
+               offset_bytes[1] = (offset >> 8) & 0xff;
+               /* fall through */
+       case 1:
+               num_msgs = 2;
+               offset_bytes[0] = offset & 0xff;
+
+               msgs[0].addr = slave_addr;
+               msgs[0].flags = 0;
+               msgs[0].len = offset_size;
+               msgs[0].buf = offset_bytes;
+
+               msgs[1].addr = slave_addr;
+               msgs[1].flags = I2C_M_RD,
+               msgs[1].len = len;
+               msgs[1].buf = data;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       return cnt;
+       bus->controlling_dd = dd;
+       ret = i2c_transfer(&bus->adapter, msgs, num_msgs);
+       if (ret != num_msgs) {
+               dd_dev_err(dd, "%s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; read failed, ret %d\n",
+                          __func__, bus->num, slave_addr, offset, len, ret);
+               return ret < 0 ? ret : -EIO;
+       }
+       return 0;
+}
+
+/*
+ * Raw i2c write.  No set-up or lock checking.
+ *
+ * Return 0 on success, -errno on error.
+ */
+static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
+                      int offset, void *bp, int len)
+{
+       struct hfi1_devdata *dd = ppd->dd;
+       struct hfi1_i2c_bus *bus;
+       u8 slave_addr;
+       int offset_size;
+
+       bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
+       slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
+       offset_size = (i2c_addr >> 8) & 0x3;
+       return i2c_bus_write(dd, bus, slave_addr, offset, offset_size, bp, len);
 }
 
 /*
  * Caller must hold the i2c chain resource.
+ *
+ * Return number of bytes written, or -errno.
  */
 int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
              void *bp, int len)
@@ -99,63 +338,36 @@ int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
        if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
                return -EACCES;
 
-       /* make sure the TWSI bus is in a sane state */
-       ret = hfi1_twsi_reset(ppd->dd, target);
-       if (ret) {
-               hfi1_dev_porterr(ppd->dd, ppd->port,
-                                "I2C chain %d write interface reset failed\n",
-                                target);
+       ret = __i2c_write(ppd, target, i2c_addr, offset, bp, len);
+       if (ret)
                return ret;
-       }
 
-       return __i2c_write(ppd, target, i2c_addr, offset, bp, len);
+       return len;
 }
 
 /*
  * Raw i2c read.  No set-up or lock checking.
+ *
+ * Return 0 on success, -errno on error.
  */
 static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr,
                      int offset, void *bp, int len)
 {
        struct hfi1_devdata *dd = ppd->dd;
-       int ret, cnt, pass = 0;
-       int orig_offset = offset;
-
-       cnt = 0;
-       while (cnt < len) {
-               int rlen = len - cnt;
-
-               ret = hfi1_twsi_blk_rd(dd, target, i2c_addr, offset,
-                                      bp + cnt, rlen);
-               /* Some QSFP's fail first try. Retry as experiment */
-               if (ret && cnt == 0 && ++pass < I2C_MAX_RETRY)
-                       continue;
-               if (ret) {
-                       /* hfi1_twsi_blk_rd() 1 for error, else 0 */
-                       ret = -EIO;
-                       goto exit;
-               }
-               offset += rlen;
-               cnt += rlen;
-       }
-
-       ret = cnt;
-
-exit:
-       if (ret < 0) {
-               hfi1_dev_porterr(dd, ppd->port,
-                                "I2C chain %d read failed, addr 0x%x, offset 0x%x, len %d\n",
-                                target, i2c_addr, orig_offset, len);
-       }
-
-       /* Must wait min 20us between qsfp i2c transactions */
-       udelay(20);
-
-       return ret;
+       struct hfi1_i2c_bus *bus;
+       u8 slave_addr;
+       int offset_size;
+
+       bus = target ? dd->asic_data->i2c_bus1 : dd->asic_data->i2c_bus0;
+       slave_addr = (i2c_addr & 0xff) >> 1; /* convert to 7-bit addr */
+       offset_size = (i2c_addr >> 8) & 0x3;
+       return i2c_bus_read(dd, bus, slave_addr, offset, offset_size, bp, len);
 }
 
 /*
  * Caller must hold the i2c chain resource.
+ *
+ * Return number of bytes read, or -errno.
  */
 int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
             void *bp, int len)
@@ -165,16 +377,11 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
        if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
                return -EACCES;
 
-       /* make sure the TWSI bus is in a sane state */
-       ret = hfi1_twsi_reset(ppd->dd, target);
-       if (ret) {
-               hfi1_dev_porterr(ppd->dd, ppd->port,
-                                "I2C chain %d read interface reset failed\n",
-                                target);
+       ret = __i2c_read(ppd, target, i2c_addr, offset, bp, len);
+       if (ret)
                return ret;
-       }
 
-       return __i2c_read(ppd, target, i2c_addr, offset, bp, len);
+       return len;
 }
 
 /*
@@ -182,6 +389,8 @@ int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset,
  * by writing @addr = ((256 * n) + m)
  *
  * Caller must hold the i2c chain resource.
+ *
+ * Return number of bytes written or -errno.
  */
 int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
               int len)
@@ -189,21 +398,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
        int count = 0;
        int offset;
        int nwrite;
-       int ret;
+       int ret = 0;
        u8 page;
 
        if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
                return -EACCES;
 
-       /* make sure the TWSI bus is in a sane state */
-       ret = hfi1_twsi_reset(ppd->dd, target);
-       if (ret) {
-               hfi1_dev_porterr(ppd->dd, ppd->port,
-                                "QSFP chain %d write interface reset failed\n",
-                                target);
-               return ret;
-       }
-
        while (count < len) {
                /*
                 * Set the qsfp page based on a zero-based address
@@ -213,11 +413,12 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
 
                ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
                                  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
-               if (ret != 1) {
+               /* QSFPs require a 5-10msec delay after write operations */
+               mdelay(5);
+               if (ret) {
                        hfi1_dev_porterr(ppd->dd, ppd->port,
                                         "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
                                         target, ret);
-                       ret = -EIO;
                        break;
                }
 
@@ -229,11 +430,13 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
 
                ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
                                  offset, bp + count, nwrite);
-               if (ret <= 0)   /* stop on error or nothing written */
+               /* QSFPs require a 5-10msec delay after write operations */
+               mdelay(5);
+               if (ret)        /* stop on error */
                        break;
 
-               count += ret;
-               addr += ret;
+               count += nwrite;
+               addr += nwrite;
        }
 
        if (ret < 0)
@@ -243,7 +446,7 @@ int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
 
 /*
  * Perform a stand-alone single QSFP write.  Acquire the resource, do the
- * read, then release the resource.
+ * write, then release the resource.
  */
 int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
                   int len)
@@ -266,6 +469,8 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
  * by reading @addr = ((256 * n) + m)
  *
  * Caller must hold the i2c chain resource.
+ *
+ * Return the number of bytes read or -errno.
  */
 int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
              int len)
@@ -273,21 +478,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
        int count = 0;
        int offset;
        int nread;
-       int ret;
+       int ret = 0;
        u8 page;
 
        if (!check_chip_resource(ppd->dd, i2c_target(target), __func__))
                return -EACCES;
 
-       /* make sure the TWSI bus is in a sane state */
-       ret = hfi1_twsi_reset(ppd->dd, target);
-       if (ret) {
-               hfi1_dev_porterr(ppd->dd, ppd->port,
-                                "QSFP chain %d read interface reset failed\n",
-                                target);
-               return ret;
-       }
-
        while (count < len) {
                /*
                 * Set the qsfp page based on a zero-based address
@@ -296,11 +492,12 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
                page = (u8)(addr / QSFP_PAGESIZE);
                ret = __i2c_write(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
                                  QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1);
-               if (ret != 1) {
+               /* QSFPs require a 5-10msec delay after write operations */
+               mdelay(5);
+               if (ret) {
                        hfi1_dev_porterr(ppd->dd, ppd->port,
                                         "QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d\n",
                                         target, ret);
-                       ret = -EIO;
                        break;
                }
 
@@ -310,15 +507,13 @@ int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
                if (((addr % QSFP_RW_BOUNDARY) + nread) > QSFP_RW_BOUNDARY)
                        nread = QSFP_RW_BOUNDARY - (addr % QSFP_RW_BOUNDARY);
 
-               /* QSFPs require a 5-10msec delay after write operations */
-               mdelay(5);
                ret = __i2c_read(ppd, target, QSFP_DEV | QSFP_OFFSET_SIZE,
                                 offset, bp + count, nread);
-               if (ret <= 0)   /* stop on error or nothing read */
+               if (ret)        /* stop on error */
                        break;
 
-               count += ret;
-               addr += ret;
+               count += nread;
+               addr += nread;
        }
 
        if (ret < 0)
index dadc66c..69275eb 100644 (file)
@@ -238,3 +238,6 @@ int one_qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
                   int len);
 int one_qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp,
                  int len);
+struct hfi1_asic_data;
+int set_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad);
+void clean_up_i2c(struct hfi1_devdata *dd, struct hfi1_asic_data *ad);
index 792f15e..5da190e 100644 (file)
@@ -477,6 +477,37 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                                qp->s_flags |= RVT_S_WAIT_FENCE;
                                goto bail;
                        }
+                       /*
+                        * Local operations are processed immediately
+                        * after all prior requests have completed
+                        */
+                       if (wqe->wr.opcode == IB_WR_REG_MR ||
+                           wqe->wr.opcode == IB_WR_LOCAL_INV) {
+                               int local_ops = 0;
+                               int err = 0;
+
+                               if (qp->s_last != qp->s_cur)
+                                       goto bail;
+                               if (++qp->s_cur == qp->s_size)
+                                       qp->s_cur = 0;
+                               if (++qp->s_tail == qp->s_size)
+                                       qp->s_tail = 0;
+                               if (!(wqe->wr.send_flags &
+                                     RVT_SEND_COMPLETION_ONLY)) {
+                                       err = rvt_invalidate_rkey(
+                                               qp,
+                                               wqe->wr.ex.invalidate_rkey);
+                                       local_ops = 1;
+                               }
+                               hfi1_send_complete(qp, wqe,
+                                                  err ? IB_WC_LOC_PROT_ERR
+                                                      : IB_WC_SUCCESS);
+                               if (local_ops)
+                                       atomic_dec(&qp->local_ops_pending);
+                               qp->s_hdrwords = 0;
+                               goto done_free_tx;
+                       }
+
                        newreq = 1;
                        qp->s_psn = wqe->psn;
                }
@@ -491,6 +522,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                switch (wqe->wr.opcode) {
                case IB_WR_SEND:
                case IB_WR_SEND_WITH_IMM:
+               case IB_WR_SEND_WITH_INV:
                        /* If no credit, return. */
                        if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT) &&
                            cmp_msn(wqe->ssn, qp->s_lsn + 1) > 0) {
@@ -504,11 +536,17 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                        }
                        if (wqe->wr.opcode == IB_WR_SEND) {
                                qp->s_state = OP(SEND_ONLY);
-                       } else {
+                       } else if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
                                qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE);
                                /* Immediate data comes after the BTH */
                                ohdr->u.imm_data = wqe->wr.ex.imm_data;
                                hwords += 1;
+                       } else {
+                               qp->s_state = OP(SEND_ONLY_WITH_INVALIDATE);
+                               /* Invalidate rkey comes after the BTH */
+                               ohdr->u.ieth = cpu_to_be32(
+                                               wqe->wr.ex.invalidate_rkey);
+                               hwords += 1;
                        }
                        if (wqe->wr.send_flags & IB_SEND_SOLICITED)
                                bth0 |= IB_BTH_SOLICITED;
@@ -671,11 +709,16 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                }
                if (wqe->wr.opcode == IB_WR_SEND) {
                        qp->s_state = OP(SEND_LAST);
-               } else {
+               } else if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
                        qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
                        /* Immediate data comes after the BTH */
                        ohdr->u.imm_data = wqe->wr.ex.imm_data;
                        hwords += 1;
+               } else {
+                       qp->s_state = OP(SEND_LAST_WITH_INVALIDATE);
+                       /* invalidate data comes after the BTH */
+                       ohdr->u.ieth = cpu_to_be32(wqe->wr.ex.invalidate_rkey);
+                       hwords += 1;
                }
                if (wqe->wr.send_flags & IB_SEND_SOLICITED)
                        bth0 |= IB_BTH_SOLICITED;
@@ -1047,7 +1090,7 @@ void hfi1_rc_timeout(unsigned long arg)
                ibp->rvp.n_rc_timeouts++;
                qp->s_flags &= ~RVT_S_TIMER;
                del_timer(&qp->s_timer);
-               trace_hfi1_rc_timeout(qp, qp->s_last_psn + 1);
+               trace_hfi1_timeout(qp, qp->s_last_psn + 1);
                restart_rc(qp, qp->s_last_psn + 1, 1);
                hfi1_schedule_send(qp);
        }
@@ -1171,7 +1214,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct hfi1_ib_header *hdr)
         * If we were waiting for sends to complete before re-sending,
         * and they are now complete, restart sending.
         */
-       trace_hfi1_rc_sendcomplete(qp, psn);
+       trace_hfi1_sendcomplete(qp, psn);
        if (qp->s_flags & RVT_S_WAIT_PSN &&
            cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) {
                qp->s_flags &= ~RVT_S_WAIT_PSN;
@@ -1567,7 +1610,7 @@ static void rc_rcv_resp(struct hfi1_ibport *ibp,
 
        spin_lock_irqsave(&qp->s_lock, flags);
 
-       trace_hfi1_rc_ack(qp, psn);
+       trace_hfi1_ack(qp, psn);
 
        /* Ignore invalid responses. */
        smp_read_barrier_depends(); /* see post_one_send */
@@ -1782,7 +1825,7 @@ static noinline int rc_rcv_error(struct hfi1_other_headers *ohdr, void *data,
        u8 i, prev;
        int old_req;
 
-       trace_hfi1_rc_rcv_error(qp, psn);
+       trace_hfi1_rcv_error(qp, psn);
        if (diff > 0) {
                /*
                 * Packet sequence error.
@@ -2086,7 +2129,6 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
        u32 tlen = packet->tlen;
        struct rvt_qp *qp = packet->qp;
        struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num);
-       struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
        struct hfi1_other_headers *ohdr = packet->ohdr;
        u32 bth0, opcode;
        u32 hdrsize = packet->hlen;
@@ -2097,30 +2139,15 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
        int diff;
        struct ib_reth *reth;
        unsigned long flags;
-       u32 bth1;
        int ret, is_fecn = 0;
        int copy_last = 0;
+       u32 rkey;
 
        bth0 = be32_to_cpu(ohdr->bth[0]);
        if (hfi1_ruc_check_hdr(ibp, hdr, rcv_flags & HFI1_HAS_GRH, qp, bth0))
                return;
 
-       bth1 = be32_to_cpu(ohdr->bth[1]);
-       if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) {
-               if (bth1 & HFI1_BECN_SMASK) {
-                       u16 rlid = qp->remote_ah_attr.dlid;
-                       u32 lqpn, rqpn;
-
-                       lqpn = qp->ibqp.qp_num;
-                       rqpn = qp->remote_qpn;
-                       process_becn(
-                               ppd,
-                               qp->remote_ah_attr.sl,
-                               rlid, lqpn, rqpn,
-                               IB_CC_SVCTYPE_RC);
-               }
-               is_fecn = bth1 & HFI1_FECN_SMASK;
-       }
+       is_fecn = process_ecn(qp, packet, false);
 
        psn = be32_to_cpu(ohdr->bth[2]);
        opcode = (bth0 >> 24) & 0xff;
@@ -2154,7 +2181,8 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
        case OP(SEND_MIDDLE):
                if (opcode == OP(SEND_MIDDLE) ||
                    opcode == OP(SEND_LAST) ||
-                   opcode == OP(SEND_LAST_WITH_IMMEDIATE))
+                   opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
+                   opcode == OP(SEND_LAST_WITH_INVALIDATE))
                        break;
                goto nack_inv;
 
@@ -2170,6 +2198,7 @@ void hfi1_rc_rcv(struct hfi1_packet *packet)
                if (opcode == OP(SEND_MIDDLE) ||
                    opcode == OP(SEND_LAST) ||
                    opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
+                   opcode == OP(SEND_LAST_WITH_INVALIDATE) ||
                    opcode == OP(RDMA_WRITE_MIDDLE) ||
                    opcode == OP(RDMA_WRITE_LAST) ||
                    opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
@@ -2218,6 +2247,7 @@ send_middle:
 
        case OP(SEND_ONLY):
        case OP(SEND_ONLY_WITH_IMMEDIATE):
+       case OP(SEND_ONLY_WITH_INVALIDATE):
                ret = hfi1_rvt_get_rwqe(qp, 0);
                if (ret < 0)
                        goto nack_op_err;
@@ -2226,12 +2256,22 @@ send_middle:
                qp->r_rcv_len = 0;
                if (opcode == OP(SEND_ONLY))
                        goto no_immediate_data;
+               if (opcode == OP(SEND_ONLY_WITH_INVALIDATE))
+                       goto send_last_inv;
                /* FALLTHROUGH for SEND_ONLY_WITH_IMMEDIATE */
        case OP(SEND_LAST_WITH_IMMEDIATE):
 send_last_imm:
                wc.ex.imm_data = ohdr->u.imm_data;
                wc.wc_flags = IB_WC_WITH_IMM;
                goto send_last;
+       case OP(SEND_LAST_WITH_INVALIDATE):
+send_last_inv:
+               rkey = be32_to_cpu(ohdr->u.ieth);
+               if (rvt_invalidate_rkey(qp, rkey))
+                       goto no_immediate_data;
+               wc.ex.invalidate_rkey = rkey;
+               wc.wc_flags = IB_WC_WITH_INVALIDATE;
+               goto send_last;
        case OP(RDMA_WRITE_LAST):
                copy_last = ibpd_to_rvtpd(qp->ibqp.pd)->user;
                /* fall through */
index a659aec..48d5094 100644 (file)
@@ -372,6 +372,7 @@ static void ruc_loopback(struct rvt_qp *sqp)
        int ret;
        int copy_last = 0;
        u32 to;
+       int local_ops = 0;
 
        rcu_read_lock();
 
@@ -440,11 +441,31 @@ again:
        sqp->s_sge.num_sge = wqe->wr.num_sge;
        sqp->s_len = wqe->length;
        switch (wqe->wr.opcode) {
+       case IB_WR_REG_MR:
+               goto send_comp;
+
+       case IB_WR_LOCAL_INV:
+               if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
+                       if (rvt_invalidate_rkey(sqp,
+                                               wqe->wr.ex.invalidate_rkey))
+                               send_status = IB_WC_LOC_PROT_ERR;
+                       local_ops = 1;
+               }
+               goto send_comp;
+
+       case IB_WR_SEND_WITH_INV:
+               if (!rvt_invalidate_rkey(qp, wqe->wr.ex.invalidate_rkey)) {
+                       wc.wc_flags = IB_WC_WITH_INVALIDATE;
+                       wc.ex.invalidate_rkey = wqe->wr.ex.invalidate_rkey;
+               }
+               goto send;
+
        case IB_WR_SEND_WITH_IMM:
                wc.wc_flags = IB_WC_WITH_IMM;
                wc.ex.imm_data = wqe->wr.ex.imm_data;
                /* FALLTHROUGH */
        case IB_WR_SEND:
+send:
                ret = hfi1_rvt_get_rwqe(qp, 0);
                if (ret < 0)
                        goto op_err;
@@ -583,6 +604,10 @@ send_comp:
 flush_send:
        sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
        hfi1_send_complete(sqp, wqe, send_status);
+       if (local_ops) {
+               atomic_dec(&sqp->local_ops_pending);
+               local_ops = 0;
+       }
        goto again;
 
 rnr_nak:
@@ -683,10 +708,10 @@ u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr,
        return sizeof(struct ib_grh) / sizeof(u32);
 }
 
-#define BTH2_OFFSET (offsetof(struct hfi1_pio_header, hdr.u.oth.bth[2]) / 4)
+#define BTH2_OFFSET (offsetof(struct hfi1_sdma_header, hdr.u.oth.bth[2]) / 4)
 
 /**
- * build_ahg - create ahg in s_hdr
+ * build_ahg - create ahg in s_ahg
  * @qp: a pointer to QP
  * @npsn: the next PSN for the request/response
  *
@@ -708,19 +733,18 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn)
                        qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde);
                if (qp->s_ahgidx >= 0) {
                        qp->s_ahgpsn = npsn;
-                       priv->s_hdr->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
+                       priv->s_ahg->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
                        /* save to protect a change in another thread */
-                       priv->s_hdr->sde = priv->s_sde;
-                       priv->s_hdr->ahgidx = qp->s_ahgidx;
+                       priv->s_ahg->ahgidx = qp->s_ahgidx;
                        qp->s_flags |= RVT_S_AHG_VALID;
                }
        } else {
                /* subsequent middle after valid */
                if (qp->s_ahgidx >= 0) {
-                       priv->s_hdr->tx_flags |= SDMA_TXREQ_F_USE_AHG;
-                       priv->s_hdr->ahgidx = qp->s_ahgidx;
-                       priv->s_hdr->ahgcount++;
-                       priv->s_hdr->ahgdesc[0] =
+                       priv->s_ahg->tx_flags |= SDMA_TXREQ_F_USE_AHG;
+                       priv->s_ahg->ahgidx = qp->s_ahgidx;
+                       priv->s_ahg->ahgcount++;
+                       priv->s_ahg->ahgdesc[0] =
                                sdma_build_ahg_descriptor(
                                        (__force u16)cpu_to_be16((u16)npsn),
                                        BTH2_OFFSET,
@@ -728,8 +752,8 @@ static inline void build_ahg(struct rvt_qp *qp, u32 npsn)
                                        16);
                        if ((npsn & 0xffff0000) !=
                                        (qp->s_ahgpsn & 0xffff0000)) {
-                               priv->s_hdr->ahgcount++;
-                               priv->s_hdr->ahgdesc[1] =
+                               priv->s_ahg->ahgcount++;
+                               priv->s_ahg->ahgdesc[1] =
                                        sdma_build_ahg_descriptor(
                                                (__force u16)cpu_to_be16(
                                                        (u16)(npsn >> 16)),
@@ -766,7 +790,7 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr,
        }
        lrh0 |= (priv->s_sc & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4;
        /*
-        * reset s_hdr/AHG fields
+        * reset s_ahg/AHG fields
         *
         * This insures that the ahgentry/ahgcount
         * are at a non-AHG default to protect
@@ -776,10 +800,9 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct hfi1_other_headers *ohdr,
         * build_ahg() will modify as appropriate
         * to use the AHG feature.
         */
-       priv->s_hdr->tx_flags = 0;
-       priv->s_hdr->ahgcount = 0;
-       priv->s_hdr->ahgidx = 0;
-       priv->s_hdr->sde = NULL;
+       priv->s_ahg->tx_flags = 0;
+       priv->s_ahg->ahgcount = 0;
+       priv->s_ahg->ahgidx = 0;
        if (qp->s_mig_state == IB_MIG_MIGRATED)
                bth0 |= IB_BTH_MIG_REQ;
        else
@@ -890,7 +913,7 @@ void hfi1_do_send(struct rvt_qp *qp)
                         */
                        if (hfi1_verbs_send(qp, &ps))
                                return;
-                       /* Record that s_hdr is empty. */
+                       /* Record that s_ahg is empty. */
                        qp->s_hdrwords = 0;
                        /* allow other tasks to run */
                        if (unlikely(time_after(jiffies, timeout))) {
index 91fc2ae..74c84c6 100644 (file)
@@ -49,6 +49,7 @@
 #include "hfi.h"
 #include "mad.h"
 #include "trace.h"
+#include "affinity.h"
 
 /*
  * Start of per-port congestion control structures and support code
@@ -622,6 +623,27 @@ static ssize_t show_tempsense(struct device *device,
        return ret;
 }
 
+static ssize_t show_sdma_affinity(struct device *device,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct hfi1_ibdev *dev =
+               container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
+       struct hfi1_devdata *dd = dd_from_dev(dev);
+
+       return hfi1_get_sdma_affinity(dd, buf);
+}
+
+static ssize_t store_sdma_affinity(struct device *device,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct hfi1_ibdev *dev =
+               container_of(device, struct hfi1_ibdev, rdi.ibdev.dev);
+       struct hfi1_devdata *dd = dd_from_dev(dev);
+
+       return hfi1_set_sdma_affinity(dd, buf, count);
+}
+
 /*
  * end of per-unit (or driver, in some cases, but replicated
  * per unit) functions
@@ -636,6 +658,8 @@ static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
 static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
 static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
 static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
+static DEVICE_ATTR(sdma_affinity, S_IWUSR | S_IRUGO, show_sdma_affinity,
+                  store_sdma_affinity);
 
 static struct device_attribute *hfi1_attributes[] = {
        &dev_attr_hw_rev,
@@ -646,6 +670,7 @@ static struct device_attribute *hfi1_attributes[] = {
        &dev_attr_boardversion,
        &dev_attr_tempsense,
        &dev_attr_chip_reset,
+       &dev_attr_sdma_affinity,
 };
 
 int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
index 28c1d08..92dc88f 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-#undef TRACE_SYSTEM_VAR
-#define TRACE_SYSTEM_VAR hfi1
-
-#if !defined(__HFI1_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
-#define __HFI1_TRACE_H
-
-#include <linux/tracepoint.h>
-#include <linux/trace_seq.h>
-
-#include "hfi.h"
-#include "mad.h"
-#include "sdma.h"
-
-#define DD_DEV_ENTRY(dd)       __string(dev, dev_name(&(dd)->pcidev->dev))
-#define DD_DEV_ASSIGN(dd)      __assign_str(dev, dev_name(&(dd)->pcidev->dev))
-
-#define packettype_name(etype) { RHF_RCV_TYPE_##etype, #etype }
-#define show_packettype(etype)                  \
-__print_symbolic(etype,                         \
-       packettype_name(EXPECTED),              \
-       packettype_name(EAGER),                 \
-       packettype_name(IB),                    \
-       packettype_name(ERROR),                 \
-       packettype_name(BYPASS))
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_rx
-
-TRACE_EVENT(hfi1_rcvhdr,
-           TP_PROTO(struct hfi1_devdata *dd,
-                    u32 ctxt,
-                    u64 eflags,
-                    u32 etype,
-                    u32 hlen,
-                    u32 tlen,
-                    u32 updegr,
-                    u32 etail
-                    ),
-           TP_ARGS(dd, ctxt, eflags, etype, hlen, tlen, updegr, etail),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __field(u64, eflags)
-                            __field(u32, ctxt)
-                            __field(u32, etype)
-                            __field(u32, hlen)
-                            __field(u32, tlen)
-                            __field(u32, updegr)
-                            __field(u32, etail)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd);
-                          __entry->eflags = eflags;
-                          __entry->ctxt = ctxt;
-                          __entry->etype = etype;
-                          __entry->hlen = hlen;
-                          __entry->tlen = tlen;
-                          __entry->updegr = updegr;
-                          __entry->etail = etail;
-                          ),
-           TP_printk(
-                     "[%s] ctxt %d eflags 0x%llx etype %d,%s hlen %d tlen %d updegr %d etail %d",
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->eflags,
-                     __entry->etype, show_packettype(__entry->etype),
-                     __entry->hlen,
-                     __entry->tlen,
-                     __entry->updegr,
-                     __entry->etail
-                     )
-);
-
-TRACE_EVENT(hfi1_receive_interrupt,
-           TP_PROTO(struct hfi1_devdata *dd, u32 ctxt),
-           TP_ARGS(dd, ctxt),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __field(u32, ctxt)
-                            __field(u8, slow_path)
-                            __field(u8, dma_rtail)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd);
-                          __entry->ctxt = ctxt;
-                          if (dd->rcd[ctxt]->do_interrupt ==
-                              &handle_receive_interrupt) {
-                               __entry->slow_path = 1;
-                               __entry->dma_rtail = 0xFF;
-                          } else if (dd->rcd[ctxt]->do_interrupt ==
-                                     &handle_receive_interrupt_dma_rtail){
-                               __entry->dma_rtail = 1;
-                               __entry->slow_path = 0;
-                          } else if (dd->rcd[ctxt]->do_interrupt ==
-                                     &handle_receive_interrupt_nodma_rtail) {
-                               __entry->dma_rtail = 0;
-                               __entry->slow_path = 0;
-                          }
-                          ),
-           TP_printk("[%s] ctxt %d SlowPath: %d DmaRtail: %d",
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->slow_path,
-                     __entry->dma_rtail
-                     )
-);
-
-TRACE_EVENT(hfi1_exp_tid_reg,
-           TP_PROTO(unsigned ctxt, u16 subctxt, u32 rarr,
-                    u32 npages, unsigned long va, unsigned long pa,
-                    dma_addr_t dma),
-           TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
-           TP_STRUCT__entry(
-                   __field(unsigned, ctxt)
-                   __field(u16, subctxt)
-                   __field(u32, rarr)
-                   __field(u32, npages)
-                   __field(unsigned long, va)
-                   __field(unsigned long, pa)
-                   __field(dma_addr_t, dma)
-                   ),
-           TP_fast_assign(
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->rarr = rarr;
-                   __entry->npages = npages;
-                   __entry->va = va;
-                   __entry->pa = pa;
-                   __entry->dma = dma;
-                   ),
-           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->rarr,
-                     __entry->npages,
-                     __entry->pa,
-                     __entry->va,
-                     __entry->dma
-                   )
-       );
-
-TRACE_EVENT(hfi1_exp_tid_unreg,
-           TP_PROTO(unsigned ctxt, u16 subctxt, u32 rarr, u32 npages,
-                    unsigned long va, unsigned long pa, dma_addr_t dma),
-           TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
-           TP_STRUCT__entry(
-                   __field(unsigned, ctxt)
-                   __field(u16, subctxt)
-                   __field(u32, rarr)
-                   __field(u32, npages)
-                   __field(unsigned long, va)
-                   __field(unsigned long, pa)
-                   __field(dma_addr_t, dma)
-                   ),
-           TP_fast_assign(
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->rarr = rarr;
-                   __entry->npages = npages;
-                   __entry->va = va;
-                   __entry->pa = pa;
-                   __entry->dma = dma;
-                   ),
-           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->rarr,
-                     __entry->npages,
-                     __entry->pa,
-                     __entry->va,
-                     __entry->dma
-                   )
-       );
-
-TRACE_EVENT(hfi1_exp_tid_inval,
-           TP_PROTO(unsigned ctxt, u16 subctxt, unsigned long va, u32 rarr,
-                    u32 npages, dma_addr_t dma),
-           TP_ARGS(ctxt, subctxt, va, rarr, npages, dma),
-           TP_STRUCT__entry(
-                   __field(unsigned, ctxt)
-                   __field(u16, subctxt)
-                   __field(unsigned long, va)
-                   __field(u32, rarr)
-                   __field(u32, npages)
-                   __field(dma_addr_t, dma)
-                   ),
-           TP_fast_assign(
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->va = va;
-                   __entry->rarr = rarr;
-                   __entry->npages = npages;
-                   __entry->dma = dma;
-                   ),
-           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx dma: 0x%llx",
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->rarr,
-                     __entry->npages,
-                     __entry->va,
-                     __entry->dma
-                   )
-       );
-
-TRACE_EVENT(hfi1_mmu_invalidate,
-           TP_PROTO(unsigned ctxt, u16 subctxt, const char *type,
-                    unsigned long start, unsigned long end),
-           TP_ARGS(ctxt, subctxt, type, start, end),
-           TP_STRUCT__entry(
-                   __field(unsigned, ctxt)
-                   __field(u16, subctxt)
-                   __string(type, type)
-                   __field(unsigned long, start)
-                   __field(unsigned long, end)
-                   ),
-           TP_fast_assign(
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __assign_str(type, type);
-                   __entry->start = start;
-                   __entry->end = end;
-                   ),
-           TP_printk("[%3u:%02u] MMU Invalidate (%s) 0x%lx - 0x%lx",
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __get_str(type),
-                     __entry->start,
-                     __entry->end
-                   )
-       );
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_tx
-
-TRACE_EVENT(hfi1_piofree,
-           TP_PROTO(struct send_context *sc, int extra),
-           TP_ARGS(sc, extra),
-           TP_STRUCT__entry(DD_DEV_ENTRY(sc->dd)
-                            __field(u32, sw_index)
-                            __field(u32, hw_context)
-                            __field(int, extra)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(sc->dd);
-                          __entry->sw_index = sc->sw_index;
-                          __entry->hw_context = sc->hw_context;
-                          __entry->extra = extra;
-                          ),
-           TP_printk("[%s] ctxt %u(%u) extra %d",
-                     __get_str(dev),
-                     __entry->sw_index,
-                     __entry->hw_context,
-                     __entry->extra
-                     )
-);
-
-TRACE_EVENT(hfi1_wantpiointr,
-           TP_PROTO(struct send_context *sc, u32 needint, u64 credit_ctrl),
-           TP_ARGS(sc, needint, credit_ctrl),
-           TP_STRUCT__entry(DD_DEV_ENTRY(sc->dd)
-                            __field(u32, sw_index)
-                            __field(u32, hw_context)
-                            __field(u32, needint)
-                            __field(u64, credit_ctrl)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(sc->dd);
-                          __entry->sw_index = sc->sw_index;
-                          __entry->hw_context = sc->hw_context;
-                          __entry->needint = needint;
-                          __entry->credit_ctrl = credit_ctrl;
-                          ),
-           TP_printk("[%s] ctxt %u(%u) on %d credit_ctrl 0x%llx",
-                     __get_str(dev),
-                     __entry->sw_index,
-                     __entry->hw_context,
-                     __entry->needint,
-                     (unsigned long long)__entry->credit_ctrl
-                      )
-);
-
-DECLARE_EVENT_CLASS(hfi1_qpsleepwakeup_template,
-                   TP_PROTO(struct rvt_qp *qp, u32 flags),
-                   TP_ARGS(qp, flags),
-                   TP_STRUCT__entry(
-                           DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device))
-                           __field(u32, qpn)
-                           __field(u32, flags)
-                           __field(u32, s_flags)
-                           ),
-                   TP_fast_assign(
-                           DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
-                           __entry->flags = flags;
-                           __entry->qpn = qp->ibqp.qp_num;
-                           __entry->s_flags = qp->s_flags;
-                           ),
-                   TP_printk(
-                           "[%s] qpn 0x%x flags 0x%x s_flags 0x%x",
-                           __get_str(dev),
-                           __entry->qpn,
-                           __entry->flags,
-                           __entry->s_flags
-                           )
-);
-
-DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpwakeup,
-            TP_PROTO(struct rvt_qp *qp, u32 flags),
-            TP_ARGS(qp, flags));
-
-DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpsleep,
-            TP_PROTO(struct rvt_qp *qp, u32 flags),
-            TP_ARGS(qp, flags));
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_ibhdrs
-
-u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr);
-const char *parse_everbs_hdrs(struct trace_seq *p, u8 opcode, void *ehdrs);
-
-#define __parse_ib_ehdrs(op, ehdrs) parse_everbs_hdrs(p, op, ehdrs)
-
-const char *parse_sdma_flags(struct trace_seq *p, u64 desc0, u64 desc1);
-
-#define __parse_sdma_flags(desc0, desc1) parse_sdma_flags(p, desc0, desc1)
-
-#define lrh_name(lrh) { HFI1_##lrh, #lrh }
-#define show_lnh(lrh)                    \
-__print_symbolic(lrh,                    \
-       lrh_name(LRH_BTH),               \
-       lrh_name(LRH_GRH))
-
-#define ib_opcode_name(opcode) { IB_OPCODE_##opcode, #opcode  }
-#define show_ib_opcode(opcode)                             \
-__print_symbolic(opcode,                                   \
-       ib_opcode_name(RC_SEND_FIRST),                     \
-       ib_opcode_name(RC_SEND_MIDDLE),                    \
-       ib_opcode_name(RC_SEND_LAST),                      \
-       ib_opcode_name(RC_SEND_LAST_WITH_IMMEDIATE),       \
-       ib_opcode_name(RC_SEND_ONLY),                      \
-       ib_opcode_name(RC_SEND_ONLY_WITH_IMMEDIATE),       \
-       ib_opcode_name(RC_RDMA_WRITE_FIRST),               \
-       ib_opcode_name(RC_RDMA_WRITE_MIDDLE),              \
-       ib_opcode_name(RC_RDMA_WRITE_LAST),                \
-       ib_opcode_name(RC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
-       ib_opcode_name(RC_RDMA_WRITE_ONLY),                \
-       ib_opcode_name(RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
-       ib_opcode_name(RC_RDMA_READ_REQUEST),              \
-       ib_opcode_name(RC_RDMA_READ_RESPONSE_FIRST),       \
-       ib_opcode_name(RC_RDMA_READ_RESPONSE_MIDDLE),      \
-       ib_opcode_name(RC_RDMA_READ_RESPONSE_LAST),        \
-       ib_opcode_name(RC_RDMA_READ_RESPONSE_ONLY),        \
-       ib_opcode_name(RC_ACKNOWLEDGE),                    \
-       ib_opcode_name(RC_ATOMIC_ACKNOWLEDGE),             \
-       ib_opcode_name(RC_COMPARE_SWAP),                   \
-       ib_opcode_name(RC_FETCH_ADD),                      \
-       ib_opcode_name(RC_SEND_LAST_WITH_INVALIDATE),      \
-       ib_opcode_name(RC_SEND_ONLY_WITH_INVALIDATE),      \
-       ib_opcode_name(UC_SEND_FIRST),                     \
-       ib_opcode_name(UC_SEND_MIDDLE),                    \
-       ib_opcode_name(UC_SEND_LAST),                      \
-       ib_opcode_name(UC_SEND_LAST_WITH_IMMEDIATE),       \
-       ib_opcode_name(UC_SEND_ONLY),                      \
-       ib_opcode_name(UC_SEND_ONLY_WITH_IMMEDIATE),       \
-       ib_opcode_name(UC_RDMA_WRITE_FIRST),               \
-       ib_opcode_name(UC_RDMA_WRITE_MIDDLE),              \
-       ib_opcode_name(UC_RDMA_WRITE_LAST),                \
-       ib_opcode_name(UC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \
-       ib_opcode_name(UC_RDMA_WRITE_ONLY),                \
-       ib_opcode_name(UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \
-       ib_opcode_name(UD_SEND_ONLY),                      \
-       ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE),       \
-       ib_opcode_name(CNP))
-
-#define LRH_PRN "vl %d lver %d sl %d lnh %d,%s dlid %.4x len %d slid %.4x"
-#define BTH_PRN \
-       "op 0x%.2x,%s se %d m %d pad %d tver %d pkey 0x%.4x " \
-       "f %d b %d qpn 0x%.6x a %d psn 0x%.8x"
-#define EHDR_PRN "%s"
-
-DECLARE_EVENT_CLASS(hfi1_ibhdr_template,
-                   TP_PROTO(struct hfi1_devdata *dd,
-                            struct hfi1_ib_header *hdr),
-                   TP_ARGS(dd, hdr),
-                   TP_STRUCT__entry(
-                           DD_DEV_ENTRY(dd)
-                           /* LRH */
-                           __field(u8, vl)
-                           __field(u8, lver)
-                           __field(u8, sl)
-                           __field(u8, lnh)
-                           __field(u16, dlid)
-                           __field(u16, len)
-                           __field(u16, slid)
-                           /* BTH */
-                           __field(u8, opcode)
-                           __field(u8, se)
-                           __field(u8, m)
-                           __field(u8, pad)
-                           __field(u8, tver)
-                           __field(u16, pkey)
-                           __field(u8, f)
-                           __field(u8, b)
-                           __field(u32, qpn)
-                           __field(u8, a)
-                           __field(u32, psn)
-                           /* extended headers */
-                           __dynamic_array(u8, ehdrs, ibhdr_exhdr_len(hdr))
-                           ),
-                   TP_fast_assign(
-                          struct hfi1_other_headers *ohdr;
-
-                          DD_DEV_ASSIGN(dd);
-                          /* LRH */
-                          __entry->vl =
-                          (u8)(be16_to_cpu(hdr->lrh[0]) >> 12);
-                          __entry->lver =
-                          (u8)(be16_to_cpu(hdr->lrh[0]) >> 8) & 0xf;
-                          __entry->sl =
-                          (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
-                          __entry->lnh =
-                          (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
-                          __entry->dlid =
-                          be16_to_cpu(hdr->lrh[1]);
-                          /* allow for larger len */
-                          __entry->len =
-                          be16_to_cpu(hdr->lrh[2]);
-                          __entry->slid =
-                          be16_to_cpu(hdr->lrh[3]);
-                          /* BTH */
-                          if (__entry->lnh == HFI1_LRH_BTH)
-                               ohdr = &hdr->u.oth;
-                          else
-                               ohdr = &hdr->u.l.oth;
-                         __entry->opcode =
-                         (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
-                         __entry->se =
-                         (be32_to_cpu(ohdr->bth[0]) >> 23) & 1;
-                         __entry->m =
-                         (be32_to_cpu(ohdr->bth[0]) >> 22) & 1;
-                         __entry->pad =
-                         (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-                         __entry->tver =
-                         (be32_to_cpu(ohdr->bth[0]) >> 16) & 0xf;
-                         __entry->pkey =
-                         be32_to_cpu(ohdr->bth[0]) & 0xffff;
-                         __entry->f =
-                         (be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) &
-                         HFI1_FECN_MASK;
-                         __entry->b =
-                         (be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) &
-                         HFI1_BECN_MASK;
-                         __entry->qpn =
-                         be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
-                         __entry->a =
-                         (be32_to_cpu(ohdr->bth[2]) >> 31) & 1;
-                         /* allow for larger PSN */
-                         __entry->psn =
-                         be32_to_cpu(ohdr->bth[2]) & 0x7fffffff;
-                         /* extended headers */
-                         memcpy(__get_dynamic_array(ehdrs), &ohdr->u,
-                                ibhdr_exhdr_len(hdr));
-                        ),
-                   TP_printk("[%s] " LRH_PRN " " BTH_PRN " " EHDR_PRN,
-                             __get_str(dev),
-                             /* LRH */
-                             __entry->vl,
-                             __entry->lver,
-                             __entry->sl,
-                             __entry->lnh, show_lnh(__entry->lnh),
-                             __entry->dlid,
-                             __entry->len,
-                             __entry->slid,
-                             /* BTH */
-                             __entry->opcode, show_ib_opcode(__entry->opcode),
-                             __entry->se,
-                             __entry->m,
-                             __entry->pad,
-                             __entry->tver,
-                             __entry->pkey,
-                             __entry->f,
-                             __entry->b,
-                             __entry->qpn,
-                             __entry->a,
-                             __entry->psn,
-                             /* extended headers */
-                             __parse_ib_ehdrs(
-                                       __entry->opcode,
-                                       (void *)__get_dynamic_array(ehdrs))
-                            )
-);
-
-DEFINE_EVENT(hfi1_ibhdr_template, input_ibhdr,
-            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
-            TP_ARGS(dd, hdr));
-
-DEFINE_EVENT(hfi1_ibhdr_template, pio_output_ibhdr,
-            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
-            TP_ARGS(dd, hdr));
-
-DEFINE_EVENT(hfi1_ibhdr_template, ack_output_ibhdr,
-            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
-            TP_ARGS(dd, hdr));
-
-DEFINE_EVENT(hfi1_ibhdr_template, sdma_output_ibhdr,
-            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
-            TP_ARGS(dd, hdr));
-
-#define SNOOP_PRN \
-       "slid %.4x dlid %.4x qpn 0x%.6x opcode 0x%.2x,%s " \
-       "svc lvl %d pkey 0x%.4x [header = %d bytes] [data = %d bytes]"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_snoop
-
-TRACE_EVENT(snoop_capture,
-           TP_PROTO(struct hfi1_devdata *dd,
-                    int hdr_len,
-                    struct hfi1_ib_header *hdr,
-                    int data_len,
-                    void *data),
-           TP_ARGS(dd, hdr_len, hdr, data_len, data),
-           TP_STRUCT__entry(
-               DD_DEV_ENTRY(dd)
-               __field(u16, slid)
-               __field(u16, dlid)
-               __field(u32, qpn)
-               __field(u8, opcode)
-               __field(u8, sl)
-               __field(u16, pkey)
-               __field(u32, hdr_len)
-               __field(u32, data_len)
-               __field(u8, lnh)
-               __dynamic_array(u8, raw_hdr, hdr_len)
-               __dynamic_array(u8, raw_pkt, data_len)
-               ),
-           TP_fast_assign(
-               struct hfi1_other_headers *ohdr;
-
-               __entry->lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
-               if (__entry->lnh == HFI1_LRH_BTH)
-                       ohdr = &hdr->u.oth;
-               else
-                       ohdr = &hdr->u.l.oth;
-               DD_DEV_ASSIGN(dd);
-               __entry->slid = be16_to_cpu(hdr->lrh[3]);
-               __entry->dlid = be16_to_cpu(hdr->lrh[1]);
-               __entry->qpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
-               __entry->opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
-               __entry->sl = (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
-               __entry->pkey = be32_to_cpu(ohdr->bth[0]) & 0xffff;
-               __entry->hdr_len = hdr_len;
-               __entry->data_len = data_len;
-               memcpy(__get_dynamic_array(raw_hdr), hdr, hdr_len);
-               memcpy(__get_dynamic_array(raw_pkt), data, data_len);
-               ),
-           TP_printk(
-               "[%s] " SNOOP_PRN,
-               __get_str(dev),
-               __entry->slid,
-               __entry->dlid,
-               __entry->qpn,
-               __entry->opcode,
-               show_ib_opcode(__entry->opcode),
-               __entry->sl,
-               __entry->pkey,
-               __entry->hdr_len,
-               __entry->data_len
-               )
-);
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_ctxts
-
-#define UCTXT_FMT \
-       "cred:%u, credaddr:0x%llx, piobase:0x%llx, rcvhdr_cnt:%u, "     \
-       "rcvbase:0x%llx, rcvegrc:%u, rcvegrb:0x%llx"
-TRACE_EVENT(hfi1_uctxtdata,
-           TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ctxtdata *uctxt),
-           TP_ARGS(dd, uctxt),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __field(unsigned, ctxt)
-                            __field(u32, credits)
-                            __field(u64, hw_free)
-                            __field(u64, piobase)
-                            __field(u16, rcvhdrq_cnt)
-                            __field(u64, rcvhdrq_phys)
-                            __field(u32, eager_cnt)
-                            __field(u64, rcvegr_phys)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd);
-                          __entry->ctxt = uctxt->ctxt;
-                          __entry->credits = uctxt->sc->credits;
-                          __entry->hw_free = (u64)uctxt->sc->hw_free;
-                          __entry->piobase = (u64)uctxt->sc->base_addr;
-                          __entry->rcvhdrq_cnt = uctxt->rcvhdrq_cnt;
-                          __entry->rcvhdrq_phys = uctxt->rcvhdrq_phys;
-                          __entry->eager_cnt = uctxt->egrbufs.alloced;
-                          __entry->rcvegr_phys =
-                          uctxt->egrbufs.rcvtids[0].phys;
-                          ),
-           TP_printk("[%s] ctxt %u " UCTXT_FMT,
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->credits,
-                     __entry->hw_free,
-                     __entry->piobase,
-                     __entry->rcvhdrq_cnt,
-                     __entry->rcvhdrq_phys,
-                     __entry->eager_cnt,
-                     __entry->rcvegr_phys
-                     )
-);
-
-#define CINFO_FMT \
-       "egrtids:%u, egr_size:%u, hdrq_cnt:%u, hdrq_size:%u, sdma_ring_size:%u"
-TRACE_EVENT(hfi1_ctxt_info,
-           TP_PROTO(struct hfi1_devdata *dd, unsigned ctxt, unsigned subctxt,
-                    struct hfi1_ctxt_info cinfo),
-           TP_ARGS(dd, ctxt, subctxt, cinfo),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __field(unsigned, ctxt)
-                            __field(unsigned, subctxt)
-                            __field(u16, egrtids)
-                            __field(u16, rcvhdrq_cnt)
-                            __field(u16, rcvhdrq_size)
-                            __field(u16, sdma_ring_size)
-                            __field(u32, rcvegr_size)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd);
-                           __entry->ctxt = ctxt;
-                           __entry->subctxt = subctxt;
-                           __entry->egrtids = cinfo.egrtids;
-                           __entry->rcvhdrq_cnt = cinfo.rcvhdrq_cnt;
-                           __entry->rcvhdrq_size = cinfo.rcvhdrq_entsize;
-                           __entry->sdma_ring_size = cinfo.sdma_ring_size;
-                           __entry->rcvegr_size = cinfo.rcvegr_size;
-                           ),
-           TP_printk("[%s] ctxt %u:%u " CINFO_FMT,
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->egrtids,
-                     __entry->rcvegr_size,
-                     __entry->rcvhdrq_cnt,
-                     __entry->rcvhdrq_size,
-                     __entry->sdma_ring_size
-                     )
-);
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_sma
-
-#define BCT_FORMAT \
-       "shared_limit %x vls 0-7 [%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x] 15 [%x,%x]"
-
-#define BCT(field) \
-       be16_to_cpu( \
-               ((struct buffer_control *)__get_dynamic_array(bct))->field \
-       )
-
-DECLARE_EVENT_CLASS(hfi1_bct_template,
-                   TP_PROTO(struct hfi1_devdata *dd,
-                            struct buffer_control *bc),
-                   TP_ARGS(dd, bc),
-                   TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                                    __dynamic_array(u8, bct, sizeof(*bc))
-                                    ),
-                   TP_fast_assign(DD_DEV_ASSIGN(dd);
-                                  memcpy(__get_dynamic_array(bct), bc,
-                                         sizeof(*bc));
-                                  ),
-                   TP_printk(BCT_FORMAT,
-                             BCT(overall_shared_limit),
-
-                             BCT(vl[0].dedicated),
-                             BCT(vl[0].shared),
-
-                             BCT(vl[1].dedicated),
-                             BCT(vl[1].shared),
-
-                             BCT(vl[2].dedicated),
-                             BCT(vl[2].shared),
-
-                             BCT(vl[3].dedicated),
-                             BCT(vl[3].shared),
-
-                             BCT(vl[4].dedicated),
-                             BCT(vl[4].shared),
-
-                             BCT(vl[5].dedicated),
-                             BCT(vl[5].shared),
-
-                             BCT(vl[6].dedicated),
-                             BCT(vl[6].shared),
-
-                             BCT(vl[7].dedicated),
-                             BCT(vl[7].shared),
-
-                             BCT(vl[15].dedicated),
-                             BCT(vl[15].shared)
-                             )
-);
-
-DEFINE_EVENT(hfi1_bct_template, bct_set,
-            TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc),
-            TP_ARGS(dd, bc));
-
-DEFINE_EVENT(hfi1_bct_template, bct_get,
-            TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc),
-            TP_ARGS(dd, bc));
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_sdma
-
-TRACE_EVENT(hfi1_sdma_descriptor,
-           TP_PROTO(struct sdma_engine *sde,
-                    u64 desc0,
-                    u64 desc1,
-                    u16 e,
-                    void *descp),
-       TP_ARGS(sde, desc0, desc1, e, descp),
-       TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                        __field(void *, descp)
-                        __field(u64, desc0)
-                        __field(u64, desc1)
-                        __field(u16, e)
-                        __field(u8, idx)
-                        ),
-       TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                      __entry->desc0 = desc0;
-                      __entry->desc1 = desc1;
-                      __entry->idx = sde->this_idx;
-                      __entry->descp = descp;
-                      __entry->e = e;
-                      ),
-       TP_printk(
-                 "[%s] SDE(%u) flags:%s addr:0x%016llx gen:%u len:%u d0:%016llx d1:%016llx to %p,%u",
-                 __get_str(dev),
-                 __entry->idx,
-                 __parse_sdma_flags(__entry->desc0, __entry->desc1),
-                 (__entry->desc0 >> SDMA_DESC0_PHY_ADDR_SHIFT) &
-                 SDMA_DESC0_PHY_ADDR_MASK,
-                 (u8)((__entry->desc1 >> SDMA_DESC1_GENERATION_SHIFT) &
-                      SDMA_DESC1_GENERATION_MASK),
-                 (u16)((__entry->desc0 >> SDMA_DESC0_BYTE_COUNT_SHIFT) &
-                       SDMA_DESC0_BYTE_COUNT_MASK),
-                 __entry->desc0,
-                 __entry->desc1,
-                 __entry->descp,
-                 __entry->e
-                 )
-);
-
-TRACE_EVENT(hfi1_sdma_engine_select,
-           TP_PROTO(struct hfi1_devdata *dd, u32 sel, u8 vl, u8 idx),
-           TP_ARGS(dd, sel, vl, idx),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __field(u32, sel)
-                            __field(u8, vl)
-                            __field(u8, idx)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd);
-                          __entry->sel = sel;
-                          __entry->vl = vl;
-                          __entry->idx = idx;
-                          ),
-           TP_printk("[%s] selecting SDE %u sel 0x%x vl %u",
-                     __get_str(dev),
-                     __entry->idx,
-                     __entry->sel,
-                     __entry->vl
-                     )
-);
-
-DECLARE_EVENT_CLASS(hfi1_sdma_engine_class,
-                   TP_PROTO(struct sdma_engine *sde, u64 status),
-                   TP_ARGS(sde, status),
-                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                                    __field(u64, status)
-                                    __field(u8, idx)
-                                    ),
-                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                                  __entry->status = status;
-                                  __entry->idx = sde->this_idx;
-                                  ),
-                   TP_printk("[%s] SDE(%u) status %llx",
-                             __get_str(dev),
-                             __entry->idx,
-                             (unsigned long long)__entry->status
-                             )
-);
-
-DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_interrupt,
-            TP_PROTO(struct sdma_engine *sde, u64 status),
-            TP_ARGS(sde, status)
-);
-
-DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_progress,
-            TP_PROTO(struct sdma_engine *sde, u64 status),
-            TP_ARGS(sde, status)
-);
-
-DECLARE_EVENT_CLASS(hfi1_sdma_ahg_ad,
-                   TP_PROTO(struct sdma_engine *sde, int aidx),
-                   TP_ARGS(sde, aidx),
-                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                                    __field(int, aidx)
-                                    __field(u8, idx)
-                                    ),
-                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                                  __entry->idx = sde->this_idx;
-                                  __entry->aidx = aidx;
-                                  ),
-                   TP_printk("[%s] SDE(%u) aidx %d",
-                             __get_str(dev),
-                             __entry->idx,
-                             __entry->aidx
-                             )
-);
-
-DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_allocate,
-            TP_PROTO(struct sdma_engine *sde, int aidx),
-            TP_ARGS(sde, aidx));
-
-DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_deallocate,
-            TP_PROTO(struct sdma_engine *sde, int aidx),
-            TP_ARGS(sde, aidx));
-
-#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
-TRACE_EVENT(hfi1_sdma_progress,
-           TP_PROTO(struct sdma_engine *sde,
-                    u16 hwhead,
-                    u16 swhead,
-                    struct sdma_txreq *txp
-                    ),
-           TP_ARGS(sde, hwhead, swhead, txp),
-           TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                            __field(u64, sn)
-                            __field(u16, hwhead)
-                            __field(u16, swhead)
-                            __field(u16, txnext)
-                            __field(u16, tx_tail)
-                            __field(u16, tx_head)
-                            __field(u8, idx)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                          __entry->hwhead = hwhead;
-                          __entry->swhead = swhead;
-                          __entry->tx_tail = sde->tx_tail;
-                          __entry->tx_head = sde->tx_head;
-                          __entry->txnext = txp ? txp->next_descq_idx : ~0;
-                          __entry->idx = sde->this_idx;
-                          __entry->sn = txp ? txp->sn : ~0;
-                          ),
-           TP_printk(
-                     "[%s] SDE(%u) sn %llu hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u",
-                     __get_str(dev),
-                     __entry->idx,
-                     __entry->sn,
-                     __entry->hwhead,
-                     __entry->swhead,
-                     __entry->txnext,
-                     __entry->tx_head,
-                     __entry->tx_tail
-                     )
-);
-#else
-TRACE_EVENT(hfi1_sdma_progress,
-           TP_PROTO(struct sdma_engine *sde,
-                    u16 hwhead, u16 swhead,
-                    struct sdma_txreq *txp
-           ),
-       TP_ARGS(sde, hwhead, swhead, txp),
-       TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                        __field(u16, hwhead)
-                        __field(u16, swhead)
-                        __field(u16, txnext)
-                        __field(u16, tx_tail)
-                        __field(u16, tx_head)
-                        __field(u8, idx)
-                        ),
-       TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                      __entry->hwhead = hwhead;
-                      __entry->swhead = swhead;
-                      __entry->tx_tail = sde->tx_tail;
-                      __entry->tx_head = sde->tx_head;
-                      __entry->txnext = txp ? txp->next_descq_idx : ~0;
-                      __entry->idx = sde->this_idx;
-                      ),
-       TP_printk(
-                 "[%s] SDE(%u) hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u",
-                 __get_str(dev),
-                 __entry->idx,
-                 __entry->hwhead,
-                 __entry->swhead,
-                 __entry->txnext,
-                 __entry->tx_head,
-                 __entry->tx_tail
-                 )
-);
-#endif
-
-DECLARE_EVENT_CLASS(hfi1_sdma_sn,
-                   TP_PROTO(struct sdma_engine *sde, u64 sn),
-                   TP_ARGS(sde, sn),
-                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                                    __field(u64, sn)
-                                    __field(u8, idx)
-                                    ),
-                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                                  __entry->sn = sn;
-                                  __entry->idx = sde->this_idx;
-                                  ),
-                   TP_printk("[%s] SDE(%u) sn %llu",
-                             __get_str(dev),
-                             __entry->idx,
-                             __entry->sn
-                             )
-);
-
-DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_out_sn,
-            TP_PROTO(
-               struct sdma_engine *sde,
-               u64 sn
-            ),
-            TP_ARGS(sde, sn)
-);
-
-DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_in_sn,
-            TP_PROTO(struct sdma_engine *sde, u64 sn),
-            TP_ARGS(sde, sn)
-);
-
-#define USDMA_HDR_FORMAT \
-       "[%s:%u:%u:%u] PBC=(0x%x 0x%x) LRH=(0x%x 0x%x) BTH=(0x%x 0x%x 0x%x) KDETH=(0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x) TIDVal=0x%x"
-
-TRACE_EVENT(hfi1_sdma_user_header,
-           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req,
-                    struct hfi1_pkt_header *hdr, u32 tidval),
-           TP_ARGS(dd, ctxt, subctxt, req, hdr, tidval),
-           TP_STRUCT__entry(
-                   DD_DEV_ENTRY(dd)
-                   __field(u16, ctxt)
-                   __field(u8, subctxt)
-                   __field(u16, req)
-                   __field(__le32, pbc0)
-                   __field(__le32, pbc1)
-                   __field(__be32, lrh0)
-                   __field(__be32, lrh1)
-                   __field(__be32, bth0)
-                   __field(__be32, bth1)
-                   __field(__be32, bth2)
-                   __field(__le32, kdeth0)
-                   __field(__le32, kdeth1)
-                   __field(__le32, kdeth2)
-                   __field(__le32, kdeth3)
-                   __field(__le32, kdeth4)
-                   __field(__le32, kdeth5)
-                   __field(__le32, kdeth6)
-                   __field(__le32, kdeth7)
-                   __field(__le32, kdeth8)
-                   __field(u32, tidval)
-                   ),
-           TP_fast_assign(
-                   __le32 *pbc = (__le32 *)hdr->pbc;
-                   __be32 *lrh = (__be32 *)hdr->lrh;
-                   __be32 *bth = (__be32 *)hdr->bth;
-                   __le32 *kdeth = (__le32 *)&hdr->kdeth;
-
-                   DD_DEV_ASSIGN(dd);
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->req = req;
-                   __entry->pbc0 = pbc[0];
-                   __entry->pbc1 = pbc[1];
-                   __entry->lrh0 = be32_to_cpu(lrh[0]);
-                   __entry->lrh1 = be32_to_cpu(lrh[1]);
-                   __entry->bth0 = be32_to_cpu(bth[0]);
-                   __entry->bth1 = be32_to_cpu(bth[1]);
-                   __entry->bth2 = be32_to_cpu(bth[2]);
-                   __entry->kdeth0 = kdeth[0];
-                   __entry->kdeth1 = kdeth[1];
-                   __entry->kdeth2 = kdeth[2];
-                   __entry->kdeth3 = kdeth[3];
-                   __entry->kdeth4 = kdeth[4];
-                   __entry->kdeth5 = kdeth[5];
-                   __entry->kdeth6 = kdeth[6];
-                   __entry->kdeth7 = kdeth[7];
-                   __entry->kdeth8 = kdeth[8];
-                   __entry->tidval = tidval;
-                   ),
-           TP_printk(USDMA_HDR_FORMAT,
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->req,
-                     __entry->pbc1,
-                     __entry->pbc0,
-                     __entry->lrh0,
-                     __entry->lrh1,
-                     __entry->bth0,
-                     __entry->bth1,
-                     __entry->bth2,
-                     __entry->kdeth0,
-                     __entry->kdeth1,
-                     __entry->kdeth2,
-                     __entry->kdeth3,
-                     __entry->kdeth4,
-                     __entry->kdeth5,
-                     __entry->kdeth6,
-                     __entry->kdeth7,
-                     __entry->kdeth8,
-                     __entry->tidval
-                   )
-       );
-
-#define SDMA_UREQ_FMT \
-       "[%s:%u:%u] ver/op=0x%x, iovcnt=%u, npkts=%u, frag=%u, idx=%u"
-TRACE_EVENT(hfi1_sdma_user_reqinfo,
-           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 *i),
-           TP_ARGS(dd, ctxt, subctxt, i),
-           TP_STRUCT__entry(
-                   DD_DEV_ENTRY(dd);
-                   __field(u16, ctxt)
-                   __field(u8, subctxt)
-                   __field(u8, ver_opcode)
-                   __field(u8, iovcnt)
-                   __field(u16, npkts)
-                   __field(u16, fragsize)
-                   __field(u16, comp_idx)
-                   ),
-           TP_fast_assign(
-                   DD_DEV_ASSIGN(dd);
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->ver_opcode = i[0] & 0xff;
-                   __entry->iovcnt = (i[0] >> 8) & 0xff;
-                   __entry->npkts = i[1];
-                   __entry->fragsize = i[2];
-                   __entry->comp_idx = i[3];
-                   ),
-           TP_printk(SDMA_UREQ_FMT,
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->ver_opcode,
-                     __entry->iovcnt,
-                     __entry->npkts,
-                     __entry->fragsize,
-                     __entry->comp_idx
-                   )
-       );
-
-#define usdma_complete_name(st) { st, #st }
-#define show_usdma_complete_state(st)                  \
-       __print_symbolic(st,                            \
-                        usdma_complete_name(FREE),     \
-                        usdma_complete_name(QUEUED),   \
-                        usdma_complete_name(COMPLETE), \
-                        usdma_complete_name(ERROR))
-
-TRACE_EVENT(hfi1_sdma_user_completion,
-           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 idx,
-                    u8 state, int code),
-           TP_ARGS(dd, ctxt, subctxt, idx, state, code),
-           TP_STRUCT__entry(
-                   DD_DEV_ENTRY(dd)
-                   __field(u16, ctxt)
-                   __field(u8, subctxt)
-                   __field(u16, idx)
-                   __field(u8, state)
-                   __field(int, code)
-                   ),
-           TP_fast_assign(
-                   DD_DEV_ASSIGN(dd);
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->idx = idx;
-                   __entry->state = state;
-                   __entry->code = code;
-                   ),
-           TP_printk("[%s:%u:%u:%u] SDMA completion state %s (%d)",
-                     __get_str(dev), __entry->ctxt, __entry->subctxt,
-                     __entry->idx, show_usdma_complete_state(__entry->state),
-                     __entry->code)
-       );
-
-const char *print_u32_array(struct trace_seq *, u32 *, int);
-#define __print_u32_hex(arr, len) print_u32_array(p, arr, len)
-
-TRACE_EVENT(hfi1_sdma_user_header_ahg,
-           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req,
-                    u8 sde, u8 ahgidx, u32 *ahg, int len, u32 tidval),
-           TP_ARGS(dd, ctxt, subctxt, req, sde, ahgidx, ahg, len, tidval),
-           TP_STRUCT__entry(
-                   DD_DEV_ENTRY(dd)
-                   __field(u16, ctxt)
-                   __field(u8, subctxt)
-                   __field(u16, req)
-                   __field(u8, sde)
-                   __field(u8, idx)
-                   __field(int, len)
-                   __field(u32, tidval)
-                   __array(u32, ahg, 10)
-                   ),
-           TP_fast_assign(
-                   DD_DEV_ASSIGN(dd);
-                   __entry->ctxt = ctxt;
-                   __entry->subctxt = subctxt;
-                   __entry->req = req;
-                   __entry->sde = sde;
-                   __entry->idx = ahgidx;
-                   __entry->len = len;
-                   __entry->tidval = tidval;
-                   memcpy(__entry->ahg, ahg, len * sizeof(u32));
-                   ),
-           TP_printk("[%s:%u:%u:%u] (SDE%u/AHG%u) ahg[0-%d]=(%s) TIDVal=0x%x",
-                     __get_str(dev),
-                     __entry->ctxt,
-                     __entry->subctxt,
-                     __entry->req,
-                     __entry->sde,
-                     __entry->idx,
-                     __entry->len - 1,
-                     __print_u32_hex(__entry->ahg, __entry->len),
-                     __entry->tidval
-                   )
-       );
-
-TRACE_EVENT(hfi1_sdma_state,
-           TP_PROTO(struct sdma_engine *sde,
-                    const char *cstate,
-                    const char *nstate
-                    ),
-           TP_ARGS(sde, cstate, nstate),
-           TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
-                            __string(curstate, cstate)
-                            __string(newstate, nstate)
-                            ),
-       TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
-                      __assign_str(curstate, cstate);
-                      __assign_str(newstate, nstate);
-                      ),
-       TP_printk("[%s] current state %s new state %s",
-                 __get_str(dev),
-                 __get_str(curstate),
-                 __get_str(newstate)
-                 )
-);
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_rc
-
-DECLARE_EVENT_CLASS(hfi1_rc_template,
-                   TP_PROTO(struct rvt_qp *qp, u32 psn),
-                   TP_ARGS(qp, psn),
-                   TP_STRUCT__entry(
-                       DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device))
-                       __field(u32, qpn)
-                       __field(u32, s_flags)
-                       __field(u32, psn)
-                       __field(u32, s_psn)
-                       __field(u32, s_next_psn)
-                       __field(u32, s_sending_psn)
-                       __field(u32, s_sending_hpsn)
-                       __field(u32, r_psn)
-                       ),
-                   TP_fast_assign(
-                       DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
-                       __entry->qpn = qp->ibqp.qp_num;
-                       __entry->s_flags = qp->s_flags;
-                       __entry->psn = psn;
-                       __entry->s_psn = qp->s_psn;
-                       __entry->s_next_psn = qp->s_next_psn;
-                       __entry->s_sending_psn = qp->s_sending_psn;
-                       __entry->s_sending_hpsn = qp->s_sending_hpsn;
-                       __entry->r_psn = qp->r_psn;
-                       ),
-                   TP_printk(
-                       "[%s] qpn 0x%x s_flags 0x%x psn 0x%x s_psn 0x%x s_next_psn 0x%x s_sending_psn 0x%x sending_hpsn 0x%x r_psn 0x%x",
-                       __get_str(dev),
-                       __entry->qpn,
-                       __entry->s_flags,
-                       __entry->psn,
-                       __entry->s_psn,
-                       __entry->s_next_psn,
-                       __entry->s_sending_psn,
-                       __entry->s_sending_hpsn,
-                       __entry->r_psn
-                       )
-);
-
-DEFINE_EVENT(hfi1_rc_template, hfi1_rc_sendcomplete,
-            TP_PROTO(struct rvt_qp *qp, u32 psn),
-            TP_ARGS(qp, psn)
-);
-
-DEFINE_EVENT(hfi1_rc_template, hfi1_rc_ack,
-            TP_PROTO(struct rvt_qp *qp, u32 psn),
-            TP_ARGS(qp, psn)
-);
-
-DEFINE_EVENT(hfi1_rc_template, hfi1_rc_timeout,
-            TP_PROTO(struct rvt_qp *qp, u32 psn),
-            TP_ARGS(qp, psn)
-);
-
-DEFINE_EVENT(hfi1_rc_template, hfi1_rc_rcv_error,
-            TP_PROTO(struct rvt_qp *qp, u32 psn),
-            TP_ARGS(qp, psn)
-);
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_misc
-
-TRACE_EVENT(hfi1_interrupt,
-           TP_PROTO(struct hfi1_devdata *dd, const struct is_table *is_entry,
-                    int src),
-           TP_ARGS(dd, is_entry, src),
-           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
-                            __array(char, buf, 64)
-                            __field(int, src)
-                            ),
-           TP_fast_assign(DD_DEV_ASSIGN(dd)
-                          is_entry->is_name(__entry->buf, 64,
-                                            src - is_entry->start);
-                          __entry->src = src;
-                          ),
-           TP_printk("[%s] source: %s [%d]", __get_str(dev), __entry->buf,
-                     __entry->src)
-);
-
-/*
- * Note:
- * This produces a REALLY ugly trace in the console output when the string is
- * too long.
- */
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM hfi1_trace
-
-#define MAX_MSG_LEN 512
-
-DECLARE_EVENT_CLASS(hfi1_trace_template,
-                   TP_PROTO(const char *function, struct va_format *vaf),
-                   TP_ARGS(function, vaf),
-                   TP_STRUCT__entry(__string(function, function)
-                                    __dynamic_array(char, msg, MAX_MSG_LEN)
-                                    ),
-                   TP_fast_assign(__assign_str(function, function);
-                                  WARN_ON_ONCE(vsnprintf
-                                               (__get_dynamic_array(msg),
-                                                MAX_MSG_LEN, vaf->fmt,
-                                                *vaf->va) >=
-                                               MAX_MSG_LEN);
-                                  ),
-                   TP_printk("(%s) %s",
-                             __get_str(function),
-                             __get_str(msg))
-);
-
-/*
- * It may be nice to macroize the __hfi1_trace but the va_* stuff requires an
- * actual function to work and can not be in a macro.
- */
-#define __hfi1_trace_def(lvl) \
-void __hfi1_trace_##lvl(const char *funct, char *fmt, ...);            \
-                                                                       \
-DEFINE_EVENT(hfi1_trace_template, hfi1_ ##lvl,                         \
-       TP_PROTO(const char *function, struct va_format *vaf),          \
-       TP_ARGS(function, vaf))
-
-#define __hfi1_trace_fn(lvl) \
-void __hfi1_trace_##lvl(const char *func, char *fmt, ...)              \
-{                                                                      \
-       struct va_format vaf = {                                        \
-               .fmt = fmt,                                             \
-       };                                                              \
-       va_list args;                                                   \
-                                                                       \
-       va_start(args, fmt);                                            \
-       vaf.va = &args;                                                 \
-       trace_hfi1_ ##lvl(func, &vaf);                                  \
-       va_end(args);                                                   \
-       return;                                                         \
-}
-
-/*
- * To create a new trace level simply define it below and as a __hfi1_trace_fn
- * in trace.c. This will create all the hooks for calling
- * hfi1_cdbg(LVL, fmt, ...); as well as take care of all
- * the debugfs stuff.
- */
-__hfi1_trace_def(PKT);
-__hfi1_trace_def(PROC);
-__hfi1_trace_def(SDMA);
-__hfi1_trace_def(LINKVERB);
-__hfi1_trace_def(DEBUG);
-__hfi1_trace_def(SNOOP);
-__hfi1_trace_def(CNTR);
-__hfi1_trace_def(PIO);
-__hfi1_trace_def(DC8051);
-__hfi1_trace_def(FIRMWARE);
-__hfi1_trace_def(RCVCTRL);
-__hfi1_trace_def(TID);
-__hfi1_trace_def(MMU);
-__hfi1_trace_def(IOCTL);
-
-#define hfi1_cdbg(which, fmt, ...) \
-       __hfi1_trace_##which(__func__, fmt, ##__VA_ARGS__)
-
-#define hfi1_dbg(fmt, ...) \
-       hfi1_cdbg(DEBUG, fmt, ##__VA_ARGS__)
-
-/*
- * Define HFI1_EARLY_DBG at compile time or here to enable early trace
- * messages. Do not check in an enablement for this.
- */
-
-#ifdef HFI1_EARLY_DBG
-#define hfi1_dbg_early(fmt, ...) \
-       trace_printk(fmt, ##__VA_ARGS__)
-#else
-#define hfi1_dbg_early(fmt, ...)
-#endif
-
-#endif /* __HFI1_TRACE_H */
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace
-#include <trace/define_trace.h>
+#include "trace_dbg.h"
+#include "trace_misc.h"
+#include "trace_ctxts.h"
+#include "trace_ibhdrs.h"
+#include "trace_rc.h"
+#include "trace_rx.h"
+#include "trace_tx.h"
diff --git a/drivers/infiniband/hw/hfi1/trace_ctxts.h b/drivers/infiniband/hw/hfi1/trace_ctxts.h
new file mode 100644 (file)
index 0000000..31654bb
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+* Copyright(c) 2015, 2016 Intel Corporation.
+*
+* This file is provided under a dual BSD/GPLv2 license.  When using or
+* redistributing this file, you may do so under either license.
+*
+* GPL LICENSE SUMMARY
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License 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.
+*
+* BSD LICENSE
+*
+* 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.
+*  - Neither the name of Intel Corporation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER 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.
+*
+*/
+#if !defined(__HFI1_TRACE_CTXTS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_CTXTS_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_ctxts
+
+#define UCTXT_FMT \
+       "cred:%u, credaddr:0x%llx, piobase:0x%p, rcvhdr_cnt:%u, "       \
+       "rcvbase:0x%llx, rcvegrc:%u, rcvegrb:0x%llx"
+TRACE_EVENT(hfi1_uctxtdata,
+           TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ctxtdata *uctxt),
+           TP_ARGS(dd, uctxt),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                            __field(unsigned int, ctxt)
+                            __field(u32, credits)
+                            __field(u64, hw_free)
+                            __field(void __iomem *, piobase)
+                            __field(u16, rcvhdrq_cnt)
+                            __field(u64, rcvhdrq_phys)
+                            __field(u32, eager_cnt)
+                            __field(u64, rcvegr_phys)
+                            ),
+           TP_fast_assign(DD_DEV_ASSIGN(dd);
+                          __entry->ctxt = uctxt->ctxt;
+                          __entry->credits = uctxt->sc->credits;
+                          __entry->hw_free = le64_to_cpu(*uctxt->sc->hw_free);
+                          __entry->piobase = uctxt->sc->base_addr;
+                          __entry->rcvhdrq_cnt = uctxt->rcvhdrq_cnt;
+                          __entry->rcvhdrq_phys = uctxt->rcvhdrq_phys;
+                          __entry->eager_cnt = uctxt->egrbufs.alloced;
+                          __entry->rcvegr_phys =
+                          uctxt->egrbufs.rcvtids[0].phys;
+                          ),
+           TP_printk("[%s] ctxt %u " UCTXT_FMT,
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->credits,
+                     __entry->hw_free,
+                     __entry->piobase,
+                     __entry->rcvhdrq_cnt,
+                     __entry->rcvhdrq_phys,
+                     __entry->eager_cnt,
+                     __entry->rcvegr_phys
+                     )
+);
+
+#define CINFO_FMT \
+       "egrtids:%u, egr_size:%u, hdrq_cnt:%u, hdrq_size:%u, sdma_ring_size:%u"
+TRACE_EVENT(hfi1_ctxt_info,
+           TP_PROTO(struct hfi1_devdata *dd, unsigned int ctxt,
+                    unsigned int subctxt,
+                    struct hfi1_ctxt_info cinfo),
+           TP_ARGS(dd, ctxt, subctxt, cinfo),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                            __field(unsigned int, ctxt)
+                            __field(unsigned int, subctxt)
+                            __field(u16, egrtids)
+                            __field(u16, rcvhdrq_cnt)
+                            __field(u16, rcvhdrq_size)
+                            __field(u16, sdma_ring_size)
+                            __field(u32, rcvegr_size)
+                            ),
+           TP_fast_assign(DD_DEV_ASSIGN(dd);
+                           __entry->ctxt = ctxt;
+                           __entry->subctxt = subctxt;
+                           __entry->egrtids = cinfo.egrtids;
+                           __entry->rcvhdrq_cnt = cinfo.rcvhdrq_cnt;
+                           __entry->rcvhdrq_size = cinfo.rcvhdrq_entsize;
+                           __entry->sdma_ring_size = cinfo.sdma_ring_size;
+                           __entry->rcvegr_size = cinfo.rcvegr_size;
+                           ),
+           TP_printk("[%s] ctxt %u:%u " CINFO_FMT,
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->egrtids,
+                     __entry->rcvegr_size,
+                     __entry->rcvhdrq_cnt,
+                     __entry->rcvhdrq_size,
+                     __entry->sdma_ring_size
+                     )
+);
+
+#endif /* __HFI1_TRACE_CTXTS_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_ctxts
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_dbg.h b/drivers/infiniband/hw/hfi1/trace_dbg.h
new file mode 100644 (file)
index 0000000..0e7d929
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+* Copyright(c) 2015, 2016 Intel Corporation.
+*
+* This file is provided under a dual BSD/GPLv2 license.  When using or
+* redistributing this file, you may do so under either license.
+*
+* GPL LICENSE SUMMARY
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License 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.
+*
+* BSD LICENSE
+*
+* 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.
+*  - Neither the name of Intel Corporation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER 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.
+*
+*/
+#if !defined(__HFI1_TRACE_EXTRA_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_EXTRA_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+/*
+ * Note:
+ * This produces a REALLY ugly trace in the console output when the string is
+ * too long.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_dbg
+
+#define MAX_MSG_LEN 512
+
+DECLARE_EVENT_CLASS(hfi1_trace_template,
+                   TP_PROTO(const char *function, struct va_format *vaf),
+                   TP_ARGS(function, vaf),
+                   TP_STRUCT__entry(__string(function, function)
+                                    __dynamic_array(char, msg, MAX_MSG_LEN)
+                                    ),
+                   TP_fast_assign(__assign_str(function, function);
+                                  WARN_ON_ONCE(vsnprintf
+                                               (__get_dynamic_array(msg),
+                                                MAX_MSG_LEN, vaf->fmt,
+                                                *vaf->va) >=
+                                               MAX_MSG_LEN);
+                                  ),
+                   TP_printk("(%s) %s",
+                             __get_str(function),
+                             __get_str(msg))
+);
+
+/*
+ * It may be nice to macroize the __hfi1_trace but the va_* stuff requires an
+ * actual function to work and can not be in a macro.
+ */
+#define __hfi1_trace_def(lvl) \
+void __hfi1_trace_##lvl(const char *funct, char *fmt, ...);            \
+                                                                       \
+DEFINE_EVENT(hfi1_trace_template, hfi1_ ##lvl,                         \
+       TP_PROTO(const char *function, struct va_format *vaf),          \
+       TP_ARGS(function, vaf))
+
+#define __hfi1_trace_fn(lvl) \
+void __hfi1_trace_##lvl(const char *func, char *fmt, ...)              \
+{                                                                      \
+       struct va_format vaf = {                                        \
+               .fmt = fmt,                                             \
+       };                                                              \
+       va_list args;                                                   \
+                                                                       \
+       va_start(args, fmt);                                            \
+       vaf.va = &args;                                                 \
+       trace_hfi1_ ##lvl(func, &vaf);                                  \
+       va_end(args);                                                   \
+       return;                                                         \
+}
+
+/*
+ * To create a new trace level simply define it below and as a __hfi1_trace_fn
+ * in trace.c. This will create all the hooks for calling
+ * hfi1_cdbg(LVL, fmt, ...); as well as take care of all
+ * the debugfs stuff.
+ */
+__hfi1_trace_def(PKT);
+__hfi1_trace_def(PROC);
+__hfi1_trace_def(SDMA);
+__hfi1_trace_def(LINKVERB);
+__hfi1_trace_def(DEBUG);
+__hfi1_trace_def(SNOOP);
+__hfi1_trace_def(CNTR);
+__hfi1_trace_def(PIO);
+__hfi1_trace_def(DC8051);
+__hfi1_trace_def(FIRMWARE);
+__hfi1_trace_def(RCVCTRL);
+__hfi1_trace_def(TID);
+__hfi1_trace_def(MMU);
+__hfi1_trace_def(IOCTL);
+
+#define hfi1_cdbg(which, fmt, ...) \
+       __hfi1_trace_##which(__func__, fmt, ##__VA_ARGS__)
+
+#define hfi1_dbg(fmt, ...) \
+       hfi1_cdbg(DEBUG, fmt, ##__VA_ARGS__)
+
+/*
+ * Define HFI1_EARLY_DBG at compile time or here to enable early trace
+ * messages. Do not check in an enablement for this.
+ */
+
+#ifdef HFI1_EARLY_DBG
+#define hfi1_dbg_early(fmt, ...) \
+       trace_printk(fmt, ##__VA_ARGS__)
+#else
+#define hfi1_dbg_early(fmt, ...)
+#endif
+
+#endif /* __HFI1_TRACE_EXTRA_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_dbg
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_ibhdrs.h b/drivers/infiniband/hw/hfi1/trace_ibhdrs.h
new file mode 100644 (file)
index 0000000..c3e41ae
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright(c) 2015, 2016 Intel Corporation.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * BSD LICENSE
+ *
+ * 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.
+ *  - Neither the name of Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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.
+ *
+ */
+#if !defined(__HFI1_TRACE_IBHDRS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_IBHDRS_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_ibhdrs
+
+u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr);
+const char *parse_everbs_hdrs(struct trace_seq *p, u8 opcode, void *ehdrs);
+
+#define __parse_ib_ehdrs(op, ehdrs) parse_everbs_hdrs(p, op, ehdrs)
+
+#define lrh_name(lrh) { HFI1_##lrh, #lrh }
+#define show_lnh(lrh)                    \
+__print_symbolic(lrh,                    \
+       lrh_name(LRH_BTH),               \
+       lrh_name(LRH_GRH))
+
+#define LRH_PRN "vl %d lver %d sl %d lnh %d,%s dlid %.4x len %d slid %.4x"
+#define BTH_PRN \
+       "op 0x%.2x,%s se %d m %d pad %d tver %d pkey 0x%.4x " \
+       "f %d b %d qpn 0x%.6x a %d psn 0x%.8x"
+#define EHDR_PRN "%s"
+
+DECLARE_EVENT_CLASS(hfi1_ibhdr_template,
+                   TP_PROTO(struct hfi1_devdata *dd,
+                            struct hfi1_ib_header *hdr),
+                   TP_ARGS(dd, hdr),
+                   TP_STRUCT__entry(
+                       DD_DEV_ENTRY(dd)
+                       /* LRH */
+                       __field(u8, vl)
+                       __field(u8, lver)
+                       __field(u8, sl)
+                       __field(u8, lnh)
+                       __field(u16, dlid)
+                       __field(u16, len)
+                       __field(u16, slid)
+                       /* BTH */
+                       __field(u8, opcode)
+                       __field(u8, se)
+                       __field(u8, m)
+                       __field(u8, pad)
+                       __field(u8, tver)
+                       __field(u16, pkey)
+                       __field(u8, f)
+                       __field(u8, b)
+                       __field(u32, qpn)
+                       __field(u8, a)
+                       __field(u32, psn)
+                       /* extended headers */
+                       __dynamic_array(u8, ehdrs, ibhdr_exhdr_len(hdr))
+                       ),
+                     TP_fast_assign(
+                       struct hfi1_other_headers *ohdr;
+
+                       DD_DEV_ASSIGN(dd);
+                       /* LRH */
+                       __entry->vl =
+                       (u8)(be16_to_cpu(hdr->lrh[0]) >> 12);
+                       __entry->lver =
+                       (u8)(be16_to_cpu(hdr->lrh[0]) >> 8) & 0xf;
+                       __entry->sl =
+                       (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
+                       __entry->lnh =
+                       (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
+                       __entry->dlid =
+                       be16_to_cpu(hdr->lrh[1]);
+                       /* allow for larger len */
+                       __entry->len =
+                       be16_to_cpu(hdr->lrh[2]);
+                       __entry->slid =
+                       be16_to_cpu(hdr->lrh[3]);
+                       /* BTH */
+                       if (__entry->lnh == HFI1_LRH_BTH)
+                       ohdr = &hdr->u.oth;
+                       else
+                       ohdr = &hdr->u.l.oth;
+                       __entry->opcode =
+                       (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
+                       __entry->se =
+                       (be32_to_cpu(ohdr->bth[0]) >> 23) & 1;
+                       __entry->m =
+                       (be32_to_cpu(ohdr->bth[0]) >> 22) & 1;
+                       __entry->pad =
+                       (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+                       __entry->tver =
+                       (be32_to_cpu(ohdr->bth[0]) >> 16) & 0xf;
+                       __entry->pkey =
+                       be32_to_cpu(ohdr->bth[0]) & 0xffff;
+                       __entry->f =
+                       (be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) &
+                       HFI1_FECN_MASK;
+                       __entry->b =
+                       (be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) &
+                       HFI1_BECN_MASK;
+                       __entry->qpn =
+                       be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
+                       __entry->a =
+                       (be32_to_cpu(ohdr->bth[2]) >> 31) & 1;
+                       /* allow for larger PSN */
+                       __entry->psn =
+                       be32_to_cpu(ohdr->bth[2]) & 0x7fffffff;
+                       /* extended headers */
+                       memcpy(__get_dynamic_array(ehdrs), &ohdr->u,
+                              ibhdr_exhdr_len(hdr));
+                       ),
+               TP_printk("[%s] " LRH_PRN " " BTH_PRN " " EHDR_PRN,
+                         __get_str(dev),
+                         /* LRH */
+                         __entry->vl,
+                         __entry->lver,
+                         __entry->sl,
+                         __entry->lnh, show_lnh(__entry->lnh),
+                         __entry->dlid,
+                         __entry->len,
+                         __entry->slid,
+                         /* BTH */
+                         __entry->opcode, show_ib_opcode(__entry->opcode),
+                         __entry->se,
+                         __entry->m,
+                         __entry->pad,
+                         __entry->tver,
+                         __entry->pkey,
+                         __entry->f,
+                         __entry->b,
+                         __entry->qpn,
+                         __entry->a,
+                         __entry->psn,
+                         /* extended headers */
+                         __parse_ib_ehdrs(
+                               __entry->opcode,
+                               (void *)__get_dynamic_array(ehdrs))
+                       )
+);
+
+DEFINE_EVENT(hfi1_ibhdr_template, input_ibhdr,
+            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
+            TP_ARGS(dd, hdr));
+
+DEFINE_EVENT(hfi1_ibhdr_template, pio_output_ibhdr,
+            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
+            TP_ARGS(dd, hdr));
+
+DEFINE_EVENT(hfi1_ibhdr_template, ack_output_ibhdr,
+            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
+            TP_ARGS(dd, hdr));
+
+DEFINE_EVENT(hfi1_ibhdr_template, sdma_output_ibhdr,
+            TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr),
+            TP_ARGS(dd, hdr));
+
+#endif /* __HFI1_TRACE_IBHDRS_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_ibhdrs
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_misc.h b/drivers/infiniband/hw/hfi1/trace_misc.h
new file mode 100644 (file)
index 0000000..d308454
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+* Copyright(c) 2015, 2016 Intel Corporation.
+*
+* This file is provided under a dual BSD/GPLv2 license.  When using or
+* redistributing this file, you may do so under either license.
+*
+* GPL LICENSE SUMMARY
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License 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.
+*
+* BSD LICENSE
+*
+* 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.
+*  - Neither the name of Intel Corporation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER 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.
+*
+*/
+#if !defined(__HFI1_TRACE_MISC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_MISC_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_misc
+
+TRACE_EVENT(hfi1_interrupt,
+           TP_PROTO(struct hfi1_devdata *dd, const struct is_table *is_entry,
+                    int src),
+           TP_ARGS(dd, is_entry, src),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                            __array(char, buf, 64)
+                            __field(int, src)
+                            ),
+           TP_fast_assign(DD_DEV_ASSIGN(dd)
+                          is_entry->is_name(__entry->buf, 64,
+                                            src - is_entry->start);
+                          __entry->src = src;
+                          ),
+           TP_printk("[%s] source: %s [%d]", __get_str(dev), __entry->buf,
+                     __entry->src)
+);
+
+#endif /* __HFI1_TRACE_MISC_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_misc
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_rc.h b/drivers/infiniband/hw/hfi1/trace_rc.h
new file mode 100644 (file)
index 0000000..5ea5005
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+* Copyright(c) 2015, 2016 Intel Corporation.
+*
+* This file is provided under a dual BSD/GPLv2 license.  When using or
+* redistributing this file, you may do so under either license.
+*
+* GPL LICENSE SUMMARY
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License 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.
+*
+* BSD LICENSE
+*
+* 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.
+*  - Neither the name of Intel Corporation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER 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.
+*
+*/
+#if !defined(__HFI1_TRACE_RC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_RC_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_rc
+
+DECLARE_EVENT_CLASS(hfi1_rc_template,
+                   TP_PROTO(struct rvt_qp *qp, u32 psn),
+                   TP_ARGS(qp, psn),
+                   TP_STRUCT__entry(
+                       DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device))
+                       __field(u32, qpn)
+                       __field(u32, s_flags)
+                       __field(u32, psn)
+                       __field(u32, s_psn)
+                       __field(u32, s_next_psn)
+                       __field(u32, s_sending_psn)
+                       __field(u32, s_sending_hpsn)
+                       __field(u32, r_psn)
+                       ),
+                   TP_fast_assign(
+                       DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+                       __entry->qpn = qp->ibqp.qp_num;
+                       __entry->s_flags = qp->s_flags;
+                       __entry->psn = psn;
+                       __entry->s_psn = qp->s_psn;
+                       __entry->s_next_psn = qp->s_next_psn;
+                       __entry->s_sending_psn = qp->s_sending_psn;
+                       __entry->s_sending_hpsn = qp->s_sending_hpsn;
+                       __entry->r_psn = qp->r_psn;
+                       ),
+                   TP_printk(
+                       "[%s] qpn 0x%x s_flags 0x%x psn 0x%x s_psn 0x%x s_next_psn 0x%x s_sending_psn 0x%x sending_hpsn 0x%x r_psn 0x%x",
+                       __get_str(dev),
+                       __entry->qpn,
+                       __entry->s_flags,
+                       __entry->psn,
+                       __entry->s_psn,
+                       __entry->s_next_psn,
+                       __entry->s_sending_psn,
+                       __entry->s_sending_hpsn,
+                       __entry->r_psn
+                       )
+);
+
+DEFINE_EVENT(hfi1_rc_template, hfi1_sendcomplete,
+            TP_PROTO(struct rvt_qp *qp, u32 psn),
+            TP_ARGS(qp, psn)
+);
+
+DEFINE_EVENT(hfi1_rc_template, hfi1_ack,
+            TP_PROTO(struct rvt_qp *qp, u32 psn),
+            TP_ARGS(qp, psn)
+);
+
+DEFINE_EVENT(hfi1_rc_template, hfi1_timeout,
+            TP_PROTO(struct rvt_qp *qp, u32 psn),
+            TP_ARGS(qp, psn)
+);
+
+DEFINE_EVENT(hfi1_rc_template, hfi1_rcv_error,
+            TP_PROTO(struct rvt_qp *qp, u32 psn),
+            TP_ARGS(qp, psn)
+);
+
+#endif /* __HFI1_TRACE_RC_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_rc
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_rx.h b/drivers/infiniband/hw/hfi1/trace_rx.h
new file mode 100644 (file)
index 0000000..9ba1f61
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright(c) 2015, 2016 Intel Corporation.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * BSD LICENSE
+ *
+ * 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.
+ *  - Neither the name of Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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.
+ *
+ */
+#if !defined(__HFI1_TRACE_RX_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_RX_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_rx
+
+TRACE_EVENT(hfi1_rcvhdr,
+           TP_PROTO(struct hfi1_devdata *dd,
+                    u32 ctxt,
+                    u64 eflags,
+                    u32 etype,
+                    u32 hlen,
+                    u32 tlen,
+                    u32 updegr,
+                    u32 etail
+                   ),
+           TP_ARGS(dd, ctxt, eflags, etype, hlen, tlen, updegr, etail),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                            __field(u64, eflags)
+                            __field(u32, ctxt)
+                            __field(u32, etype)
+                            __field(u32, hlen)
+                            __field(u32, tlen)
+                            __field(u32, updegr)
+                            __field(u32, etail)
+                            ),
+            TP_fast_assign(DD_DEV_ASSIGN(dd);
+                           __entry->eflags = eflags;
+                           __entry->ctxt = ctxt;
+                           __entry->etype = etype;
+                           __entry->hlen = hlen;
+                           __entry->tlen = tlen;
+                           __entry->updegr = updegr;
+                           __entry->etail = etail;
+                           ),
+            TP_printk(
+               "[%s] ctxt %d eflags 0x%llx etype %d,%s hlen %d tlen %d updegr %d etail %d",
+               __get_str(dev),
+               __entry->ctxt,
+               __entry->eflags,
+               __entry->etype, show_packettype(__entry->etype),
+               __entry->hlen,
+               __entry->tlen,
+               __entry->updegr,
+               __entry->etail
+               )
+);
+
+TRACE_EVENT(hfi1_receive_interrupt,
+           TP_PROTO(struct hfi1_devdata *dd, u32 ctxt),
+           TP_ARGS(dd, ctxt),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                            __field(u32, ctxt)
+                            __field(u8, slow_path)
+                            __field(u8, dma_rtail)
+                            ),
+           TP_fast_assign(DD_DEV_ASSIGN(dd);
+                       __entry->ctxt = ctxt;
+                       if (dd->rcd[ctxt]->do_interrupt ==
+                           &handle_receive_interrupt) {
+                               __entry->slow_path = 1;
+                               __entry->dma_rtail = 0xFF;
+                       } else if (dd->rcd[ctxt]->do_interrupt ==
+                                       &handle_receive_interrupt_dma_rtail){
+                               __entry->dma_rtail = 1;
+                               __entry->slow_path = 0;
+                       } else if (dd->rcd[ctxt]->do_interrupt ==
+                                       &handle_receive_interrupt_nodma_rtail) {
+                               __entry->dma_rtail = 0;
+                               __entry->slow_path = 0;
+                       }
+                       ),
+           TP_printk("[%s] ctxt %d SlowPath: %d DmaRtail: %d",
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->slow_path,
+                     __entry->dma_rtail
+                     )
+);
+
+TRACE_EVENT(hfi1_exp_tid_reg,
+           TP_PROTO(unsigned int ctxt, u16 subctxt, u32 rarr,
+                    u32 npages, unsigned long va, unsigned long pa,
+                    dma_addr_t dma),
+           TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
+           TP_STRUCT__entry(
+                            __field(unsigned int, ctxt)
+                            __field(u16, subctxt)
+                            __field(u32, rarr)
+                            __field(u32, npages)
+                            __field(unsigned long, va)
+                            __field(unsigned long, pa)
+                            __field(dma_addr_t, dma)
+                            ),
+           TP_fast_assign(
+                          __entry->ctxt = ctxt;
+                          __entry->subctxt = subctxt;
+                          __entry->rarr = rarr;
+                          __entry->npages = npages;
+                          __entry->va = va;
+                          __entry->pa = pa;
+                          __entry->dma = dma;
+                          ),
+           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->rarr,
+                     __entry->npages,
+                     __entry->pa,
+                     __entry->va,
+                     __entry->dma
+                     )
+       );
+
+TRACE_EVENT(hfi1_exp_tid_unreg,
+           TP_PROTO(unsigned int ctxt, u16 subctxt, u32 rarr, u32 npages,
+                    unsigned long va, unsigned long pa, dma_addr_t dma),
+           TP_ARGS(ctxt, subctxt, rarr, npages, va, pa, dma),
+           TP_STRUCT__entry(
+                            __field(unsigned int, ctxt)
+                            __field(u16, subctxt)
+                            __field(u32, rarr)
+                            __field(u32, npages)
+                            __field(unsigned long, va)
+                            __field(unsigned long, pa)
+                            __field(dma_addr_t, dma)
+                            ),
+           TP_fast_assign(
+                          __entry->ctxt = ctxt;
+                          __entry->subctxt = subctxt;
+                          __entry->rarr = rarr;
+                          __entry->npages = npages;
+                          __entry->va = va;
+                          __entry->pa = pa;
+                          __entry->dma = dma;
+                          ),
+           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx, va:0x%lx dma:0x%llx",
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->rarr,
+                     __entry->npages,
+                     __entry->pa,
+                     __entry->va,
+                     __entry->dma
+                     )
+       );
+
+TRACE_EVENT(hfi1_exp_tid_inval,
+           TP_PROTO(unsigned int ctxt, u16 subctxt, unsigned long va, u32 rarr,
+                    u32 npages, dma_addr_t dma),
+           TP_ARGS(ctxt, subctxt, va, rarr, npages, dma),
+           TP_STRUCT__entry(
+                            __field(unsigned int, ctxt)
+                            __field(u16, subctxt)
+                            __field(unsigned long, va)
+                            __field(u32, rarr)
+                            __field(u32, npages)
+                            __field(dma_addr_t, dma)
+                            ),
+           TP_fast_assign(
+                          __entry->ctxt = ctxt;
+                          __entry->subctxt = subctxt;
+                          __entry->va = va;
+                          __entry->rarr = rarr;
+                          __entry->npages = npages;
+                          __entry->dma = dma;
+                         ),
+           TP_printk("[%u:%u] entry:%u, %u pages @ 0x%lx dma: 0x%llx",
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->rarr,
+                     __entry->npages,
+                     __entry->va,
+                     __entry->dma
+                     )
+           );
+
+TRACE_EVENT(hfi1_mmu_invalidate,
+           TP_PROTO(unsigned int ctxt, u16 subctxt, const char *type,
+                    unsigned long start, unsigned long end),
+           TP_ARGS(ctxt, subctxt, type, start, end),
+           TP_STRUCT__entry(
+                            __field(unsigned int, ctxt)
+                            __field(u16, subctxt)
+                            __string(type, type)
+                            __field(unsigned long, start)
+                            __field(unsigned long, end)
+                            ),
+           TP_fast_assign(
+                       __entry->ctxt = ctxt;
+                       __entry->subctxt = subctxt;
+                       __assign_str(type, type);
+                       __entry->start = start;
+                       __entry->end = end;
+           ),
+           TP_printk("[%3u:%02u] MMU Invalidate (%s) 0x%lx - 0x%lx",
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __get_str(type),
+                     __entry->start,
+                     __entry->end
+                     )
+           );
+
+#define SNOOP_PRN \
+       "slid %.4x dlid %.4x qpn 0x%.6x opcode 0x%.2x,%s " \
+       "svc lvl %d pkey 0x%.4x [header = %d bytes] [data = %d bytes]"
+
+TRACE_EVENT(snoop_capture,
+           TP_PROTO(struct hfi1_devdata *dd,
+                    int hdr_len,
+                    struct hfi1_ib_header *hdr,
+                    int data_len,
+                    void *data),
+           TP_ARGS(dd, hdr_len, hdr, data_len, data),
+           TP_STRUCT__entry(
+                            DD_DEV_ENTRY(dd)
+                            __field(u16, slid)
+                            __field(u16, dlid)
+                            __field(u32, qpn)
+                            __field(u8, opcode)
+                            __field(u8, sl)
+                            __field(u16, pkey)
+                            __field(u32, hdr_len)
+                            __field(u32, data_len)
+                            __field(u8, lnh)
+                            __dynamic_array(u8, raw_hdr, hdr_len)
+                            __dynamic_array(u8, raw_pkt, data_len)
+                            ),
+           TP_fast_assign(
+               struct hfi1_other_headers *ohdr;
+
+               __entry->lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3);
+               if (__entry->lnh == HFI1_LRH_BTH)
+               ohdr = &hdr->u.oth;
+               else
+               ohdr = &hdr->u.l.oth;
+               DD_DEV_ASSIGN(dd);
+               __entry->slid = be16_to_cpu(hdr->lrh[3]);
+               __entry->dlid = be16_to_cpu(hdr->lrh[1]);
+               __entry->qpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
+               __entry->opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff;
+               __entry->sl = (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
+               __entry->pkey = be32_to_cpu(ohdr->bth[0]) & 0xffff;
+               __entry->hdr_len = hdr_len;
+               __entry->data_len = data_len;
+               memcpy(__get_dynamic_array(raw_hdr), hdr, hdr_len);
+               memcpy(__get_dynamic_array(raw_pkt), data, data_len);
+               ),
+           TP_printk(
+               "[%s] " SNOOP_PRN,
+               __get_str(dev),
+               __entry->slid,
+               __entry->dlid,
+               __entry->qpn,
+               __entry->opcode,
+               show_ib_opcode(__entry->opcode),
+               __entry->sl,
+               __entry->pkey,
+               __entry->hdr_len,
+               __entry->data_len
+               )
+);
+
+#endif /* __HFI1_TRACE_RX_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_rx
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/trace_tx.h b/drivers/infiniband/hw/hfi1/trace_tx.h
new file mode 100644 (file)
index 0000000..415d6be
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * Copyright(c) 2015, 2016 Intel Corporation.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * BSD LICENSE
+ *
+ * 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.
+ *  - Neither the name of Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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.
+ *
+ */
+#if !defined(__HFI1_TRACE_TX_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HFI1_TRACE_TX_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "hfi.h"
+#include "mad.h"
+#include "sdma.h"
+
+const char *parse_sdma_flags(struct trace_seq *p, u64 desc0, u64 desc1);
+
+#define __parse_sdma_flags(desc0, desc1) parse_sdma_flags(p, desc0, desc1)
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hfi1_tx
+
+TRACE_EVENT(hfi1_piofree,
+           TP_PROTO(struct send_context *sc, int extra),
+           TP_ARGS(sc, extra),
+           TP_STRUCT__entry(DD_DEV_ENTRY(sc->dd)
+           __field(u32, sw_index)
+           __field(u32, hw_context)
+           __field(int, extra)
+           ),
+           TP_fast_assign(DD_DEV_ASSIGN(sc->dd);
+           __entry->sw_index = sc->sw_index;
+           __entry->hw_context = sc->hw_context;
+           __entry->extra = extra;
+           ),
+           TP_printk("[%s] ctxt %u(%u) extra %d",
+                     __get_str(dev),
+                     __entry->sw_index,
+                     __entry->hw_context,
+                     __entry->extra
+           )
+);
+
+TRACE_EVENT(hfi1_wantpiointr,
+           TP_PROTO(struct send_context *sc, u32 needint, u64 credit_ctrl),
+           TP_ARGS(sc, needint, credit_ctrl),
+           TP_STRUCT__entry(DD_DEV_ENTRY(sc->dd)
+                       __field(u32, sw_index)
+                       __field(u32, hw_context)
+                       __field(u32, needint)
+                       __field(u64, credit_ctrl)
+                       ),
+           TP_fast_assign(DD_DEV_ASSIGN(sc->dd);
+                       __entry->sw_index = sc->sw_index;
+                       __entry->hw_context = sc->hw_context;
+                       __entry->needint = needint;
+                       __entry->credit_ctrl = credit_ctrl;
+                       ),
+           TP_printk("[%s] ctxt %u(%u) on %d credit_ctrl 0x%llx",
+                     __get_str(dev),
+                     __entry->sw_index,
+                     __entry->hw_context,
+                     __entry->needint,
+                     (unsigned long long)__entry->credit_ctrl
+                     )
+);
+
+DECLARE_EVENT_CLASS(hfi1_qpsleepwakeup_template,
+                   TP_PROTO(struct rvt_qp *qp, u32 flags),
+                   TP_ARGS(qp, flags),
+                   TP_STRUCT__entry(
+                   DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device))
+                   __field(u32, qpn)
+                   __field(u32, flags)
+                   __field(u32, s_flags)
+                   ),
+                   TP_fast_assign(
+                   DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device))
+                   __entry->flags = flags;
+                   __entry->qpn = qp->ibqp.qp_num;
+                   __entry->s_flags = qp->s_flags;
+                   ),
+                   TP_printk(
+                   "[%s] qpn 0x%x flags 0x%x s_flags 0x%x",
+                   __get_str(dev),
+                   __entry->qpn,
+                   __entry->flags,
+                   __entry->s_flags
+                   )
+);
+
+DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpwakeup,
+            TP_PROTO(struct rvt_qp *qp, u32 flags),
+            TP_ARGS(qp, flags));
+
+DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpsleep,
+            TP_PROTO(struct rvt_qp *qp, u32 flags),
+            TP_ARGS(qp, flags));
+
+TRACE_EVENT(hfi1_sdma_descriptor,
+           TP_PROTO(struct sdma_engine *sde,
+                    u64 desc0,
+                    u64 desc1,
+                    u16 e,
+                    void *descp),
+                    TP_ARGS(sde, desc0, desc1, e, descp),
+                    TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+                    __field(void *, descp)
+                    __field(u64, desc0)
+                    __field(u64, desc1)
+                    __field(u16, e)
+                    __field(u8, idx)
+                    ),
+                    TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+                    __entry->desc0 = desc0;
+                    __entry->desc1 = desc1;
+                    __entry->idx = sde->this_idx;
+                    __entry->descp = descp;
+                    __entry->e = e;
+                    ),
+           TP_printk(
+           "[%s] SDE(%u) flags:%s addr:0x%016llx gen:%u len:%u d0:%016llx d1:%016llx to %p,%u",
+           __get_str(dev),
+           __entry->idx,
+           __parse_sdma_flags(__entry->desc0, __entry->desc1),
+           (__entry->desc0 >> SDMA_DESC0_PHY_ADDR_SHIFT) &
+           SDMA_DESC0_PHY_ADDR_MASK,
+           (u8)((__entry->desc1 >> SDMA_DESC1_GENERATION_SHIFT) &
+           SDMA_DESC1_GENERATION_MASK),
+           (u16)((__entry->desc0 >> SDMA_DESC0_BYTE_COUNT_SHIFT) &
+           SDMA_DESC0_BYTE_COUNT_MASK),
+           __entry->desc0,
+           __entry->desc1,
+           __entry->descp,
+           __entry->e
+           )
+);
+
+TRACE_EVENT(hfi1_sdma_engine_select,
+           TP_PROTO(struct hfi1_devdata *dd, u32 sel, u8 vl, u8 idx),
+           TP_ARGS(dd, sel, vl, idx),
+           TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+           __field(u32, sel)
+           __field(u8, vl)
+           __field(u8, idx)
+           ),
+           TP_fast_assign(DD_DEV_ASSIGN(dd);
+           __entry->sel = sel;
+           __entry->vl = vl;
+           __entry->idx = idx;
+           ),
+           TP_printk("[%s] selecting SDE %u sel 0x%x vl %u",
+                     __get_str(dev),
+                     __entry->idx,
+                     __entry->sel,
+                     __entry->vl
+                     )
+);
+
+DECLARE_EVENT_CLASS(hfi1_sdma_engine_class,
+                   TP_PROTO(struct sdma_engine *sde, u64 status),
+                   TP_ARGS(sde, status),
+                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+                   __field(u64, status)
+                   __field(u8, idx)
+                   ),
+                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+                   __entry->status = status;
+                   __entry->idx = sde->this_idx;
+                   ),
+                   TP_printk("[%s] SDE(%u) status %llx",
+                             __get_str(dev),
+                             __entry->idx,
+                             (unsigned long long)__entry->status
+                             )
+);
+
+DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_interrupt,
+            TP_PROTO(struct sdma_engine *sde, u64 status),
+            TP_ARGS(sde, status)
+);
+
+DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_progress,
+            TP_PROTO(struct sdma_engine *sde, u64 status),
+            TP_ARGS(sde, status)
+);
+
+DECLARE_EVENT_CLASS(hfi1_sdma_ahg_ad,
+                   TP_PROTO(struct sdma_engine *sde, int aidx),
+                   TP_ARGS(sde, aidx),
+                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+                   __field(int, aidx)
+                   __field(u8, idx)
+                   ),
+                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+                   __entry->idx = sde->this_idx;
+                   __entry->aidx = aidx;
+                   ),
+                   TP_printk("[%s] SDE(%u) aidx %d",
+                             __get_str(dev),
+                             __entry->idx,
+                             __entry->aidx
+                             )
+);
+
+DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_allocate,
+            TP_PROTO(struct sdma_engine *sde, int aidx),
+            TP_ARGS(sde, aidx));
+
+DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_deallocate,
+            TP_PROTO(struct sdma_engine *sde, int aidx),
+            TP_ARGS(sde, aidx));
+
+#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
+TRACE_EVENT(hfi1_sdma_progress,
+           TP_PROTO(struct sdma_engine *sde,
+                    u16 hwhead,
+                    u16 swhead,
+                    struct sdma_txreq *txp
+                    ),
+           TP_ARGS(sde, hwhead, swhead, txp),
+           TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+           __field(u64, sn)
+           __field(u16, hwhead)
+           __field(u16, swhead)
+           __field(u16, txnext)
+           __field(u16, tx_tail)
+           __field(u16, tx_head)
+           __field(u8, idx)
+           ),
+           TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+           __entry->hwhead = hwhead;
+           __entry->swhead = swhead;
+           __entry->tx_tail = sde->tx_tail;
+           __entry->tx_head = sde->tx_head;
+           __entry->txnext = txp ? txp->next_descq_idx : ~0;
+           __entry->idx = sde->this_idx;
+           __entry->sn = txp ? txp->sn : ~0;
+           ),
+           TP_printk(
+           "[%s] SDE(%u) sn %llu hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u",
+           __get_str(dev),
+           __entry->idx,
+           __entry->sn,
+           __entry->hwhead,
+           __entry->swhead,
+           __entry->txnext,
+           __entry->tx_head,
+           __entry->tx_tail
+           )
+);
+#else
+TRACE_EVENT(hfi1_sdma_progress,
+           TP_PROTO(struct sdma_engine *sde,
+                    u16 hwhead, u16 swhead,
+                    struct sdma_txreq *txp
+                    ),
+           TP_ARGS(sde, hwhead, swhead, txp),
+           TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+                   __field(u16, hwhead)
+                   __field(u16, swhead)
+                   __field(u16, txnext)
+                   __field(u16, tx_tail)
+                   __field(u16, tx_head)
+                   __field(u8, idx)
+                   ),
+           TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+                   __entry->hwhead = hwhead;
+                   __entry->swhead = swhead;
+                   __entry->tx_tail = sde->tx_tail;
+                   __entry->tx_head = sde->tx_head;
+                   __entry->txnext = txp ? txp->next_descq_idx : ~0;
+                   __entry->idx = sde->this_idx;
+                   ),
+           TP_printk(
+                   "[%s] SDE(%u) hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u",
+                   __get_str(dev),
+                   __entry->idx,
+                   __entry->hwhead,
+                   __entry->swhead,
+                   __entry->txnext,
+                   __entry->tx_head,
+                   __entry->tx_tail
+           )
+);
+#endif
+
+DECLARE_EVENT_CLASS(hfi1_sdma_sn,
+                   TP_PROTO(struct sdma_engine *sde, u64 sn),
+                   TP_ARGS(sde, sn),
+                   TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+                   __field(u64, sn)
+                   __field(u8, idx)
+                   ),
+                   TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+                   __entry->sn = sn;
+                   __entry->idx = sde->this_idx;
+                   ),
+                   TP_printk("[%s] SDE(%u) sn %llu",
+                             __get_str(dev),
+                             __entry->idx,
+                             __entry->sn
+                             )
+);
+
+DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_out_sn,
+            TP_PROTO(
+            struct sdma_engine *sde,
+            u64 sn
+            ),
+            TP_ARGS(sde, sn)
+);
+
+DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_in_sn,
+            TP_PROTO(struct sdma_engine *sde, u64 sn),
+            TP_ARGS(sde, sn)
+);
+
+#define USDMA_HDR_FORMAT \
+       "[%s:%u:%u:%u] PBC=(0x%x 0x%x) LRH=(0x%x 0x%x) BTH=(0x%x 0x%x 0x%x) KDETH=(0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x) TIDVal=0x%x"
+
+TRACE_EVENT(hfi1_sdma_user_header,
+           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req,
+                    struct hfi1_pkt_header *hdr, u32 tidval),
+           TP_ARGS(dd, ctxt, subctxt, req, hdr, tidval),
+           TP_STRUCT__entry(
+                   DD_DEV_ENTRY(dd)
+                   __field(u16, ctxt)
+                   __field(u8, subctxt)
+                   __field(u16, req)
+                   __field(u32, pbc0)
+                   __field(u32, pbc1)
+                   __field(u32, lrh0)
+                   __field(u32, lrh1)
+                   __field(u32, bth0)
+                   __field(u32, bth1)
+                   __field(u32, bth2)
+                   __field(u32, kdeth0)
+                   __field(u32, kdeth1)
+                   __field(u32, kdeth2)
+                   __field(u32, kdeth3)
+                   __field(u32, kdeth4)
+                   __field(u32, kdeth5)
+                   __field(u32, kdeth6)
+                   __field(u32, kdeth7)
+                   __field(u32, kdeth8)
+                   __field(u32, tidval)
+                   ),
+                   TP_fast_assign(
+                   __le32 *pbc = (__le32 *)hdr->pbc;
+                   __be32 *lrh = (__be32 *)hdr->lrh;
+                   __be32 *bth = (__be32 *)hdr->bth;
+                   __le32 *kdeth = (__le32 *)&hdr->kdeth;
+
+                   DD_DEV_ASSIGN(dd);
+                   __entry->ctxt = ctxt;
+                   __entry->subctxt = subctxt;
+                   __entry->req = req;
+                   __entry->pbc0 = le32_to_cpu(pbc[0]);
+                   __entry->pbc1 = le32_to_cpu(pbc[1]);
+                   __entry->lrh0 = be32_to_cpu(lrh[0]);
+                   __entry->lrh1 = be32_to_cpu(lrh[1]);
+                   __entry->bth0 = be32_to_cpu(bth[0]);
+                   __entry->bth1 = be32_to_cpu(bth[1]);
+                   __entry->bth2 = be32_to_cpu(bth[2]);
+                   __entry->kdeth0 = le32_to_cpu(kdeth[0]);
+                   __entry->kdeth1 = le32_to_cpu(kdeth[1]);
+                   __entry->kdeth2 = le32_to_cpu(kdeth[2]);
+                   __entry->kdeth3 = le32_to_cpu(kdeth[3]);
+                   __entry->kdeth4 = le32_to_cpu(kdeth[4]);
+                   __entry->kdeth5 = le32_to_cpu(kdeth[5]);
+                   __entry->kdeth6 = le32_to_cpu(kdeth[6]);
+                   __entry->kdeth7 = le32_to_cpu(kdeth[7]);
+                   __entry->kdeth8 = le32_to_cpu(kdeth[8]);
+                   __entry->tidval = tidval;
+           ),
+           TP_printk(USDMA_HDR_FORMAT,
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->req,
+                     __entry->pbc1,
+                     __entry->pbc0,
+                     __entry->lrh0,
+                     __entry->lrh1,
+                     __entry->bth0,
+                     __entry->bth1,
+                     __entry->bth2,
+                     __entry->kdeth0,
+                     __entry->kdeth1,
+                     __entry->kdeth2,
+                     __entry->kdeth3,
+                     __entry->kdeth4,
+                     __entry->kdeth5,
+                     __entry->kdeth6,
+                     __entry->kdeth7,
+                     __entry->kdeth8,
+                     __entry->tidval
+           )
+);
+
+#define SDMA_UREQ_FMT \
+       "[%s:%u:%u] ver/op=0x%x, iovcnt=%u, npkts=%u, frag=%u, idx=%u"
+TRACE_EVENT(hfi1_sdma_user_reqinfo,
+           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 *i),
+           TP_ARGS(dd, ctxt, subctxt, i),
+           TP_STRUCT__entry(
+                   DD_DEV_ENTRY(dd);
+                   __field(u16, ctxt)
+                   __field(u8, subctxt)
+                   __field(u8, ver_opcode)
+                   __field(u8, iovcnt)
+                   __field(u16, npkts)
+                   __field(u16, fragsize)
+                   __field(u16, comp_idx)
+           ),
+           TP_fast_assign(
+                   DD_DEV_ASSIGN(dd);
+                   __entry->ctxt = ctxt;
+                   __entry->subctxt = subctxt;
+                   __entry->ver_opcode = i[0] & 0xff;
+                   __entry->iovcnt = (i[0] >> 8) & 0xff;
+                   __entry->npkts = i[1];
+                   __entry->fragsize = i[2];
+                   __entry->comp_idx = i[3];
+           ),
+           TP_printk(SDMA_UREQ_FMT,
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->ver_opcode,
+                     __entry->iovcnt,
+                     __entry->npkts,
+                     __entry->fragsize,
+                     __entry->comp_idx
+                     )
+);
+
+#define usdma_complete_name(st) { st, #st }
+#define show_usdma_complete_state(st)                  \
+       __print_symbolic(st,                            \
+                       usdma_complete_name(FREE),      \
+                       usdma_complete_name(QUEUED),    \
+                       usdma_complete_name(COMPLETE), \
+                       usdma_complete_name(ERROR))
+
+TRACE_EVENT(hfi1_sdma_user_completion,
+           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 idx,
+                    u8 state, int code),
+           TP_ARGS(dd, ctxt, subctxt, idx, state, code),
+           TP_STRUCT__entry(
+           DD_DEV_ENTRY(dd)
+           __field(u16, ctxt)
+           __field(u8, subctxt)
+           __field(u16, idx)
+           __field(u8, state)
+           __field(int, code)
+           ),
+           TP_fast_assign(
+           DD_DEV_ASSIGN(dd);
+           __entry->ctxt = ctxt;
+           __entry->subctxt = subctxt;
+           __entry->idx = idx;
+           __entry->state = state;
+           __entry->code = code;
+           ),
+           TP_printk("[%s:%u:%u:%u] SDMA completion state %s (%d)",
+                     __get_str(dev), __entry->ctxt, __entry->subctxt,
+                     __entry->idx, show_usdma_complete_state(__entry->state),
+                     __entry->code)
+);
+
+const char *print_u32_array(struct trace_seq *, u32 *, int);
+#define __print_u32_hex(arr, len) print_u32_array(p, arr, len)
+
+TRACE_EVENT(hfi1_sdma_user_header_ahg,
+           TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req,
+                    u8 sde, u8 ahgidx, u32 *ahg, int len, u32 tidval),
+           TP_ARGS(dd, ctxt, subctxt, req, sde, ahgidx, ahg, len, tidval),
+           TP_STRUCT__entry(
+           DD_DEV_ENTRY(dd)
+           __field(u16, ctxt)
+           __field(u8, subctxt)
+           __field(u16, req)
+           __field(u8, sde)
+           __field(u8, idx)
+           __field(int, len)
+           __field(u32, tidval)
+           __array(u32, ahg, 10)
+           ),
+           TP_fast_assign(
+           DD_DEV_ASSIGN(dd);
+           __entry->ctxt = ctxt;
+           __entry->subctxt = subctxt;
+           __entry->req = req;
+           __entry->sde = sde;
+           __entry->idx = ahgidx;
+           __entry->len = len;
+           __entry->tidval = tidval;
+           memcpy(__entry->ahg, ahg, len * sizeof(u32));
+           ),
+           TP_printk("[%s:%u:%u:%u] (SDE%u/AHG%u) ahg[0-%d]=(%s) TIDVal=0x%x",
+                     __get_str(dev),
+                     __entry->ctxt,
+                     __entry->subctxt,
+                     __entry->req,
+                     __entry->sde,
+                     __entry->idx,
+                     __entry->len - 1,
+                     __print_u32_hex(__entry->ahg, __entry->len),
+                     __entry->tidval
+                     )
+);
+
+TRACE_EVENT(hfi1_sdma_state,
+           TP_PROTO(struct sdma_engine *sde,
+                    const char *cstate,
+                    const char *nstate
+                    ),
+           TP_ARGS(sde, cstate, nstate),
+           TP_STRUCT__entry(DD_DEV_ENTRY(sde->dd)
+               __string(curstate, cstate)
+               __string(newstate, nstate)
+           ),
+           TP_fast_assign(DD_DEV_ASSIGN(sde->dd);
+               __assign_str(curstate, cstate);
+               __assign_str(newstate, nstate);
+           ),
+           TP_printk("[%s] current state %s new state %s",
+                     __get_str(dev),
+                     __get_str(curstate),
+                     __get_str(newstate)
+           )
+);
+
+#define BCT_FORMAT \
+       "shared_limit %x vls 0-7 [%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x] 15 [%x,%x]"
+
+#define BCT(field) \
+       be16_to_cpu( \
+       ((struct buffer_control *)__get_dynamic_array(bct))->field \
+       )
+
+DECLARE_EVENT_CLASS(hfi1_bct_template,
+                   TP_PROTO(struct hfi1_devdata *dd,
+                            struct buffer_control *bc),
+                   TP_ARGS(dd, bc),
+                   TP_STRUCT__entry(DD_DEV_ENTRY(dd)
+                   __dynamic_array(u8, bct, sizeof(*bc))
+                   ),
+                   TP_fast_assign(DD_DEV_ASSIGN(dd);
+                                  memcpy(__get_dynamic_array(bct), bc,
+                                         sizeof(*bc));
+                   ),
+                   TP_printk(BCT_FORMAT,
+                             BCT(overall_shared_limit),
+
+                             BCT(vl[0].dedicated),
+                             BCT(vl[0].shared),
+
+                             BCT(vl[1].dedicated),
+                             BCT(vl[1].shared),
+
+                             BCT(vl[2].dedicated),
+                             BCT(vl[2].shared),
+
+                             BCT(vl[3].dedicated),
+                             BCT(vl[3].shared),
+
+                             BCT(vl[4].dedicated),
+                             BCT(vl[4].shared),
+
+                             BCT(vl[5].dedicated),
+                             BCT(vl[5].shared),
+
+                             BCT(vl[6].dedicated),
+                             BCT(vl[6].shared),
+
+                             BCT(vl[7].dedicated),
+                             BCT(vl[7].shared),
+
+                             BCT(vl[15].dedicated),
+                             BCT(vl[15].shared)
+                   )
+);
+
+DEFINE_EVENT(hfi1_bct_template, bct_set,
+            TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc),
+            TP_ARGS(dd, bc));
+
+DEFINE_EVENT(hfi1_bct_template, bct_get,
+            TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc),
+            TP_ARGS(dd, bc));
+
+#endif /* __HFI1_TRACE_TX_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace_tx
+#include <trace/define_trace.h>
diff --git a/drivers/infiniband/hw/hfi1/twsi.c b/drivers/infiniband/hw/hfi1/twsi.c
deleted file mode 100644 (file)
index e82e52a..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright(c) 2015, 2016 Intel Corporation.
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License 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.
- *
- * BSD LICENSE
- *
- * 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.
- *  - Neither the name of Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER 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/delay.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-
-#include "hfi.h"
-#include "twsi.h"
-
-/*
- * "Two Wire Serial Interface" support.
- *
- * Originally written for a not-quite-i2c serial eeprom, which is
- * still used on some supported boards. Later boards have added a
- * variety of other uses, most board-specific, so the bit-boffing
- * part has been split off to this file, while the other parts
- * have been moved to chip-specific files.
- *
- * We have also dropped all pretense of fully generic (e.g. pretend
- * we don't know whether '1' is the higher voltage) interface, as
- * the restrictions of the generic i2c interface (e.g. no access from
- * driver itself) make it unsuitable for this use.
- */
-
-#define READ_CMD 1
-#define WRITE_CMD 0
-
-/**
- * i2c_wait_for_writes - wait for a write
- * @dd: the hfi1_ib device
- *
- * We use this instead of udelay directly, so we can make sure
- * that previous register writes have been flushed all the way
- * to the chip.  Since we are delaying anyway, the cost doesn't
- * hurt, and makes the bit twiddling more regular
- */
-static void i2c_wait_for_writes(struct hfi1_devdata *dd, u32 target)
-{
-       /*
-        * implicit read of EXTStatus is as good as explicit
-        * read of scratch, if all we want to do is flush
-        * writes.
-        */
-       hfi1_gpio_mod(dd, target, 0, 0, 0);
-       rmb(); /* inlined, so prevent compiler reordering */
-}
-
-/*
- * QSFP modules are allowed to hold SCL low for 500uSec. Allow twice that
- * for "almost compliant" modules
- */
-#define SCL_WAIT_USEC 1000
-
-/* BUF_WAIT is time bus must be free between STOP or ACK and to next START.
- * Should be 20, but some chips need more.
- */
-#define TWSI_BUF_WAIT_USEC 60
-
-static void scl_out(struct hfi1_devdata *dd, u32 target, u8 bit)
-{
-       u32 mask;
-
-       udelay(1);
-
-       mask = QSFP_HFI0_I2CCLK;
-
-       /* SCL is meant to be bare-drain, so never set "OUT", just DIR */
-       hfi1_gpio_mod(dd, target, 0, bit ? 0 : mask, mask);
-
-       /*
-        * Allow for slow slaves by simple
-        * delay for falling edge, sampling on rise.
-        */
-       if (!bit) {
-               udelay(2);
-       } else {
-               int rise_usec;
-
-               for (rise_usec = SCL_WAIT_USEC; rise_usec > 0; rise_usec -= 2) {
-                       if (mask & hfi1_gpio_mod(dd, target, 0, 0, 0))
-                               break;
-                       udelay(2);
-               }
-               if (rise_usec <= 0)
-                       dd_dev_err(dd, "SCL interface stuck low > %d uSec\n",
-                                  SCL_WAIT_USEC);
-       }
-       i2c_wait_for_writes(dd, target);
-}
-
-static u8 scl_in(struct hfi1_devdata *dd, u32 target, int wait)
-{
-       u32 read_val, mask;
-
-       mask = QSFP_HFI0_I2CCLK;
-       /* SCL is meant to be bare-drain, so never set "OUT", just DIR */
-       hfi1_gpio_mod(dd, target, 0, 0, mask);
-       read_val = hfi1_gpio_mod(dd, target, 0, 0, 0);
-       if (wait)
-               i2c_wait_for_writes(dd, target);
-       return (read_val & mask) >> GPIO_SCL_NUM;
-}
-
-static void sda_out(struct hfi1_devdata *dd, u32 target, u8 bit)
-{
-       u32 mask;
-
-       mask = QSFP_HFI0_I2CDAT;
-
-       /* SDA is meant to be bare-drain, so never set "OUT", just DIR */
-       hfi1_gpio_mod(dd, target, 0, bit ? 0 : mask, mask);
-
-       i2c_wait_for_writes(dd, target);
-       udelay(2);
-}
-
-static u8 sda_in(struct hfi1_devdata *dd, u32 target, int wait)
-{
-       u32 read_val, mask;
-
-       mask = QSFP_HFI0_I2CDAT;
-       /* SDA is meant to be bare-drain, so never set "OUT", just DIR */
-       hfi1_gpio_mod(dd, target, 0, 0, mask);
-       read_val = hfi1_gpio_mod(dd, target, 0, 0, 0);
-       if (wait)
-               i2c_wait_for_writes(dd, target);
-       return (read_val & mask) >> GPIO_SDA_NUM;
-}
-
-/**
- * i2c_ackrcv - see if ack following write is true
- * @dd: the hfi1_ib device
- */
-static int i2c_ackrcv(struct hfi1_devdata *dd, u32 target)
-{
-       u8 ack_received;
-
-       /* AT ENTRY SCL = LOW */
-       /* change direction, ignore data */
-       ack_received = sda_in(dd, target, 1);
-       scl_out(dd, target, 1);
-       ack_received = sda_in(dd, target, 1) == 0;
-       scl_out(dd, target, 0);
-       return ack_received;
-}
-
-static void stop_cmd(struct hfi1_devdata *dd, u32 target);
-
-/**
- * rd_byte - read a byte, sending STOP on last, else ACK
- * @dd: the hfi1_ib device
- *
- * Returns byte shifted out of device
- */
-static int rd_byte(struct hfi1_devdata *dd, u32 target, int last)
-{
-       int bit_cntr, data;
-
-       data = 0;
-
-       for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) {
-               data <<= 1;
-               scl_out(dd, target, 1);
-               data |= sda_in(dd, target, 0);
-               scl_out(dd, target, 0);
-       }
-       if (last) {
-               scl_out(dd, target, 1);
-               stop_cmd(dd, target);
-       } else {
-               sda_out(dd, target, 0);
-               scl_out(dd, target, 1);
-               scl_out(dd, target, 0);
-               sda_out(dd, target, 1);
-       }
-       return data;
-}
-
-/**
- * wr_byte - write a byte, one bit at a time
- * @dd: the hfi1_ib device
- * @data: the byte to write
- *
- * Returns 0 if we got the following ack, otherwise 1
- */
-static int wr_byte(struct hfi1_devdata *dd, u32 target, u8 data)
-{
-       int bit_cntr;
-       u8 bit;
-
-       for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) {
-               bit = (data >> bit_cntr) & 1;
-               sda_out(dd, target, bit);
-               scl_out(dd, target, 1);
-               scl_out(dd, target, 0);
-       }
-       return (!i2c_ackrcv(dd, target)) ? 1 : 0;
-}
-
-/*
- * issue TWSI start sequence:
- * (both clock/data high, clock high, data low while clock is high)
- */
-static void start_seq(struct hfi1_devdata *dd, u32 target)
-{
-       sda_out(dd, target, 1);
-       scl_out(dd, target, 1);
-       sda_out(dd, target, 0);
-       udelay(1);
-       scl_out(dd, target, 0);
-}
-
-/**
- * stop_seq - transmit the stop sequence
- * @dd: the hfi1_ib device
- *
- * (both clock/data low, clock high, data high while clock is high)
- */
-static void stop_seq(struct hfi1_devdata *dd, u32 target)
-{
-       scl_out(dd, target, 0);
-       sda_out(dd, target, 0);
-       scl_out(dd, target, 1);
-       sda_out(dd, target, 1);
-}
-
-/**
- * stop_cmd - transmit the stop condition
- * @dd: the hfi1_ib device
- *
- * (both clock/data low, clock high, data high while clock is high)
- */
-static void stop_cmd(struct hfi1_devdata *dd, u32 target)
-{
-       stop_seq(dd, target);
-       udelay(TWSI_BUF_WAIT_USEC);
-}
-
-/**
- * hfi1_twsi_reset - reset I2C communication
- * @dd: the hfi1_ib device
- * returns 0 if ok, -EIO on error
- */
-int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target)
-{
-       int clock_cycles_left = 9;
-       u32 mask;
-
-       /* Both SCL and SDA should be high. If not, there
-        * is something wrong.
-        */
-       mask = QSFP_HFI0_I2CCLK | QSFP_HFI0_I2CDAT;
-
-       /*
-        * Force pins to desired innocuous state.
-        * This is the default power-on state with out=0 and dir=0,
-        * So tri-stated and should be floating high (barring HW problems)
-        */
-       hfi1_gpio_mod(dd, target, 0, 0, mask);
-
-       /* Check if SCL is low, if it is low then we have a slave device
-        * misbehaving and there is not much we can do.
-        */
-       if (!scl_in(dd, target, 0))
-               return -EIO;
-
-       /* Check if SDA is low, if it is low then we have to clock SDA
-        * up to 9 times for the device to release the bus
-        */
-       while (clock_cycles_left--) {
-               if (sda_in(dd, target, 0))
-                       return 0;
-               scl_out(dd, target, 0);
-               scl_out(dd, target, 1);
-       }
-
-       return -EIO;
-}
-
-#define HFI1_TWSI_START 0x100
-#define HFI1_TWSI_STOP 0x200
-
-/* Write byte to TWSI, optionally prefixed with START or suffixed with
- * STOP.
- * returns 0 if OK (ACK received), else != 0
- */
-static int twsi_wr(struct hfi1_devdata *dd, u32 target, int data, int flags)
-{
-       int ret = 1;
-
-       if (flags & HFI1_TWSI_START)
-               start_seq(dd, target);
-
-       /* Leaves SCL low (from i2c_ackrcv()) */
-       ret = wr_byte(dd, target, data);
-
-       if (flags & HFI1_TWSI_STOP)
-               stop_cmd(dd, target);
-       return ret;
-}
-
-/* Added functionality for IBA7220-based cards */
-#define HFI1_TEMP_DEV 0x98
-
-/*
- * hfi1_twsi_blk_rd
- * General interface for data transfer from twsi devices.
- * One vestige of its former role is that it recognizes a device
- * HFI1_TWSI_NO_DEV and does the correct operation for the legacy part,
- * which responded to all TWSI device codes, interpreting them as
- * address within device. On all other devices found on board handled by
- * this driver, the device is followed by a N-byte "address" which selects
- * the "register" or "offset" within the device from which data should
- * be read.
- */
-int hfi1_twsi_blk_rd(struct hfi1_devdata *dd, u32 target, int dev, int addr,
-                    void *buffer, int len)
-{
-       u8 *bp = buffer;
-       int ret = 1;
-       int i;
-       int offset_size;
-
-       /* obtain the offset size, strip it from the device address */
-       offset_size = (dev >> 8) & 0xff;
-       dev &= 0xff;
-
-       /* allow at most a 2 byte offset */
-       if (offset_size > 2)
-               goto bail;
-
-       if (dev == HFI1_TWSI_NO_DEV) {
-               /* legacy not-really-I2C */
-               addr = (addr << 1) | READ_CMD;
-               ret = twsi_wr(dd, target, addr, HFI1_TWSI_START);
-       } else {
-               /* Actual I2C */
-               if (offset_size) {
-                       ret = twsi_wr(dd, target,
-                                     dev | WRITE_CMD, HFI1_TWSI_START);
-                       if (ret) {
-                               stop_cmd(dd, target);
-                               goto bail;
-                       }
-
-                       for (i = 0; i < offset_size; i++) {
-                               ret = twsi_wr(dd, target,
-                                             (addr >> (i * 8)) & 0xff, 0);
-                               udelay(TWSI_BUF_WAIT_USEC);
-                               if (ret) {
-                                       dd_dev_err(dd, "Failed to write byte %d of offset 0x%04X\n",
-                                                  i, addr);
-                                       goto bail;
-                               }
-                       }
-               }
-               ret = twsi_wr(dd, target, dev | READ_CMD, HFI1_TWSI_START);
-       }
-       if (ret) {
-               stop_cmd(dd, target);
-               goto bail;
-       }
-
-       /*
-        * block devices keeps clocking data out as long as we ack,
-        * automatically incrementing the address. Some have "pages"
-        * whose boundaries will not be crossed, but the handling
-        * of these is left to the caller, who is in a better
-        * position to know.
-        */
-       while (len-- > 0) {
-               /*
-                * Get and store data, sending ACK if length remaining,
-                * else STOP
-                */
-               *bp++ = rd_byte(dd, target, !len);
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/*
- * hfi1_twsi_blk_wr
- * General interface for data transfer to twsi devices.
- * One vestige of its former role is that it recognizes a device
- * HFI1_TWSI_NO_DEV and does the correct operation for the legacy part,
- * which responded to all TWSI device codes, interpreting them as
- * address within device. On all other devices found on board handled by
- * this driver, the device is followed by a N-byte "address" which selects
- * the "register" or "offset" within the device to which data should
- * be written.
- */
-int hfi1_twsi_blk_wr(struct hfi1_devdata *dd, u32 target, int dev, int addr,
-                    const void *buffer, int len)
-{
-       const u8 *bp = buffer;
-       int ret = 1;
-       int i;
-       int offset_size;
-
-       /* obtain the offset size, strip it from the device address */
-       offset_size = (dev >> 8) & 0xff;
-       dev &= 0xff;
-
-       /* allow at most a 2 byte offset */
-       if (offset_size > 2)
-               goto bail;
-
-       if (dev == HFI1_TWSI_NO_DEV) {
-               if (twsi_wr(dd, target, (addr << 1) | WRITE_CMD,
-                           HFI1_TWSI_START)) {
-                       goto failed_write;
-               }
-       } else {
-               /* Real I2C */
-               if (twsi_wr(dd, target, dev | WRITE_CMD, HFI1_TWSI_START))
-                       goto failed_write;
-       }
-
-       for (i = 0; i < offset_size; i++) {
-               ret = twsi_wr(dd, target, (addr >> (i * 8)) & 0xff, 0);
-               udelay(TWSI_BUF_WAIT_USEC);
-               if (ret) {
-                       dd_dev_err(dd, "Failed to write byte %d of offset 0x%04X\n",
-                                  i, addr);
-                       goto bail;
-               }
-       }
-
-       for (i = 0; i < len; i++)
-               if (twsi_wr(dd, target, *bp++, 0))
-                       goto failed_write;
-
-       ret = 0;
-
-failed_write:
-       stop_cmd(dd, target);
-
-bail:
-       return ret;
-}
diff --git a/drivers/infiniband/hw/hfi1/twsi.h b/drivers/infiniband/hw/hfi1/twsi.h
deleted file mode 100644 (file)
index 5b8a5b5..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef _TWSI_H
-#define _TWSI_H
-/*
- * Copyright(c) 2015, 2016 Intel Corporation.
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License 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.
- *
- * BSD LICENSE
- *
- * 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.
- *  - Neither the name of Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#define HFI1_TWSI_NO_DEV 0xFF
-
-struct hfi1_devdata;
-
-/* Bit position of SDA/SCL pins in ASIC_QSFP* registers  */
-#define  GPIO_SDA_NUM 1
-#define  GPIO_SCL_NUM 0
-
-/* these functions must be called with qsfp_lock held */
-int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target);
-int hfi1_twsi_blk_rd(struct hfi1_devdata *dd, u32 target, int dev, int addr,
-                    void *buffer, int len);
-int hfi1_twsi_blk_wr(struct hfi1_devdata *dd, u32 target, int dev, int addr,
-                    const void *buffer, int len);
-
-#endif /* _TWSI_H */
index df773d4..a726d96 100644 (file)
@@ -118,6 +118,31 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                        clear_ahg(qp);
                        goto bail;
                }
+               /*
+                * Local operations are processed immediately
+                * after all prior requests have completed.
+                */
+               if (wqe->wr.opcode == IB_WR_REG_MR ||
+                   wqe->wr.opcode == IB_WR_LOCAL_INV) {
+                       int local_ops = 0;
+                       int err = 0;
+
+                       if (qp->s_last != qp->s_cur)
+                               goto bail;
+                       if (++qp->s_cur == qp->s_size)
+                               qp->s_cur = 0;
+                       if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
+                               err = rvt_invalidate_rkey(
+                                       qp, wqe->wr.ex.invalidate_rkey);
+                               local_ops = 1;
+                       }
+                       hfi1_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR
+                                                       : IB_WC_SUCCESS);
+                       if (local_ops)
+                               atomic_dec(&qp->local_ops_pending);
+                       qp->s_hdrwords = 0;
+                       goto done_free_tx;
+               }
                /*
                 * Start a new request.
                 */
@@ -294,46 +319,12 @@ void hfi1_uc_rcv(struct hfi1_packet *packet)
        struct ib_reth *reth;
        int has_grh = rcv_flags & HFI1_HAS_GRH;
        int ret;
-       u32 bth1;
 
        bth0 = be32_to_cpu(ohdr->bth[0]);
        if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, bth0))
                return;
 
-       bth1 = be32_to_cpu(ohdr->bth[1]);
-       if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) {
-               if (bth1 & HFI1_BECN_SMASK) {
-                       struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-                       u32 rqpn, lqpn;
-                       u16 rlid = be16_to_cpu(hdr->lrh[3]);
-                       u8 sl, sc5;
-
-                       lqpn = bth1 & RVT_QPN_MASK;
-                       rqpn = qp->remote_qpn;
-
-                       sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl];
-                       sl = ibp->sc_to_sl[sc5];
-
-                       process_becn(ppd, sl, rlid, lqpn, rqpn,
-                                    IB_CC_SVCTYPE_UC);
-               }
-
-               if (bth1 & HFI1_FECN_SMASK) {
-                       struct ib_grh *grh = NULL;
-                       u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]);
-                       u16 slid = be16_to_cpu(hdr->lrh[3]);
-                       u16 dlid = be16_to_cpu(hdr->lrh[1]);
-                       u32 src_qp = qp->remote_qpn;
-                       u8 sc5;
-
-                       sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl];
-                       if (has_grh)
-                               grh = &hdr->u.l.grh;
-
-                       return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5,
-                                  grh);
-               }
-       }
+       process_ecn(qp, packet, true);
 
        psn = be32_to_cpu(ohdr->bth[2]);
        opcode = (bth0 >> 24) & 0xff;
index be91f6f..f01e8e1 100644 (file)
@@ -184,8 +184,12 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
        }
 
        if (ah_attr->ah_flags & IB_AH_GRH) {
-               hfi1_copy_sge(&qp->r_sge, &ah_attr->grh,
-                             sizeof(struct ib_grh), 1, 0);
+               struct ib_grh grh;
+               struct ib_global_route grd = ah_attr->grh;
+
+               hfi1_make_grh(ibp, &grh, &grd, 0, 0);
+               hfi1_copy_sge(&qp->r_sge, &grh,
+                             sizeof(grh), 1, 0);
                wc.wc_flags |= IB_WC_GRH;
        } else {
                hfi1_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1);
@@ -430,10 +434,9 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
                                         qp->qkey : wqe->ud_wr.remote_qkey);
        ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
        /* disarm any ahg */
-       priv->s_hdr->ahgcount = 0;
-       priv->s_hdr->ahgidx = 0;
-       priv->s_hdr->tx_flags = 0;
-       priv->s_hdr->sde = NULL;
+       priv->s_ahg->ahgcount = 0;
+       priv->s_ahg->ahgidx = 0;
+       priv->s_ahg->tx_flags = 0;
        /* pbc */
        ps->s_txreq->hdr_dwords = qp->s_hdrwords + 2;
 
@@ -665,13 +668,13 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
        struct hfi1_other_headers *ohdr = packet->ohdr;
        int opcode;
        u32 hdrsize = packet->hlen;
-       u32 pad;
        struct ib_wc wc;
        u32 qkey;
        u32 src_qp;
        u16 dlid, pkey;
        int mgmt_pkey_idx = -1;
        struct hfi1_ibport *ibp = &packet->rcd->ppd->ibport_data;
+       struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
        struct hfi1_ib_header *hdr = packet->hdr;
        u32 rcv_flags = packet->rcv_flags;
        void *data = packet->ebuf;
@@ -680,52 +683,33 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
        bool has_grh = rcv_flags & HFI1_HAS_GRH;
        u8 sc5 = hdr2sc((struct hfi1_message_header *)hdr, packet->rhf);
        u32 bth1;
-       int is_mcast;
-       struct ib_grh *grh = NULL;
+       u8 sl_from_sc, sl;
+       u16 slid;
+       u8 extra_bytes;
 
        qkey = be32_to_cpu(ohdr->u.ud.deth[0]);
        src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK;
        dlid = be16_to_cpu(hdr->lrh[1]);
-       is_mcast = (dlid > be16_to_cpu(IB_MULTICAST_LID_BASE)) &&
-                       (dlid != be16_to_cpu(IB_LID_PERMISSIVE));
        bth1 = be32_to_cpu(ohdr->bth[1]);
-       if (unlikely(bth1 & HFI1_BECN_SMASK)) {
-               /*
-                * In pre-B0 h/w the CNP_OPCODE is handled via an
-                * error path.
-                */
-               struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-               u32 lqpn =  be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK;
-               u8 sl;
-
-               sl = ibp->sc_to_sl[sc5];
-
-               process_becn(ppd, sl, 0, lqpn, 0, IB_CC_SVCTYPE_UD);
-       }
+       slid = be16_to_cpu(hdr->lrh[3]);
+       pkey = (u16)be32_to_cpu(ohdr->bth[0]);
+       sl = (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf;
+       extra_bytes = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
+       extra_bytes += (SIZE_OF_CRC << 2);
+       sl_from_sc = ibp->sc_to_sl[sc5];
 
-       /*
-        * The opcode is in the low byte when its in network order
-        * (top byte when in host order).
-        */
        opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
        opcode &= 0xff;
 
-       pkey = (u16)be32_to_cpu(ohdr->bth[0]);
-
-       if (!is_mcast && (opcode != IB_OPCODE_CNP) && bth1 & HFI1_FECN_SMASK) {
-               u16 slid = be16_to_cpu(hdr->lrh[3]);
-
-               return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5, grh);
-       }
+       process_ecn(qp, packet, (opcode != IB_OPCODE_CNP));
        /*
         * Get the number of bytes the message was padded by
         * and drop incomplete packets.
         */
-       pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-       if (unlikely(tlen < (hdrsize + pad + 4)))
+       if (unlikely(tlen < (hdrsize + extra_bytes)))
                goto drop;
 
-       tlen -= hdrsize + pad + 4;
+       tlen -= hdrsize + extra_bytes;
 
        /*
         * Check that the permissive LID is only used on QP0
@@ -736,10 +720,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
                             hdr->lrh[3] == IB_LID_PERMISSIVE))
                        goto drop;
                if (qp->ibqp.qp_num > 1) {
-                       struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
-                       u16 slid;
-
-                       slid = be16_to_cpu(hdr->lrh[3]);
                        if (unlikely(rcv_pkey_check(ppd, pkey, sc5, slid))) {
                                /*
                                 * Traps will not be sent for packets dropped
@@ -748,12 +728,9 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
                                 * IB spec (release 1.3, section 10.9.4)
                                 */
                                hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_P_KEY,
-                                              pkey,
-                                              (be16_to_cpu(hdr->lrh[0]) >> 4) &
-                                               0xF,
+                                              pkey, sl,
                                               src_qp, qp->ibqp.qp_num,
-                                              be16_to_cpu(hdr->lrh[3]),
-                                              be16_to_cpu(hdr->lrh[1]));
+                                              slid, dlid);
                                return;
                        }
                } else {
@@ -763,22 +740,18 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
                                goto drop;
                }
                if (unlikely(qkey != qp->qkey)) {
-                       hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_Q_KEY, qkey,
-                                      (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF,
+                       hfi1_bad_pqkey(ibp, OPA_TRAP_BAD_Q_KEY, qkey, sl,
                                       src_qp, qp->ibqp.qp_num,
-                                      be16_to_cpu(hdr->lrh[3]),
-                                      be16_to_cpu(hdr->lrh[1]));
+                                      slid, dlid);
                        return;
                }
                /* Drop invalid MAD packets (see 13.5.3.1). */
                if (unlikely(qp->ibqp.qp_num == 1 &&
-                            (tlen > 2048 ||
-                             (be16_to_cpu(hdr->lrh[0]) >> 12) == 15)))
+                            (tlen > 2048 || (sc5 == 0xF))))
                        goto drop;
        } else {
                /* Received on QP0, and so by definition, this is an SMP */
                struct opa_smp *smp = (struct opa_smp *)data;
-               u16 slid = be16_to_cpu(hdr->lrh[3]);
 
                if (opa_smp_check(ibp, pkey, sc5, qp, slid, smp))
                        goto drop;
@@ -861,7 +834,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
            qp->ibqp.qp_type == IB_QPT_SMI) {
                if (mgmt_pkey_idx < 0) {
                        if (net_ratelimit()) {
-                               struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
                                struct hfi1_devdata *dd = ppd->dd;
 
                                dd_dev_err(dd, "QP type %d mgmt_pkey_idx < 0 and packet not dropped???\n",
@@ -874,8 +846,8 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
                wc.pkey_index = 0;
        }
 
-       wc.slid = be16_to_cpu(hdr->lrh[3]);
-       wc.sl = ibp->sc_to_sl[sc5];
+       wc.slid = slid;
+       wc.sl = sl_from_sc;
 
        /*
         * Save the LMC lower bits if the destination LID is a unicast LID.
index 1b640a3..64d2652 100644 (file)
@@ -82,24 +82,25 @@ struct tid_pageset {
               ((unsigned long)vaddr & PAGE_MASK)) >> PAGE_SHIFT))
 
 static void unlock_exp_tids(struct hfi1_ctxtdata *, struct exp_tid_set *,
-                           struct rb_root *);
+                           struct hfi1_filedata *);
 static u32 find_phys_blocks(struct page **, unsigned, struct tid_pageset *);
 static int set_rcvarray_entry(struct file *, unsigned long, u32,
                              struct tid_group *, struct page **, unsigned);
-static int mmu_rb_insert(struct rb_root *, struct mmu_rb_node *);
-static void mmu_rb_remove(struct rb_root *, struct mmu_rb_node *,
-                         struct mm_struct *);
-static int mmu_rb_invalidate(struct rb_root *, struct mmu_rb_node *);
+static int tid_rb_insert(void *, struct mmu_rb_node *);
+static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
+                                   struct tid_rb_node *tnode);
+static void tid_rb_remove(void *, struct mmu_rb_node *);
+static int tid_rb_invalidate(void *, struct mmu_rb_node *);
 static int program_rcvarray(struct file *, unsigned long, struct tid_group *,
                            struct tid_pageset *, unsigned, u16, struct page **,
                            u32 *, unsigned *, unsigned *);
 static int unprogram_rcvarray(struct file *, u32, struct tid_group **);
-static void clear_tid_node(struct hfi1_filedata *, u16, struct tid_rb_node *);
+static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node);
 
 static struct mmu_rb_ops tid_rb_ops = {
-       .insert = mmu_rb_insert,
-       .remove = mmu_rb_remove,
-       .invalidate = mmu_rb_invalidate
+       .insert = tid_rb_insert,
+       .remove = tid_rb_remove,
+       .invalidate = tid_rb_invalidate
 };
 
 static inline u32 rcventry2tidinfo(u32 rcventry)
@@ -162,7 +163,6 @@ int hfi1_user_exp_rcv_init(struct file *fp)
 
        spin_lock_init(&fd->tid_lock);
        spin_lock_init(&fd->invalid_lock);
-       fd->tid_rb_root = RB_ROOT;
 
        if (!uctxt->subctxt_cnt || !fd->subctxt) {
                exp_tid_group_init(&uctxt->tid_group_list);
@@ -197,7 +197,7 @@ int hfi1_user_exp_rcv_init(struct file *fp)
        if (!fd->entry_to_rb)
                return -ENOMEM;
 
-       if (!HFI1_CAP_IS_USET(TID_UNMAP)) {
+       if (!HFI1_CAP_UGET_MASK(uctxt->flags, TID_UNMAP)) {
                fd->invalid_tid_idx = 0;
                fd->invalid_tids = kzalloc(uctxt->expected_count *
                                           sizeof(u32), GFP_KERNEL);
@@ -208,15 +208,15 @@ int hfi1_user_exp_rcv_init(struct file *fp)
 
                /*
                 * Register MMU notifier callbacks. If the registration
-                * fails, continue but turn off the TID caching for
-                * all user contexts.
+                * fails, continue without TID caching for this context.
                 */
-               ret = hfi1_mmu_rb_register(&fd->tid_rb_root, &tid_rb_ops);
+               ret = hfi1_mmu_rb_register(fd, fd->mm, &tid_rb_ops,
+                                          dd->pport->hfi1_wq,
+                                          &fd->handler);
                if (ret) {
                        dd_dev_info(dd,
                                    "Failed MMU notifier registration %d\n",
                                    ret);
-                       HFI1_CAP_USET(TID_UNMAP);
                        ret = 0;
                }
        }
@@ -235,7 +235,7 @@ int hfi1_user_exp_rcv_init(struct file *fp)
         * init.
         */
        spin_lock(&fd->tid_lock);
-       if (uctxt->subctxt_cnt && !HFI1_CAP_IS_USET(TID_UNMAP)) {
+       if (uctxt->subctxt_cnt && fd->handler) {
                u16 remainder;
 
                fd->tid_limit = uctxt->expected_count / uctxt->subctxt_cnt;
@@ -261,18 +261,16 @@ int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd)
         * The notifier would have been removed when the process'es mm
         * was freed.
         */
-       if (!HFI1_CAP_IS_USET(TID_UNMAP))
-               hfi1_mmu_rb_unregister(&fd->tid_rb_root);
+       if (fd->handler)
+               hfi1_mmu_rb_unregister(fd->handler);
 
        kfree(fd->invalid_tids);
 
        if (!uctxt->cnt) {
                if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list))
-                       unlock_exp_tids(uctxt, &uctxt->tid_full_list,
-                                       &fd->tid_rb_root);
+                       unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd);
                if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list))
-                       unlock_exp_tids(uctxt, &uctxt->tid_used_list,
-                                       &fd->tid_rb_root);
+                       unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd);
                list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list,
                                         list) {
                        list_del_init(&grp->list);
@@ -399,12 +397,12 @@ int hfi1_user_exp_rcv_setup(struct file *fp, struct hfi1_tid_info *tinfo)
         * pages, accept the amount pinned so far and program only that.
         * User space knows how to deal with partially programmed buffers.
         */
-       if (!hfi1_can_pin_pages(dd, fd->tid_n_pinned, npages)) {
+       if (!hfi1_can_pin_pages(dd, fd->mm, fd->tid_n_pinned, npages)) {
                ret = -ENOMEM;
                goto bail;
        }
 
-       pinned = hfi1_acquire_user_pages(vaddr, npages, true, pages);
+       pinned = hfi1_acquire_user_pages(fd->mm, vaddr, npages, true, pages);
        if (pinned <= 0) {
                ret = pinned;
                goto bail;
@@ -559,7 +557,7 @@ nomem:
         * for example), unpin all unmapped pages so we can pin them nex time.
         */
        if (mapped_pages != pinned) {
-               hfi1_release_user_pages(current->mm, &pages[mapped_pages],
+               hfi1_release_user_pages(fd->mm, &pages[mapped_pages],
                                        pinned - mapped_pages,
                                        false);
                fd->tid_n_pinned -= pinned - mapped_pages;
@@ -829,7 +827,6 @@ static int set_rcvarray_entry(struct file *fp, unsigned long vaddr,
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct tid_rb_node *node;
        struct hfi1_devdata *dd = uctxt->dd;
-       struct rb_root *root = &fd->tid_rb_root;
        dma_addr_t phys;
 
        /*
@@ -861,10 +858,10 @@ static int set_rcvarray_entry(struct file *fp, unsigned long vaddr,
        node->freed = false;
        memcpy(node->pages, pages, sizeof(struct page *) * npages);
 
-       if (HFI1_CAP_IS_USET(TID_UNMAP))
-               ret = mmu_rb_insert(root, &node->mmu);
+       if (!fd->handler)
+               ret = tid_rb_insert(fd, &node->mmu);
        else
-               ret = hfi1_mmu_rb_insert(root, &node->mmu);
+               ret = hfi1_mmu_rb_insert(fd->handler, &node->mmu);
 
        if (ret) {
                hfi1_cdbg(TID, "Failed to insert RB node %u 0x%lx, 0x%lx %d",
@@ -904,19 +901,19 @@ static int unprogram_rcvarray(struct file *fp, u32 tidinfo,
        node = fd->entry_to_rb[rcventry];
        if (!node || node->rcventry != (uctxt->expected_base + rcventry))
                return -EBADF;
-       if (HFI1_CAP_IS_USET(TID_UNMAP))
-               mmu_rb_remove(&fd->tid_rb_root, &node->mmu, NULL);
-       else
-               hfi1_mmu_rb_remove(&fd->tid_rb_root, &node->mmu);
 
        if (grp)
                *grp = node->grp;
-       clear_tid_node(fd, fd->subctxt, node);
+
+       if (!fd->handler)
+               cacheless_tid_rb_remove(fd, node);
+       else
+               hfi1_mmu_rb_remove(fd->handler, &node->mmu);
+
        return 0;
 }
 
-static void clear_tid_node(struct hfi1_filedata *fd, u16 subctxt,
-                          struct tid_rb_node *node)
+static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
 {
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct hfi1_devdata *dd = uctxt->dd;
@@ -934,7 +931,7 @@ static void clear_tid_node(struct hfi1_filedata *fd, u16 subctxt,
 
        pci_unmap_single(dd->pcidev, node->dma_addr, node->mmu.len,
                         PCI_DMA_FROMDEVICE);
-       hfi1_release_user_pages(current->mm, node->pages, node->npages, true);
+       hfi1_release_user_pages(fd->mm, node->pages, node->npages, true);
        fd->tid_n_pinned -= node->npages;
 
        node->grp->used--;
@@ -949,12 +946,15 @@ static void clear_tid_node(struct hfi1_filedata *fd, u16 subctxt,
        kfree(node);
 }
 
+/*
+ * As a simple helper for hfi1_user_exp_rcv_free, this function deals with
+ * clearing nodes in the non-cached case.
+ */
 static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt,
-                           struct exp_tid_set *set, struct rb_root *root)
+                           struct exp_tid_set *set,
+                           struct hfi1_filedata *fd)
 {
        struct tid_group *grp, *ptr;
-       struct hfi1_filedata *fd = container_of(root, struct hfi1_filedata,
-                                               tid_rb_root);
        int i;
 
        list_for_each_entry_safe(grp, ptr, &set->list, list) {
@@ -969,22 +969,23 @@ static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt,
                                                          uctxt->expected_base];
                                if (!node || node->rcventry != rcventry)
                                        continue;
-                               if (HFI1_CAP_IS_USET(TID_UNMAP))
-                                       mmu_rb_remove(&fd->tid_rb_root,
-                                                     &node->mmu, NULL);
-                               else
-                                       hfi1_mmu_rb_remove(&fd->tid_rb_root,
-                                                          &node->mmu);
-                               clear_tid_node(fd, -1, node);
+
+                               cacheless_tid_rb_remove(fd, node);
                        }
                }
        }
 }
 
-static int mmu_rb_invalidate(struct rb_root *root, struct mmu_rb_node *mnode)
+/*
+ * Always return 0 from this function.  A non-zero return indicates that the
+ * remove operation will be called and that memory should be unpinned.
+ * However, the driver cannot unpin out from under PSM.  Instead, retain the
+ * memory (by returning 0) and inform PSM that the memory is going away.  PSM
+ * will call back later when it has removed the memory from its list.
+ */
+static int tid_rb_invalidate(void *arg, struct mmu_rb_node *mnode)
 {
-       struct hfi1_filedata *fdata =
-               container_of(root, struct hfi1_filedata, tid_rb_root);
+       struct hfi1_filedata *fdata = arg;
        struct hfi1_ctxtdata *uctxt = fdata->uctxt;
        struct tid_rb_node *node =
                container_of(mnode, struct tid_rb_node, mmu);
@@ -1025,10 +1026,9 @@ static int mmu_rb_invalidate(struct rb_root *root, struct mmu_rb_node *mnode)
        return 0;
 }
 
-static int mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *node)
+static int tid_rb_insert(void *arg, struct mmu_rb_node *node)
 {
-       struct hfi1_filedata *fdata =
-               container_of(root, struct hfi1_filedata, tid_rb_root);
+       struct hfi1_filedata *fdata = arg;
        struct tid_rb_node *tnode =
                container_of(node, struct tid_rb_node, mmu);
        u32 base = fdata->uctxt->expected_base;
@@ -1037,14 +1037,20 @@ static int mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *node)
        return 0;
 }
 
-static void mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node,
-                         struct mm_struct *mm)
+static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
+                                   struct tid_rb_node *tnode)
 {
-       struct hfi1_filedata *fdata =
-               container_of(root, struct hfi1_filedata, tid_rb_root);
-       struct tid_rb_node *tnode =
-               container_of(node, struct tid_rb_node, mmu);
        u32 base = fdata->uctxt->expected_base;
 
        fdata->entry_to_rb[tnode->rcventry - base] = NULL;
+       clear_tid_node(fdata, tnode);
+}
+
+static void tid_rb_remove(void *arg, struct mmu_rb_node *node)
+{
+       struct hfi1_filedata *fdata = arg;
+       struct tid_rb_node *tnode =
+               container_of(node, struct tid_rb_node, mmu);
+
+       cacheless_tid_rb_remove(fdata, tnode);
 }
index 88e10b5..20f4ddc 100644 (file)
@@ -68,7 +68,8 @@ MODULE_PARM_DESC(cache_size, "Send and receive side cache size limit (in MB)");
  * could keeping caching buffers.
  *
  */
-bool hfi1_can_pin_pages(struct hfi1_devdata *dd, u32 nlocked, u32 npages)
+bool hfi1_can_pin_pages(struct hfi1_devdata *dd, struct mm_struct *mm,
+                       u32 nlocked, u32 npages)
 {
        unsigned long ulimit = rlimit(RLIMIT_MEMLOCK), pinned, cache_limit,
                size = (cache_size * (1UL << 20)); /* convert to bytes */
@@ -89,9 +90,9 @@ bool hfi1_can_pin_pages(struct hfi1_devdata *dd, u32 nlocked, u32 npages)
        /* Convert to number of pages */
        size = DIV_ROUND_UP(size, PAGE_SIZE);
 
-       down_read(&current->mm->mmap_sem);
-       pinned = current->mm->pinned_vm;
-       up_read(&current->mm->mmap_sem);
+       down_read(&mm->mmap_sem);
+       pinned = mm->pinned_vm;
+       up_read(&mm->mmap_sem);
 
        /* First, check the absolute limit against all pinned pages. */
        if (pinned + npages >= ulimit && !can_lock)
@@ -100,8 +101,8 @@ bool hfi1_can_pin_pages(struct hfi1_devdata *dd, u32 nlocked, u32 npages)
        return ((nlocked + npages) <= size) || can_lock;
 }
 
-int hfi1_acquire_user_pages(unsigned long vaddr, size_t npages, bool writable,
-                           struct page **pages)
+int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t npages,
+                           bool writable, struct page **pages)
 {
        int ret;
 
@@ -109,9 +110,9 @@ int hfi1_acquire_user_pages(unsigned long vaddr, size_t npages, bool writable,
        if (ret < 0)
                return ret;
 
-       down_write(&current->mm->mmap_sem);
-       current->mm->pinned_vm += ret;
-       up_write(&current->mm->mmap_sem);
+       down_write(&mm->mmap_sem);
+       mm->pinned_vm += ret;
+       up_write(&mm->mmap_sem);
 
        return ret;
 }
index 47ffd27..0ecf279 100644 (file)
@@ -145,7 +145,7 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12
 /* Last packet in the request */
 #define TXREQ_FLAGS_REQ_LAST_PKT BIT(0)
 
-#define SDMA_REQ_IN_USE     0
+/* SDMA request flag bits */
 #define SDMA_REQ_FOR_THREAD 1
 #define SDMA_REQ_SEND_DONE  2
 #define SDMA_REQ_HAVE_AHG   3
@@ -183,16 +183,18 @@ struct user_sdma_iovec {
        struct sdma_mmu_node *node;
 };
 
-#define SDMA_CACHE_NODE_EVICT 0
-
 struct sdma_mmu_node {
        struct mmu_rb_node rb;
-       struct list_head list;
        struct hfi1_user_sdma_pkt_q *pq;
        atomic_t refcount;
        struct page **pages;
        unsigned npages;
-       unsigned long flags;
+};
+
+/* evict operation argument */
+struct evict_data {
+       u32 cleared;    /* count evicted so far */
+       u32 target;     /* target count to evict */
 };
 
 struct user_sdma_request {
@@ -305,14 +307,16 @@ static int defer_packet_queue(
        unsigned seq);
 static void activate_packet_queue(struct iowait *, int);
 static bool sdma_rb_filter(struct mmu_rb_node *, unsigned long, unsigned long);
-static int sdma_rb_insert(struct rb_root *, struct mmu_rb_node *);
-static void sdma_rb_remove(struct rb_root *, struct mmu_rb_node *,
-                          struct mm_struct *);
-static int sdma_rb_invalidate(struct rb_root *, struct mmu_rb_node *);
+static int sdma_rb_insert(void *, struct mmu_rb_node *);
+static int sdma_rb_evict(void *arg, struct mmu_rb_node *mnode,
+                        void *arg2, bool *stop);
+static void sdma_rb_remove(void *, struct mmu_rb_node *);
+static int sdma_rb_invalidate(void *, struct mmu_rb_node *);
 
 static struct mmu_rb_ops sdma_rb_ops = {
        .filter = sdma_rb_filter,
        .insert = sdma_rb_insert,
+       .evict = sdma_rb_evict,
        .remove = sdma_rb_remove,
        .invalidate = sdma_rb_invalidate
 };
@@ -397,6 +401,11 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
        if (!pq->reqs)
                goto pq_reqs_nomem;
 
+       memsize = BITS_TO_LONGS(hfi1_sdma_comp_ring_size) * sizeof(long);
+       pq->req_in_use = kzalloc(memsize, GFP_KERNEL);
+       if (!pq->req_in_use)
+               goto pq_reqs_no_in_use;
+
        INIT_LIST_HEAD(&pq->list);
        pq->dd = dd;
        pq->ctxt = uctxt->ctxt;
@@ -405,9 +414,8 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
        pq->state = SDMA_PKT_Q_INACTIVE;
        atomic_set(&pq->n_reqs, 0);
        init_waitqueue_head(&pq->wait);
-       pq->sdma_rb_root = RB_ROOT;
-       INIT_LIST_HEAD(&pq->evict);
-       spin_lock_init(&pq->evict_lock);
+       atomic_set(&pq->n_locked, 0);
+       pq->mm = fd->mm;
 
        iowait_init(&pq->busy, 0, NULL, defer_packet_queue,
                    activate_packet_queue, NULL);
@@ -437,7 +445,8 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
        cq->nentries = hfi1_sdma_comp_ring_size;
        fd->cq = cq;
 
-       ret = hfi1_mmu_rb_register(&pq->sdma_rb_root, &sdma_rb_ops);
+       ret = hfi1_mmu_rb_register(pq, pq->mm, &sdma_rb_ops, dd->pport->hfi1_wq,
+                                  &pq->handler);
        if (ret) {
                dd_dev_err(dd, "Failed to register with MMU %d", ret);
                goto done;
@@ -453,6 +462,8 @@ cq_comps_nomem:
 cq_nomem:
        kmem_cache_destroy(pq->txreq_cache);
 pq_txreq_nomem:
+       kfree(pq->req_in_use);
+pq_reqs_no_in_use:
        kfree(pq->reqs);
 pq_reqs_nomem:
        kfree(pq);
@@ -472,8 +483,9 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
        hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit,
                  uctxt->ctxt, fd->subctxt);
        pq = fd->pq;
-       hfi1_mmu_rb_unregister(&pq->sdma_rb_root);
        if (pq) {
+               if (pq->handler)
+                       hfi1_mmu_rb_unregister(pq->handler);
                spin_lock_irqsave(&uctxt->sdma_qlock, flags);
                if (!list_empty(&pq->list))
                        list_del_init(&pq->list);
@@ -484,6 +496,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
                        pq->wait,
                        (ACCESS_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
                kfree(pq->reqs);
+               kfree(pq->req_in_use);
                kmem_cache_destroy(pq->txreq_cache);
                kfree(pq);
                fd->pq = NULL;
@@ -496,10 +509,31 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
        return 0;
 }
 
+static u8 dlid_to_selector(u16 dlid)
+{
+       static u8 mapping[256];
+       static int initialized;
+       static u8 next;
+       int hash;
+
+       if (!initialized) {
+               memset(mapping, 0xFF, 256);
+               initialized = 1;
+       }
+
+       hash = ((dlid >> 8) ^ dlid) & 0xFF;
+       if (mapping[hash] == 0xFF) {
+               mapping[hash] = next;
+               next = (next + 1) & 0x7F;
+       }
+
+       return mapping[hash];
+}
+
 int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                                   unsigned long dim, unsigned long *count)
 {
-       int ret = 0, i = 0;
+       int ret = 0, i;
        struct hfi1_filedata *fd = fp->private_data;
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct hfi1_user_sdma_pkt_q *pq = fd->pq;
@@ -511,6 +545,8 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
        struct user_sdma_request *req;
        u8 opcode, sc, vl;
        int req_queued = 0;
+       u16 dlid;
+       u8 selector;
 
        if (iovec[idx].iov_len < sizeof(info) + sizeof(req->hdr)) {
                hfi1_cdbg(
@@ -529,30 +565,48 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
 
        trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt,
                                     (u16 *)&info);
-       if (cq->comps[info.comp_idx].status == QUEUED ||
-           test_bit(SDMA_REQ_IN_USE, &pq->reqs[info.comp_idx].flags)) {
-               hfi1_cdbg(SDMA, "[%u:%u:%u] Entry %u is in QUEUED state",
-                         dd->unit, uctxt->ctxt, fd->subctxt,
-                         info.comp_idx);
-               return -EBADSLT;
+
+       if (info.comp_idx >= hfi1_sdma_comp_ring_size) {
+               hfi1_cdbg(SDMA,
+                         "[%u:%u:%u:%u] Invalid comp index",
+                         dd->unit, uctxt->ctxt, fd->subctxt, info.comp_idx);
+               return -EINVAL;
        }
+
+       /*
+        * Sanity check the header io vector count.  Need at least 1 vector
+        * (header) and cannot be larger than the actual io vector count.
+        */
+       if (req_iovcnt(info.ctrl) < 1 || req_iovcnt(info.ctrl) > dim) {
+               hfi1_cdbg(SDMA,
+                         "[%u:%u:%u:%u] Invalid iov count %d, dim %ld",
+                         dd->unit, uctxt->ctxt, fd->subctxt, info.comp_idx,
+                         req_iovcnt(info.ctrl), dim);
+               return -EINVAL;
+       }
+
        if (!info.fragsize) {
                hfi1_cdbg(SDMA,
                          "[%u:%u:%u:%u] Request does not specify fragsize",
                          dd->unit, uctxt->ctxt, fd->subctxt, info.comp_idx);
                return -EINVAL;
        }
+
+       /* Try to claim the request. */
+       if (test_and_set_bit(info.comp_idx, pq->req_in_use)) {
+               hfi1_cdbg(SDMA, "[%u:%u:%u] Entry %u is in use",
+                         dd->unit, uctxt->ctxt, fd->subctxt,
+                         info.comp_idx);
+               return -EBADSLT;
+       }
        /*
-        * We've done all the safety checks that we can up to this point,
-        * "allocate" the request entry.
+        * All safety checks have been done and this request has been claimed.
         */
        hfi1_cdbg(SDMA, "[%u:%u:%u] Using req/comp entry %u\n", dd->unit,
                  uctxt->ctxt, fd->subctxt, info.comp_idx);
        req = pq->reqs + info.comp_idx;
        memset(req, 0, sizeof(*req));
-       /* Mark the request as IN_USE before we start filling it in. */
-       set_bit(SDMA_REQ_IN_USE, &req->flags);
-       req->data_iovs = req_iovcnt(info.ctrl) - 1;
+       req->data_iovs = req_iovcnt(info.ctrl) - 1; /* subtract header vector */
        req->pq = pq;
        req->cq = cq;
        req->status = -1;
@@ -560,13 +614,22 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
 
        memcpy(&req->info, &info, sizeof(info));
 
-       if (req_opcode(info.ctrl) == EXPECTED)
+       if (req_opcode(info.ctrl) == EXPECTED) {
+               /* expected must have a TID info and at least one data vector */
+               if (req->data_iovs < 2) {
+                       SDMA_DBG(req,
+                                "Not enough vectors for expected request");
+                       ret = -EINVAL;
+                       goto free_req;
+               }
                req->data_iovs--;
+       }
 
        if (!info.npkts || req->data_iovs > MAX_VECTORS_PER_REQ) {
                SDMA_DBG(req, "Too many vectors (%u/%u)", req->data_iovs,
                         MAX_VECTORS_PER_REQ);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto free_req;
        }
        /* Copy the header from the user buffer */
        ret = copy_from_user(&req->hdr, iovec[idx].iov_base + sizeof(info),
@@ -634,7 +697,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
        idx++;
 
        /* Save all the IO vector structures */
-       while (i < req->data_iovs) {
+       for (i = 0; i < req->data_iovs; i++) {
                INIT_LIST_HEAD(&req->iovs[i].list);
                memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(struct iovec));
                ret = pin_vector_pages(req, &req->iovs[i]);
@@ -642,7 +705,7 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                        req->status = ret;
                        goto free_req;
                }
-               req->data_len += req->iovs[i++].iov.iov_len;
+               req->data_len += req->iovs[i].iov.iov_len;
        }
        SDMA_DBG(req, "total data length %u", req->data_len);
 
@@ -686,9 +749,13 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
                idx++;
        }
 
+       dlid = be16_to_cpu(req->hdr.lrh[1]);
+       selector = dlid_to_selector(dlid);
+
        /* Have to select the engine */
        req->sde = sdma_select_engine_vl(dd,
-                                        (u32)(uctxt->ctxt + fd->subctxt),
+                                        (u32)(uctxt->ctxt + fd->subctxt +
+                                              selector),
                                         vl);
        if (!req->sde || !sdma_running(req->sde)) {
                ret = -ECOMM;
@@ -766,14 +833,21 @@ static inline u32 compute_data_length(struct user_sdma_request *req,
         * The size of the data of the first packet is in the header
         * template. However, it includes the header and ICRC, which need
         * to be subtracted.
+        * The minimum representable packet data length in a header is 4 bytes,
+        * therefore, when the data length request is less than 4 bytes, there's
+        * only one packet, and the packet data length is equal to that of the
+        * request data length.
         * The size of the remaining packets is the minimum of the frag
         * size (MTU) or remaining data in the request.
         */
        u32 len;
 
        if (!req->seqnum) {
-               len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) -
-                      (sizeof(tx->hdr) - 4));
+               if (req->data_len < sizeof(u32))
+                       len = req->data_len;
+               else
+                       len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) -
+                              (sizeof(tx->hdr) - 4));
        } else if (req_opcode(req->info.ctrl) == EXPECTED) {
                u32 tidlen = EXP_TID_GET(req->tids[req->tididx], LEN) *
                        PAGE_SIZE;
@@ -803,6 +877,13 @@ static inline u32 compute_data_length(struct user_sdma_request *req,
        return len;
 }
 
+static inline u32 pad_len(u32 len)
+{
+       if (len & (sizeof(u32) - 1))
+               len += sizeof(u32) - (len & (sizeof(u32) - 1));
+       return len;
+}
+
 static inline u32 get_lrh_len(struct hfi1_pkt_header hdr, u32 len)
 {
        /* (Size of complete header - size of PBC) + 4B ICRC + data length */
@@ -894,7 +975,8 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts)
                if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) {
                        if (!req->seqnum) {
                                u16 pbclen = le16_to_cpu(req->hdr.pbc[0]);
-                               u32 lrhlen = get_lrh_len(req->hdr, datalen);
+                               u32 lrhlen = get_lrh_len(req->hdr,
+                                                        pad_len(datalen));
                                /*
                                 * Copy the request header into the tx header
                                 * because the HW needs a cacheline-aligned
@@ -1048,39 +1130,24 @@ static inline int num_user_pages(const struct iovec *iov)
 
 static u32 sdma_cache_evict(struct hfi1_user_sdma_pkt_q *pq, u32 npages)
 {
-       u32 cleared = 0;
-       struct sdma_mmu_node *node, *ptr;
-       struct list_head to_evict = LIST_HEAD_INIT(to_evict);
-
-       spin_lock(&pq->evict_lock);
-       list_for_each_entry_safe_reverse(node, ptr, &pq->evict, list) {
-               /* Make sure that no one is still using the node. */
-               if (!atomic_read(&node->refcount)) {
-                       set_bit(SDMA_CACHE_NODE_EVICT, &node->flags);
-                       list_del_init(&node->list);
-                       list_add(&node->list, &to_evict);
-                       cleared += node->npages;
-                       if (cleared >= npages)
-                               break;
-               }
-       }
-       spin_unlock(&pq->evict_lock);
-
-       list_for_each_entry_safe(node, ptr, &to_evict, list)
-               hfi1_mmu_rb_remove(&pq->sdma_rb_root, &node->rb);
+       struct evict_data evict_data;
 
-       return cleared;
+       evict_data.cleared = 0;
+       evict_data.target = npages;
+       hfi1_mmu_rb_evict(pq->handler, &evict_data);
+       return evict_data.cleared;
 }
 
 static int pin_vector_pages(struct user_sdma_request *req,
-                           struct user_sdma_iovec *iovec) {
+                           struct user_sdma_iovec *iovec)
+{
        int ret = 0, pinned, npages, cleared;
        struct page **pages;
        struct hfi1_user_sdma_pkt_q *pq = req->pq;
        struct sdma_mmu_node *node = NULL;
        struct mmu_rb_node *rb_node;
 
-       rb_node = hfi1_mmu_rb_extract(&pq->sdma_rb_root,
+       rb_node = hfi1_mmu_rb_extract(pq->handler,
                                      (unsigned long)iovec->iov.iov_base,
                                      iovec->iov.iov_len);
        if (rb_node && !IS_ERR(rb_node))
@@ -1096,7 +1163,6 @@ static int pin_vector_pages(struct user_sdma_request *req,
                node->rb.addr = (unsigned long)iovec->iov.iov_base;
                node->pq = pq;
                atomic_set(&node->refcount, 0);
-               INIT_LIST_HEAD(&node->list);
        }
 
        npages = num_user_pages(&iovec->iov);
@@ -1111,28 +1177,14 @@ static int pin_vector_pages(struct user_sdma_request *req,
 
                npages -= node->npages;
 
-               /*
-                * If rb_node is NULL, it means that this is brand new node
-                * and, therefore not on the eviction list.
-                * If, however, the rb_node is non-NULL, it means that the
-                * node is already in RB tree and, therefore on the eviction
-                * list (nodes are unconditionally inserted in the eviction
-                * list). In that case, we have to remove the node prior to
-                * calling the eviction function in order to prevent it from
-                * freeing this node.
-                */
-               if (rb_node) {
-                       spin_lock(&pq->evict_lock);
-                       list_del_init(&node->list);
-                       spin_unlock(&pq->evict_lock);
-               }
 retry:
-               if (!hfi1_can_pin_pages(pq->dd, pq->n_locked, npages)) {
+               if (!hfi1_can_pin_pages(pq->dd, pq->mm,
+                                       atomic_read(&pq->n_locked), npages)) {
                        cleared = sdma_cache_evict(pq, npages);
                        if (cleared >= npages)
                                goto retry;
                }
-               pinned = hfi1_acquire_user_pages(
+               pinned = hfi1_acquire_user_pages(pq->mm,
                        ((unsigned long)iovec->iov.iov_base +
                         (node->npages * PAGE_SIZE)), npages, 0,
                        pages + node->npages);
@@ -1142,7 +1194,7 @@ retry:
                        goto bail;
                }
                if (pinned != npages) {
-                       unpin_vector_pages(current->mm, pages, node->npages,
+                       unpin_vector_pages(pq->mm, pages, node->npages,
                                           pinned);
                        ret = -EFAULT;
                        goto bail;
@@ -1152,28 +1204,22 @@ retry:
                node->pages = pages;
                node->npages += pinned;
                npages = node->npages;
-               spin_lock(&pq->evict_lock);
-               list_add(&node->list, &pq->evict);
-               pq->n_locked += pinned;
-               spin_unlock(&pq->evict_lock);
+               atomic_add(pinned, &pq->n_locked);
        }
        iovec->pages = node->pages;
        iovec->npages = npages;
        iovec->node = node;
 
-       ret = hfi1_mmu_rb_insert(&req->pq->sdma_rb_root, &node->rb);
+       ret = hfi1_mmu_rb_insert(req->pq->handler, &node->rb);
        if (ret) {
-               spin_lock(&pq->evict_lock);
-               if (!list_empty(&node->list))
-                       list_del(&node->list);
-               pq->n_locked -= node->npages;
-               spin_unlock(&pq->evict_lock);
+               atomic_sub(node->npages, &pq->n_locked);
+               iovec->node = NULL;
                goto bail;
        }
        return 0;
 bail:
        if (rb_node)
-               unpin_vector_pages(current->mm, node->pages, 0, node->npages);
+               unpin_vector_pages(pq->mm, node->pages, 0, node->npages);
        kfree(node);
        return ret;
 }
@@ -1181,7 +1227,7 @@ bail:
 static void unpin_vector_pages(struct mm_struct *mm, struct page **pages,
                               unsigned start, unsigned npages)
 {
-       hfi1_release_user_pages(mm, pages + start, npages, 0);
+       hfi1_release_user_pages(mm, pages + start, npages, false);
        kfree(pages);
 }
 
@@ -1192,16 +1238,14 @@ static int check_header_template(struct user_sdma_request *req,
        /*
         * Perform safety checks for any type of packet:
         *    - transfer size is multiple of 64bytes
-        *    - packet length is multiple of 4bytes
-        *    - entire request length is multiple of 4bytes
+        *    - packet length is multiple of 4 bytes
         *    - packet length is not larger than MTU size
         *
         * These checks are only done for the first packet of the
         * transfer since the header is "given" to us by user space.
         * For the remainder of the packets we compute the values.
         */
-       if (req->info.fragsize % PIO_BLOCK_SIZE ||
-           lrhlen & 0x3 || req->data_len & 0x3  ||
+       if (req->info.fragsize % PIO_BLOCK_SIZE || lrhlen & 0x3 ||
            lrhlen > get_lrh_len(*hdr, req->info.fragsize))
                return -EINVAL;
 
@@ -1263,7 +1307,7 @@ static int set_txreq_header(struct user_sdma_request *req,
        struct hfi1_pkt_header *hdr = &tx->hdr;
        u16 pbclen;
        int ret;
-       u32 tidval = 0, lrhlen = get_lrh_len(*hdr, datalen);
+       u32 tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(datalen));
 
        /* Copy the header template to the request before modification */
        memcpy(hdr, &req->hdr, sizeof(*hdr));
@@ -1374,7 +1418,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
        struct hfi1_user_sdma_pkt_q *pq = req->pq;
        struct hfi1_pkt_header *hdr = &req->hdr;
        u16 pbclen = le16_to_cpu(hdr->pbc[0]);
-       u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, len);
+       u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, pad_len(len));
 
        if (PBC2LRH(pbclen) != lrhlen) {
                /* PBC.PbcLengthDWs */
@@ -1534,14 +1578,14 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin)
                                continue;
 
                        if (unpin)
-                               hfi1_mmu_rb_remove(&req->pq->sdma_rb_root,
+                               hfi1_mmu_rb_remove(req->pq->handler,
                                                   &node->rb);
                        else
                                atomic_dec(&node->refcount);
                }
        }
        kfree(req->tids);
-       clear_bit(SDMA_REQ_IN_USE, &req->flags);
+       clear_bit(req->info.comp_idx, req->pq->req_in_use);
 }
 
 static inline void set_comp_state(struct hfi1_user_sdma_pkt_q *pq,
@@ -1564,7 +1608,7 @@ static bool sdma_rb_filter(struct mmu_rb_node *node, unsigned long addr,
        return (bool)(node->addr == addr);
 }
 
-static int sdma_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
+static int sdma_rb_insert(void *arg, struct mmu_rb_node *mnode)
 {
        struct sdma_mmu_node *node =
                container_of(mnode, struct sdma_mmu_node, rb);
@@ -1573,48 +1617,45 @@ static int sdma_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
        return 0;
 }
 
-static void sdma_rb_remove(struct rb_root *root, struct mmu_rb_node *mnode,
-                          struct mm_struct *mm)
+/*
+ * Return 1 to remove the node from the rb tree and call the remove op.
+ *
+ * Called with the rb tree lock held.
+ */
+static int sdma_rb_evict(void *arg, struct mmu_rb_node *mnode,
+                        void *evict_arg, bool *stop)
+{
+       struct sdma_mmu_node *node =
+               container_of(mnode, struct sdma_mmu_node, rb);
+       struct evict_data *evict_data = evict_arg;
+
+       /* is this node still being used? */
+       if (atomic_read(&node->refcount))
+               return 0; /* keep this node */
+
+       /* this node will be evicted, add its pages to our count */
+       evict_data->cleared += node->npages;
+
+       /* have enough pages been cleared? */
+       if (evict_data->cleared >= evict_data->target)
+               *stop = true;
+
+       return 1; /* remove this node */
+}
+
+static void sdma_rb_remove(void *arg, struct mmu_rb_node *mnode)
 {
        struct sdma_mmu_node *node =
                container_of(mnode, struct sdma_mmu_node, rb);
 
-       spin_lock(&node->pq->evict_lock);
-       /*
-        * We've been called by the MMU notifier but this node has been
-        * scheduled for eviction. The eviction function will take care
-        * of freeing this node.
-        * We have to take the above lock first because we are racing
-        * against the setting of the bit in the eviction function.
-        */
-       if (mm && test_bit(SDMA_CACHE_NODE_EVICT, &node->flags)) {
-               spin_unlock(&node->pq->evict_lock);
-               return;
-       }
+       atomic_sub(node->npages, &node->pq->n_locked);
 
-       if (!list_empty(&node->list))
-               list_del(&node->list);
-       node->pq->n_locked -= node->npages;
-       spin_unlock(&node->pq->evict_lock);
+       unpin_vector_pages(node->pq->mm, node->pages, 0, node->npages);
 
-       /*
-        * If mm is set, we are being called by the MMU notifier and we
-        * should not pass a mm_struct to unpin_vector_page(). This is to
-        * prevent a deadlock when hfi1_release_user_pages() attempts to
-        * take the mmap_sem, which the MMU notifier has already taken.
-        */
-       unpin_vector_pages(mm ? NULL : current->mm, node->pages, 0,
-                          node->npages);
-       /*
-        * If called by the MMU notifier, we have to adjust the pinned
-        * page count ourselves.
-        */
-       if (mm)
-               mm->pinned_vm -= node->npages;
        kfree(node);
 }
 
-static int sdma_rb_invalidate(struct rb_root *root, struct mmu_rb_node *mnode)
+static int sdma_rb_invalidate(void *arg, struct mmu_rb_node *mnode)
 {
        struct sdma_mmu_node *node =
                container_of(mnode, struct sdma_mmu_node, rb);
index b9240e3..3900171 100644 (file)
@@ -63,14 +63,14 @@ struct hfi1_user_sdma_pkt_q {
        struct hfi1_devdata *dd;
        struct kmem_cache *txreq_cache;
        struct user_sdma_request *reqs;
+       unsigned long *req_in_use;
        struct iowait busy;
        unsigned state;
        wait_queue_head_t wait;
        unsigned long unpinned;
-       struct rb_root sdma_rb_root;
-       u32 n_locked;
-       struct list_head evict;
-       spinlock_t evict_lock; /* protect evict and n_locked */
+       struct mmu_rb_handler *handler;
+       atomic_t n_locked;
+       struct mm_struct *mm;
 };
 
 struct hfi1_user_sdma_comp_q {
index 849c4b9..2b35954 100644 (file)
@@ -306,7 +306,10 @@ const enum ib_wc_opcode ib_hfi1_wc_opcode[] = {
        [IB_WR_SEND_WITH_IMM] = IB_WC_SEND,
        [IB_WR_RDMA_READ] = IB_WC_RDMA_READ,
        [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP,
-       [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD
+       [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD,
+       [IB_WR_SEND_WITH_INV] = IB_WC_SEND,
+       [IB_WR_LOCAL_INV] = IB_WC_LOCAL_INV,
+       [IB_WR_REG_MR] = IB_WC_REG_MR
 };
 
 /*
@@ -378,6 +381,8 @@ static const opcode_handler opcode_handler_tbl[256] = {
        [IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE]             = &hfi1_rc_rcv,
        [IB_OPCODE_RC_COMPARE_SWAP]                   = &hfi1_rc_rcv,
        [IB_OPCODE_RC_FETCH_ADD]                      = &hfi1_rc_rcv,
+       [IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE]      = &hfi1_rc_rcv,
+       [IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE]      = &hfi1_rc_rcv,
        /* UC */
        [IB_OPCODE_UC_SEND_FIRST]                     = &hfi1_uc_rcv,
        [IB_OPCODE_UC_SEND_MIDDLE]                    = &hfi1_uc_rcv,
@@ -540,19 +545,15 @@ void hfi1_skip_sge(struct rvt_sge_state *ss, u32 length, int release)
 /*
  * Make sure the QP is ready and able to accept the given opcode.
  */
-static inline int qp_ok(int opcode, struct hfi1_packet *packet)
+static inline opcode_handler qp_ok(int opcode, struct hfi1_packet *packet)
 {
-       struct hfi1_ibport *ibp;
-
        if (!(ib_rvt_state_ops[packet->qp->state] & RVT_PROCESS_RECV_OK))
-               goto dropit;
+               return NULL;
        if (((opcode & RVT_OPCODE_QP_MASK) == packet->qp->allowed_ops) ||
            (opcode == IB_OPCODE_CNP))
-               return 1;
-dropit:
-       ibp = &packet->rcd->ppd->ibport_data;
-       ibp->rvp.n_pkt_drops++;
-       return 0;
+               return opcode_handler_tbl[opcode];
+
+       return NULL;
 }
 
 /**
@@ -571,6 +572,7 @@ void hfi1_ib_rcv(struct hfi1_packet *packet)
        struct hfi1_pportdata *ppd = rcd->ppd;
        struct hfi1_ibport *ibp = &ppd->ibport_data;
        struct rvt_dev_info *rdi = &ppd->dd->verbs_dev.rdi;
+       opcode_handler packet_handler;
        unsigned long flags;
        u32 qp_num;
        int lnh;
@@ -616,8 +618,11 @@ void hfi1_ib_rcv(struct hfi1_packet *packet)
                list_for_each_entry_rcu(p, &mcast->qp_list, list) {
                        packet->qp = p->qp;
                        spin_lock_irqsave(&packet->qp->r_lock, flags);
-                       if (likely((qp_ok(opcode, packet))))
-                               opcode_handler_tbl[opcode](packet);
+                       packet_handler = qp_ok(opcode, packet);
+                       if (likely(packet_handler))
+                               packet_handler(packet);
+                       else
+                               ibp->rvp.n_pkt_drops++;
                        spin_unlock_irqrestore(&packet->qp->r_lock, flags);
                }
                /*
@@ -634,8 +639,11 @@ void hfi1_ib_rcv(struct hfi1_packet *packet)
                        goto drop;
                }
                spin_lock_irqsave(&packet->qp->r_lock, flags);
-               if (likely((qp_ok(opcode, packet))))
-                       opcode_handler_tbl[opcode](packet);
+               packet_handler = qp_ok(opcode, packet);
+               if (likely(packet_handler))
+                       packet_handler(packet);
+               else
+                       ibp->rvp.n_pkt_drops++;
                spin_unlock_irqrestore(&packet->qp->r_lock, flags);
                rcu_read_unlock();
        }
@@ -808,19 +816,19 @@ static int build_verbs_tx_desc(
        struct rvt_sge_state *ss,
        u32 length,
        struct verbs_txreq *tx,
-       struct ahg_ib_header *ahdr,
+       struct hfi1_ahg_info *ahg_info,
        u64 pbc)
 {
        int ret = 0;
-       struct hfi1_pio_header *phdr = &tx->phdr;
+       struct hfi1_sdma_header *phdr = &tx->phdr;
        u16 hdrbytes = tx->hdr_dwords << 2;
 
-       if (!ahdr->ahgcount) {
+       if (!ahg_info->ahgcount) {
                ret = sdma_txinit_ahg(
                        &tx->txreq,
-                       ahdr->tx_flags,
+                       ahg_info->tx_flags,
                        hdrbytes + length,
-                       ahdr->ahgidx,
+                       ahg_info->ahgidx,
                        0,
                        NULL,
                        0,
@@ -838,11 +846,11 @@ static int build_verbs_tx_desc(
        } else {
                ret = sdma_txinit_ahg(
                        &tx->txreq,
-                       ahdr->tx_flags,
+                       ahg_info->tx_flags,
                        length,
-                       ahdr->ahgidx,
-                       ahdr->ahgcount,
-                       ahdr->ahgdesc,
+                       ahg_info->ahgidx,
+                       ahg_info->ahgcount,
+                       ahg_info->ahgdesc,
                        hdrbytes,
                        verbs_sdma_complete);
                if (ret)
@@ -860,7 +868,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
                        u64 pbc)
 {
        struct hfi1_qp_priv *priv = qp->priv;
-       struct ahg_ib_header *ahdr = priv->s_hdr;
+       struct hfi1_ahg_info *ahg_info = priv->s_ahg;
        u32 hdrwords = qp->s_hdrwords;
        struct rvt_sge_state *ss = qp->s_cur_sge;
        u32 len = qp->s_cur_size;
@@ -888,7 +896,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
                                         plen);
                }
                tx->wqe = qp->s_wqe;
-               ret = build_verbs_tx_desc(tx->sde, ss, len, tx, ahdr, pbc);
+               ret = build_verbs_tx_desc(tx->sde, ss, len, tx, ahg_info, pbc);
                if (unlikely(ret))
                        goto bail_build;
        }
@@ -1291,19 +1299,24 @@ int hfi1_verbs_send(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
 static void hfi1_fill_device_attr(struct hfi1_devdata *dd)
 {
        struct rvt_dev_info *rdi = &dd->verbs_dev.rdi;
+       u16 ver = dd->dc8051_ver;
 
        memset(&rdi->dparms.props, 0, sizeof(rdi->dparms.props));
 
+       rdi->dparms.props.fw_ver = ((u64)(dc8051_ver_maj(ver)) << 16) |
+                                   (u64)dc8051_ver_min(ver);
        rdi->dparms.props.device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
                        IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
                        IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN |
-                       IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE;
+                       IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE |
+                       IB_DEVICE_MEM_MGT_EXTENSIONS;
        rdi->dparms.props.page_size_cap = PAGE_SIZE;
        rdi->dparms.props.vendor_id = dd->oui1 << 16 | dd->oui2 << 8 | dd->oui3;
        rdi->dparms.props.vendor_part_id = dd->pcidev->device;
        rdi->dparms.props.hw_ver = dd->minrev;
        rdi->dparms.props.sys_image_guid = ib_hfi1_sys_image_guid;
-       rdi->dparms.props.max_mr_size = ~0ULL;
+       rdi->dparms.props.max_mr_size = U64_MAX;
+       rdi->dparms.props.max_fast_reg_page_list_len = UINT_MAX;
        rdi->dparms.props.max_qp = hfi1_max_qps;
        rdi->dparms.props.max_qp_wr = hfi1_max_qp_wrs;
        rdi->dparms.props.max_sge = hfi1_max_sges;
@@ -1567,6 +1580,17 @@ static void init_ibport(struct hfi1_pportdata *ppd)
        RCU_INIT_POINTER(ibp->rvp.qp[1], NULL);
 }
 
+static void hfi1_get_dev_fw_str(struct ib_device *ibdev, char *str,
+                               size_t str_len)
+{
+       struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
+       struct hfi1_ibdev *dev = dev_from_rdi(rdi);
+       u16 ver = dd_from_dev(dev)->dc8051_ver;
+
+       snprintf(str, str_len, "%u.%u", dc8051_ver_maj(ver),
+                dc8051_ver_min(ver));
+}
+
 /**
  * hfi1_register_ib_device - register our device with the infiniband core
  * @dd: the device data structure
@@ -1613,6 +1637,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
 
        /* keep process mad in the driver */
        ibdev->process_mad = hfi1_process_mad;
+       ibdev->get_dev_fw_str = hfi1_get_dev_fw_str;
 
        strncpy(ibdev->node_desc, init_utsname()->nodename,
                sizeof(ibdev->node_desc));
@@ -1680,6 +1705,9 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
        dd->verbs_dev.rdi.dparms.nports = dd->num_pports;
        dd->verbs_dev.rdi.dparms.npkeys = hfi1_get_npkeys(dd);
 
+       /* post send table */
+       dd->verbs_dev.rdi.post_parms = hfi1_post_parms;
+
        ppd = dd->pport;
        for (i = 0; i < dd->num_pports; i++, ppd++)
                rvt_init_port(&dd->verbs_dev.rdi,
@@ -1730,8 +1758,7 @@ void hfi1_cnp_rcv(struct hfi1_packet *packet)
        struct rvt_qp *qp = packet->qp;
        u32 lqpn, rqpn = 0;
        u16 rlid = 0;
-       u8 sl, sc5, sc4_bit, svc_type;
-       bool sc4_set = has_sc4_bit(packet);
+       u8 sl, sc5, svc_type;
 
        switch (packet->qp->ibqp.qp_type) {
        case IB_QPT_UC:
@@ -1754,9 +1781,7 @@ void hfi1_cnp_rcv(struct hfi1_packet *packet)
                return;
        }
 
-       sc4_bit = sc4_set << 4;
-       sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf;
-       sc5 |= sc4_bit;
+       sc5 = hdr2sc((struct hfi1_message_header *)hdr, packet->rhf);
        sl = ibp->sc_to_sl[sc5];
        lqpn = qp->ibqp.qp_num;
 
index 4883567..d1b101c 100644 (file)
@@ -178,16 +178,14 @@ struct hfi1_ib_header {
        } u;
 } __packed;
 
-struct ahg_ib_header {
-       struct sdma_engine *sde;
+struct hfi1_ahg_info {
        u32 ahgdesc[2];
        u16 tx_flags;
        u8 ahgcount;
        u8 ahgidx;
-       struct hfi1_ib_header ibh;
 };
 
-struct hfi1_pio_header {
+struct hfi1_sdma_header {
        __le64 pbc;
        struct hfi1_ib_header hdr;
 } __packed;
@@ -197,7 +195,7 @@ struct hfi1_pio_header {
  * pair is made common
  */
 struct hfi1_qp_priv {
-       struct ahg_ib_header *s_hdr;              /* next header to send */
+       struct hfi1_ahg_info *s_ahg;              /* ahg info for next header */
        struct sdma_engine *s_sde;                /* current sde */
        struct send_context *s_sendcontext;       /* current sendcontext */
        u8 s_sc;                                  /* SC[0..4] for next packet */
index a1d6e08..5660897 100644 (file)
@@ -56,7 +56,7 @@
 #include "iowait.h"
 
 struct verbs_txreq {
-       struct hfi1_pio_header  phdr;
+       struct hfi1_sdma_header phdr;
        struct sdma_txreq       txreq;
        struct rvt_qp           *qp;
        struct rvt_swqe         *wqe;
index d2fa725..5026dc7 100644 (file)
@@ -1567,12 +1567,12 @@ static enum i40iw_status_code i40iw_del_multiple_qhash(
                ret = i40iw_manage_qhash(iwdev, cm_info,
                                         I40IW_QHASH_TYPE_TCP_SYN,
                                         I40IW_QHASH_MANAGE_TYPE_DELETE, NULL, false);
-               kfree(child_listen_node);
-               cm_parent_listen_node->cm_core->stats_listen_nodes_destroyed++;
                i40iw_debug(&iwdev->sc_dev,
                            I40IW_DEBUG_CM,
                            "freed pointer = %p\n",
                            child_listen_node);
+               kfree(child_listen_node);
+               cm_parent_listen_node->cm_core->stats_listen_nodes_destroyed++;
        }
        spin_unlock_irqrestore(&iwdev->cm_core.listen_list_lock, flags);
 
index bd942da..2fac1db 100644 (file)
@@ -1557,6 +1557,9 @@ enum i40iw_alignment {
 #define I40IW_RING_MOVE_TAIL(_ring) \
        (_ring).tail = ((_ring).tail + 1) % (_ring).size
 
+#define I40IW_RING_MOVE_HEAD_NOCHECK(_ring) \
+       (_ring).head = ((_ring).head + 1) % (_ring).size
+
 #define I40IW_RING_MOVE_TAIL_BY_COUNT(_ring, _count) \
        (_ring).tail = ((_ring).tail + (_count)) % (_ring).size
 
index e9c6e82..c62d354 100644 (file)
@@ -1025,6 +1025,8 @@ static void  i40iw_ieq_compl_pfpdu(struct i40iw_puda_rsrc *ieq,
        u16 txoffset, bufoffset;
 
        buf = i40iw_puda_get_listbuf(pbufl);
+       if (!buf)
+               return;
        nextseqnum = buf->seqnum + fpdu_len;
        txbuf->totallen = buf->hdrlen + fpdu_len;
        txbuf->data = (u8 *)txbuf->mem.va + buf->hdrlen;
@@ -1048,6 +1050,8 @@ static void  i40iw_ieq_compl_pfpdu(struct i40iw_puda_rsrc *ieq,
                fpdu_len -= buf->datalen;
                i40iw_puda_ret_bufpool(ieq, buf);
                buf = i40iw_puda_get_listbuf(pbufl);
+               if (!buf)
+                       return;
                bufoffset = (u16)(buf->data - (u8 *)buf->mem.va);
        } while (1);
 
index 16cc617..2b1a04e 100644 (file)
@@ -667,7 +667,7 @@ struct i40iw_tcp_offload_info {
        bool time_stamp;
        u8 cwnd_inc_limit;
        bool drop_ooo_seg;
-       bool dup_ack_thresh;
+       u8 dup_ack_thresh;
        u8 ttl;
        u8 src_mac_addr_idx;
        bool avoid_stretch_ack;
index e35faea..4d28c3c 100644 (file)
@@ -291,9 +291,9 @@ static enum i40iw_status_code i40iw_rdma_write(struct i40iw_qp_uk *qp,
 
        i40iw_set_fragment(wqe, 0, op_info->lo_sg_list);
 
-       for (i = 1; i < op_info->num_lo_sges; i++) {
-               byte_off = 32 + (i - 1) * 16;
+       for (i = 1, byte_off = 32; i < op_info->num_lo_sges; i++) {
                i40iw_set_fragment(wqe, byte_off, &op_info->lo_sg_list[i]);
+               byte_off += 16;
        }
 
        wmb(); /* make sure WQE is populated before valid bit is set */
@@ -401,9 +401,9 @@ static enum i40iw_status_code i40iw_send(struct i40iw_qp_uk *qp,
 
        i40iw_set_fragment(wqe, 0, op_info->sg_list);
 
-       for (i = 1; i < op_info->num_sges; i++) {
-               byte_off = 32 + (i - 1) * 16;
+       for (i = 1, byte_off = 32; i < op_info->num_sges; i++) {
                i40iw_set_fragment(wqe, byte_off, &op_info->sg_list[i]);
+               byte_off += 16;
        }
 
        wmb(); /* make sure WQE is populated before valid bit is set */
@@ -685,9 +685,9 @@ static enum i40iw_status_code i40iw_post_receive(struct i40iw_qp_uk *qp,
 
        i40iw_set_fragment(wqe, 0, info->sg_list);
 
-       for (i = 1; i < info->num_sges; i++) {
-               byte_off = 32 + (i - 1) * 16;
+       for (i = 1, byte_off = 32; i < info->num_sges; i++) {
                i40iw_set_fragment(wqe, byte_off, &info->sg_list[i]);
+               byte_off += 16;
        }
 
        wmb(); /* make sure WQE is populated before valid bit is set */
@@ -753,8 +753,7 @@ static enum i40iw_status_code i40iw_cq_post_entries(struct i40iw_cq_uk *cq,
  * @post_cq: update cq tail
  */
 static enum i40iw_status_code i40iw_cq_poll_completion(struct i40iw_cq_uk *cq,
-                                                      struct i40iw_cq_poll_info *info,
-                                                      bool post_cq)
+                                                      struct i40iw_cq_poll_info *info)
 {
        u64 comp_ctx, qword0, qword2, qword3, wqe_qword;
        u64 *cqe, *sw_wqe;
@@ -762,7 +761,6 @@ static enum i40iw_status_code i40iw_cq_poll_completion(struct i40iw_cq_uk *cq,
        struct i40iw_ring *pring = NULL;
        u32 wqe_idx, q_type, array_idx = 0;
        enum i40iw_status_code ret_code = 0;
-       enum i40iw_status_code ret_code2 = 0;
        bool move_cq_head = true;
        u8 polarity;
        u8 addl_wqes = 0;
@@ -870,19 +868,14 @@ exit:
                        move_cq_head = false;
 
        if (move_cq_head) {
-               I40IW_RING_MOVE_HEAD(cq->cq_ring, ret_code2);
-
-               if (ret_code2 && !ret_code)
-                       ret_code = ret_code2;
+               I40IW_RING_MOVE_HEAD_NOCHECK(cq->cq_ring);
 
                if (I40IW_RING_GETCURRENT_HEAD(cq->cq_ring) == 0)
                        cq->polarity ^= 1;
 
-               if (post_cq) {
-                       I40IW_RING_MOVE_TAIL(cq->cq_ring);
-                       set_64bit_val(cq->shadow_area, 0,
-                                     I40IW_RING_GETCURRENT_HEAD(cq->cq_ring));
-               }
+               I40IW_RING_MOVE_TAIL(cq->cq_ring);
+               set_64bit_val(cq->shadow_area, 0,
+                             I40IW_RING_GETCURRENT_HEAD(cq->cq_ring));
        } else {
                if (info->is_srq)
                        return ret_code;
index 4627646..276bcef 100644 (file)
@@ -327,7 +327,7 @@ struct i40iw_cq_ops {
        void (*iw_cq_request_notification)(struct i40iw_cq_uk *,
                                           enum i40iw_completion_notify);
        enum i40iw_status_code (*iw_cq_poll_completion)(struct i40iw_cq_uk *,
-                                                       struct i40iw_cq_poll_info *, bool);
+                                                       struct i40iw_cq_poll_info *);
        enum i40iw_status_code (*iw_cq_post_entries)(struct i40iw_cq_uk *, u8 count);
        void (*iw_cq_clean)(void *, struct i40iw_cq_uk *);
 };
index 283b64c..2360338 100644 (file)
@@ -529,7 +529,7 @@ static int i40iw_setup_kmode_qp(struct i40iw_device *iwdev,
                status = i40iw_get_wqe_shift(rq_size, ukinfo->max_rq_frag_cnt, 0, &rqshift);
 
        if (status)
-               return -ENOSYS;
+               return -ENOMEM;
 
        sqdepth = sq_size << sqshift;
        rqdepth = rq_size << rqshift;
@@ -671,7 +671,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd,
        iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp;
 
        if (init_attr->qp_type != IB_QPT_RC) {
-               err_code = -ENOSYS;
+               err_code = -EINVAL;
                goto error;
        }
        if (iwdev->push_mode)
@@ -1840,6 +1840,7 @@ struct ib_mr *i40iw_reg_phys_mr(struct ib_pd *pd,
        iwmr->ibmr.lkey = stag;
        iwmr->page_cnt = 1;
        iwmr->pgaddrmem[0]  = addr;
+       iwmr->length = size;
        status = i40iw_hwreg_mr(iwdev, iwmr, access);
        if (status) {
                i40iw_free_stag(iwdev, stag);
@@ -1863,7 +1864,7 @@ static struct ib_mr *i40iw_get_dma_mr(struct ib_pd *pd, int acc)
 {
        u64 kva = 0;
 
-       return i40iw_reg_phys_mr(pd, 0, 0xffffffffffULL, acc, &kva);
+       return i40iw_reg_phys_mr(pd, 0, 0, acc, &kva);
 }
 
 /**
@@ -1974,18 +1975,6 @@ static ssize_t i40iw_show_rev(struct device *dev,
        return sprintf(buf, "%x\n", hw_rev);
 }
 
-/**
- * i40iw_show_fw_ver
- */
-static ssize_t i40iw_show_fw_ver(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       u32 firmware_version = I40IW_FW_VERSION;
-
-       return sprintf(buf, "%u.%u\n", firmware_version,
-                      (firmware_version & 0x000000ff));
-}
-
 /**
  * i40iw_show_hca
  */
@@ -2006,13 +1995,11 @@ static ssize_t i40iw_show_board(struct device *dev,
 }
 
 static DEVICE_ATTR(hw_rev, S_IRUGO, i40iw_show_rev, NULL);
-static DEVICE_ATTR(fw_ver, S_IRUGO, i40iw_show_fw_ver, NULL);
 static DEVICE_ATTR(hca_type, S_IRUGO, i40iw_show_hca, NULL);
 static DEVICE_ATTR(board_id, S_IRUGO, i40iw_show_board, NULL);
 
 static struct device_attribute *i40iw_dev_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id
 };
@@ -2091,8 +2078,12 @@ static int i40iw_post_send(struct ib_qp *ibqp,
                                ret = ukqp->ops.iw_send(ukqp, &info, ib_wr->ex.invalidate_rkey, false);
                        }
 
-                       if (ret)
-                               err = -EIO;
+                       if (ret) {
+                               if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
+                                       err = -ENOMEM;
+                               else
+                                       err = -EINVAL;
+                       }
                        break;
                case IB_WR_RDMA_WRITE:
                        info.op_type = I40IW_OP_TYPE_RDMA_WRITE;
@@ -2113,8 +2104,12 @@ static int i40iw_post_send(struct ib_qp *ibqp,
                                ret = ukqp->ops.iw_rdma_write(ukqp, &info, false);
                        }
 
-                       if (ret)
-                               err = -EIO;
+                       if (ret) {
+                               if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
+                                       err = -ENOMEM;
+                               else
+                                       err = -EINVAL;
+                       }
                        break;
                case IB_WR_RDMA_READ_WITH_INV:
                        inv_stag = true;
@@ -2132,15 +2127,19 @@ static int i40iw_post_send(struct ib_qp *ibqp,
                        info.op.rdma_read.lo_addr.stag = ib_wr->sg_list->lkey;
                        info.op.rdma_read.lo_addr.len = ib_wr->sg_list->length;
                        ret = ukqp->ops.iw_rdma_read(ukqp, &info, inv_stag, false);
-                       if (ret)
-                               err = -EIO;
+                       if (ret) {
+                               if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
+                                       err = -ENOMEM;
+                               else
+                                       err = -EINVAL;
+                       }
                        break;
                case IB_WR_LOCAL_INV:
                        info.op_type = I40IW_OP_TYPE_INV_STAG;
                        info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey;
                        ret = ukqp->ops.iw_stag_local_invalidate(ukqp, &info, true);
                        if (ret)
-                               err = -EIO;
+                               err = -ENOMEM;
                        break;
                case IB_WR_REG_MR:
                {
@@ -2174,7 +2173,7 @@ static int i40iw_post_send(struct ib_qp *ibqp,
 
                        ret = dev->iw_priv_qp_ops->iw_mr_fast_register(&iwqp->sc_qp, &info, true);
                        if (ret)
-                               err = -EIO;
+                               err = -ENOMEM;
                        break;
                }
                default:
@@ -2214,6 +2213,7 @@ static int i40iw_post_recv(struct ib_qp *ibqp,
        struct i40iw_sge sg_list[I40IW_MAX_WQ_FRAGMENT_COUNT];
        enum i40iw_status_code ret = 0;
        unsigned long flags;
+       int err = 0;
 
        iwqp = (struct i40iw_qp *)ibqp;
        ukqp = &iwqp->sc_qp.qp_uk;
@@ -2228,6 +2228,10 @@ static int i40iw_post_recv(struct ib_qp *ibqp,
                ret = ukqp->ops.iw_post_receive(ukqp, &post_recv);
                if (ret) {
                        i40iw_pr_err(" post_recv err %d\n", ret);
+                       if (ret == I40IW_ERR_QP_TOOMANY_WRS_POSTED)
+                               err = -ENOMEM;
+                       else
+                               err = -EINVAL;
                        *bad_wr = ib_wr;
                        goto out;
                }
@@ -2235,9 +2239,7 @@ static int i40iw_post_recv(struct ib_qp *ibqp,
        }
  out:
        spin_unlock_irqrestore(&iwqp->lock, flags);
-       if (ret)
-               return -ENOSYS;
-       return 0;
+       return err;
 }
 
 /**
@@ -2264,7 +2266,7 @@ static int i40iw_poll_cq(struct ib_cq *ibcq,
 
        spin_lock_irqsave(&iwcq->lock, flags);
        while (cqe_count < num_entries) {
-               ret = ukcq->ops.iw_cq_poll_completion(ukcq, &cq_poll_info, true);
+               ret = ukcq->ops.iw_cq_poll_completion(ukcq, &cq_poll_info);
                if (ret == I40IW_ERR_QUEUE_EMPTY) {
                        break;
                } else if (ret == I40IW_ERR_QUEUE_DESTROYED) {
@@ -2437,6 +2439,15 @@ static const char * const i40iw_hw_stat_names[] = {
                "iwRdmaInv"
 };
 
+static void i40iw_get_dev_fw_str(struct ib_device *dev, char *str,
+                                size_t str_len)
+{
+       u32 firmware_version = I40IW_FW_VERSION;
+
+       snprintf(str, str_len, "%u.%u", firmware_version,
+                      (firmware_version & 0x000000ff));
+}
+
 /**
  * i40iw_alloc_hw_stats - Allocate a hw stats structure
  * @ibdev: device pointer from stack
@@ -2528,7 +2539,7 @@ static int i40iw_modify_port(struct ib_device *ibdev,
                             int port_modify_mask,
                             struct ib_port_modify *props)
 {
-       return 0;
+       return -ENOSYS;
 }
 
 /**
@@ -2660,6 +2671,7 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev
        memcpy(iwibdev->ibdev.iwcm->ifname, netdev->name,
               sizeof(iwibdev->ibdev.iwcm->ifname));
        iwibdev->ibdev.get_port_immutable   = i40iw_port_immutable;
+       iwibdev->ibdev.get_dev_fw_str       = i40iw_get_dev_fw_str;
        iwibdev->ibdev.poll_cq = i40iw_poll_cq;
        iwibdev->ibdev.req_notify_cq = i40iw_req_notify_cq;
        iwibdev->ibdev.post_send = i40iw_post_send;
@@ -2723,7 +2735,7 @@ int i40iw_register_rdma_device(struct i40iw_device *iwdev)
 
        iwdev->iwibdev = i40iw_init_rdma_device(iwdev);
        if (!iwdev->iwibdev)
-               return -ENOSYS;
+               return -ENOMEM;
        iwibdev = iwdev->iwibdev;
 
        ret = ib_register_device(&iwibdev->ibdev, NULL);
@@ -2748,5 +2760,5 @@ error:
        kfree(iwdev->iwibdev->ibdev.iwcm);
        iwdev->iwibdev->ibdev.iwcm = NULL;
        ib_dealloc_device(&iwdev->iwibdev->ibdev);
-       return -ENOSYS;
+       return ret;
 }
index 9f8b516..d6fc8a6 100644 (file)
@@ -288,7 +288,7 @@ static int mlx4_alloc_resize_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq,
        if (cq->resize_buf)
                return -EBUSY;
 
-       cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+       cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_KERNEL);
        if (!cq->resize_buf)
                return -ENOMEM;
 
@@ -316,7 +316,7 @@ static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq
        if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
                return -EFAULT;
 
-       cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
+       cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_KERNEL);
        if (!cq->resize_buf)
                return -ENOMEM;
 
index 42a4607..2af44c2 100644 (file)
@@ -2025,16 +2025,6 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr,
        return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device);
 }
 
-static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
-                          char *buf)
-{
-       struct mlx4_ib_dev *dev =
-               container_of(device, struct mlx4_ib_dev, ib_dev.dev);
-       return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32),
-                      (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
-                      (int) dev->dev->caps.fw_ver & 0xffff);
-}
-
 static ssize_t show_rev(struct device *device, struct device_attribute *attr,
                        char *buf)
 {
@@ -2053,17 +2043,204 @@ static ssize_t show_board(struct device *device, struct device_attribute *attr,
 }
 
 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 struct device_attribute *mlx4_class_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id
 };
 
+struct diag_counter {
+       const char *name;
+       u32 offset;
+};
+
+#define DIAG_COUNTER(_name, _offset)                   \
+       { .name = #_name, .offset = _offset }
+
+static const struct diag_counter diag_basic[] = {
+       DIAG_COUNTER(rq_num_lle, 0x00),
+       DIAG_COUNTER(sq_num_lle, 0x04),
+       DIAG_COUNTER(rq_num_lqpoe, 0x08),
+       DIAG_COUNTER(sq_num_lqpoe, 0x0C),
+       DIAG_COUNTER(rq_num_lpe, 0x18),
+       DIAG_COUNTER(sq_num_lpe, 0x1C),
+       DIAG_COUNTER(rq_num_wrfe, 0x20),
+       DIAG_COUNTER(sq_num_wrfe, 0x24),
+       DIAG_COUNTER(sq_num_mwbe, 0x2C),
+       DIAG_COUNTER(sq_num_bre, 0x34),
+       DIAG_COUNTER(sq_num_rire, 0x44),
+       DIAG_COUNTER(rq_num_rire, 0x48),
+       DIAG_COUNTER(sq_num_rae, 0x4C),
+       DIAG_COUNTER(rq_num_rae, 0x50),
+       DIAG_COUNTER(sq_num_roe, 0x54),
+       DIAG_COUNTER(sq_num_tree, 0x5C),
+       DIAG_COUNTER(sq_num_rree, 0x64),
+       DIAG_COUNTER(rq_num_rnr, 0x68),
+       DIAG_COUNTER(sq_num_rnr, 0x6C),
+       DIAG_COUNTER(rq_num_oos, 0x100),
+       DIAG_COUNTER(sq_num_oos, 0x104),
+};
+
+static const struct diag_counter diag_ext[] = {
+       DIAG_COUNTER(rq_num_dup, 0x130),
+       DIAG_COUNTER(sq_num_to, 0x134),
+};
+
+static const struct diag_counter diag_device_only[] = {
+       DIAG_COUNTER(num_cqovf, 0x1A0),
+       DIAG_COUNTER(rq_num_udsdprd, 0x118),
+};
+
+static struct rdma_hw_stats *mlx4_ib_alloc_hw_stats(struct ib_device *ibdev,
+                                                   u8 port_num)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+       struct mlx4_ib_diag_counters *diag = dev->diag_counters;
+
+       if (!diag[!!port_num].name)
+               return NULL;
+
+       return rdma_alloc_hw_stats_struct(diag[!!port_num].name,
+                                         diag[!!port_num].num_counters,
+                                         RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static int mlx4_ib_get_hw_stats(struct ib_device *ibdev,
+                               struct rdma_hw_stats *stats,
+                               u8 port, int index)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+       struct mlx4_ib_diag_counters *diag = dev->diag_counters;
+       u32 hw_value[ARRAY_SIZE(diag_device_only) +
+               ARRAY_SIZE(diag_ext) + ARRAY_SIZE(diag_basic)] = {};
+       int ret;
+       int i;
+
+       ret = mlx4_query_diag_counters(dev->dev,
+                                      MLX4_OP_MOD_QUERY_TRANSPORT_CI_ERRORS,
+                                      diag[!!port].offset, hw_value,
+                                      diag[!!port].num_counters, port);
+
+       if (ret)
+               return ret;
+
+       for (i = 0; i < diag[!!port].num_counters; i++)
+               stats->value[i] = hw_value[i];
+
+       return diag[!!port].num_counters;
+}
+
+static int __mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev,
+                                        const char ***name,
+                                        u32 **offset,
+                                        u32 *num,
+                                        bool port)
+{
+       u32 num_counters;
+
+       num_counters = ARRAY_SIZE(diag_basic);
+
+       if (ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT)
+               num_counters += ARRAY_SIZE(diag_ext);
+
+       if (!port)
+               num_counters += ARRAY_SIZE(diag_device_only);
+
+       *name = kcalloc(num_counters, sizeof(**name), GFP_KERNEL);
+       if (!*name)
+               return -ENOMEM;
+
+       *offset = kcalloc(num_counters, sizeof(**offset), GFP_KERNEL);
+       if (!*offset)
+               goto err_name;
+
+       *num = num_counters;
+
+       return 0;
+
+err_name:
+       kfree(*name);
+       return -ENOMEM;
+}
+
+static void mlx4_ib_fill_diag_counters(struct mlx4_ib_dev *ibdev,
+                                      const char **name,
+                                      u32 *offset,
+                                      bool port)
+{
+       int i;
+       int j;
+
+       for (i = 0, j = 0; i < ARRAY_SIZE(diag_basic); i++, j++) {
+               name[i] = diag_basic[i].name;
+               offset[i] = diag_basic[i].offset;
+       }
+
+       if (ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT) {
+               for (i = 0; i < ARRAY_SIZE(diag_ext); i++, j++) {
+                       name[j] = diag_ext[i].name;
+                       offset[j] = diag_ext[i].offset;
+               }
+       }
+
+       if (!port) {
+               for (i = 0; i < ARRAY_SIZE(diag_device_only); i++, j++) {
+                       name[j] = diag_device_only[i].name;
+                       offset[j] = diag_device_only[i].offset;
+               }
+       }
+}
+
+static int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev)
+{
+       struct mlx4_ib_diag_counters *diag = ibdev->diag_counters;
+       int i;
+       int ret;
+       bool per_port = !!(ibdev->dev->caps.flags2 &
+               MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT);
+
+       for (i = 0; i < MLX4_DIAG_COUNTERS_TYPES; i++) {
+               /* i == 1 means we are building port counters */
+               if (i && !per_port)
+                       continue;
+
+               ret = __mlx4_ib_alloc_diag_counters(ibdev, &diag[i].name,
+                                                   &diag[i].offset,
+                                                   &diag[i].num_counters, i);
+               if (ret)
+                       goto err_alloc;
+
+               mlx4_ib_fill_diag_counters(ibdev, diag[i].name,
+                                          diag[i].offset, i);
+       }
+
+       ibdev->ib_dev.get_hw_stats      = mlx4_ib_get_hw_stats;
+       ibdev->ib_dev.alloc_hw_stats    = mlx4_ib_alloc_hw_stats;
+
+       return 0;
+
+err_alloc:
+       if (i) {
+               kfree(diag[i - 1].name);
+               kfree(diag[i - 1].offset);
+       }
+
+       return ret;
+}
+
+static void mlx4_ib_diag_cleanup(struct mlx4_ib_dev *ibdev)
+{
+       int i;
+
+       for (i = 0; i < MLX4_DIAG_COUNTERS_TYPES; i++) {
+               kfree(ibdev->diag_counters[i].offset);
+               kfree(ibdev->diag_counters[i].name);
+       }
+}
+
 #define MLX4_IB_INVALID_MAC    ((u64)-1)
 static void mlx4_ib_update_qps(struct mlx4_ib_dev *ibdev,
                               struct net_device *dev,
@@ -2280,6 +2457,17 @@ static int mlx4_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_fw_ver_str(struct ib_device *device, char *str,
+                          size_t str_len)
+{
+       struct mlx4_ib_dev *dev =
+               container_of(device, struct mlx4_ib_dev, ib_dev);
+       snprintf(str, str_len, "%d.%d.%d",
+                (int) (dev->dev->caps.fw_ver >> 32),
+                (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
+                (int) dev->dev->caps.fw_ver & 0xffff);
+}
+
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
        struct mlx4_ib_dev *ibdev;
@@ -2413,6 +2601,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        ibdev->ib_dev.detach_mcast      = mlx4_ib_mcg_detach;
        ibdev->ib_dev.process_mad       = mlx4_ib_process_mad;
        ibdev->ib_dev.get_port_immutable = mlx4_port_immutable;
+       ibdev->ib_dev.get_dev_fw_str    = get_fw_ver_str;
        ibdev->ib_dev.disassociate_ucontext = mlx4_ib_disassociate_ucontext;
 
        if (!mlx4_is_slave(ibdev->dev)) {
@@ -2555,9 +2744,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
                atomic64_set(&iboe->mac[j - 1], ibdev->dev->caps.def_mac[j]);
 
-       if (ib_register_device(&ibdev->ib_dev, NULL))
+       if (mlx4_ib_alloc_diag_counters(ibdev))
                goto err_steer_free_bitmap;
 
+       if (ib_register_device(&ibdev->ib_dev, NULL))
+               goto err_diag_counters;
+
        if (mlx4_ib_mad_init(ibdev))
                goto err_reg;
 
@@ -2623,6 +2815,9 @@ err_mad:
 err_reg:
        ib_unregister_device(&ibdev->ib_dev);
 
+err_diag_counters:
+       mlx4_ib_diag_cleanup(ibdev);
+
 err_steer_free_bitmap:
        kfree(ibdev->ib_uc_qpns_bitmap);
 
@@ -2726,6 +2921,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
        mlx4_ib_close_sriov(ibdev);
        mlx4_ib_mad_cleanup(ibdev);
        ib_unregister_device(&ibdev->ib_dev);
+       mlx4_ib_diag_cleanup(ibdev);
        if (ibdev->iboe.nb.notifier_call) {
                if (unregister_netdevice_notifier(&ibdev->iboe.nb))
                        pr_warn("failure unregistering notifier\n");
index 29acda2..7c5832e 100644 (file)
@@ -549,6 +549,14 @@ struct mlx4_ib_counters {
        u32                     default_counter;
 };
 
+#define MLX4_DIAG_COUNTERS_TYPES 2
+
+struct mlx4_ib_diag_counters {
+       const char **name;
+       u32 *offset;
+       u32 num_counters;
+};
+
 struct mlx4_ib_dev {
        struct ib_device        ib_dev;
        struct mlx4_dev        *dev;
@@ -585,6 +593,7 @@ struct mlx4_ib_dev {
        /* protect resources needed as part of reset flow */
        spinlock_t              reset_flow_resource_lock;
        struct list_head                qp_list;
+       struct mlx4_ib_diag_counters diag_counters[MLX4_DIAG_COUNTERS_TYPES];
 };
 
 struct ib_event_work {
index 9c0e67b..308a358 100644 (file)
@@ -424,6 +424,83 @@ static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe,
        item->key = be32_to_cpu(cqe->mkey);
 }
 
+static void sw_send_comp(struct mlx5_ib_qp *qp, int num_entries,
+                        struct ib_wc *wc, int *npolled)
+{
+       struct mlx5_ib_wq *wq;
+       unsigned int cur;
+       unsigned int idx;
+       int np;
+       int i;
+
+       wq = &qp->sq;
+       cur = wq->head - wq->tail;
+       np = *npolled;
+
+       if (cur == 0)
+               return;
+
+       for (i = 0;  i < cur && np < num_entries; i++) {
+               idx = wq->last_poll & (wq->wqe_cnt - 1);
+               wc->wr_id = wq->wrid[idx];
+               wc->status = IB_WC_WR_FLUSH_ERR;
+               wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
+               wq->tail++;
+               np++;
+               wc->qp = &qp->ibqp;
+               wc++;
+               wq->last_poll = wq->w_list[idx].next;
+       }
+       *npolled = np;
+}
+
+static void sw_recv_comp(struct mlx5_ib_qp *qp, int num_entries,
+                        struct ib_wc *wc, int *npolled)
+{
+       struct mlx5_ib_wq *wq;
+       unsigned int cur;
+       int np;
+       int i;
+
+       wq = &qp->rq;
+       cur = wq->head - wq->tail;
+       np = *npolled;
+
+       if (cur == 0)
+               return;
+
+       for (i = 0;  i < cur && np < num_entries; i++) {
+               wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+               wc->status = IB_WC_WR_FLUSH_ERR;
+               wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
+               wq->tail++;
+               np++;
+               wc->qp = &qp->ibqp;
+               wc++;
+       }
+       *npolled = np;
+}
+
+static void mlx5_ib_poll_sw_comp(struct mlx5_ib_cq *cq, int num_entries,
+                                struct ib_wc *wc, int *npolled)
+{
+       struct mlx5_ib_qp *qp;
+
+       *npolled = 0;
+       /* Find uncompleted WQEs belonging to that cq and retrun mmics ones */
+       list_for_each_entry(qp, &cq->list_send_qp, cq_send_list) {
+               sw_send_comp(qp, num_entries, wc + *npolled, npolled);
+               if (*npolled >= num_entries)
+                       return;
+       }
+
+       list_for_each_entry(qp, &cq->list_recv_qp, cq_recv_list) {
+               sw_recv_comp(qp, num_entries, wc + *npolled, npolled);
+               if (*npolled >= num_entries)
+                       return;
+       }
+}
+
 static int mlx5_poll_one(struct mlx5_ib_cq *cq,
                         struct mlx5_ib_qp **cur_qp,
                         struct ib_wc *wc)
@@ -594,12 +671,18 @@ 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;
+       struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
+       struct mlx5_core_dev *mdev = dev->mdev;
        unsigned long flags;
        int soft_polled = 0;
        int npolled;
        int err = 0;
 
        spin_lock_irqsave(&cq->lock, flags);
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               mlx5_ib_poll_sw_comp(cq, num_entries, wc, &npolled);
+               goto out;
+       }
 
        if (unlikely(!list_empty(&cq->wc_list)))
                soft_polled = poll_soft_wc(cq, num_entries, wc);
@@ -612,7 +695,7 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
 
        if (npolled)
                mlx5_cq_set_ci(&cq->mcq);
-
+out:
        spin_unlock_irqrestore(&cq->lock, flags);
 
        if (err == 0 || err == -EAGAIN)
@@ -843,6 +926,8 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
        cq->resize_buf = NULL;
        cq->resize_umem = NULL;
        cq->create_flags = attr->flags;
+       INIT_LIST_HEAD(&cq->list_send_qp);
+       INIT_LIST_HEAD(&cq->list_recv_qp);
 
        if (context) {
                err = create_cq_user(dev, udata, context, cq, entries,
index 53e03c8..79e6309 100644 (file)
@@ -69,15 +69,6 @@ static bool mlx5_ib_deth_sqpn_cap(struct mlx5_ib_dev *dev)
        return MLX5_CAP_GEN(dev->mdev, set_deth_sqpn);
 }
 
-static u32 next_outstanding(struct mlx5_ib_gsi_qp *gsi, u32 index)
-{
-       return ++index % gsi->cap.max_send_wr;
-}
-
-#define for_each_outstanding_wr(gsi, index) \
-       for (index = gsi->outstanding_ci; index != gsi->outstanding_pi; \
-            index = next_outstanding(gsi, index))
-
 /* Call with gsi->lock locked */
 static void generate_completions(struct mlx5_ib_gsi_qp *gsi)
 {
@@ -85,8 +76,9 @@ static void generate_completions(struct mlx5_ib_gsi_qp *gsi)
        struct mlx5_ib_gsi_wr *wr;
        u32 index;
 
-       for_each_outstanding_wr(gsi, index) {
-               wr = &gsi->outstanding_wrs[index];
+       for (index = gsi->outstanding_ci; index != gsi->outstanding_pi;
+            index++) {
+               wr = &gsi->outstanding_wrs[index % gsi->cap.max_send_wr];
 
                if (!wr->completed)
                        break;
@@ -430,8 +422,9 @@ static int mlx5_ib_add_outstanding_wr(struct mlx5_ib_gsi_qp *gsi,
                return -ENOMEM;
        }
 
-       gsi_wr = &gsi->outstanding_wrs[gsi->outstanding_pi];
-       gsi->outstanding_pi = next_outstanding(gsi, gsi->outstanding_pi);
+       gsi_wr = &gsi->outstanding_wrs[gsi->outstanding_pi %
+                                      gsi->cap.max_send_wr];
+       gsi->outstanding_pi++;
 
        if (!wc) {
                memset(&gsi_wr->wc, 0, sizeof(gsi_wr->wc));
index dad63f0..a84bb76 100644 (file)
 #include <asm/pat.h>
 #endif
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <rdma/ib_user_verbs.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_cache.h>
 #include <linux/mlx5/port.h>
 #include <linux/mlx5/vport.h>
+#include <linux/list.h>
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
 #include <linux/in.h>
@@ -457,8 +459,17 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        int max_rq_sg;
        int max_sq_sg;
        u64 min_page_size = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz);
+       struct mlx5_ib_query_device_resp resp = {};
+       size_t resp_len;
+       u64 max_tso;
 
-       if (uhw->inlen || uhw->outlen)
+       resp_len = sizeof(resp.comp_mask) + sizeof(resp.response_length);
+       if (uhw->outlen && uhw->outlen < resp_len)
+               return -EINVAL;
+       else
+               resp.response_length = resp_len;
+
+       if (uhw->inlen && !ib_is_udata_cleared(uhw, 0, uhw->inlen))
                return -EINVAL;
 
        memset(props, 0, sizeof(*props));
@@ -511,10 +522,21 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        if (MLX5_CAP_GEN(mdev, block_lb_mc))
                props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
 
-       if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads) &&
-           (MLX5_CAP_ETH(dev->mdev, csum_cap)))
+       if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads)) {
+               if (MLX5_CAP_ETH(mdev, csum_cap))
                        props->device_cap_flags |= IB_DEVICE_RAW_IP_CSUM;
 
+               if (field_avail(typeof(resp), tso_caps, uhw->outlen)) {
+                       max_tso = MLX5_CAP_ETH(mdev, max_lso_cap);
+                       if (max_tso) {
+                               resp.tso_caps.max_tso = 1 << max_tso;
+                               resp.tso_caps.supported_qpts |=
+                                       1 << IB_QPT_RAW_PACKET;
+                               resp.response_length += sizeof(resp.tso_caps);
+                       }
+               }
+       }
+
        if (MLX5_CAP_GEN(mdev, ipoib_basic_offloads)) {
                props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM;
                props->device_cap_flags |= IB_DEVICE_UD_TSO;
@@ -576,6 +598,13 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        if (!mlx5_core_is_pf(mdev))
                props->device_cap_flags |= IB_DEVICE_VIRTUAL_FUNCTION;
 
+       if (uhw->outlen) {
+               err = ib_copy_to_udata(uhw, &resp, resp.response_length);
+
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -983,6 +1012,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
                        goto out_uars;
        }
 
+       INIT_LIST_HEAD(&context->vma_private_list);
        INIT_LIST_HEAD(&context->db_page_list);
        mutex_init(&context->db_page_mutex);
 
@@ -992,6 +1022,11 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        if (field_avail(typeof(resp), cqe_version, udata->outlen))
                resp.response_length += sizeof(resp.cqe_version);
 
+       if (field_avail(typeof(resp), cmds_supp_uhw, udata->outlen)) {
+               resp.cmds_supp_uhw |= MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE;
+               resp.response_length += sizeof(resp.cmds_supp_uhw);
+       }
+
        /*
         * We don't want to expose information from the PCI bar that is located
         * after 4096 bytes, so if the arch only supports larger pages, let's
@@ -1006,8 +1041,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
                        offsetof(struct mlx5_init_seg, internal_timer_h) %
                        PAGE_SIZE;
                resp.response_length += sizeof(resp.hca_core_clock_offset) +
-                                       sizeof(resp.reserved2) +
-                                       sizeof(resp.reserved3);
+                                       sizeof(resp.reserved2);
        }
 
        err = ib_copy_to_udata(udata, &resp, resp.response_length);
@@ -1086,6 +1120,125 @@ static int get_index(unsigned long offset)
        return get_arg(offset);
 }
 
+static void  mlx5_ib_vma_open(struct vm_area_struct *area)
+{
+       /* vma_open is called when a new VMA is created on top of our VMA.  This
+        * is done through either mremap flow or split_vma (usually due to
+        * mlock, madvise, munmap, etc.) We do not support a clone of the VMA,
+        * as this VMA is strongly hardware related.  Therefore we set the
+        * vm_ops of the newly created/cloned VMA to NULL, to prevent it from
+        * calling us again and trying to do incorrect actions.  We assume that
+        * the original VMA size is exactly a single page, and therefore all
+        * "splitting" operation will not happen to it.
+        */
+       area->vm_ops = NULL;
+}
+
+static void  mlx5_ib_vma_close(struct vm_area_struct *area)
+{
+       struct mlx5_ib_vma_private_data *mlx5_ib_vma_priv_data;
+
+       /* It's guaranteed that all VMAs opened on a FD are closed before the
+        * file itself is closed, therefore no sync is needed with the regular
+        * closing flow. (e.g. mlx5 ib_dealloc_ucontext)
+        * However need a sync with accessing the vma as part of
+        * mlx5_ib_disassociate_ucontext.
+        * The close operation is usually called under mm->mmap_sem except when
+        * process is exiting.
+        * The exiting case is handled explicitly as part of
+        * mlx5_ib_disassociate_ucontext.
+        */
+       mlx5_ib_vma_priv_data = (struct mlx5_ib_vma_private_data *)area->vm_private_data;
+
+       /* setting the vma context pointer to null in the mlx5_ib driver's
+        * private data, to protect a race condition in
+        * mlx5_ib_disassociate_ucontext().
+        */
+       mlx5_ib_vma_priv_data->vma = NULL;
+       list_del(&mlx5_ib_vma_priv_data->list);
+       kfree(mlx5_ib_vma_priv_data);
+}
+
+static const struct vm_operations_struct mlx5_ib_vm_ops = {
+       .open = mlx5_ib_vma_open,
+       .close = mlx5_ib_vma_close
+};
+
+static int mlx5_ib_set_vma_data(struct vm_area_struct *vma,
+                               struct mlx5_ib_ucontext *ctx)
+{
+       struct mlx5_ib_vma_private_data *vma_prv;
+       struct list_head *vma_head = &ctx->vma_private_list;
+
+       vma_prv = kzalloc(sizeof(*vma_prv), GFP_KERNEL);
+       if (!vma_prv)
+               return -ENOMEM;
+
+       vma_prv->vma = vma;
+       vma->vm_private_data = vma_prv;
+       vma->vm_ops =  &mlx5_ib_vm_ops;
+
+       list_add(&vma_prv->list, vma_head);
+
+       return 0;
+}
+
+static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
+{
+       int ret;
+       struct vm_area_struct *vma;
+       struct mlx5_ib_vma_private_data *vma_private, *n;
+       struct mlx5_ib_ucontext *context = to_mucontext(ibcontext);
+       struct task_struct *owning_process  = NULL;
+       struct mm_struct   *owning_mm       = NULL;
+
+       owning_process = get_pid_task(ibcontext->tgid, PIDTYPE_PID);
+       if (!owning_process)
+               return;
+
+       owning_mm = get_task_mm(owning_process);
+       if (!owning_mm) {
+               pr_info("no mm, disassociate ucontext is pending task termination\n");
+               while (1) {
+                       put_task_struct(owning_process);
+                       usleep_range(1000, 2000);
+                       owning_process = get_pid_task(ibcontext->tgid,
+                                                     PIDTYPE_PID);
+                       if (!owning_process ||
+                           owning_process->state == TASK_DEAD) {
+                               pr_info("disassociate ucontext done, task was terminated\n");
+                               /* in case task was dead need to release the
+                                * task struct.
+                                */
+                               if (owning_process)
+                                       put_task_struct(owning_process);
+                               return;
+                       }
+               }
+       }
+
+       /* need to protect from a race on closing the vma as part of
+        * mlx5_ib_vma_close.
+        */
+       down_read(&owning_mm->mmap_sem);
+       list_for_each_entry_safe(vma_private, n, &context->vma_private_list,
+                                list) {
+               vma = vma_private->vma;
+               ret = zap_vma_ptes(vma, vma->vm_start,
+                                  PAGE_SIZE);
+               WARN_ONCE(ret, "%s: zap_vma_ptes failed", __func__);
+               /* context going to be destroyed, should
+                * not access ops any more.
+                */
+               vma->vm_ops = NULL;
+               list_del(&vma_private->list);
+               kfree(vma_private);
+       }
+       up_read(&owning_mm->mmap_sem);
+       mmput(owning_mm);
+       put_task_struct(owning_process);
+}
+
 static inline char *mmap_cmd2str(enum mlx5_ib_mmap_cmd cmd)
 {
        switch (cmd) {
@@ -1101,8 +1254,10 @@ static inline char *mmap_cmd2str(enum mlx5_ib_mmap_cmd cmd)
 }
 
 static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,
-                   struct vm_area_struct *vma, struct mlx5_uuar_info *uuari)
+                   struct vm_area_struct *vma,
+                   struct mlx5_ib_ucontext *context)
 {
+       struct mlx5_uuar_info *uuari = &context->uuari;
        int err;
        unsigned long idx;
        phys_addr_t pfn, pa;
@@ -1152,14 +1307,13 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,
        mlx5_ib_dbg(dev, "mapped %s at 0x%lx, PA %pa\n", mmap_cmd2str(cmd),
                    vma->vm_start, &pa);
 
-       return 0;
+       return mlx5_ib_set_vma_data(vma, context);
 }
 
 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;
        phys_addr_t pfn;
 
@@ -1168,7 +1322,7 @@ static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vm
        case MLX5_IB_MMAP_WC_PAGE:
        case MLX5_IB_MMAP_NC_PAGE:
        case MLX5_IB_MMAP_REGULAR_PAGE:
-               return uar_mmap(dev, command, vma, uuari);
+               return uar_mmap(dev, command, vma, context);
 
        case MLX5_IB_MMAP_GET_CONTIGUOUS_PAGES:
                return -ENOSYS;
@@ -1331,6 +1485,32 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v,
                       &ib_spec->ipv4.val.dst_ip,
                       sizeof(ib_spec->ipv4.val.dst_ip));
                break;
+       case IB_FLOW_SPEC_IPV6:
+               if (ib_spec->size != sizeof(ib_spec->ipv6))
+                       return -EINVAL;
+
+               MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c,
+                        ethertype, 0xffff);
+               MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v,
+                        ethertype, ETH_P_IPV6);
+
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
+                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                      &ib_spec->ipv6.mask.src_ip,
+                      sizeof(ib_spec->ipv6.mask.src_ip));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v,
+                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                      &ib_spec->ipv6.val.src_ip,
+                      sizeof(ib_spec->ipv6.val.src_ip));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c,
+                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                      &ib_spec->ipv6.mask.dst_ip,
+                      sizeof(ib_spec->ipv6.mask.dst_ip));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v,
+                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                      &ib_spec->ipv6.val.dst_ip,
+                      sizeof(ib_spec->ipv6.val.dst_ip));
+               break;
        case IB_FLOW_SPEC_TCP:
                if (ib_spec->size != sizeof(ib_spec->tcp_udp))
                        return -EINVAL;
@@ -1801,15 +1981,6 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr,
        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.%04d\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)
 {
@@ -1828,7 +1999,6 @@ static ssize_t show_board(struct device *device, struct device_attribute *attr,
 }
 
 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);
@@ -1836,7 +2006,6 @@ 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,
@@ -1854,6 +2023,65 @@ static void pkey_change_handler(struct work_struct *work)
        mutex_unlock(&ports->devr->mutex);
 }
 
+static void mlx5_ib_handle_internal_error(struct mlx5_ib_dev *ibdev)
+{
+       struct mlx5_ib_qp *mqp;
+       struct mlx5_ib_cq *send_mcq, *recv_mcq;
+       struct mlx5_core_cq *mcq;
+       struct list_head cq_armed_list;
+       unsigned long flags_qp;
+       unsigned long flags_cq;
+       unsigned long flags;
+
+       INIT_LIST_HEAD(&cq_armed_list);
+
+       /* Go over qp list reside on that ibdev, sync with create/destroy qp.*/
+       spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags);
+       list_for_each_entry(mqp, &ibdev->qp_list, qps_list) {
+               spin_lock_irqsave(&mqp->sq.lock, flags_qp);
+               if (mqp->sq.tail != mqp->sq.head) {
+                       send_mcq = to_mcq(mqp->ibqp.send_cq);
+                       spin_lock_irqsave(&send_mcq->lock, flags_cq);
+                       if (send_mcq->mcq.comp &&
+                           mqp->ibqp.send_cq->comp_handler) {
+                               if (!send_mcq->mcq.reset_notify_added) {
+                                       send_mcq->mcq.reset_notify_added = 1;
+                                       list_add_tail(&send_mcq->mcq.reset_notify,
+                                                     &cq_armed_list);
+                               }
+                       }
+                       spin_unlock_irqrestore(&send_mcq->lock, flags_cq);
+               }
+               spin_unlock_irqrestore(&mqp->sq.lock, flags_qp);
+               spin_lock_irqsave(&mqp->rq.lock, flags_qp);
+               /* no handling is needed for SRQ */
+               if (!mqp->ibqp.srq) {
+                       if (mqp->rq.tail != mqp->rq.head) {
+                               recv_mcq = to_mcq(mqp->ibqp.recv_cq);
+                               spin_lock_irqsave(&recv_mcq->lock, flags_cq);
+                               if (recv_mcq->mcq.comp &&
+                                   mqp->ibqp.recv_cq->comp_handler) {
+                                       if (!recv_mcq->mcq.reset_notify_added) {
+                                               recv_mcq->mcq.reset_notify_added = 1;
+                                               list_add_tail(&recv_mcq->mcq.reset_notify,
+                                                             &cq_armed_list);
+                                       }
+                               }
+                               spin_unlock_irqrestore(&recv_mcq->lock,
+                                                      flags_cq);
+                       }
+               }
+               spin_unlock_irqrestore(&mqp->rq.lock, flags_qp);
+       }
+       /*At that point all inflight post send were put to be executed as of we
+        * lock/unlock above locks Now need to arm all involved CQs.
+        */
+       list_for_each_entry(mcq, &cq_armed_list, reset_notify) {
+               mcq->comp(mcq);
+       }
+       spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags);
+}
+
 static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
                          enum mlx5_dev_event event, unsigned long param)
 {
@@ -1866,6 +2094,7 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
        case MLX5_DEV_EVENT_SYS_ERROR:
                ibdev->ib_active = false;
                ibev.event = IB_EVENT_DEVICE_FATAL;
+               mlx5_ib_handle_internal_error(ibdev);
                break;
 
        case MLX5_DEV_EVENT_PORT_UP:
@@ -2272,6 +2501,15 @@ static int mlx5_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_str(struct ib_device *ibdev, char *str,
+                          size_t str_len)
+{
+       struct mlx5_ib_dev *dev =
+               container_of(ibdev, struct mlx5_ib_dev, ib_dev);
+       snprintf(str, str_len, "%d.%d.%04d", fw_rev_maj(dev->mdev),
+                      fw_rev_min(dev->mdev), fw_rev_sub(dev->mdev));
+}
+
 static int mlx5_enable_roce(struct mlx5_ib_dev *dev)
 {
        int err;
@@ -2298,6 +2536,113 @@ static void mlx5_disable_roce(struct mlx5_ib_dev *dev)
        unregister_netdevice_notifier(&dev->roce.nb);
 }
 
+static void mlx5_ib_dealloc_q_counters(struct mlx5_ib_dev *dev)
+{
+       unsigned int i;
+
+       for (i = 0; i < dev->num_ports; i++)
+               mlx5_core_dealloc_q_counter(dev->mdev,
+                                           dev->port[i].q_cnt_id);
+}
+
+static int mlx5_ib_alloc_q_counters(struct mlx5_ib_dev *dev)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < dev->num_ports; i++) {
+               ret = mlx5_core_alloc_q_counter(dev->mdev,
+                                               &dev->port[i].q_cnt_id);
+               if (ret) {
+                       mlx5_ib_warn(dev,
+                                    "couldn't allocate queue counter for port %d, err %d\n",
+                                    i + 1, ret);
+                       goto dealloc_counters;
+               }
+       }
+
+       return 0;
+
+dealloc_counters:
+       while (--i >= 0)
+               mlx5_core_dealloc_q_counter(dev->mdev,
+                                           dev->port[i].q_cnt_id);
+
+       return ret;
+}
+
+static const char * const names[] = {
+       "rx_write_requests",
+       "rx_read_requests",
+       "rx_atomic_requests",
+       "out_of_buffer",
+       "out_of_sequence",
+       "duplicate_request",
+       "rnr_nak_retry_err",
+       "packet_seq_err",
+       "implied_nak_seq_err",
+       "local_ack_timeout_err",
+};
+
+static const size_t stats_offsets[] = {
+       MLX5_BYTE_OFF(query_q_counter_out, rx_write_requests),
+       MLX5_BYTE_OFF(query_q_counter_out, rx_read_requests),
+       MLX5_BYTE_OFF(query_q_counter_out, rx_atomic_requests),
+       MLX5_BYTE_OFF(query_q_counter_out, out_of_buffer),
+       MLX5_BYTE_OFF(query_q_counter_out, out_of_sequence),
+       MLX5_BYTE_OFF(query_q_counter_out, duplicate_request),
+       MLX5_BYTE_OFF(query_q_counter_out, rnr_nak_retry_err),
+       MLX5_BYTE_OFF(query_q_counter_out, packet_seq_err),
+       MLX5_BYTE_OFF(query_q_counter_out, implied_nak_seq_err),
+       MLX5_BYTE_OFF(query_q_counter_out, local_ack_timeout_err),
+};
+
+static struct rdma_hw_stats *mlx5_ib_alloc_hw_stats(struct ib_device *ibdev,
+                                                   u8 port_num)
+{
+       BUILD_BUG_ON(ARRAY_SIZE(names) != ARRAY_SIZE(stats_offsets));
+
+       /* We support only per port stats */
+       if (port_num == 0)
+               return NULL;
+
+       return rdma_alloc_hw_stats_struct(names, ARRAY_SIZE(names),
+                                         RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static int mlx5_ib_get_hw_stats(struct ib_device *ibdev,
+                               struct rdma_hw_stats *stats,
+                               u8 port, int index)
+{
+       struct mlx5_ib_dev *dev = to_mdev(ibdev);
+       int outlen = MLX5_ST_SZ_BYTES(query_q_counter_out);
+       void *out;
+       __be32 val;
+       int ret;
+       int i;
+
+       if (!port || !stats)
+               return -ENOSYS;
+
+       out = mlx5_vzalloc(outlen);
+       if (!out)
+               return -ENOMEM;
+
+       ret = mlx5_core_query_q_counter(dev->mdev,
+                                       dev->port[port - 1].q_cnt_id, 0,
+                                       out, outlen);
+       if (ret)
+               goto free;
+
+       for (i = 0; i < ARRAY_SIZE(names); i++) {
+               val = *(__be32 *)(out + stats_offsets[i]);
+               stats->value[i] = (u64)be32_to_cpu(val);
+       }
+free:
+       kvfree(out);
+       return ARRAY_SIZE(names);
+}
+
 static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 {
        struct mlx5_ib_dev *dev;
@@ -2320,10 +2665,15 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 
        dev->mdev = mdev;
 
+       dev->port = kcalloc(MLX5_CAP_GEN(mdev, num_ports), sizeof(*dev->port),
+                           GFP_KERNEL);
+       if (!dev->port)
+               goto err_dealloc;
+
        rwlock_init(&dev->roce.netdev_lock);
        err = get_port_caps(dev);
        if (err)
-               goto err_dealloc;
+               goto err_free_port;
 
        if (mlx5_use_mad_ifc(dev))
                get_ext_port_caps(dev);
@@ -2418,6 +2768,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
        dev->ib_dev.map_mr_sg           = mlx5_ib_map_mr_sg;
        dev->ib_dev.check_mr_status     = mlx5_ib_check_mr_status;
        dev->ib_dev.get_port_immutable  = mlx5_port_immutable;
+       dev->ib_dev.get_dev_fw_str      = get_dev_fw_str;
        if (mlx5_core_is_pf(mdev)) {
                dev->ib_dev.get_vf_config       = mlx5_ib_get_vf_config;
                dev->ib_dev.set_vf_link_state   = mlx5_ib_set_vf_link_state;
@@ -2425,6 +2776,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
                dev->ib_dev.set_vf_guid         = mlx5_ib_set_vf_guid;
        }
 
+       dev->ib_dev.disassociate_ucontext = mlx5_ib_disassociate_ucontext;
+
        mlx5_ib_internal_fill_odp_caps(dev);
 
        if (MLX5_CAP_GEN(mdev, imaicl)) {
@@ -2435,6 +2788,12 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
                        (1ull << IB_USER_VERBS_CMD_DEALLOC_MW);
        }
 
+       if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt) &&
+           MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) {
+               dev->ib_dev.get_hw_stats        = mlx5_ib_get_hw_stats;
+               dev->ib_dev.alloc_hw_stats      = mlx5_ib_alloc_hw_stats;
+       }
+
        if (MLX5_CAP_GEN(mdev, xrc)) {
                dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
                dev->ib_dev.dealloc_xrcd = mlx5_ib_dealloc_xrcd;
@@ -2447,9 +2806,19 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
            IB_LINK_LAYER_ETHERNET) {
                dev->ib_dev.create_flow = mlx5_ib_create_flow;
                dev->ib_dev.destroy_flow = mlx5_ib_destroy_flow;
+               dev->ib_dev.create_wq    = mlx5_ib_create_wq;
+               dev->ib_dev.modify_wq    = mlx5_ib_modify_wq;
+               dev->ib_dev.destroy_wq   = mlx5_ib_destroy_wq;
+               dev->ib_dev.create_rwq_ind_table = mlx5_ib_create_rwq_ind_table;
+               dev->ib_dev.destroy_rwq_ind_table = mlx5_ib_destroy_rwq_ind_table;
                dev->ib_dev.uverbs_ex_cmd_mask |=
                        (1ull << IB_USER_VERBS_EX_CMD_CREATE_FLOW) |
-                       (1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW);
+                       (1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW) |
+                       (1ull << IB_USER_VERBS_EX_CMD_CREATE_WQ) |
+                       (1ull << IB_USER_VERBS_EX_CMD_MODIFY_WQ) |
+                       (1ull << IB_USER_VERBS_EX_CMD_DESTROY_WQ) |
+                       (1ull << IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL) |
+                       (1ull << IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL);
        }
        err = init_node_data(dev);
        if (err)
@@ -2457,6 +2826,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
 
        mutex_init(&dev->flow_db.lock);
        mutex_init(&dev->cap_mask_mutex);
+       INIT_LIST_HEAD(&dev->qp_list);
+       spin_lock_init(&dev->reset_flow_resource_lock);
 
        if (ll == IB_LINK_LAYER_ETHERNET) {
                err = mlx5_enable_roce(dev);
@@ -2472,10 +2843,14 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
        if (err)
                goto err_rsrc;
 
-       err = ib_register_device(&dev->ib_dev, NULL);
+       err = mlx5_ib_alloc_q_counters(dev);
        if (err)
                goto err_odp;
 
+       err = ib_register_device(&dev->ib_dev, NULL);
+       if (err)
+               goto err_q_cnt;
+
        err = create_umr_res(dev);
        if (err)
                goto err_dev;
@@ -2497,6 +2872,9 @@ err_umrc:
 err_dev:
        ib_unregister_device(&dev->ib_dev);
 
+err_q_cnt:
+       mlx5_ib_dealloc_q_counters(dev);
+
 err_odp:
        mlx5_ib_odp_remove_one(dev);
 
@@ -2507,6 +2885,9 @@ err_disable_roce:
        if (ll == IB_LINK_LAYER_ETHERNET)
                mlx5_disable_roce(dev);
 
+err_free_port:
+       kfree(dev->port);
+
 err_dealloc:
        ib_dealloc_device((struct ib_device *)dev);
 
@@ -2519,11 +2900,13 @@ static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context)
        enum rdma_link_layer ll = mlx5_ib_port_link_layer(&dev->ib_dev, 1);
 
        ib_unregister_device(&dev->ib_dev);
+       mlx5_ib_dealloc_q_counters(dev);
        destroy_umrc_res(dev);
        mlx5_ib_odp_remove_one(dev);
        destroy_dev_resources(&dev->devr);
        if (ll == IB_LINK_LAYER_ETHERNET)
                mlx5_disable_roce(dev);
+       kfree(dev->port);
        ib_dealloc_device(&dev->ib_dev);
 }
 
index c4a9825..372385d 100644 (file)
@@ -105,6 +105,11 @@ enum {
        MLX5_CQE_VERSION_V1,
 };
 
+struct mlx5_ib_vma_private_data {
+       struct list_head list;
+       struct vm_area_struct *vma;
+};
+
 struct mlx5_ib_ucontext {
        struct ib_ucontext      ibucontext;
        struct list_head        db_page_list;
@@ -116,6 +121,7 @@ struct mlx5_ib_ucontext {
        u8                      cqe_version;
        /* Transport Domain number */
        u32                     tdn;
+       struct list_head        vma_private_list;
 };
 
 static inline struct mlx5_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
@@ -217,12 +223,41 @@ struct mlx5_ib_wq {
        void                   *qend;
 };
 
+struct mlx5_ib_rwq {
+       struct ib_wq            ibwq;
+       u32                     rqn;
+       u32                     rq_num_pas;
+       u32                     log_rq_stride;
+       u32                     log_rq_size;
+       u32                     rq_page_offset;
+       u32                     log_page_size;
+       struct ib_umem          *umem;
+       size_t                  buf_size;
+       unsigned int            page_shift;
+       int                     create_type;
+       struct mlx5_db          db;
+       u32                     user_index;
+       u32                     wqe_count;
+       u32                     wqe_shift;
+       int                     wq_sig;
+};
+
 enum {
        MLX5_QP_USER,
        MLX5_QP_KERNEL,
        MLX5_QP_EMPTY
 };
 
+enum {
+       MLX5_WQ_USER,
+       MLX5_WQ_KERNEL
+};
+
+struct mlx5_ib_rwq_ind_table {
+       struct ib_rwq_ind_table ib_rwq_ind_tbl;
+       u32                     rqtn;
+};
+
 /*
  * Connect-IB can trigger up to four concurrent pagefaults
  * per-QP.
@@ -266,6 +301,10 @@ struct mlx5_ib_qp_trans {
        u8                      resp_depth;
 };
 
+struct mlx5_ib_rss_qp {
+       u32     tirn;
+};
+
 struct mlx5_ib_rq {
        struct mlx5_ib_qp_base base;
        struct mlx5_ib_wq       *rq;
@@ -294,6 +333,7 @@ struct mlx5_ib_qp {
        union {
                struct mlx5_ib_qp_trans trans_qp;
                struct mlx5_ib_raw_packet_qp raw_packet_qp;
+               struct mlx5_ib_rss_qp rss_qp;
        };
        struct mlx5_buf         buf;
 
@@ -340,6 +380,9 @@ struct mlx5_ib_qp {
        spinlock_t              disable_page_faults_lock;
        struct mlx5_ib_pfault   pagefaults[MLX5_IB_PAGEFAULT_CONTEXTS];
 #endif
+       struct list_head        qps_list;
+       struct list_head        cq_recv_list;
+       struct list_head        cq_send_list;
 };
 
 struct mlx5_ib_cq_buf {
@@ -401,6 +444,8 @@ struct mlx5_ib_cq {
        struct mlx5_ib_cq_buf  *resize_buf;
        struct ib_umem         *resize_umem;
        int                     cqe_size;
+       struct list_head        list_send_qp;
+       struct list_head        list_recv_qp;
        u32                     create_flags;
        struct list_head        wc_list;
        enum ib_cq_notify_flags notify_flags;
@@ -546,6 +591,10 @@ struct mlx5_ib_resources {
        struct mutex    mutex;
 };
 
+struct mlx5_ib_port {
+       u16 q_cnt_id;
+};
+
 struct mlx5_roce {
        /* Protect mlx5_ib_get_netdev from invoking dev_hold() with a NULL
         * netdev pointer
@@ -581,6 +630,11 @@ struct mlx5_ib_dev {
        struct srcu_struct      mr_srcu;
 #endif
        struct mlx5_ib_flow_db  flow_db;
+       /* protect resources needed as part of reset flow */
+       spinlock_t              reset_flow_resource_lock;
+       struct list_head        qp_list;
+       /* Array with num_ports elements */
+       struct mlx5_ib_port     *port;
 };
 
 static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -628,6 +682,16 @@ 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_rwq *to_mrwq(struct ib_wq *ibwq)
+{
+       return container_of(ibwq, struct mlx5_ib_rwq, ibwq);
+}
+
+static inline struct mlx5_ib_rwq_ind_table *to_mrwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl)
+{
+       return container_of(ib_rwq_ind_tbl, struct mlx5_ib_rwq_ind_table, ib_rwq_ind_tbl);
+}
+
 static inline struct mlx5_ib_srq *to_mibsrq(struct mlx5_core_srq *msrq)
 {
        return container_of(msrq, struct mlx5_ib_srq, msrq);
@@ -762,6 +826,16 @@ 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);
 int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
                            struct ib_mr_status *mr_status);
+struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
+                               struct ib_wq_init_attr *init_attr,
+                               struct ib_udata *udata);
+int mlx5_ib_destroy_wq(struct ib_wq *wq);
+int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
+                     u32 wq_attr_mask, struct ib_udata *udata);
+struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
+                                                     struct ib_rwq_ind_table_init_attr *init_attr,
+                                                     struct ib_udata *udata);
+int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *wq_ind_table);
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
 extern struct workqueue_struct *mlx5_ib_page_fault_wq;
index 8cf2ce5..4b02130 100644 (file)
@@ -1193,12 +1193,16 @@ error:
 
 static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
 {
+       struct mlx5_core_dev *mdev = dev->mdev;
        struct umr_common *umrc = &dev->umrc;
        struct mlx5_ib_umr_context umr_context;
        struct mlx5_umr_wr umrwr = {};
        struct ib_send_wr *bad;
        int err;
 
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
+               return 0;
+
        mlx5_ib_init_umr_context(&umr_context);
 
        umrwr.wr.wr_cqe = &umr_context.cqe;
index ce0a7ab..0dd7d93 100644 (file)
@@ -77,6 +77,10 @@ struct mlx5_wqe_eth_pad {
        u8 rsvd0[16];
 };
 
+static void get_cqs(enum ib_qp_type qp_type,
+                   struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
+                   struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq);
+
 static int is_qp0(enum ib_qp_type qp_type)
 {
        return qp_type == IB_QPT_SMI;
@@ -609,6 +613,11 @@ static int to_mlx5_st(enum ib_qp_type type)
        }
 }
 
+static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq,
+                            struct mlx5_ib_cq *recv_cq);
+static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq,
+                              struct mlx5_ib_cq *recv_cq);
+
 static int uuarn_to_uar_index(struct mlx5_uuar_info *uuari, int uuarn)
 {
        return uuari->uars[uuarn / MLX5_BF_REGS_PER_PAGE].index;
@@ -649,6 +658,71 @@ err_umem:
        return err;
 }
 
+static void destroy_user_rq(struct ib_pd *pd, struct mlx5_ib_rwq *rwq)
+{
+       struct mlx5_ib_ucontext *context;
+
+       context = to_mucontext(pd->uobject->context);
+       mlx5_ib_db_unmap_user(context, &rwq->db);
+       if (rwq->umem)
+               ib_umem_release(rwq->umem);
+}
+
+static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
+                         struct mlx5_ib_rwq *rwq,
+                         struct mlx5_ib_create_wq *ucmd)
+{
+       struct mlx5_ib_ucontext *context;
+       int page_shift = 0;
+       int npages;
+       u32 offset = 0;
+       int ncont = 0;
+       int err;
+
+       if (!ucmd->buf_addr)
+               return -EINVAL;
+
+       context = to_mucontext(pd->uobject->context);
+       rwq->umem = ib_umem_get(pd->uobject->context, ucmd->buf_addr,
+                              rwq->buf_size, 0, 0);
+       if (IS_ERR(rwq->umem)) {
+               mlx5_ib_dbg(dev, "umem_get failed\n");
+               err = PTR_ERR(rwq->umem);
+               return err;
+       }
+
+       mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, &npages, &page_shift,
+                          &ncont, NULL);
+       err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift,
+                                    &rwq->rq_page_offset);
+       if (err) {
+               mlx5_ib_warn(dev, "bad offset\n");
+               goto err_umem;
+       }
+
+       rwq->rq_num_pas = ncont;
+       rwq->page_shift = page_shift;
+       rwq->log_page_size =  page_shift - MLX5_ADAPTER_PAGE_SHIFT;
+       rwq->wq_sig = !!(ucmd->flags & MLX5_WQ_FLAG_SIGNATURE);
+
+       mlx5_ib_dbg(dev, "addr 0x%llx, size %zd, npages %d, page_shift %d, ncont %d, offset %d\n",
+                   (unsigned long long)ucmd->buf_addr, rwq->buf_size,
+                   npages, page_shift, ncont, offset);
+
+       err = mlx5_ib_db_map_user(context, ucmd->db_addr, &rwq->db);
+       if (err) {
+               mlx5_ib_dbg(dev, "map failed\n");
+               goto err_umem;
+       }
+
+       rwq->create_type = MLX5_WQ_USER;
+       return 0;
+
+err_umem:
+       ib_umem_release(rwq->umem);
+       return err;
+}
+
 static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
                          struct mlx5_ib_qp *qp, struct ib_udata *udata,
                          struct ib_qp_init_attr *attr,
@@ -1201,6 +1275,187 @@ static void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp,
        rq->doorbell = &qp->db;
 }
 
+static void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
+{
+       mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn);
+}
+
+static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
+                                struct ib_pd *pd,
+                                struct ib_qp_init_attr *init_attr,
+                                struct ib_udata *udata)
+{
+       struct ib_uobject *uobj = pd->uobject;
+       struct ib_ucontext *ucontext = uobj->context;
+       struct mlx5_ib_ucontext *mucontext = to_mucontext(ucontext);
+       struct mlx5_ib_create_qp_resp resp = {};
+       int inlen;
+       int err;
+       u32 *in;
+       void *tirc;
+       void *hfso;
+       u32 selected_fields = 0;
+       size_t min_resp_len;
+       u32 tdn = mucontext->tdn;
+       struct mlx5_ib_create_qp_rss ucmd = {};
+       size_t required_cmd_sz;
+
+       if (init_attr->qp_type != IB_QPT_RAW_PACKET)
+               return -EOPNOTSUPP;
+
+       if (init_attr->create_flags || init_attr->send_cq)
+               return -EINVAL;
+
+       min_resp_len = offsetof(typeof(resp), uuar_index) + sizeof(resp.uuar_index);
+       if (udata->outlen < min_resp_len)
+               return -EINVAL;
+
+       required_cmd_sz = offsetof(typeof(ucmd), reserved1) + sizeof(ucmd.reserved1);
+       if (udata->inlen < required_cmd_sz) {
+               mlx5_ib_dbg(dev, "invalid inlen\n");
+               return -EINVAL;
+       }
+
+       if (udata->inlen > sizeof(ucmd) &&
+           !ib_is_udata_cleared(udata, sizeof(ucmd),
+                                udata->inlen - sizeof(ucmd))) {
+               mlx5_ib_dbg(dev, "inlen is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
+               mlx5_ib_dbg(dev, "copy failed\n");
+               return -EFAULT;
+       }
+
+       if (ucmd.comp_mask) {
+               mlx5_ib_dbg(dev, "invalid comp mask\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (memchr_inv(ucmd.reserved, 0, sizeof(ucmd.reserved)) || ucmd.reserved1) {
+               mlx5_ib_dbg(dev, "invalid reserved\n");
+               return -EOPNOTSUPP;
+       }
+
+       err = ib_copy_to_udata(udata, &resp, min_resp_len);
+       if (err) {
+               mlx5_ib_dbg(dev, "copy failed\n");
+               return -EINVAL;
+       }
+
+       inlen = MLX5_ST_SZ_BYTES(create_tir_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
+       MLX5_SET(tirc, tirc, disp_type,
+                MLX5_TIRC_DISP_TYPE_INDIRECT);
+       MLX5_SET(tirc, tirc, indirect_table,
+                init_attr->rwq_ind_tbl->ind_tbl_num);
+       MLX5_SET(tirc, tirc, transport_domain, tdn);
+
+       hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
+       switch (ucmd.rx_hash_function) {
+       case MLX5_RX_HASH_FUNC_TOEPLITZ:
+       {
+               void *rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key);
+               size_t len = MLX5_FLD_SZ_BYTES(tirc, rx_hash_toeplitz_key);
+
+               if (len != ucmd.rx_key_len) {
+                       err = -EINVAL;
+                       goto err;
+               }
+
+               MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ);
+               MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
+               memcpy(rss_key, ucmd.rx_hash_key, len);
+               break;
+       }
+       default:
+               err = -EOPNOTSUPP;
+               goto err;
+       }
+
+       if (!ucmd.rx_hash_fields_mask) {
+               /* special case when this TIR serves as steering entry without hashing */
+               if (!init_attr->rwq_ind_tbl->log_ind_tbl_size)
+                       goto create_tir;
+               err = -EINVAL;
+               goto err;
+       }
+
+       if (((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
+            (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4)) &&
+            ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
+            (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       /* If none of IPV4 & IPV6 SRC/DST was set - this bit field is ignored */
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4))
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+       else if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
+                (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+
+       if (((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
+            (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP)) &&
+            ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
+            (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       /* If none of TCP & UDP SRC/DST was set - this bit field is ignored */
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP))
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_TCP);
+       else if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
+                (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_UDP);
+
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6))
+               selected_fields |= MLX5_HASH_FIELD_SEL_SRC_IP;
+
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
+               selected_fields |= MLX5_HASH_FIELD_SEL_DST_IP;
+
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP))
+               selected_fields |= MLX5_HASH_FIELD_SEL_L4_SPORT;
+
+       if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP) ||
+           (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
+               selected_fields |= MLX5_HASH_FIELD_SEL_L4_DPORT;
+
+       MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields);
+
+create_tir:
+       err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn);
+
+       if (err)
+               goto err;
+
+       kvfree(in);
+       /* qpn is reserved for that QP */
+       qp->trans_qp.base.mqp.qpn = 0;
+       return 0;
+
+err:
+       kvfree(in);
+       return err;
+}
+
 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)
@@ -1211,6 +1466,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        struct mlx5_ib_create_qp_resp resp;
        struct mlx5_create_qp_mbox_in *in;
        struct mlx5_ib_create_qp ucmd;
+       struct mlx5_ib_cq *send_cq;
+       struct mlx5_ib_cq *recv_cq;
+       unsigned long flags;
        int inlen = sizeof(*in);
        int err;
        u32 uidx = MLX5_IB_DEFAULT_UIDX;
@@ -1227,6 +1485,14 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        spin_lock_init(&qp->sq.lock);
        spin_lock_init(&qp->rq.lock);
 
+       if (init_attr->rwq_ind_tbl) {
+               if (!udata)
+                       return -ENOSYS;
+
+               err = create_rss_raw_qp_tir(dev, qp, pd, init_attr, udata);
+               return err;
+       }
+
        if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
                if (!MLX5_CAP_GEN(mdev, block_lb_mc)) {
                        mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n");
@@ -1460,6 +1726,23 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        base->container_mibqp = qp;
        base->mqp.event = mlx5_ib_qp_event;
 
+       get_cqs(init_attr->qp_type, init_attr->send_cq, init_attr->recv_cq,
+               &send_cq, &recv_cq);
+       spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
+       mlx5_ib_lock_cqs(send_cq, recv_cq);
+       /* Maintain device to QPs access, needed for further handling via reset
+        * flow
+        */
+       list_add_tail(&qp->qps_list, &dev->qp_list);
+       /* Maintain CQ to QPs access, needed for further handling via reset flow
+        */
+       if (send_cq)
+               list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp);
+       if (recv_cq)
+               list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp);
+       mlx5_ib_unlock_cqs(send_cq, recv_cq);
+       spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
+
        return 0;
 
 err_create:
@@ -1478,23 +1761,23 @@ static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv
        if (send_cq) {
                if (recv_cq) {
                        if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
-                               spin_lock_irq(&send_cq->lock);
+                               spin_lock(&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);
+                               spin_lock(&send_cq->lock);
                                __acquire(&recv_cq->lock);
                        } else {
-                               spin_lock_irq(&recv_cq->lock);
+                               spin_lock(&recv_cq->lock);
                                spin_lock_nested(&send_cq->lock,
                                                 SINGLE_DEPTH_NESTING);
                        }
                } else {
-                       spin_lock_irq(&send_cq->lock);
+                       spin_lock(&send_cq->lock);
                        __acquire(&recv_cq->lock);
                }
        } else if (recv_cq) {
-               spin_lock_irq(&recv_cq->lock);
+               spin_lock(&recv_cq->lock);
                __acquire(&send_cq->lock);
        } else {
                __acquire(&send_cq->lock);
@@ -1509,21 +1792,21 @@ static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *re
                if (recv_cq) {
                        if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
                                spin_unlock(&recv_cq->lock);
-                               spin_unlock_irq(&send_cq->lock);
+                               spin_unlock(&send_cq->lock);
                        } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
                                __release(&recv_cq->lock);
-                               spin_unlock_irq(&send_cq->lock);
+                               spin_unlock(&send_cq->lock);
                        } else {
                                spin_unlock(&send_cq->lock);
-                               spin_unlock_irq(&recv_cq->lock);
+                               spin_unlock(&recv_cq->lock);
                        }
                } else {
                        __release(&recv_cq->lock);
-                       spin_unlock_irq(&send_cq->lock);
+                       spin_unlock(&send_cq->lock);
                }
        } else if (recv_cq) {
                __release(&send_cq->lock);
-               spin_unlock_irq(&recv_cq->lock);
+               spin_unlock(&recv_cq->lock);
        } else {
                __release(&recv_cq->lock);
                __release(&send_cq->lock);
@@ -1535,17 +1818,18 @@ 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,
+static void get_cqs(enum ib_qp_type qp_type,
+                   struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
                    struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq)
 {
-       switch (qp->ibqp.qp_type) {
+       switch (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);
+               *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
                *recv_cq = NULL;
                break;
 
@@ -1557,8 +1841,8 @@ static void get_cqs(struct mlx5_ib_qp *qp,
        case IB_QPT_RAW_IPV6:
        case IB_QPT_RAW_ETHERTYPE:
        case IB_QPT_RAW_PACKET:
-               *send_cq = to_mcq(qp->ibqp.send_cq);
-               *recv_cq = to_mcq(qp->ibqp.recv_cq);
+               *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
+               *recv_cq = ib_recv_cq ? to_mcq(ib_recv_cq) : NULL;
                break;
 
        case IB_QPT_MAX:
@@ -1577,8 +1861,14 @@ 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_ib_qp_base *base = &qp->trans_qp.base;
        struct mlx5_modify_qp_mbox_in *in;
+       unsigned long flags;
        int err;
 
+       if (qp->ibqp.rwq_ind_tbl) {
+               destroy_rss_raw_qp_tir(dev, qp);
+               return;
+       }
+
        base = qp->ibqp.qp_type == IB_QPT_RAW_PACKET ?
               &qp->raw_packet_qp.rq.base :
               &qp->trans_qp.base;
@@ -1602,17 +1892,28 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
                                     base->mqp.qpn);
        }
 
-       get_cqs(qp, &send_cq, &recv_cq);
+       get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
+               &send_cq, &recv_cq);
+
+       spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
+       mlx5_ib_lock_cqs(send_cq, recv_cq);
+       /* del from lists under both locks above to protect reset flow paths */
+       list_del(&qp->qps_list);
+       if (send_cq)
+               list_del(&qp->cq_send_list);
+
+       if (recv_cq)
+               list_del(&qp->cq_recv_list);
 
        if (qp->create_type == MLX5_QP_KERNEL) {
-               mlx5_ib_lock_cqs(send_cq, recv_cq);
                __mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
                                   qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
                if (send_cq != recv_cq)
                        __mlx5_ib_cq_clean(send_cq, base->mqp.qpn,
                                           NULL);
-               mlx5_ib_unlock_cqs(send_cq, recv_cq);
        }
+       mlx5_ib_unlock_cqs(send_cq, recv_cq);
+       spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
 
        if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
                destroy_raw_packet_qp(dev, qp);
@@ -2300,7 +2601,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        pd = get_pd(qp);
-       get_cqs(qp, &send_cq, &recv_cq);
+       get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
+               &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;
@@ -2349,6 +2651,15 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
        else
                sqd_event = 0;
 
+       if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
+               u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num :
+                              qp->port) - 1;
+               struct mlx5_ib_port *mibport = &dev->port[port_num];
+
+               context->qp_counter_set_usr_page |=
+                       cpu_to_be32((u32)(mibport->q_cnt_id) << 24);
+       }
+
        if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
                context->sq_crq_size |= cpu_to_be16(1 << 4);
 
@@ -2439,6 +2750,9 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        int port;
        enum rdma_link_layer ll = IB_LINK_LAYER_UNSPECIFIED;
 
+       if (ibqp->rwq_ind_tbl)
+               return -ENOSYS;
+
        if (unlikely(ibqp->qp_type == IB_QPT_GSI))
                return mlx5_ib_gsi_modify_qp(ibqp, attr, attr_mask);
 
@@ -3397,6 +3711,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *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;
        struct mlx5_ib_mr *mr;
        struct mlx5_wqe_data_seg *dpseg;
@@ -3424,6 +3739,13 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
        spin_lock_irqsave(&qp->sq.lock, flags);
 
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               err = -EIO;
+               *bad_wr = wr;
+               nreq = 0;
+               goto out;
+       }
+
        for (nreq = 0; wr; nreq++, wr = wr->next) {
                if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) {
                        mlx5_ib_warn(dev, "\n");
@@ -3725,6 +4047,8 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
        struct mlx5_ib_qp *qp = to_mqp(ibqp);
        struct mlx5_wqe_data_seg *scat;
        struct mlx5_rwqe_sig *sig;
+       struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx5_core_dev *mdev = dev->mdev;
        unsigned long flags;
        int err = 0;
        int nreq;
@@ -3736,6 +4060,13 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
        spin_lock_irqsave(&qp->rq.lock, flags);
 
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               err = -EIO;
+               *bad_wr = wr;
+               nreq = 0;
+               goto out;
+       }
+
        ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
 
        for (nreq = 0; wr; nreq++, wr = wr->next) {
@@ -4055,6 +4386,9 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
        int err = 0;
        u8 raw_packet_qp_state;
 
+       if (ibqp->rwq_ind_tbl)
+               return -ENOSYS;
+
        if (unlikely(ibqp->qp_type == IB_QPT_GSI))
                return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask,
                                            qp_init_attr);
@@ -4164,3 +4498,322 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
 
        return 0;
 }
+
+static int  create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
+                     struct ib_wq_init_attr *init_attr)
+{
+       struct mlx5_ib_dev *dev;
+       __be64 *rq_pas0;
+       void *in;
+       void *rqc;
+       void *wq;
+       int inlen;
+       int err;
+
+       dev = to_mdev(pd->device);
+
+       inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas;
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
+       MLX5_SET(rqc,  rqc, mem_rq_type,
+                MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE);
+       MLX5_SET(rqc, rqc, user_index, rwq->user_index);
+       MLX5_SET(rqc,  rqc, cqn, to_mcq(init_attr->cq)->mcq.cqn);
+       MLX5_SET(rqc,  rqc, state, MLX5_RQC_STATE_RST);
+       MLX5_SET(rqc,  rqc, flush_in_error_en, 1);
+       wq = MLX5_ADDR_OF(rqc, rqc, wq);
+       MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
+       MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
+       MLX5_SET(wq, wq, log_wq_stride, rwq->log_rq_stride);
+       MLX5_SET(wq, wq, log_wq_sz, rwq->log_rq_size);
+       MLX5_SET(wq, wq, pd, to_mpd(pd)->pdn);
+       MLX5_SET(wq, wq, page_offset, rwq->rq_page_offset);
+       MLX5_SET(wq, wq, log_wq_pg_sz, rwq->log_page_size);
+       MLX5_SET(wq, wq, wq_signature, rwq->wq_sig);
+       MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma);
+       rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
+       mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0);
+       err = mlx5_core_create_rq(dev->mdev, in, inlen, &rwq->rqn);
+       kvfree(in);
+       return err;
+}
+
+static int set_user_rq_size(struct mlx5_ib_dev *dev,
+                           struct ib_wq_init_attr *wq_init_attr,
+                           struct mlx5_ib_create_wq *ucmd,
+                           struct mlx5_ib_rwq *rwq)
+{
+       /* Sanity check RQ size before proceeding */
+       if (wq_init_attr->max_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_wq_sz)))
+               return -EINVAL;
+
+       if (!ucmd->rq_wqe_count)
+               return -EINVAL;
+
+       rwq->wqe_count = ucmd->rq_wqe_count;
+       rwq->wqe_shift = ucmd->rq_wqe_shift;
+       rwq->buf_size = (rwq->wqe_count << rwq->wqe_shift);
+       rwq->log_rq_stride = rwq->wqe_shift;
+       rwq->log_rq_size = ilog2(rwq->wqe_count);
+       return 0;
+}
+
+static int prepare_user_rq(struct ib_pd *pd,
+                          struct ib_wq_init_attr *init_attr,
+                          struct ib_udata *udata,
+                          struct mlx5_ib_rwq *rwq)
+{
+       struct mlx5_ib_dev *dev = to_mdev(pd->device);
+       struct mlx5_ib_create_wq ucmd = {};
+       int err;
+       size_t required_cmd_sz;
+
+       required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
+       if (udata->inlen < required_cmd_sz) {
+               mlx5_ib_dbg(dev, "invalid inlen\n");
+               return -EINVAL;
+       }
+
+       if (udata->inlen > sizeof(ucmd) &&
+           !ib_is_udata_cleared(udata, sizeof(ucmd),
+                                udata->inlen - sizeof(ucmd))) {
+               mlx5_ib_dbg(dev, "inlen is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
+               mlx5_ib_dbg(dev, "copy failed\n");
+               return -EFAULT;
+       }
+
+       if (ucmd.comp_mask) {
+               mlx5_ib_dbg(dev, "invalid comp mask\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (ucmd.reserved) {
+               mlx5_ib_dbg(dev, "invalid reserved\n");
+               return -EOPNOTSUPP;
+       }
+
+       err = set_user_rq_size(dev, init_attr, &ucmd, rwq);
+       if (err) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               return err;
+       }
+
+       err = create_user_rq(dev, pd, rwq, &ucmd);
+       if (err) {
+               mlx5_ib_dbg(dev, "err %d\n", err);
+               if (err)
+                       return err;
+       }
+
+       rwq->user_index = ucmd.user_index;
+       return 0;
+}
+
+struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
+                               struct ib_wq_init_attr *init_attr,
+                               struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev;
+       struct mlx5_ib_rwq *rwq;
+       struct mlx5_ib_create_wq_resp resp = {};
+       size_t min_resp_len;
+       int err;
+
+       if (!udata)
+               return ERR_PTR(-ENOSYS);
+
+       min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
+       if (udata->outlen && udata->outlen < min_resp_len)
+               return ERR_PTR(-EINVAL);
+
+       dev = to_mdev(pd->device);
+       switch (init_attr->wq_type) {
+       case IB_WQT_RQ:
+               rwq = kzalloc(sizeof(*rwq), GFP_KERNEL);
+               if (!rwq)
+                       return ERR_PTR(-ENOMEM);
+               err = prepare_user_rq(pd, init_attr, udata, rwq);
+               if (err)
+                       goto err;
+               err = create_rq(rwq, pd, init_attr);
+               if (err)
+                       goto err_user_rq;
+               break;
+       default:
+               mlx5_ib_dbg(dev, "unsupported wq type %d\n",
+                           init_attr->wq_type);
+               return ERR_PTR(-EINVAL);
+       }
+
+       rwq->ibwq.wq_num = rwq->rqn;
+       rwq->ibwq.state = IB_WQS_RESET;
+       if (udata->outlen) {
+               resp.response_length = offsetof(typeof(resp), response_length) +
+                               sizeof(resp.response_length);
+               err = ib_copy_to_udata(udata, &resp, resp.response_length);
+               if (err)
+                       goto err_copy;
+       }
+
+       return &rwq->ibwq;
+
+err_copy:
+       mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
+err_user_rq:
+       destroy_user_rq(pd, rwq);
+err:
+       kfree(rwq);
+       return ERR_PTR(err);
+}
+
+int mlx5_ib_destroy_wq(struct ib_wq *wq)
+{
+       struct mlx5_ib_dev *dev = to_mdev(wq->device);
+       struct mlx5_ib_rwq *rwq = to_mrwq(wq);
+
+       mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
+       destroy_user_rq(wq->pd, rwq);
+       kfree(rwq);
+
+       return 0;
+}
+
+struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
+                                                     struct ib_rwq_ind_table_init_attr *init_attr,
+                                                     struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(device);
+       struct mlx5_ib_rwq_ind_table *rwq_ind_tbl;
+       int sz = 1 << init_attr->log_ind_tbl_size;
+       struct mlx5_ib_create_rwq_ind_tbl_resp resp = {};
+       size_t min_resp_len;
+       int inlen;
+       int err;
+       int i;
+       u32 *in;
+       void *rqtc;
+
+       if (udata->inlen > 0 &&
+           !ib_is_udata_cleared(udata, 0,
+                                udata->inlen))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
+       if (udata->outlen && udata->outlen < min_resp_len)
+               return ERR_PTR(-EINVAL);
+
+       rwq_ind_tbl = kzalloc(sizeof(*rwq_ind_tbl), GFP_KERNEL);
+       if (!rwq_ind_tbl)
+               return ERR_PTR(-ENOMEM);
+
+       inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz;
+       in = mlx5_vzalloc(inlen);
+       if (!in) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
+
+       MLX5_SET(rqtc, rqtc, rqt_actual_size, sz);
+       MLX5_SET(rqtc, rqtc, rqt_max_size, sz);
+
+       for (i = 0; i < sz; i++)
+               MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num);
+
+       err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn);
+       kvfree(in);
+
+       if (err)
+               goto err;
+
+       rwq_ind_tbl->ib_rwq_ind_tbl.ind_tbl_num = rwq_ind_tbl->rqtn;
+       if (udata->outlen) {
+               resp.response_length = offsetof(typeof(resp), response_length) +
+                                       sizeof(resp.response_length);
+               err = ib_copy_to_udata(udata, &resp, resp.response_length);
+               if (err)
+                       goto err_copy;
+       }
+
+       return &rwq_ind_tbl->ib_rwq_ind_tbl;
+
+err_copy:
+       mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn);
+err:
+       kfree(rwq_ind_tbl);
+       return ERR_PTR(err);
+}
+
+int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl)
+{
+       struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl);
+       struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device);
+
+       mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn);
+
+       kfree(rwq_ind_tbl);
+       return 0;
+}
+
+int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
+                     u32 wq_attr_mask, struct ib_udata *udata)
+{
+       struct mlx5_ib_dev *dev = to_mdev(wq->device);
+       struct mlx5_ib_rwq *rwq = to_mrwq(wq);
+       struct mlx5_ib_modify_wq ucmd = {};
+       size_t required_cmd_sz;
+       int curr_wq_state;
+       int wq_state;
+       int inlen;
+       int err;
+       void *rqc;
+       void *in;
+
+       required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
+       if (udata->inlen < required_cmd_sz)
+               return -EINVAL;
+
+       if (udata->inlen > sizeof(ucmd) &&
+           !ib_is_udata_cleared(udata, sizeof(ucmd),
+                                udata->inlen - sizeof(ucmd)))
+               return -EOPNOTSUPP;
+
+       if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen)))
+               return -EFAULT;
+
+       if (ucmd.comp_mask || ucmd.reserved)
+               return -EOPNOTSUPP;
+
+       inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
+
+       curr_wq_state = (wq_attr_mask & IB_WQ_CUR_STATE) ?
+               wq_attr->curr_wq_state : wq->state;
+       wq_state = (wq_attr_mask & IB_WQ_STATE) ?
+               wq_attr->wq_state : curr_wq_state;
+       if (curr_wq_state == IB_WQS_ERR)
+               curr_wq_state = MLX5_RQC_STATE_ERR;
+       if (wq_state == IB_WQS_ERR)
+               wq_state = MLX5_RQC_STATE_ERR;
+       MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
+       MLX5_SET(rqc, rqc, state, wq_state);
+
+       err = mlx5_core_modify_rq(dev->mdev, rwq->rqn, in, inlen);
+       kvfree(in);
+       if (!err)
+               rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state;
+
+       return err;
+}
index 3b2ddd6..ed6ac52 100644 (file)
@@ -74,14 +74,12 @@ static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
 }
 
 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,
-                          int is_xrc)
+                          struct mlx5_srq_attr *in,
+                          struct ib_udata *udata, int buf_size)
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
        struct mlx5_ib_create_srq ucmd = {};
        size_t ucmdlen;
-       void *xsrqc;
        int err;
        int npages;
        int page_shift;
@@ -104,7 +102,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
                                 udata->inlen - sizeof(ucmd)))
                return -EINVAL;
 
-       if (is_xrc) {
+       if (in->type == IB_SRQT_XRC) {
                err = get_srq_user_index(to_mucontext(pd->uobject->context),
                                         &ucmd, udata->inlen, &uidx);
                if (err)
@@ -130,14 +128,13 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
                goto err_umem;
        }
 
-       *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont;
-       *in = mlx5_vzalloc(*inlen);
-       if (!(*in)) {
+       in->pas = mlx5_vzalloc(sizeof(*in->pas) * ncont);
+       if (!in->pas) {
                err = -ENOMEM;
                goto err_umem;
        }
 
-       mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0);
+       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);
@@ -146,20 +143,16 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
                goto err_in;
        }
 
-       (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
-       (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
-
-       if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
-            is_xrc){
-               xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
-                                    xrc_srq_context_entry);
-               MLX5_SET(xrc_srqc, xsrqc, user_index, uidx);
-       }
+       in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
+       in->page_offset = offset;
+       if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
+           in->type == IB_SRQT_XRC)
+               in->user_index = uidx;
 
        return 0;
 
 err_in:
-       kvfree(*in);
+       kvfree(in->pas);
 
 err_umem:
        ib_umem_release(srq->umem);
@@ -168,15 +161,13 @@ err_umem:
 }
 
 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 is_xrc)
+                            struct mlx5_srq_attr *in, int buf_size)
 {
        int err;
        int i;
        struct mlx5_wqe_srq_next_seg *next;
        int page_shift;
        int npages;
-       void *xsrqc;
 
        err = mlx5_db_alloc(dev->mdev, &srq->db);
        if (err) {
@@ -204,13 +195,12 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
        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) {
+       in->pas = mlx5_vzalloc(sizeof(*in->pas) * npages);
+       if (!in->pas) {
                err = -ENOMEM;
                goto err_buf;
        }
-       mlx5_fill_page_array(&srq->buf, (*in)->pas);
+       mlx5_fill_page_array(&srq->buf, in->pas);
 
        srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL);
        if (!srq->wrid) {
@@ -221,20 +211,15 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
        }
        srq->wq_sig = !!srq_signature;
 
-       (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
-
-       if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
-            is_xrc){
-               xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
-                                    xrc_srq_context_entry);
-               /* 0xffffff means we ask to work with cqe version 0 */
-               MLX5_SET(xrc_srqc, xsrqc, user_index, MLX5_IB_DEFAULT_UIDX);
-       }
+       in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
+       if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
+           in->type == IB_SRQT_XRC)
+               in->user_index = MLX5_IB_DEFAULT_UIDX;
 
        return 0;
 
 err_in:
-       kvfree(*in);
+       kvfree(in->pas);
 
 err_buf:
        mlx5_buf_free(dev->mdev, &srq->buf);
@@ -267,10 +252,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
        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;
+       struct mlx5_srq_attr in = {0};
        __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
 
        /* Sanity check SRQ size before proceeding */
@@ -302,14 +284,10 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
                    desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
                    srq->msrq.max_avail_gather);
 
-       is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
-
        if (pd->uobject)
-               err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen,
-                                     is_xrc);
+               err = create_srq_user(pd, srq, &in, udata, buf_size);
        else
-               err = create_srq_kernel(dev, srq, &in, buf_size, &inlen,
-                                       is_xrc);
+               err = create_srq_kernel(dev, srq, &in, buf_size);
 
        if (err) {
                mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
@@ -317,23 +295,23 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
                goto err_srq;
        }
 
-       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);
+       in.type = init_attr->srq_type;
+       in.log_size = ilog2(srq->msrq.max);
+       in.wqe_shift = srq->msrq.wqe_shift - 4;
+       if (srq->wq_sig)
+               in.flags |= MLX5_SRQ_FLAG_WQ_SIG;
+       if (init_attr->srq_type == IB_SRQT_XRC) {
+               in.xrcd = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
+               in.cqn = 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.xrcd = to_mxrcd(dev->devr.x0)->xrcdn;
+               in.cqn = 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, is_xrc);
-       kvfree(in);
+       in.pd = to_mpd(pd)->pdn;
+       in.db_record = srq->db.dma;
+       err = mlx5_core_create_srq(dev->mdev, &srq->msrq, &in);
+       kvfree(in.pas);
        if (err) {
                mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
                goto err_usr_kern_srq;
@@ -401,7 +379,7 @@ 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;
+       struct mlx5_srq_attr *out;
 
        out = kzalloc(sizeof(*out), GFP_KERNEL);
        if (!out)
@@ -411,7 +389,7 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
        if (ret)
                goto out_box;
 
-       srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm);
+       srq_attr->srq_limit = out->lwm;
        srq_attr->max_wr    = srq->msrq.max - 1;
        srq_attr->max_sge   = srq->msrq.max_gs;
 
@@ -458,6 +436,8 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
        struct mlx5_wqe_srq_next_seg *next;
        struct mlx5_wqe_data_seg *scat;
+       struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
+       struct mlx5_core_dev *mdev = dev->mdev;
        unsigned long flags;
        int err = 0;
        int nreq;
@@ -465,6 +445,12 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 
        spin_lock_irqsave(&srq->lock, flags);
 
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               err = -EIO;
+               *bad_wr = wr;
+               goto out;
+       }
+
        for (nreq = 0; wr; nreq++, wr = wr->next) {
                if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
                        err = -EINVAL;
@@ -507,7 +493,7 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 
                *srq->db.db = cpu_to_be32(srq->wqe_ctr);
        }
-
+out:
        spin_unlock_irqrestore(&srq->lock, flags);
 
        return err;
index 61bc308..188dac4 100644 (file)
@@ -46,6 +46,10 @@ enum {
        MLX5_SRQ_FLAG_SIGNATURE         = 1 << 0,
 };
 
+enum {
+       MLX5_WQ_FLAG_SIGNATURE          = 1 << 0,
+};
+
 
 /* Increment this value if any changes that break userspace ABI
  * compatibility are made.
@@ -79,6 +83,10 @@ enum mlx5_ib_alloc_ucontext_resp_mask {
        MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_CORE_CLOCK_OFFSET = 1UL << 0,
 };
 
+enum mlx5_user_cmds_supp_uhw {
+       MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE = 1 << 0,
+};
+
 struct mlx5_ib_alloc_ucontext_resp {
        __u32   qp_tab_size;
        __u32   bf_reg_size;
@@ -94,8 +102,8 @@ struct mlx5_ib_alloc_ucontext_resp {
        __u32   comp_mask;
        __u32   response_length;
        __u8    cqe_version;
-       __u8    reserved2;
-       __u16   reserved3;
+       __u8    cmds_supp_uhw;
+       __u16   reserved2;
        __u64   hca_core_clock_offset;
 };
 
@@ -103,6 +111,22 @@ struct mlx5_ib_alloc_pd_resp {
        __u32   pdn;
 };
 
+struct mlx5_ib_tso_caps {
+       __u32 max_tso; /* Maximum tso payload size in bytes */
+
+       /* Corresponding bit will be set if qp type from
+        * 'enum ib_qp_type' is supported, e.g.
+        * supported_qpts |= 1 << IB_QPT_UD
+        */
+       __u32 supported_qpts;
+};
+
+struct mlx5_ib_query_device_resp {
+       __u32   comp_mask;
+       __u32   response_length;
+       struct  mlx5_ib_tso_caps tso_caps;
+};
+
 struct mlx5_ib_create_cq {
        __u64   buf_addr;
        __u64   db_addr;
@@ -148,6 +172,40 @@ struct mlx5_ib_create_qp {
        __u64   sq_buf_addr;
 };
 
+/* RX Hash function flags */
+enum mlx5_rx_hash_function_flags {
+       MLX5_RX_HASH_FUNC_TOEPLITZ      = 1 << 0,
+};
+
+/*
+ * RX Hash flags, these flags allows to set which incoming packet's field should
+ * participates in RX Hash. Each flag represent certain packet's field,
+ * when the flag is set the field that is represented by the flag will
+ * participate in RX Hash calculation.
+ * Note: *IPV4 and *IPV6 flags can't be enabled together on the same QP
+ * and *TCP and *UDP flags can't be enabled together on the same QP.
+*/
+enum mlx5_rx_hash_fields {
+       MLX5_RX_HASH_SRC_IPV4   = 1 << 0,
+       MLX5_RX_HASH_DST_IPV4   = 1 << 1,
+       MLX5_RX_HASH_SRC_IPV6   = 1 << 2,
+       MLX5_RX_HASH_DST_IPV6   = 1 << 3,
+       MLX5_RX_HASH_SRC_PORT_TCP       = 1 << 4,
+       MLX5_RX_HASH_DST_PORT_TCP       = 1 << 5,
+       MLX5_RX_HASH_SRC_PORT_UDP       = 1 << 6,
+       MLX5_RX_HASH_DST_PORT_UDP       = 1 << 7
+};
+
+struct mlx5_ib_create_qp_rss {
+       __u64 rx_hash_fields_mask; /* enum mlx5_rx_hash_fields */
+       __u8 rx_hash_function; /* enum mlx5_rx_hash_function_flags */
+       __u8 rx_key_len; /* valid only for Toeplitz */
+       __u8 reserved[6];
+       __u8 rx_hash_key[128]; /* valid only for Toeplitz */
+       __u32   comp_mask;
+       __u32   reserved1;
+};
+
 struct mlx5_ib_create_qp_resp {
        __u32   uuar_index;
 };
@@ -159,6 +217,32 @@ struct mlx5_ib_alloc_mw {
        __u16   reserved2;
 };
 
+struct mlx5_ib_create_wq {
+       __u64   buf_addr;
+       __u64   db_addr;
+       __u32   rq_wqe_count;
+       __u32   rq_wqe_shift;
+       __u32   user_index;
+       __u32   flags;
+       __u32   comp_mask;
+       __u32   reserved;
+};
+
+struct mlx5_ib_create_wq_resp {
+       __u32   response_length;
+       __u32   reserved;
+};
+
+struct mlx5_ib_create_rwq_ind_tbl_resp {
+       __u32   response_length;
+       __u32   reserved;
+};
+
+struct mlx5_ib_modify_wq {
+       __u32   comp_mask;
+       __u32   reserved;
+};
+
 static inline int get_qp_user_index(struct mlx5_ib_ucontext *ucontext,
                                    struct mlx5_ib_create_qp *ucmd,
                                    int inlen,
index 9866c35..da2335f 100644 (file)
@@ -1081,16 +1081,6 @@ static ssize_t show_rev(struct device *device, struct device_attribute *attr,
        return sprintf(buf, "%x\n", dev->rev_id);
 }
 
-static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
-                          char *buf)
-{
-       struct mthca_dev *dev =
-               container_of(device, struct mthca_dev, ib_dev.dev);
-       return sprintf(buf, "%d.%d.%d\n", (int) (dev->fw_ver >> 32),
-                      (int) (dev->fw_ver >> 16) & 0xffff,
-                      (int) dev->fw_ver & 0xffff);
-}
-
 static ssize_t show_hca(struct device *device, struct device_attribute *attr,
                        char *buf)
 {
@@ -1120,13 +1110,11 @@ static ssize_t show_board(struct device *device, struct device_attribute *attr,
 }
 
 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 struct device_attribute *mthca_dev_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id
 };
@@ -1187,6 +1175,17 @@ static int mthca_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_str(struct ib_device *device, char *str,
+                          size_t str_len)
+{
+       struct mthca_dev *dev =
+               container_of(device, struct mthca_dev, ib_dev);
+       snprintf(str, str_len, "%d.%d.%d",
+                (int) (dev->fw_ver >> 32),
+                (int) (dev->fw_ver >> 16) & 0xffff,
+                (int) dev->fw_ver & 0xffff);
+}
+
 int mthca_register_device(struct mthca_dev *dev)
 {
        int ret;
@@ -1266,6 +1265,7 @@ int mthca_register_device(struct mthca_dev *dev)
        dev->ib_dev.reg_user_mr          = mthca_reg_user_mr;
        dev->ib_dev.dereg_mr             = mthca_dereg_mr;
        dev->ib_dev.get_port_immutable   = mthca_port_immutable;
+       dev->ib_dev.get_dev_fw_str       = get_dev_fw_str;
 
        if (dev->mthca_flags & MTHCA_FLAG_FMR) {
                dev->ib_dev.alloc_fmr            = mthca_alloc_fmr;
index 74c6a94..6727af2 100644 (file)
@@ -98,7 +98,7 @@ int mthca_reset(struct mthca_dev *mdev)
                err = -ENOMEM;
                mthca_err(mdev, "Couldn't allocate memory to save HCA "
                          "PCI header, aborting.\n");
-               goto out;
+               goto put_dev;
        }
 
        for (i = 0; i < 64; ++i) {
@@ -108,7 +108,7 @@ int mthca_reset(struct mthca_dev *mdev)
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't save HCA "
                                  "PCI header, aborting.\n");
-                       goto out;
+                       goto free_hca;
                }
        }
 
@@ -121,7 +121,7 @@ int mthca_reset(struct mthca_dev *mdev)
                        err = -ENOMEM;
                        mthca_err(mdev, "Couldn't allocate memory to save HCA "
                                  "bridge PCI header, aborting.\n");
-                       goto out;
+                       goto free_hca;
                }
 
                for (i = 0; i < 64; ++i) {
@@ -131,7 +131,7 @@ int mthca_reset(struct mthca_dev *mdev)
                                err = -ENODEV;
                                mthca_err(mdev, "Couldn't save HCA bridge "
                                          "PCI header, aborting.\n");
-                               goto out;
+                               goto free_bh;
                        }
                }
                bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
@@ -139,7 +139,7 @@ int mthca_reset(struct mthca_dev *mdev)
                                err = -ENODEV;
                                mthca_err(mdev, "Couldn't locate HCA bridge "
                                          "PCI-X capability, aborting.\n");
-                               goto out;
+                               goto free_bh;
                }
        }
 
@@ -152,7 +152,7 @@ int mthca_reset(struct mthca_dev *mdev)
                        err = -ENOMEM;
                        mthca_err(mdev, "Couldn't map HCA reset register, "
                                  "aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
 
                writel(MTHCA_RESET_VALUE, reset);
@@ -172,7 +172,7 @@ int mthca_reset(struct mthca_dev *mdev)
                                err = -ENODEV;
                                mthca_err(mdev, "Couldn't access HCA after reset, "
                                          "aborting.\n");
-                               goto out;
+                               goto free_bh;
                        }
 
                        if (v != 0xffffffff)
@@ -184,7 +184,7 @@ int mthca_reset(struct mthca_dev *mdev)
                err = -ENODEV;
                mthca_err(mdev, "PCI device did not come back after reset, "
                          "aborting.\n");
-               goto out;
+               goto free_bh;
        }
 
 good:
@@ -195,14 +195,14 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA bridge Upstream "
                                  "split transaction control, aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
                if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc,
                                 bridge_header[(bridge_pcix_cap + 0xc) / 4])) {
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA bridge Downstream "
                                  "split transaction control, aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
                /*
                 * Bridge control register is at 0x3e, so we'll
@@ -216,7 +216,7 @@ good:
                                err = -ENODEV;
                                mthca_err(mdev, "Couldn't restore HCA bridge reg %x, "
                                          "aborting.\n", i);
-                               goto out;
+                               goto free_bh;
                        }
                }
 
@@ -225,7 +225,7 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, "
                                  "aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
        }
 
@@ -235,7 +235,7 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA PCI-X "
                                  "command register, aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
        }
 
@@ -246,7 +246,7 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA PCI Express "
                                  "Device Control register, aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
                linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4];
                if (pcie_capability_write_word(mdev->pdev, PCI_EXP_LNKCTL,
@@ -254,7 +254,7 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA PCI Express "
                                  "Link control register, aborting.\n");
-                       goto out;
+                       goto free_bh;
                }
        }
 
@@ -266,7 +266,7 @@ good:
                        err = -ENODEV;
                        mthca_err(mdev, "Couldn't restore HCA reg %x, "
                                  "aborting.\n", i);
-                       goto out;
+                       goto free_bh;
                }
        }
 
@@ -275,14 +275,12 @@ good:
                err = -ENODEV;
                mthca_err(mdev, "Couldn't restore HCA COMMAND, "
                          "aborting.\n");
-               goto out;
        }
-
-out:
-       if (bridge)
-               pci_dev_put(bridge);
+free_bh:
        kfree(bridge_header);
+free_hca:
        kfree(hca_header);
-
+put_dev:
+       pci_dev_put(bridge);
        return err;
 }
index 464d6da..bd69125 100644 (file)
@@ -2605,23 +2605,6 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
 }
 
 
-/**
- * show_fw_ver
- */
-static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct nes_ib_device *nesibdev =
-                       container_of(dev, struct nes_ib_device, ibdev.dev);
-       struct nes_vnic *nesvnic = nesibdev->nesvnic;
-
-       nes_debug(NES_DBG_INIT, "\n");
-       return sprintf(buf, "%u.%u\n",
-               (nesvnic->nesdev->nesadapter->firmware_version >> 16),
-               (nesvnic->nesdev->nesadapter->firmware_version & 0x000000ff));
-}
-
-
 /**
  * show_hca
  */
@@ -2645,13 +2628,11 @@ static ssize_t show_board(struct device *dev, struct device_attribute *attr,
 
 
 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 struct device_attribute *nes_dev_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type,
        &dev_attr_board_id
 };
@@ -3703,6 +3684,19 @@ static int nes_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_str(struct ib_device *dev, char *str,
+                          size_t str_len)
+{
+       struct nes_ib_device *nesibdev =
+                       container_of(dev, struct nes_ib_device, ibdev);
+       struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+       nes_debug(NES_DBG_INIT, "\n");
+       snprintf(str, str_len, "%u.%u",
+                (nesvnic->nesdev->nesadapter->firmware_version >> 16),
+                (nesvnic->nesdev->nesadapter->firmware_version & 0x000000ff));
+}
+
 /**
  * nes_init_ofa_device
  */
@@ -3802,6 +3796,7 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
        nesibdev->ibdev.iwcm->create_listen = nes_create_listen;
        nesibdev->ibdev.iwcm->destroy_listen = nes_destroy_listen;
        nesibdev->ibdev.get_port_immutable   = nes_port_immutable;
+       nesibdev->ibdev.get_dev_fw_str   = get_dev_fw_str;
        memcpy(nesibdev->ibdev.iwcm->ifname, netdev->name,
               sizeof(nesibdev->ibdev.iwcm->ifname));
 
index 3d75f65..07d0c6c 100644 (file)
@@ -107,6 +107,14 @@ static int ocrdma_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void get_dev_fw_str(struct ib_device *device, char *str,
+                          size_t str_len)
+{
+       struct ocrdma_dev *dev = get_ocrdma_dev(device);
+
+       snprintf(str, str_len, "%s", &dev->attr.fw_ver[0]);
+}
+
 static int ocrdma_register_device(struct ocrdma_dev *dev)
 {
        strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);
@@ -193,6 +201,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
 
        dev->ibdev.process_mad = ocrdma_process_mad;
        dev->ibdev.get_port_immutable = ocrdma_port_immutable;
+       dev->ibdev.get_dev_fw_str     = get_dev_fw_str;
 
        if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) {
                dev->ibdev.uverbs_cmd_mask |=
@@ -262,14 +271,6 @@ static ssize_t show_rev(struct device *device, struct device_attribute *attr,
        return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->nic_info.pdev->vendor);
 }
 
-static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
-                       char *buf)
-{
-       struct ocrdma_dev *dev = dev_get_drvdata(device);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", &dev->attr.fw_ver[0]);
-}
-
 static ssize_t show_hca_type(struct device *device,
                             struct device_attribute *attr, char *buf)
 {
@@ -279,12 +280,10 @@ static ssize_t show_hca_type(struct device *device,
 }
 
 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_type, NULL);
 
 static struct device_attribute *ocrdma_attributes[] = {
        &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
        &dev_attr_hca_type
 };
 
index 575b737..9cc0aae 100644 (file)
@@ -106,6 +106,49 @@ static u32 credit_table[31] = {
        32768                   /* 1E */
 };
 
+const struct rvt_operation_params qib_post_parms[RVT_OPERATION_MAX] = {
+[IB_WR_RDMA_WRITE] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_RDMA_READ] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC,
+},
+
+[IB_WR_ATOMIC_CMP_AND_SWP] = {
+       .length = sizeof(struct ib_atomic_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
+},
+
+[IB_WR_ATOMIC_FETCH_AND_ADD] = {
+       .length = sizeof(struct ib_atomic_wr),
+       .qpt_support = BIT(IB_QPT_RC),
+       .flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
+},
+
+[IB_WR_RDMA_WRITE_WITH_IMM] = {
+       .length = sizeof(struct ib_rdma_wr),
+       .qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_SEND] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
+                      BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+[IB_WR_SEND_WITH_IMM] = {
+       .length = sizeof(struct ib_send_wr),
+       .qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
+                      BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
+},
+
+};
+
 static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map,
                         gfp_t gfp)
 {
index 846e6c7..10d0625 100644 (file)
@@ -169,8 +169,12 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
        }
 
        if (ah_attr->ah_flags & IB_AH_GRH) {
-               qib_copy_sge(&qp->r_sge, &ah_attr->grh,
-                            sizeof(struct ib_grh), 1);
+               struct ib_grh grh;
+               struct ib_global_route grd = ah_attr->grh;
+
+               qib_make_grh(ibp, &grh, &grd, 0, 0);
+               qib_copy_sge(&qp->r_sge, &grh,
+                            sizeof(grh), 1);
                wc.wc_flags |= IB_WC_GRH;
        } else
                qib_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1);
index cbf6200..fd1dfbc 100644 (file)
@@ -1582,6 +1582,8 @@ static void qib_fill_device_attr(struct qib_devdata *dd)
        rdi->dparms.props.max_total_mcast_qp_attach =
                                        rdi->dparms.props.max_mcast_qp_attach *
                                        rdi->dparms.props.max_mcast_grp;
+       /* post send table */
+       dd->verbs_dev.rdi.post_parms = qib_post_parms;
 }
 
 /**
index 4f87815..736ced6 100644 (file)
@@ -497,4 +497,6 @@ extern unsigned int ib_qib_max_srq_wrs;
 
 extern const u32 ib_qib_rnr_table[];
 
+extern const struct rvt_operation_params qib_post_parms[];
+
 #endif                          /* QIB_VERBS_H */
index 565c881..c229b9f 100644 (file)
@@ -331,6 +331,21 @@ static int usnic_port_immutable(struct ib_device *ibdev, u8 port_num,
        return 0;
 }
 
+static void usnic_get_dev_fw_str(struct ib_device *device,
+                                char *str,
+                                size_t str_len)
+{
+       struct usnic_ib_dev *us_ibdev =
+               container_of(device, struct usnic_ib_dev, ib_dev);
+       struct ethtool_drvinfo info;
+
+       mutex_lock(&us_ibdev->usdev_lock);
+       us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
+       mutex_unlock(&us_ibdev->usdev_lock);
+
+       snprintf(str, str_len, "%s", info.fw_version);
+}
+
 /* Start of PF discovery section */
 static void *usnic_ib_device_add(struct pci_dev *dev)
 {
@@ -414,6 +429,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
        us_ibdev->ib_dev.req_notify_cq = usnic_ib_req_notify_cq;
        us_ibdev->ib_dev.get_dma_mr = usnic_ib_get_dma_mr;
        us_ibdev->ib_dev.get_port_immutable = usnic_port_immutable;
+       us_ibdev->ib_dev.get_dev_fw_str     = usnic_get_dev_fw_str;
 
 
        if (ib_register_device(&us_ibdev->ib_dev, NULL))
index 3412ea0..80ef3f8 100644 (file)
 #include "usnic_ib_verbs.h"
 #include "usnic_log.h"
 
-static ssize_t usnic_ib_show_fw_ver(struct device *device,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usnic_ib_dev *us_ibdev =
-               container_of(device, struct usnic_ib_dev, ib_dev.dev);
-       struct ethtool_drvinfo info;
-
-       mutex_lock(&us_ibdev->usdev_lock);
-       us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
-       mutex_unlock(&us_ibdev->usdev_lock);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", info.fw_version);
-}
-
 static ssize_t usnic_ib_show_board(struct device *device,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -192,7 +177,6 @@ usnic_ib_show_cq_per_vf(struct device *device, struct device_attribute *attr,
                        us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ]);
 }
 
-static DEVICE_ATTR(fw_ver, S_IRUGO, usnic_ib_show_fw_ver, NULL);
 static DEVICE_ATTR(board_id, S_IRUGO, usnic_ib_show_board, NULL);
 static DEVICE_ATTR(config, S_IRUGO, usnic_ib_show_config, NULL);
 static DEVICE_ATTR(iface, S_IRUGO, usnic_ib_show_iface, NULL);
@@ -201,7 +185,6 @@ static DEVICE_ATTR(qp_per_vf, S_IRUGO, usnic_ib_show_qp_per_vf, NULL);
 static DEVICE_ATTR(cq_per_vf, S_IRUGO, usnic_ib_show_cq_per_vf, NULL);
 
 static struct device_attribute *usnic_class_attributes[] = {
-       &dev_attr_fw_ver,
        &dev_attr_board_id,
        &dev_attr_config,
        &dev_attr_iface,
index 988b6a0..8b095b2 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_INFINIBAND_RDMAVT)                += rdmavt/
+obj-$(CONFIG_RDMA_RXE)                 += rxe/
index 11aa6a3..1da8d01 100644 (file)
@@ -1,6 +1,5 @@
 config INFINIBAND_RDMAVT
        tristate "RDMA verbs transport library"
        depends on 64BIT
-       default m
        ---help---
        This is a common software verbs provider for RDMA networks.
index 6ca6fa8..f2f229e 100644 (file)
@@ -510,6 +510,7 @@ int rvt_driver_cq_init(struct rvt_dev_info *rdi)
 
        if (rdi->worker)
                return 0;
+       spin_lock_init(&rdi->n_cqs_lock);
        rdi->worker = kzalloc(sizeof(*rdi->worker), GFP_KERNEL);
        if (!rdi->worker)
                return -ENOMEM;
index 0f4d450..80c4b6b 100644 (file)
@@ -140,6 +140,7 @@ static int rvt_init_mregion(struct rvt_mregion *mr, struct ib_pd *pd,
        init_completion(&mr->comp);
        /* count returning the ptr to user */
        atomic_set(&mr->refcount, 1);
+       atomic_set(&mr->lkey_invalid, 0);
        mr->pd = pd;
        mr->max_segs = count;
        return 0;
@@ -479,6 +480,123 @@ struct ib_mr *rvt_alloc_mr(struct ib_pd *pd,
        return &mr->ibmr;
 }
 
+/**
+ * rvt_set_page - page assignment function called by ib_sg_to_pages
+ * @ibmr: memory region
+ * @addr: dma address of mapped page
+ *
+ * Return: 0 on success
+ */
+static int rvt_set_page(struct ib_mr *ibmr, u64 addr)
+{
+       struct rvt_mr *mr = to_imr(ibmr);
+       u32 ps = 1 << mr->mr.page_shift;
+       u32 mapped_segs = mr->mr.length >> mr->mr.page_shift;
+       int m, n;
+
+       if (unlikely(mapped_segs == mr->mr.max_segs))
+               return -ENOMEM;
+
+       if (mr->mr.length == 0) {
+               mr->mr.user_base = addr;
+               mr->mr.iova = addr;
+       }
+
+       m = mapped_segs / RVT_SEGSZ;
+       n = mapped_segs % RVT_SEGSZ;
+       mr->mr.map[m]->segs[n].vaddr = (void *)addr;
+       mr->mr.map[m]->segs[n].length = ps;
+       mr->mr.length += ps;
+
+       return 0;
+}
+
+/**
+ * rvt_map_mr_sg - map sg list and set it the memory region
+ * @ibmr: memory region
+ * @sg: dma mapped scatterlist
+ * @sg_nents: number of entries in sg
+ * @sg_offset: offset in bytes into sg
+ *
+ * Return: number of sg elements mapped to the memory region
+ */
+int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+                 int sg_nents, unsigned int *sg_offset)
+{
+       struct rvt_mr *mr = to_imr(ibmr);
+
+       mr->mr.length = 0;
+       mr->mr.page_shift = PAGE_SHIFT;
+       return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset,
+                             rvt_set_page);
+}
+
+/**
+ * rvt_fast_reg_mr - fast register physical MR
+ * @qp: the queue pair where the work request comes from
+ * @ibmr: the memory region to be registered
+ * @key: updated key for this memory region
+ * @access: access flags for this memory region
+ *
+ * Returns 0 on success.
+ */
+int rvt_fast_reg_mr(struct rvt_qp *qp, struct ib_mr *ibmr, u32 key,
+                   int access)
+{
+       struct rvt_mr *mr = to_imr(ibmr);
+
+       if (qp->ibqp.pd != mr->mr.pd)
+               return -EACCES;
+
+       /* not applicable to dma MR or user MR */
+       if (!mr->mr.lkey || mr->umem)
+               return -EINVAL;
+
+       if ((key & 0xFFFFFF00) != (mr->mr.lkey & 0xFFFFFF00))
+               return -EINVAL;
+
+       ibmr->lkey = key;
+       ibmr->rkey = key;
+       mr->mr.lkey = key;
+       mr->mr.access_flags = access;
+       atomic_set(&mr->mr.lkey_invalid, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL(rvt_fast_reg_mr);
+
+/**
+ * rvt_invalidate_rkey - invalidate an MR rkey
+ * @qp: queue pair associated with the invalidate op
+ * @rkey: rkey to invalidate
+ *
+ * Returns 0 on success.
+ */
+int rvt_invalidate_rkey(struct rvt_qp *qp, u32 rkey)
+{
+       struct rvt_dev_info *dev = ib_to_rvt(qp->ibqp.device);
+       struct rvt_lkey_table *rkt = &dev->lkey_table;
+       struct rvt_mregion *mr;
+
+       if (rkey == 0)
+               return -EINVAL;
+
+       rcu_read_lock();
+       mr = rcu_dereference(
+               rkt->table[(rkey >> (32 - dev->dparms.lkey_table_size))]);
+       if (unlikely(!mr || mr->lkey != rkey || qp->ibqp.pd != mr->pd))
+               goto bail;
+
+       atomic_set(&mr->lkey_invalid, 1);
+       rcu_read_unlock();
+       return 0;
+
+bail:
+       rcu_read_unlock();
+       return -EINVAL;
+}
+EXPORT_SYMBOL(rvt_invalidate_rkey);
+
 /**
  * rvt_alloc_fmr - allocate a fast memory region
  * @pd: the protection domain for this memory region
@@ -682,7 +800,8 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd,
        }
        mr = rcu_dereference(
                rkt->table[(sge->lkey >> (32 - dev->dparms.lkey_table_size))]);
-       if (unlikely(!mr || mr->lkey != sge->lkey || mr->pd != &pd->ibpd))
+       if (unlikely(!mr || atomic_read(&mr->lkey_invalid) ||
+                    mr->lkey != sge->lkey || mr->pd != &pd->ibpd))
                goto bail;
 
        off = sge->addr - mr->user_base;
@@ -782,7 +901,8 @@ int rvt_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge,
 
        mr = rcu_dereference(
                rkt->table[(rkey >> (32 - dev->dparms.lkey_table_size))]);
-       if (unlikely(!mr || mr->lkey != rkey || qp->ibqp.pd != mr->pd))
+       if (unlikely(!mr || atomic_read(&mr->lkey_invalid) ||
+                    mr->lkey != rkey || qp->ibqp.pd != mr->pd))
                goto bail;
 
        off = vaddr - mr->iova;
index 6938051..132800e 100644 (file)
@@ -82,6 +82,8 @@ int rvt_dereg_mr(struct ib_mr *ibmr);
 struct ib_mr *rvt_alloc_mr(struct ib_pd *pd,
                           enum ib_mr_type mr_type,
                           u32 max_num_sg);
+int rvt_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+                 int sg_nents, unsigned int *sg_offset);
 struct ib_fmr *rvt_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
                             struct ib_fmr_attr *fmr_attr);
 int rvt_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
index 41ba7e9..bdb540f 100644 (file)
@@ -435,8 +435,7 @@ static void rvt_clear_mr_refs(struct rvt_qp *qp, int clr_sends)
        for (n = 0; n < rvt_max_atomic(rdi); n++) {
                struct rvt_ack_entry *e = &qp->s_ack_queue[n];
 
-               if (e->opcode == IB_OPCODE_RC_RDMA_READ_REQUEST &&
-                   e->rdma_sge.mr) {
+               if (e->rdma_sge.mr) {
                        rvt_put_mr(e->rdma_sge.mr);
                        e->rdma_sge.mr = NULL;
                }
@@ -584,6 +583,7 @@ static void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp,
                qp->r_rq.wq->tail = 0;
        }
        qp->r_sge.num_sge = 0;
+       atomic_set(&qp->s_reserved_used, 0);
 }
 
 /**
@@ -613,6 +613,7 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
        struct rvt_dev_info *rdi = ib_to_rvt(ibpd->device);
        void *priv = NULL;
        gfp_t gfp;
+       size_t sqsize;
 
        if (!rdi)
                return ERR_PTR(-EINVAL);
@@ -643,7 +644,9 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                    init_attr->cap.max_recv_wr == 0)
                        return ERR_PTR(-EINVAL);
        }
-
+       sqsize =
+               init_attr->cap.max_send_wr + 1 +
+               rdi->dparms.reserved_operations;
        switch (init_attr->qp_type) {
        case IB_QPT_SMI:
        case IB_QPT_GSI:
@@ -658,11 +661,11 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                        sizeof(struct rvt_swqe);
                if (gfp == GFP_NOIO)
                        swq = __vmalloc(
-                               (init_attr->cap.max_send_wr + 1) * sz,
+                               sqsize * sz,
                                gfp | __GFP_ZERO, PAGE_KERNEL);
                else
                        swq = vzalloc_node(
-                               (init_attr->cap.max_send_wr + 1) * sz,
+                               sqsize * sz,
                                rdi->dparms.node);
                if (!swq)
                        return ERR_PTR(-ENOMEM);
@@ -741,13 +744,14 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd,
                spin_lock_init(&qp->s_lock);
                spin_lock_init(&qp->r_rq.lock);
                atomic_set(&qp->refcount, 0);
+               atomic_set(&qp->local_ops_pending, 0);
                init_waitqueue_head(&qp->wait);
                init_timer(&qp->s_timer);
                qp->s_timer.data = (unsigned long)qp;
                INIT_LIST_HEAD(&qp->rspwait);
                qp->state = IB_QPS_RESET;
                qp->s_wq = swq;
-               qp->s_size = init_attr->cap.max_send_wr + 1;
+               qp->s_size = sqsize;
                qp->s_avail = init_attr->cap.max_send_wr;
                qp->s_max_sge = init_attr->cap.max_send_sge;
                if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
@@ -1332,7 +1336,8 @@ int rvt_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        attr->sq_psn = qp->s_next_psn & rdi->dparms.psn_mask;
        attr->dest_qp_num = qp->remote_qpn;
        attr->qp_access_flags = qp->qp_access_flags;
-       attr->cap.max_send_wr = qp->s_size - 1;
+       attr->cap.max_send_wr = qp->s_size - 1 -
+               rdi->dparms.reserved_operations;
        attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1;
        attr->cap.max_send_sge = qp->s_max_sge;
        attr->cap.max_recv_sge = qp->r_rq.max_sge;
@@ -1440,25 +1445,116 @@ int rvt_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 }
 
 /**
- * qp_get_savail - return number of avail send entries
+ * rvt_qp_valid_operation - validate post send wr request
+ * @qp - the qp
+ * @post-parms - the post send table for the driver
+ * @wr - the work request
+ *
+ * The routine validates the operation based on the
+ * validation table an returns the length of the operation
+ * which can extend beyond the ib_send_bw.  Operation
+ * dependent flags key atomic operation validation.
  *
+ * There is an exception for UD qps that validates the pd and
+ * overrides the length to include the additional UD specific
+ * length.
+ *
+ * Returns a negative error or the length of the work request
+ * for building the swqe.
+ */
+static inline int rvt_qp_valid_operation(
+       struct rvt_qp *qp,
+       const struct rvt_operation_params *post_parms,
+       struct ib_send_wr *wr)
+{
+       int len;
+
+       if (wr->opcode >= RVT_OPERATION_MAX || !post_parms[wr->opcode].length)
+               return -EINVAL;
+       if (!(post_parms[wr->opcode].qpt_support & BIT(qp->ibqp.qp_type)))
+               return -EINVAL;
+       if ((post_parms[wr->opcode].flags & RVT_OPERATION_PRIV) &&
+           ibpd_to_rvtpd(qp->ibqp.pd)->user)
+               return -EINVAL;
+       if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC_SGE &&
+           (wr->num_sge == 0 ||
+            wr->sg_list[0].length < sizeof(u64) ||
+            wr->sg_list[0].addr & (sizeof(u64) - 1)))
+               return -EINVAL;
+       if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC &&
+           !qp->s_max_rd_atomic)
+               return -EINVAL;
+       len = post_parms[wr->opcode].length;
+       /* UD specific */
+       if (qp->ibqp.qp_type != IB_QPT_UC &&
+           qp->ibqp.qp_type != IB_QPT_RC) {
+               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
+                       return -EINVAL;
+               len = sizeof(struct ib_ud_wr);
+       }
+       return len;
+}
+
+/**
+ * rvt_qp_is_avail - determine queue capacity
  * @qp - the qp
+ * @rdi - the rdmavt device
+ * @reserved_op - is reserved operation
  *
  * This assumes the s_hlock is held but the s_last
  * qp variable is uncontrolled.
+ *
+ * For non reserved operations, the qp->s_avail
+ * may be changed.
+ *
+ * The return value is zero or a -ENOMEM.
  */
-static inline u32 qp_get_savail(struct rvt_qp *qp)
+static inline int rvt_qp_is_avail(
+       struct rvt_qp *qp,
+       struct rvt_dev_info *rdi,
+       bool reserved_op)
 {
        u32 slast;
-       u32 ret;
-
+       u32 avail;
+       u32 reserved_used;
+
+       /* see rvt_qp_wqe_unreserve() */
+       smp_mb__before_atomic();
+       reserved_used = atomic_read(&qp->s_reserved_used);
+       if (unlikely(reserved_op)) {
+               /* see rvt_qp_wqe_unreserve() */
+               smp_mb__before_atomic();
+               if (reserved_used >= rdi->dparms.reserved_operations)
+                       return -ENOMEM;
+               return 0;
+       }
+       /* non-reserved operations */
+       if (likely(qp->s_avail))
+               return 0;
        smp_read_barrier_depends(); /* see rc.c */
        slast = ACCESS_ONCE(qp->s_last);
        if (qp->s_head >= slast)
-               ret = qp->s_size - (qp->s_head - slast);
+               avail = qp->s_size - (qp->s_head - slast);
        else
-               ret = slast - qp->s_head;
-       return ret - 1;
+               avail = slast - qp->s_head;
+
+       /* see rvt_qp_wqe_unreserve() */
+       smp_mb__before_atomic();
+       reserved_used = atomic_read(&qp->s_reserved_used);
+       avail =  avail - 1 -
+               (rdi->dparms.reserved_operations - reserved_used);
+       /* insure we don't assign a negative s_avail */
+       if ((s32)avail <= 0)
+               return -ENOMEM;
+       qp->s_avail = avail;
+       if (WARN_ON(qp->s_avail >
+                   (qp->s_size - 1 - rdi->dparms.reserved_operations)))
+               rvt_pr_err(rdi,
+                          "More avail entries than QP RB size.\nQP: %u, size: %u, avail: %u\nhead: %u, tail: %u, cur: %u, acked: %u, last: %u",
+                          qp->ibqp.qp_num, qp->s_size, qp->s_avail,
+                          qp->s_head, qp->s_tail, qp->s_cur,
+                          qp->s_acked, qp->s_last);
+       return 0;
 }
 
 /**
@@ -1480,49 +1576,64 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
        struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device);
        u8 log_pmtu;
        int ret;
+       size_t cplen;
+       bool reserved_op;
+       int local_ops_delayed = 0;
+
+       BUILD_BUG_ON(IB_QPT_MAX >= (sizeof(u32) * BITS_PER_BYTE));
 
        /* IB spec says that num_sge == 0 is OK. */
        if (unlikely(wr->num_sge > qp->s_max_sge))
                return -EINVAL;
 
+       ret = rvt_qp_valid_operation(qp, rdi->post_parms, wr);
+       if (ret < 0)
+               return ret;
+       cplen = ret;
+
        /*
-        * Don't allow RDMA reads or atomic operations on UC or
-        * undefined operations.
-        * Make sure buffer is large enough to hold the result for atomics.
+        * Local operations include fast register and local invalidate.
+        * Fast register needs to be processed immediately because the
+        * registered lkey may be used by following work requests and the
+        * lkey needs to be valid at the time those requests are posted.
+        * Local invalidate can be processed immediately if fencing is
+        * not required and no previous local invalidate ops are pending.
+        * Signaled local operations that have been processed immediately
+        * need to have requests with "completion only" flags set posted
+        * to the send queue in order to generate completions.
         */
-       if (qp->ibqp.qp_type == IB_QPT_UC) {
-               if ((unsigned)wr->opcode >= IB_WR_RDMA_READ)
-                       return -EINVAL;
-       } else if (qp->ibqp.qp_type != IB_QPT_RC) {
-               /* Check IB_QPT_SMI, IB_QPT_GSI, IB_QPT_UD opcode */
-               if (wr->opcode != IB_WR_SEND &&
-                   wr->opcode != IB_WR_SEND_WITH_IMM)
-                       return -EINVAL;
-               /* Check UD destination address PD */
-               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
+       if ((rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) {
+               switch (wr->opcode) {
+               case IB_WR_REG_MR:
+                       ret = rvt_fast_reg_mr(qp,
+                                             reg_wr(wr)->mr,
+                                             reg_wr(wr)->key,
+                                             reg_wr(wr)->access);
+                       if (ret || !(wr->send_flags & IB_SEND_SIGNALED))
+                               return ret;
+                       break;
+               case IB_WR_LOCAL_INV:
+                       if ((wr->send_flags & IB_SEND_FENCE) ||
+                           atomic_read(&qp->local_ops_pending)) {
+                               local_ops_delayed = 1;
+                       } else {
+                               ret = rvt_invalidate_rkey(
+                                       qp, wr->ex.invalidate_rkey);
+                               if (ret || !(wr->send_flags & IB_SEND_SIGNALED))
+                                       return ret;
+                       }
+                       break;
+               default:
                        return -EINVAL;
-       } else if ((unsigned)wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) {
-               return -EINVAL;
-       } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
-                  (wr->num_sge == 0 ||
-                   wr->sg_list[0].length < sizeof(u64) ||
-                   wr->sg_list[0].addr & (sizeof(u64) - 1))) {
-               return -EINVAL;
-       } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
-               return -EINVAL;
+               }
        }
+
+       reserved_op = rdi->post_parms[wr->opcode].flags &
+                       RVT_OPERATION_USE_RESERVE;
        /* check for avail */
-       if (unlikely(!qp->s_avail)) {
-               qp->s_avail = qp_get_savail(qp);
-               if (WARN_ON(qp->s_avail > (qp->s_size - 1)))
-                       rvt_pr_err(rdi,
-                                  "More avail entries than QP RB size.\nQP: %u, size: %u, avail: %u\nhead: %u, tail: %u, cur: %u, acked: %u, last: %u",
-                                  qp->ibqp.qp_num, qp->s_size, qp->s_avail,
-                                  qp->s_head, qp->s_tail, qp->s_cur,
-                                  qp->s_acked, qp->s_last);
-               if (!qp->s_avail)
-                       return -ENOMEM;
-       }
+       ret = rvt_qp_is_avail(qp, rdi, reserved_op);
+       if (ret)
+               return ret;
        next = qp->s_head + 1;
        if (next >= qp->s_size)
                next = 0;
@@ -1531,18 +1642,8 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
        pd = ibpd_to_rvtpd(qp->ibqp.pd);
        wqe = rvt_get_swqe_ptr(qp, qp->s_head);
 
-       if (qp->ibqp.qp_type != IB_QPT_UC &&
-           qp->ibqp.qp_type != IB_QPT_RC)
-               memcpy(&wqe->ud_wr, ud_wr(wr), sizeof(wqe->ud_wr));
-       else if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
-                wr->opcode == IB_WR_RDMA_WRITE ||
-                wr->opcode == IB_WR_RDMA_READ)
-               memcpy(&wqe->rdma_wr, rdma_wr(wr), sizeof(wqe->rdma_wr));
-       else if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-               memcpy(&wqe->atomic_wr, atomic_wr(wr), sizeof(wqe->atomic_wr));
-       else
-               memcpy(&wqe->wr, wr, sizeof(wqe->wr));
+       /* cplen has length from above */
+       memcpy(&wqe->wr, wr, cplen);
 
        wqe->length = 0;
        j = 0;
@@ -1585,14 +1686,29 @@ static int rvt_post_one_wr(struct rvt_qp *qp,
                atomic_inc(&ibah_to_rvtah(ud_wr(wr)->ah)->refcount);
        }
 
-       wqe->ssn = qp->s_ssn++;
-       wqe->psn = qp->s_next_psn;
-       wqe->lpsn = wqe->psn +
-                       (wqe->length ? ((wqe->length - 1) >> log_pmtu) : 0);
-       qp->s_next_psn = wqe->lpsn + 1;
+       if (rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL) {
+               if (local_ops_delayed)
+                       atomic_inc(&qp->local_ops_pending);
+               else
+                       wqe->wr.send_flags |= RVT_SEND_COMPLETION_ONLY;
+               wqe->ssn = 0;
+               wqe->psn = 0;
+               wqe->lpsn = 0;
+       } else {
+               wqe->ssn = qp->s_ssn++;
+               wqe->psn = qp->s_next_psn;
+               wqe->lpsn = wqe->psn +
+                               (wqe->length ?
+                                       ((wqe->length - 1) >> log_pmtu) :
+                                       0);
+               qp->s_next_psn = wqe->lpsn + 1;
+       }
        trace_rvt_post_one_wr(qp, wqe);
+       if (unlikely(reserved_op))
+               rvt_qp_wqe_reserve(qp, wqe);
+       else
+               qp->s_avail--;
        smp_wmb(); /* see request builders */
-       qp->s_avail--;
        qp->s_head = next;
 
        return 0;
index 30c4fda..d430c2f 100644 (file)
@@ -370,6 +370,7 @@ enum {
        REG_USER_MR,
        DEREG_MR,
        ALLOC_MR,
+       MAP_MR_SG,
        ALLOC_FMR,
        MAP_PHYS_FMR,
        UNMAP_FMR,
@@ -528,7 +529,8 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb)
                                                         post_send),
                                           rvt_post_send))
                        if (!rdi->driver_f.schedule_send ||
-                           !rdi->driver_f.do_send)
+                           !rdi->driver_f.do_send ||
+                           !rdi->post_parms)
                                return -EINVAL;
                break;
 
@@ -633,6 +635,12 @@ static noinline int check_support(struct rvt_dev_info *rdi, int verb)
                                      rvt_alloc_mr);
                break;
 
+       case MAP_MR_SG:
+               check_driver_override(rdi, offsetof(struct ib_device,
+                                                   map_mr_sg),
+                                     rvt_map_mr_sg);
+               break;
+
        case MAP_PHYS_FMR:
                check_driver_override(rdi, offsetof(struct ib_device,
                                                    map_phys_fmr),
diff --git a/drivers/infiniband/sw/rxe/Kconfig b/drivers/infiniband/sw/rxe/Kconfig
new file mode 100644 (file)
index 0000000..1e4e628
--- /dev/null
@@ -0,0 +1,24 @@
+config RDMA_RXE
+       tristate "Software RDMA over Ethernet (RoCE) driver"
+       depends on INET && PCI && INFINIBAND
+       depends on NET_UDP_TUNNEL
+       ---help---
+       This driver implements the InfiniBand RDMA transport over
+       the Linux network stack. It enables a system with a
+       standard Ethernet adapter to interoperate with a RoCE
+       adapter or with another system running the RXE driver.
+       Documentation on InfiniBand and RoCE can be downloaded at
+       www.infinibandta.org and www.openfabrics.org. (See also
+       siw which is a similar software driver for iWARP.)
+
+       The driver is split into two layers, one interfaces with the
+       Linux RDMA stack and implements a kernel or user space
+       verbs API. The user space verbs API requires a support
+       library named librxe which is loaded by the generic user
+       space verbs API, libibverbs. The other layer interfaces
+       with the Linux network stack at layer 3.
+
+       To configure and work with soft-RoCE driver please use the
+       following wiki page under "configure Soft-RoCE (RXE)" section:
+
+       https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
diff --git a/drivers/infiniband/sw/rxe/Makefile b/drivers/infiniband/sw/rxe/Makefile
new file mode 100644 (file)
index 0000000..3b3fb9d
--- /dev/null
@@ -0,0 +1,24 @@
+obj-$(CONFIG_RDMA_RXE) += rdma_rxe.o
+
+rdma_rxe-y := \
+       rxe.o \
+       rxe_comp.o \
+       rxe_req.o \
+       rxe_resp.o \
+       rxe_recv.o \
+       rxe_pool.o \
+       rxe_queue.o \
+       rxe_verbs.o \
+       rxe_av.o \
+       rxe_srq.o \
+       rxe_qp.o \
+       rxe_cq.o \
+       rxe_mr.o \
+       rxe_dma.o \
+       rxe_opcode.o \
+       rxe_mmap.o \
+       rxe_icrc.o \
+       rxe_mcast.o \
+       rxe_task.o \
+       rxe_net.o \
+       rxe_sysfs.o
diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c
new file mode 100644 (file)
index 0000000..55f0e8f
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+MODULE_AUTHOR("Bob Pearson, Frank Zago, John Groves, Kamal Heib");
+MODULE_DESCRIPTION("Soft RDMA transport");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.2");
+
+/* free resources for all ports on a device */
+static void rxe_cleanup_ports(struct rxe_dev *rxe)
+{
+       kfree(rxe->port.pkey_tbl);
+       rxe->port.pkey_tbl = NULL;
+
+}
+
+/* free resources for a rxe device all objects created for this device must
+ * have been destroyed
+ */
+static void rxe_cleanup(struct rxe_dev *rxe)
+{
+       rxe_pool_cleanup(&rxe->uc_pool);
+       rxe_pool_cleanup(&rxe->pd_pool);
+       rxe_pool_cleanup(&rxe->ah_pool);
+       rxe_pool_cleanup(&rxe->srq_pool);
+       rxe_pool_cleanup(&rxe->qp_pool);
+       rxe_pool_cleanup(&rxe->cq_pool);
+       rxe_pool_cleanup(&rxe->mr_pool);
+       rxe_pool_cleanup(&rxe->mw_pool);
+       rxe_pool_cleanup(&rxe->mc_grp_pool);
+       rxe_pool_cleanup(&rxe->mc_elem_pool);
+
+       rxe_cleanup_ports(rxe);
+}
+
+/* called when all references have been dropped */
+void rxe_release(struct kref *kref)
+{
+       struct rxe_dev *rxe = container_of(kref, struct rxe_dev, ref_cnt);
+
+       rxe_cleanup(rxe);
+       ib_dealloc_device(&rxe->ib_dev);
+}
+
+void rxe_dev_put(struct rxe_dev *rxe)
+{
+       kref_put(&rxe->ref_cnt, rxe_release);
+}
+EXPORT_SYMBOL_GPL(rxe_dev_put);
+
+/* initialize rxe device parameters */
+static int rxe_init_device_param(struct rxe_dev *rxe)
+{
+       rxe->max_inline_data                    = RXE_MAX_INLINE_DATA;
+
+       rxe->attr.fw_ver                        = RXE_FW_VER;
+       rxe->attr.max_mr_size                   = RXE_MAX_MR_SIZE;
+       rxe->attr.page_size_cap                 = RXE_PAGE_SIZE_CAP;
+       rxe->attr.vendor_id                     = RXE_VENDOR_ID;
+       rxe->attr.vendor_part_id                = RXE_VENDOR_PART_ID;
+       rxe->attr.hw_ver                        = RXE_HW_VER;
+       rxe->attr.max_qp                        = RXE_MAX_QP;
+       rxe->attr.max_qp_wr                     = RXE_MAX_QP_WR;
+       rxe->attr.device_cap_flags              = RXE_DEVICE_CAP_FLAGS;
+       rxe->attr.max_sge                       = RXE_MAX_SGE;
+       rxe->attr.max_sge_rd                    = RXE_MAX_SGE_RD;
+       rxe->attr.max_cq                        = RXE_MAX_CQ;
+       rxe->attr.max_cqe                       = (1 << RXE_MAX_LOG_CQE) - 1;
+       rxe->attr.max_mr                        = RXE_MAX_MR;
+       rxe->attr.max_pd                        = RXE_MAX_PD;
+       rxe->attr.max_qp_rd_atom                = RXE_MAX_QP_RD_ATOM;
+       rxe->attr.max_ee_rd_atom                = RXE_MAX_EE_RD_ATOM;
+       rxe->attr.max_res_rd_atom               = RXE_MAX_RES_RD_ATOM;
+       rxe->attr.max_qp_init_rd_atom           = RXE_MAX_QP_INIT_RD_ATOM;
+       rxe->attr.max_ee_init_rd_atom           = RXE_MAX_EE_INIT_RD_ATOM;
+       rxe->attr.atomic_cap                    = RXE_ATOMIC_CAP;
+       rxe->attr.max_ee                        = RXE_MAX_EE;
+       rxe->attr.max_rdd                       = RXE_MAX_RDD;
+       rxe->attr.max_mw                        = RXE_MAX_MW;
+       rxe->attr.max_raw_ipv6_qp               = RXE_MAX_RAW_IPV6_QP;
+       rxe->attr.max_raw_ethy_qp               = RXE_MAX_RAW_ETHY_QP;
+       rxe->attr.max_mcast_grp                 = RXE_MAX_MCAST_GRP;
+       rxe->attr.max_mcast_qp_attach           = RXE_MAX_MCAST_QP_ATTACH;
+       rxe->attr.max_total_mcast_qp_attach     = RXE_MAX_TOT_MCAST_QP_ATTACH;
+       rxe->attr.max_ah                        = RXE_MAX_AH;
+       rxe->attr.max_fmr                       = RXE_MAX_FMR;
+       rxe->attr.max_map_per_fmr               = RXE_MAX_MAP_PER_FMR;
+       rxe->attr.max_srq                       = RXE_MAX_SRQ;
+       rxe->attr.max_srq_wr                    = RXE_MAX_SRQ_WR;
+       rxe->attr.max_srq_sge                   = RXE_MAX_SRQ_SGE;
+       rxe->attr.max_fast_reg_page_list_len    = RXE_MAX_FMR_PAGE_LIST_LEN;
+       rxe->attr.max_pkeys                     = RXE_MAX_PKEYS;
+       rxe->attr.local_ca_ack_delay            = RXE_LOCAL_CA_ACK_DELAY;
+
+       rxe->max_ucontext                       = RXE_MAX_UCONTEXT;
+
+       return 0;
+}
+
+/* initialize port attributes */
+static int rxe_init_port_param(struct rxe_port *port)
+{
+       port->attr.state                = RXE_PORT_STATE;
+       port->attr.max_mtu              = RXE_PORT_MAX_MTU;
+       port->attr.active_mtu           = RXE_PORT_ACTIVE_MTU;
+       port->attr.gid_tbl_len          = RXE_PORT_GID_TBL_LEN;
+       port->attr.port_cap_flags       = RXE_PORT_PORT_CAP_FLAGS;
+       port->attr.max_msg_sz           = RXE_PORT_MAX_MSG_SZ;
+       port->attr.bad_pkey_cntr        = RXE_PORT_BAD_PKEY_CNTR;
+       port->attr.qkey_viol_cntr       = RXE_PORT_QKEY_VIOL_CNTR;
+       port->attr.pkey_tbl_len         = RXE_PORT_PKEY_TBL_LEN;
+       port->attr.lid                  = RXE_PORT_LID;
+       port->attr.sm_lid               = RXE_PORT_SM_LID;
+       port->attr.lmc                  = RXE_PORT_LMC;
+       port->attr.max_vl_num           = RXE_PORT_MAX_VL_NUM;
+       port->attr.sm_sl                = RXE_PORT_SM_SL;
+       port->attr.subnet_timeout       = RXE_PORT_SUBNET_TIMEOUT;
+       port->attr.init_type_reply      = RXE_PORT_INIT_TYPE_REPLY;
+       port->attr.active_width         = RXE_PORT_ACTIVE_WIDTH;
+       port->attr.active_speed         = RXE_PORT_ACTIVE_SPEED;
+       port->attr.phys_state           = RXE_PORT_PHYS_STATE;
+       port->mtu_cap                   =
+                               ib_mtu_enum_to_int(RXE_PORT_ACTIVE_MTU);
+       port->subnet_prefix             = cpu_to_be64(RXE_PORT_SUBNET_PREFIX);
+
+       return 0;
+}
+
+/* initialize port state, note IB convention that HCA ports are always
+ * numbered from 1
+ */
+static int rxe_init_ports(struct rxe_dev *rxe)
+{
+       struct rxe_port *port = &rxe->port;
+
+       rxe_init_port_param(port);
+
+       if (!port->attr.pkey_tbl_len || !port->attr.gid_tbl_len)
+               return -EINVAL;
+
+       port->pkey_tbl = kcalloc(port->attr.pkey_tbl_len,
+                       sizeof(*port->pkey_tbl), GFP_KERNEL);
+
+       if (!port->pkey_tbl)
+               return -ENOMEM;
+
+       port->pkey_tbl[0] = 0xffff;
+       port->port_guid = rxe->ifc_ops->port_guid(rxe);
+
+       spin_lock_init(&port->port_lock);
+
+       return 0;
+}
+
+/* init pools of managed objects */
+static int rxe_init_pools(struct rxe_dev *rxe)
+{
+       int err;
+
+       err = rxe_pool_init(rxe, &rxe->uc_pool, RXE_TYPE_UC,
+                           rxe->max_ucontext);
+       if (err)
+               goto err1;
+
+       err = rxe_pool_init(rxe, &rxe->pd_pool, RXE_TYPE_PD,
+                           rxe->attr.max_pd);
+       if (err)
+               goto err2;
+
+       err = rxe_pool_init(rxe, &rxe->ah_pool, RXE_TYPE_AH,
+                           rxe->attr.max_ah);
+       if (err)
+               goto err3;
+
+       err = rxe_pool_init(rxe, &rxe->srq_pool, RXE_TYPE_SRQ,
+                           rxe->attr.max_srq);
+       if (err)
+               goto err4;
+
+       err = rxe_pool_init(rxe, &rxe->qp_pool, RXE_TYPE_QP,
+                           rxe->attr.max_qp);
+       if (err)
+               goto err5;
+
+       err = rxe_pool_init(rxe, &rxe->cq_pool, RXE_TYPE_CQ,
+                           rxe->attr.max_cq);
+       if (err)
+               goto err6;
+
+       err = rxe_pool_init(rxe, &rxe->mr_pool, RXE_TYPE_MR,
+                           rxe->attr.max_mr);
+       if (err)
+               goto err7;
+
+       err = rxe_pool_init(rxe, &rxe->mw_pool, RXE_TYPE_MW,
+                           rxe->attr.max_mw);
+       if (err)
+               goto err8;
+
+       err = rxe_pool_init(rxe, &rxe->mc_grp_pool, RXE_TYPE_MC_GRP,
+                           rxe->attr.max_mcast_grp);
+       if (err)
+               goto err9;
+
+       err = rxe_pool_init(rxe, &rxe->mc_elem_pool, RXE_TYPE_MC_ELEM,
+                           rxe->attr.max_total_mcast_qp_attach);
+       if (err)
+               goto err10;
+
+       return 0;
+
+err10:
+       rxe_pool_cleanup(&rxe->mc_grp_pool);
+err9:
+       rxe_pool_cleanup(&rxe->mw_pool);
+err8:
+       rxe_pool_cleanup(&rxe->mr_pool);
+err7:
+       rxe_pool_cleanup(&rxe->cq_pool);
+err6:
+       rxe_pool_cleanup(&rxe->qp_pool);
+err5:
+       rxe_pool_cleanup(&rxe->srq_pool);
+err4:
+       rxe_pool_cleanup(&rxe->ah_pool);
+err3:
+       rxe_pool_cleanup(&rxe->pd_pool);
+err2:
+       rxe_pool_cleanup(&rxe->uc_pool);
+err1:
+       return err;
+}
+
+/* initialize rxe device state */
+static int rxe_init(struct rxe_dev *rxe)
+{
+       int err;
+
+       /* init default device parameters */
+       rxe_init_device_param(rxe);
+
+       err = rxe_init_ports(rxe);
+       if (err)
+               goto err1;
+
+       err = rxe_init_pools(rxe);
+       if (err)
+               goto err2;
+
+       /* init pending mmap list */
+       spin_lock_init(&rxe->mmap_offset_lock);
+       spin_lock_init(&rxe->pending_lock);
+       INIT_LIST_HEAD(&rxe->pending_mmaps);
+       INIT_LIST_HEAD(&rxe->list);
+
+       mutex_init(&rxe->usdev_lock);
+
+       return 0;
+
+err2:
+       rxe_cleanup_ports(rxe);
+err1:
+       return err;
+}
+
+int rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu)
+{
+       struct rxe_port *port = &rxe->port;
+       enum ib_mtu mtu;
+
+       mtu = eth_mtu_int_to_enum(ndev_mtu);
+
+       /* Make sure that new MTU in range */
+       mtu = mtu ? min_t(enum ib_mtu, mtu, RXE_PORT_MAX_MTU) : IB_MTU_256;
+
+       port->attr.active_mtu = mtu;
+       port->mtu_cap = ib_mtu_enum_to_int(mtu);
+
+       return 0;
+}
+EXPORT_SYMBOL(rxe_set_mtu);
+
+/* called by ifc layer to create new rxe device.
+ * The caller should allocate memory for rxe by calling ib_alloc_device.
+ */
+int rxe_add(struct rxe_dev *rxe, unsigned int mtu)
+{
+       int err;
+
+       kref_init(&rxe->ref_cnt);
+
+       err = rxe_init(rxe);
+       if (err)
+               goto err1;
+
+       err = rxe_set_mtu(rxe, mtu);
+       if (err)
+               goto err1;
+
+       err = rxe_register_device(rxe);
+       if (err)
+               goto err1;
+
+       return 0;
+
+err1:
+       rxe_dev_put(rxe);
+       return err;
+}
+EXPORT_SYMBOL(rxe_add);
+
+/* called by the ifc layer to remove a device */
+void rxe_remove(struct rxe_dev *rxe)
+{
+       rxe_unregister_device(rxe);
+
+       rxe_dev_put(rxe);
+}
+EXPORT_SYMBOL(rxe_remove);
+
+static int __init rxe_module_init(void)
+{
+       int err;
+
+       /* initialize slab caches for managed objects */
+       err = rxe_cache_init();
+       if (err) {
+               pr_err("rxe: unable to init object pools\n");
+               return err;
+       }
+
+       err = rxe_net_init();
+       if (err) {
+               pr_err("rxe: unable to init\n");
+               rxe_cache_exit();
+               return err;
+       }
+       pr_info("rxe: loaded\n");
+
+       return 0;
+}
+
+static void __exit rxe_module_exit(void)
+{
+       rxe_remove_all();
+       rxe_net_exit();
+       rxe_cache_exit();
+
+       pr_info("rxe: unloaded\n");
+}
+
+module_init(rxe_module_init);
+module_exit(rxe_module_exit);
diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
new file mode 100644 (file)
index 0000000..12c71c5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_H
+#define RXE_H
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_addr.h>
+
+#include "rxe_net.h"
+#include "rxe_opcode.h"
+#include "rxe_hdr.h"
+#include "rxe_param.h"
+#include "rxe_verbs.h"
+
+#define RXE_UVERBS_ABI_VERSION         (1)
+
+#define IB_PHYS_STATE_LINK_UP          (5)
+#define IB_PHYS_STATE_LINK_DOWN                (3)
+
+#define RXE_ROCE_V2_SPORT              (0xc000)
+
+int rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
+
+int rxe_add(struct rxe_dev *rxe, unsigned int mtu);
+void rxe_remove(struct rxe_dev *rxe);
+void rxe_remove_all(void);
+
+int rxe_rcv(struct sk_buff *skb);
+
+void rxe_dev_put(struct rxe_dev *rxe);
+struct rxe_dev *net_to_rxe(struct net_device *ndev);
+struct rxe_dev *get_rxe_by_name(const char* name);
+
+void rxe_port_up(struct rxe_dev *rxe);
+void rxe_port_down(struct rxe_dev *rxe);
+
+#endif /* RXE_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_av.c b/drivers/infiniband/sw/rxe/rxe_av.c
new file mode 100644 (file)
index 0000000..5c94742
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr)
+{
+       struct rxe_port *port;
+
+       if (attr->port_num != 1) {
+               pr_info("rxe: invalid port_num = %d\n", attr->port_num);
+               return -EINVAL;
+       }
+
+       port = &rxe->port;
+
+       if (attr->ah_flags & IB_AH_GRH) {
+               if (attr->grh.sgid_index > port->attr.gid_tbl_len) {
+                       pr_info("rxe: invalid sgid index = %d\n",
+                               attr->grh.sgid_index);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+int rxe_av_from_attr(struct rxe_dev *rxe, u8 port_num,
+                    struct rxe_av *av, struct ib_ah_attr *attr)
+{
+       memset(av, 0, sizeof(*av));
+       memcpy(&av->grh, &attr->grh, sizeof(attr->grh));
+       av->port_num = port_num;
+       return 0;
+}
+
+int rxe_av_to_attr(struct rxe_dev *rxe, struct rxe_av *av,
+                  struct ib_ah_attr *attr)
+{
+       memcpy(&attr->grh, &av->grh, sizeof(av->grh));
+       attr->port_num = av->port_num;
+       return 0;
+}
+
+int rxe_av_fill_ip_info(struct rxe_dev *rxe,
+                       struct rxe_av *av,
+                       struct ib_ah_attr *attr,
+                       struct ib_gid_attr *sgid_attr,
+                       union ib_gid *sgid)
+{
+       rdma_gid2ip(&av->sgid_addr._sockaddr, sgid);
+       rdma_gid2ip(&av->dgid_addr._sockaddr, &attr->grh.dgid);
+       av->network_type = ib_gid_to_network_type(sgid_attr->gid_type, sgid);
+
+       return 0;
+}
+
+struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt)
+{
+       if (!pkt || !pkt->qp)
+               return NULL;
+
+       if (qp_type(pkt->qp) == IB_QPT_RC || qp_type(pkt->qp) == IB_QPT_UC)
+               return &pkt->qp->pri_av;
+
+       return (pkt->wqe) ? &pkt->wqe->av : NULL;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
new file mode 100644 (file)
index 0000000..36f67de
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+#include "rxe_task.h"
+
+enum comp_state {
+       COMPST_GET_ACK,
+       COMPST_GET_WQE,
+       COMPST_COMP_WQE,
+       COMPST_COMP_ACK,
+       COMPST_CHECK_PSN,
+       COMPST_CHECK_ACK,
+       COMPST_READ,
+       COMPST_ATOMIC,
+       COMPST_WRITE_SEND,
+       COMPST_UPDATE_COMP,
+       COMPST_ERROR_RETRY,
+       COMPST_RNR_RETRY,
+       COMPST_ERROR,
+       COMPST_EXIT, /* We have an issue, and we want to rerun the completer */
+       COMPST_DONE, /* The completer finished successflly */
+};
+
+static char *comp_state_name[] =  {
+       [COMPST_GET_ACK]                = "GET ACK",
+       [COMPST_GET_WQE]                = "GET WQE",
+       [COMPST_COMP_WQE]               = "COMP WQE",
+       [COMPST_COMP_ACK]               = "COMP ACK",
+       [COMPST_CHECK_PSN]              = "CHECK PSN",
+       [COMPST_CHECK_ACK]              = "CHECK ACK",
+       [COMPST_READ]                   = "READ",
+       [COMPST_ATOMIC]                 = "ATOMIC",
+       [COMPST_WRITE_SEND]             = "WRITE/SEND",
+       [COMPST_UPDATE_COMP]            = "UPDATE COMP",
+       [COMPST_ERROR_RETRY]            = "ERROR RETRY",
+       [COMPST_RNR_RETRY]              = "RNR RETRY",
+       [COMPST_ERROR]                  = "ERROR",
+       [COMPST_EXIT]                   = "EXIT",
+       [COMPST_DONE]                   = "DONE",
+};
+
+static unsigned long rnrnak_usec[32] = {
+       [IB_RNR_TIMER_655_36] = 655360,
+       [IB_RNR_TIMER_000_01] = 10,
+       [IB_RNR_TIMER_000_02] = 20,
+       [IB_RNR_TIMER_000_03] = 30,
+       [IB_RNR_TIMER_000_04] = 40,
+       [IB_RNR_TIMER_000_06] = 60,
+       [IB_RNR_TIMER_000_08] = 80,
+       [IB_RNR_TIMER_000_12] = 120,
+       [IB_RNR_TIMER_000_16] = 160,
+       [IB_RNR_TIMER_000_24] = 240,
+       [IB_RNR_TIMER_000_32] = 320,
+       [IB_RNR_TIMER_000_48] = 480,
+       [IB_RNR_TIMER_000_64] = 640,
+       [IB_RNR_TIMER_000_96] = 960,
+       [IB_RNR_TIMER_001_28] = 1280,
+       [IB_RNR_TIMER_001_92] = 1920,
+       [IB_RNR_TIMER_002_56] = 2560,
+       [IB_RNR_TIMER_003_84] = 3840,
+       [IB_RNR_TIMER_005_12] = 5120,
+       [IB_RNR_TIMER_007_68] = 7680,
+       [IB_RNR_TIMER_010_24] = 10240,
+       [IB_RNR_TIMER_015_36] = 15360,
+       [IB_RNR_TIMER_020_48] = 20480,
+       [IB_RNR_TIMER_030_72] = 30720,
+       [IB_RNR_TIMER_040_96] = 40960,
+       [IB_RNR_TIMER_061_44] = 61410,
+       [IB_RNR_TIMER_081_92] = 81920,
+       [IB_RNR_TIMER_122_88] = 122880,
+       [IB_RNR_TIMER_163_84] = 163840,
+       [IB_RNR_TIMER_245_76] = 245760,
+       [IB_RNR_TIMER_327_68] = 327680,
+       [IB_RNR_TIMER_491_52] = 491520,
+};
+
+static inline unsigned long rnrnak_jiffies(u8 timeout)
+{
+       return max_t(unsigned long,
+               usecs_to_jiffies(rnrnak_usec[timeout]), 1);
+}
+
+static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
+{
+       switch (opcode) {
+       case IB_WR_RDMA_WRITE:                  return IB_WC_RDMA_WRITE;
+       case IB_WR_RDMA_WRITE_WITH_IMM:         return IB_WC_RDMA_WRITE;
+       case IB_WR_SEND:                        return IB_WC_SEND;
+       case IB_WR_SEND_WITH_IMM:               return IB_WC_SEND;
+       case IB_WR_RDMA_READ:                   return IB_WC_RDMA_READ;
+       case IB_WR_ATOMIC_CMP_AND_SWP:          return IB_WC_COMP_SWAP;
+       case IB_WR_ATOMIC_FETCH_AND_ADD:        return IB_WC_FETCH_ADD;
+       case IB_WR_LSO:                         return IB_WC_LSO;
+       case IB_WR_SEND_WITH_INV:               return IB_WC_SEND;
+       case IB_WR_RDMA_READ_WITH_INV:          return IB_WC_RDMA_READ;
+       case IB_WR_LOCAL_INV:                   return IB_WC_LOCAL_INV;
+       case IB_WR_REG_MR:                      return IB_WC_REG_MR;
+
+       default:
+               return 0xff;
+       }
+}
+
+void retransmit_timer(unsigned long data)
+{
+       struct rxe_qp *qp = (struct rxe_qp *)data;
+
+       if (qp->valid) {
+               qp->comp.timeout = 1;
+               rxe_run_task(&qp->comp.task, 1);
+       }
+}
+
+void rxe_comp_queue_pkt(struct rxe_dev *rxe, struct rxe_qp *qp,
+                       struct sk_buff *skb)
+{
+       int must_sched;
+
+       skb_queue_tail(&qp->resp_pkts, skb);
+
+       must_sched = skb_queue_len(&qp->resp_pkts) > 1;
+       rxe_run_task(&qp->comp.task, must_sched);
+}
+
+static inline enum comp_state get_wqe(struct rxe_qp *qp,
+                                     struct rxe_pkt_info *pkt,
+                                     struct rxe_send_wqe **wqe_p)
+{
+       struct rxe_send_wqe *wqe;
+
+       /* we come here whether or not we found a response packet to see if
+        * there are any posted WQEs
+        */
+       wqe = queue_head(qp->sq.queue);
+       *wqe_p = wqe;
+
+       /* no WQE or requester has not started it yet */
+       if (!wqe || wqe->state == wqe_state_posted)
+               return pkt ? COMPST_DONE : COMPST_EXIT;
+
+       /* WQE does not require an ack */
+       if (wqe->state == wqe_state_done)
+               return COMPST_COMP_WQE;
+
+       /* WQE caused an error */
+       if (wqe->state == wqe_state_error)
+               return COMPST_ERROR;
+
+       /* we have a WQE, if we also have an ack check its PSN */
+       return pkt ? COMPST_CHECK_PSN : COMPST_EXIT;
+}
+
+static inline void reset_retry_counters(struct rxe_qp *qp)
+{
+       qp->comp.retry_cnt = qp->attr.retry_cnt;
+       qp->comp.rnr_retry = qp->attr.rnr_retry;
+}
+
+static inline enum comp_state check_psn(struct rxe_qp *qp,
+                                       struct rxe_pkt_info *pkt,
+                                       struct rxe_send_wqe *wqe)
+{
+       s32 diff;
+
+       /* check to see if response is past the oldest WQE. if it is, complete
+        * send/write or error read/atomic
+        */
+       diff = psn_compare(pkt->psn, wqe->last_psn);
+       if (diff > 0) {
+               if (wqe->state == wqe_state_pending) {
+                       if (wqe->mask & WR_ATOMIC_OR_READ_MASK)
+                               return COMPST_ERROR_RETRY;
+
+                       reset_retry_counters(qp);
+                       return COMPST_COMP_WQE;
+               } else {
+                       return COMPST_DONE;
+               }
+       }
+
+       /* compare response packet to expected response */
+       diff = psn_compare(pkt->psn, qp->comp.psn);
+       if (diff < 0) {
+               /* response is most likely a retried packet if it matches an
+                * uncompleted WQE go complete it else ignore it
+                */
+               if (pkt->psn == wqe->last_psn)
+                       return COMPST_COMP_ACK;
+               else
+                       return COMPST_DONE;
+       } else if ((diff > 0) && (wqe->mask & WR_ATOMIC_OR_READ_MASK)) {
+               return COMPST_ERROR_RETRY;
+       } else {
+               return COMPST_CHECK_ACK;
+       }
+}
+
+static inline enum comp_state check_ack(struct rxe_qp *qp,
+                                       struct rxe_pkt_info *pkt,
+                                       struct rxe_send_wqe *wqe)
+{
+       unsigned int mask = pkt->mask;
+       u8 syn;
+
+       /* Check the sequence only */
+       switch (qp->comp.opcode) {
+       case -1:
+               /* Will catch all *_ONLY cases. */
+               if (!(mask & RXE_START_MASK))
+                       return COMPST_ERROR;
+
+               break;
+
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
+               if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE &&
+                   pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) {
+                       return COMPST_ERROR;
+               }
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       /* Check operation validity. */
+       switch (pkt->opcode) {
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST:
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY:
+               syn = aeth_syn(pkt);
+
+               if ((syn & AETH_TYPE_MASK) != AETH_ACK)
+                       return COMPST_ERROR;
+
+               /* Fall through (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE
+                * doesn't have an AETH)
+                */
+       case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
+               if (wqe->wr.opcode != IB_WR_RDMA_READ &&
+                   wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV) {
+                       return COMPST_ERROR;
+               }
+               reset_retry_counters(qp);
+               return COMPST_READ;
+
+       case IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE:
+               syn = aeth_syn(pkt);
+
+               if ((syn & AETH_TYPE_MASK) != AETH_ACK)
+                       return COMPST_ERROR;
+
+               if (wqe->wr.opcode != IB_WR_ATOMIC_CMP_AND_SWP &&
+                   wqe->wr.opcode != IB_WR_ATOMIC_FETCH_AND_ADD)
+                       return COMPST_ERROR;
+               reset_retry_counters(qp);
+               return COMPST_ATOMIC;
+
+       case IB_OPCODE_RC_ACKNOWLEDGE:
+               syn = aeth_syn(pkt);
+               switch (syn & AETH_TYPE_MASK) {
+               case AETH_ACK:
+                       reset_retry_counters(qp);
+                       return COMPST_WRITE_SEND;
+
+               case AETH_RNR_NAK:
+                       return COMPST_RNR_RETRY;
+
+               case AETH_NAK:
+                       switch (syn) {
+                       case AETH_NAK_PSN_SEQ_ERROR:
+                               /* a nak implicitly acks all packets with psns
+                                * before
+                                */
+                               if (psn_compare(pkt->psn, qp->comp.psn) > 0) {
+                                       qp->comp.psn = pkt->psn;
+                                       if (qp->req.wait_psn) {
+                                               qp->req.wait_psn = 0;
+                                               rxe_run_task(&qp->req.task, 1);
+                                       }
+                               }
+                               return COMPST_ERROR_RETRY;
+
+                       case AETH_NAK_INVALID_REQ:
+                               wqe->status = IB_WC_REM_INV_REQ_ERR;
+                               return COMPST_ERROR;
+
+                       case AETH_NAK_REM_ACC_ERR:
+                               wqe->status = IB_WC_REM_ACCESS_ERR;
+                               return COMPST_ERROR;
+
+                       case AETH_NAK_REM_OP_ERR:
+                               wqe->status = IB_WC_REM_OP_ERR;
+                               return COMPST_ERROR;
+
+                       default:
+                               pr_warn("unexpected nak %x\n", syn);
+                               wqe->status = IB_WC_REM_OP_ERR;
+                               return COMPST_ERROR;
+                       }
+
+               default:
+                       return COMPST_ERROR;
+               }
+               break;
+
+       default:
+               pr_warn("unexpected opcode\n");
+       }
+
+       return COMPST_ERROR;
+}
+
+static inline enum comp_state do_read(struct rxe_qp *qp,
+                                     struct rxe_pkt_info *pkt,
+                                     struct rxe_send_wqe *wqe)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       int ret;
+
+       ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
+                       &wqe->dma, payload_addr(pkt),
+                       payload_size(pkt), to_mem_obj, NULL);
+       if (ret)
+               return COMPST_ERROR;
+
+       if (wqe->dma.resid == 0 && (pkt->mask & RXE_END_MASK))
+               return COMPST_COMP_ACK;
+       else
+               return COMPST_UPDATE_COMP;
+}
+
+static inline enum comp_state do_atomic(struct rxe_qp *qp,
+                                       struct rxe_pkt_info *pkt,
+                                       struct rxe_send_wqe *wqe)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       int ret;
+
+       u64 atomic_orig = atmack_orig(pkt);
+
+       ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
+                       &wqe->dma, &atomic_orig,
+                       sizeof(u64), to_mem_obj, NULL);
+       if (ret)
+               return COMPST_ERROR;
+       else
+               return COMPST_COMP_ACK;
+}
+
+static void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+                         struct rxe_cqe *cqe)
+{
+       memset(cqe, 0, sizeof(*cqe));
+
+       if (!qp->is_user) {
+               struct ib_wc            *wc     = &cqe->ibwc;
+
+               wc->wr_id               = wqe->wr.wr_id;
+               wc->status              = wqe->status;
+               wc->opcode              = wr_to_wc_opcode(wqe->wr.opcode);
+               if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                   wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+                       wc->wc_flags = IB_WC_WITH_IMM;
+               wc->byte_len            = wqe->dma.length;
+               wc->qp                  = &qp->ibqp;
+       } else {
+               struct ib_uverbs_wc     *uwc    = &cqe->uibwc;
+
+               uwc->wr_id              = wqe->wr.wr_id;
+               uwc->status             = wqe->status;
+               uwc->opcode             = wr_to_wc_opcode(wqe->wr.opcode);
+               if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
+                   wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+                       uwc->wc_flags = IB_WC_WITH_IMM;
+               uwc->byte_len           = wqe->dma.length;
+               uwc->qp_num             = qp->ibqp.qp_num;
+       }
+}
+
+static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+{
+       struct rxe_cqe cqe;
+
+       if ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
+           (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+           (qp->req.state == QP_STATE_ERROR)) {
+               make_send_cqe(qp, wqe, &cqe);
+               rxe_cq_post(qp->scq, &cqe, 0);
+       }
+
+       advance_consumer(qp->sq.queue);
+
+       /*
+        * we completed something so let req run again
+        * if it is trying to fence
+        */
+       if (qp->req.wait_fence) {
+               qp->req.wait_fence = 0;
+               rxe_run_task(&qp->req.task, 1);
+       }
+}
+
+static inline enum comp_state complete_ack(struct rxe_qp *qp,
+                                          struct rxe_pkt_info *pkt,
+                                          struct rxe_send_wqe *wqe)
+{
+       unsigned long flags;
+
+       if (wqe->has_rd_atomic) {
+               wqe->has_rd_atomic = 0;
+               atomic_inc(&qp->req.rd_atomic);
+               if (qp->req.need_rd_atomic) {
+                       qp->comp.timeout_retry = 0;
+                       qp->req.need_rd_atomic = 0;
+                       rxe_run_task(&qp->req.task, 1);
+               }
+       }
+
+       if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
+               /* state_lock used by requester & completer */
+               spin_lock_irqsave(&qp->state_lock, flags);
+               if ((qp->req.state == QP_STATE_DRAIN) &&
+                   (qp->comp.psn == qp->req.psn)) {
+                       qp->req.state = QP_STATE_DRAINED;
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
+
+                       if (qp->ibqp.event_handler) {
+                               struct ib_event ev;
+
+                               ev.device = qp->ibqp.device;
+                               ev.element.qp = &qp->ibqp;
+                               ev.event = IB_EVENT_SQ_DRAINED;
+                               qp->ibqp.event_handler(&ev,
+                                       qp->ibqp.qp_context);
+                       }
+               } else {
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
+               }
+       }
+
+       do_complete(qp, wqe);
+
+       if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
+               return COMPST_UPDATE_COMP;
+       else
+               return COMPST_DONE;
+}
+
+static inline enum comp_state complete_wqe(struct rxe_qp *qp,
+                                          struct rxe_pkt_info *pkt,
+                                          struct rxe_send_wqe *wqe)
+{
+       qp->comp.opcode = -1;
+
+       if (pkt) {
+               if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
+                       qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
+
+               if (qp->req.wait_psn) {
+                       qp->req.wait_psn = 0;
+                       rxe_run_task(&qp->req.task, 1);
+               }
+       }
+
+       do_complete(qp, wqe);
+
+       return COMPST_GET_WQE;
+}
+
+int rxe_completer(void *arg)
+{
+       struct rxe_qp *qp = (struct rxe_qp *)arg;
+       struct rxe_send_wqe *wqe = wqe;
+       struct sk_buff *skb = NULL;
+       struct rxe_pkt_info *pkt = NULL;
+       enum comp_state state;
+
+       if (!qp->valid) {
+               while ((skb = skb_dequeue(&qp->resp_pkts))) {
+                       rxe_drop_ref(qp);
+                       kfree_skb(skb);
+               }
+               skb = NULL;
+               pkt = NULL;
+
+               while (queue_head(qp->sq.queue))
+                       advance_consumer(qp->sq.queue);
+
+               goto exit;
+       }
+
+       if (qp->req.state == QP_STATE_ERROR) {
+               while ((skb = skb_dequeue(&qp->resp_pkts))) {
+                       rxe_drop_ref(qp);
+                       kfree_skb(skb);
+               }
+               skb = NULL;
+               pkt = NULL;
+
+               while ((wqe = queue_head(qp->sq.queue))) {
+                       wqe->status = IB_WC_WR_FLUSH_ERR;
+                       do_complete(qp, wqe);
+               }
+
+               goto exit;
+       }
+
+       if (qp->req.state == QP_STATE_RESET) {
+               while ((skb = skb_dequeue(&qp->resp_pkts))) {
+                       rxe_drop_ref(qp);
+                       kfree_skb(skb);
+               }
+               skb = NULL;
+               pkt = NULL;
+
+               while (queue_head(qp->sq.queue))
+                       advance_consumer(qp->sq.queue);
+
+               goto exit;
+       }
+
+       if (qp->comp.timeout) {
+               qp->comp.timeout_retry = 1;
+               qp->comp.timeout = 0;
+       } else {
+               qp->comp.timeout_retry = 0;
+       }
+
+       if (qp->req.need_retry)
+               goto exit;
+
+       state = COMPST_GET_ACK;
+
+       while (1) {
+               pr_debug("state = %s\n", comp_state_name[state]);
+               switch (state) {
+               case COMPST_GET_ACK:
+                       skb = skb_dequeue(&qp->resp_pkts);
+                       if (skb) {
+                               pkt = SKB_TO_PKT(skb);
+                               qp->comp.timeout_retry = 0;
+                       }
+                       state = COMPST_GET_WQE;
+                       break;
+
+               case COMPST_GET_WQE:
+                       state = get_wqe(qp, pkt, &wqe);
+                       break;
+
+               case COMPST_CHECK_PSN:
+                       state = check_psn(qp, pkt, wqe);
+                       break;
+
+               case COMPST_CHECK_ACK:
+                       state = check_ack(qp, pkt, wqe);
+                       break;
+
+               case COMPST_READ:
+                       state = do_read(qp, pkt, wqe);
+                       break;
+
+               case COMPST_ATOMIC:
+                       state = do_atomic(qp, pkt, wqe);
+                       break;
+
+               case COMPST_WRITE_SEND:
+                       if (wqe->state == wqe_state_pending &&
+                           wqe->last_psn == pkt->psn)
+                               state = COMPST_COMP_ACK;
+                       else
+                               state = COMPST_UPDATE_COMP;
+                       break;
+
+               case COMPST_COMP_ACK:
+                       state = complete_ack(qp, pkt, wqe);
+                       break;
+
+               case COMPST_COMP_WQE:
+                       state = complete_wqe(qp, pkt, wqe);
+                       break;
+
+               case COMPST_UPDATE_COMP:
+                       if (pkt->mask & RXE_END_MASK)
+                               qp->comp.opcode = -1;
+                       else
+                               qp->comp.opcode = pkt->opcode;
+
+                       if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
+                               qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
+
+                       if (qp->req.wait_psn) {
+                               qp->req.wait_psn = 0;
+                               rxe_run_task(&qp->req.task, 1);
+                       }
+
+                       state = COMPST_DONE;
+                       break;
+
+               case COMPST_DONE:
+                       if (pkt) {
+                               rxe_drop_ref(pkt->qp);
+                               kfree_skb(skb);
+                       }
+                       goto done;
+
+               case COMPST_EXIT:
+                       if (qp->comp.timeout_retry && wqe) {
+                               state = COMPST_ERROR_RETRY;
+                               break;
+                       }
+
+                       /* re reset the timeout counter if
+                        * (1) QP is type RC
+                        * (2) the QP is alive
+                        * (3) there is a packet sent by the requester that
+                        *     might be acked (we still might get spurious
+                        *     timeouts but try to keep them as few as possible)
+                        * (4) the timeout parameter is set
+                        */
+                       if ((qp_type(qp) == IB_QPT_RC) &&
+                           (qp->req.state == QP_STATE_READY) &&
+                           (psn_compare(qp->req.psn, qp->comp.psn) > 0) &&
+                           qp->qp_timeout_jiffies)
+                               mod_timer(&qp->retrans_timer,
+                                         jiffies + qp->qp_timeout_jiffies);
+                       goto exit;
+
+               case COMPST_ERROR_RETRY:
+                       /* we come here if the retry timer fired and we did
+                        * not receive a response packet. try to retry the send
+                        * queue if that makes sense and the limits have not
+                        * been exceeded. remember that some timeouts are
+                        * spurious since we do not reset the timer but kick
+                        * it down the road or let it expire
+                        */
+
+                       /* there is nothing to retry in this case */
+                       if (!wqe || (wqe->state == wqe_state_posted))
+                               goto exit;
+
+                       if (qp->comp.retry_cnt > 0) {
+                               if (qp->comp.retry_cnt != 7)
+                                       qp->comp.retry_cnt--;
+
+                               /* no point in retrying if we have already
+                                * seen the last ack that the requester could
+                                * have caused
+                                */
+                               if (psn_compare(qp->req.psn,
+                                               qp->comp.psn) > 0) {
+                                       /* tell the requester to retry the
+                                        * send send queue next time around
+                                        */
+                                       qp->req.need_retry = 1;
+                                       rxe_run_task(&qp->req.task, 1);
+                               }
+                               goto exit;
+                       } else {
+                               wqe->status = IB_WC_RETRY_EXC_ERR;
+                               state = COMPST_ERROR;
+                       }
+                       break;
+
+               case COMPST_RNR_RETRY:
+                       if (qp->comp.rnr_retry > 0) {
+                               if (qp->comp.rnr_retry != 7)
+                                       qp->comp.rnr_retry--;
+
+                               qp->req.need_retry = 1;
+                               pr_debug("set rnr nak timer\n");
+                               mod_timer(&qp->rnr_nak_timer,
+                                         jiffies + rnrnak_jiffies(aeth_syn(pkt)
+                                               & ~AETH_TYPE_MASK));
+                               goto exit;
+                       } else {
+                               wqe->status = IB_WC_RNR_RETRY_EXC_ERR;
+                               state = COMPST_ERROR;
+                       }
+                       break;
+
+               case COMPST_ERROR:
+                       do_complete(qp, wqe);
+                       rxe_qp_error(qp);
+                       goto exit;
+               }
+       }
+
+exit:
+       /* we come here if we are done with processing and want the task to
+        * exit from the loop calling us
+        */
+       return -EAGAIN;
+
+done:
+       /* we come here if we have processed a packet we want the task to call
+        * us again to see if there is anything else to do
+        */
+       return 0;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c
new file mode 100644 (file)
index 0000000..e5e6a5e
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
+                   int cqe, int comp_vector, struct ib_udata *udata)
+{
+       int count;
+
+       if (cqe <= 0) {
+               pr_warn("cqe(%d) <= 0\n", cqe);
+               goto err1;
+       }
+
+       if (cqe > rxe->attr.max_cqe) {
+               pr_warn("cqe(%d) > max_cqe(%d)\n",
+                       cqe, rxe->attr.max_cqe);
+               goto err1;
+       }
+
+       if (cq) {
+               count = queue_count(cq->queue);
+               if (cqe < count) {
+                       pr_warn("cqe(%d) < current # elements in queue (%d)",
+                               cqe, count);
+                       goto err1;
+               }
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static void rxe_send_complete(unsigned long data)
+{
+       struct rxe_cq *cq = (struct rxe_cq *)data;
+
+       cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+}
+
+int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
+                    int comp_vector, struct ib_ucontext *context,
+                    struct ib_udata *udata)
+{
+       int err;
+
+       cq->queue = rxe_queue_init(rxe, &cqe,
+                                  sizeof(struct rxe_cqe));
+       if (!cq->queue) {
+               pr_warn("unable to create cq\n");
+               return -ENOMEM;
+       }
+
+       err = do_mmap_info(rxe, udata, false, context, cq->queue->buf,
+                          cq->queue->buf_size, &cq->queue->ip);
+       if (err) {
+               kvfree(cq->queue->buf);
+               kfree(cq->queue);
+               return err;
+       }
+
+       if (udata)
+               cq->is_user = 1;
+
+       tasklet_init(&cq->comp_task, rxe_send_complete, (unsigned long)cq);
+
+       spin_lock_init(&cq->cq_lock);
+       cq->ibcq.cqe = cqe;
+       return 0;
+}
+
+int rxe_cq_resize_queue(struct rxe_cq *cq, int cqe, struct ib_udata *udata)
+{
+       int err;
+
+       err = rxe_queue_resize(cq->queue, (unsigned int *)&cqe,
+                              sizeof(struct rxe_cqe),
+                              cq->queue->ip ? cq->queue->ip->context : NULL,
+                              udata, NULL, &cq->cq_lock);
+       if (!err)
+               cq->ibcq.cqe = cqe;
+
+       return err;
+}
+
+int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
+{
+       struct ib_event ev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cq->cq_lock, flags);
+
+       if (unlikely(queue_full(cq->queue))) {
+               spin_unlock_irqrestore(&cq->cq_lock, flags);
+               if (cq->ibcq.event_handler) {
+                       ev.device = cq->ibcq.device;
+                       ev.element.cq = &cq->ibcq;
+                       ev.event = IB_EVENT_CQ_ERR;
+                       cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
+               }
+
+               return -EBUSY;
+       }
+
+       memcpy(producer_addr(cq->queue), cqe, sizeof(*cqe));
+
+       /* make sure all changes to the CQ are written before we update the
+        * producer pointer
+        */
+       smp_wmb();
+
+       advance_producer(cq->queue);
+       spin_unlock_irqrestore(&cq->cq_lock, flags);
+
+       if ((cq->notify == IB_CQ_NEXT_COMP) ||
+           (cq->notify == IB_CQ_SOLICITED && solicited)) {
+               cq->notify = 0;
+               tasklet_schedule(&cq->comp_task);
+       }
+
+       return 0;
+}
+
+void rxe_cq_cleanup(void *arg)
+{
+       struct rxe_cq *cq = arg;
+
+       if (cq->queue)
+               rxe_queue_cleanup(cq->queue);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_dma.c b/drivers/infiniband/sw/rxe/rxe_dma.c
new file mode 100644 (file)
index 0000000..7634c1a
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+#define DMA_BAD_ADDER ((u64)0)
+
+static int rxe_mapping_error(struct ib_device *dev, u64 dma_addr)
+{
+       return dma_addr == DMA_BAD_ADDER;
+}
+
+static u64 rxe_dma_map_single(struct ib_device *dev,
+                             void *cpu_addr, size_t size,
+                             enum dma_data_direction direction)
+{
+       WARN_ON(!valid_dma_direction(direction));
+       return (uintptr_t)cpu_addr;
+}
+
+static void rxe_dma_unmap_single(struct ib_device *dev,
+                                u64 addr, size_t size,
+                                enum dma_data_direction direction)
+{
+       WARN_ON(!valid_dma_direction(direction));
+}
+
+static u64 rxe_dma_map_page(struct ib_device *dev,
+                           struct page *page,
+                           unsigned long offset,
+                           size_t size, enum dma_data_direction direction)
+{
+       u64 addr;
+
+       WARN_ON(!valid_dma_direction(direction));
+
+       if (offset + size > PAGE_SIZE) {
+               addr = DMA_BAD_ADDER;
+               goto done;
+       }
+
+       addr = (uintptr_t)page_address(page);
+       if (addr)
+               addr += offset;
+
+done:
+       return addr;
+}
+
+static void rxe_dma_unmap_page(struct ib_device *dev,
+                              u64 addr, size_t size,
+                              enum dma_data_direction direction)
+{
+       WARN_ON(!valid_dma_direction(direction));
+}
+
+static int rxe_map_sg(struct ib_device *dev, struct scatterlist *sgl,
+                     int nents, enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       u64 addr;
+       int i;
+       int ret = nents;
+
+       WARN_ON(!valid_dma_direction(direction));
+
+       for_each_sg(sgl, sg, nents, i) {
+               addr = (uintptr_t)page_address(sg_page(sg));
+               if (!addr) {
+                       ret = 0;
+                       break;
+               }
+               sg->dma_address = addr + sg->offset;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+               sg->dma_length = sg->length;
+#endif
+       }
+
+       return ret;
+}
+
+static void rxe_unmap_sg(struct ib_device *dev,
+                        struct scatterlist *sg, int nents,
+                        enum dma_data_direction direction)
+{
+       WARN_ON(!valid_dma_direction(direction));
+}
+
+static void rxe_sync_single_for_cpu(struct ib_device *dev,
+                                   u64 addr,
+                                   size_t size, enum dma_data_direction dir)
+{
+}
+
+static void rxe_sync_single_for_device(struct ib_device *dev,
+                                      u64 addr,
+                                      size_t size, enum dma_data_direction dir)
+{
+}
+
+static void *rxe_dma_alloc_coherent(struct ib_device *dev, size_t size,
+                                   u64 *dma_handle, gfp_t flag)
+{
+       struct page *p;
+       void *addr = NULL;
+
+       p = alloc_pages(flag, get_order(size));
+       if (p)
+               addr = page_address(p);
+
+       if (dma_handle)
+               *dma_handle = (uintptr_t)addr;
+
+       return addr;
+}
+
+static void rxe_dma_free_coherent(struct ib_device *dev, size_t size,
+                                 void *cpu_addr, u64 dma_handle)
+{
+       free_pages((unsigned long)cpu_addr, get_order(size));
+}
+
+struct ib_dma_mapping_ops rxe_dma_mapping_ops = {
+       .mapping_error          = rxe_mapping_error,
+       .map_single             = rxe_dma_map_single,
+       .unmap_single           = rxe_dma_unmap_single,
+       .map_page               = rxe_dma_map_page,
+       .unmap_page             = rxe_dma_unmap_page,
+       .map_sg                 = rxe_map_sg,
+       .unmap_sg               = rxe_unmap_sg,
+       .sync_single_for_cpu    = rxe_sync_single_for_cpu,
+       .sync_single_for_device = rxe_sync_single_for_device,
+       .alloc_coherent         = rxe_dma_alloc_coherent,
+       .free_coherent          = rxe_dma_free_coherent
+};
diff --git a/drivers/infiniband/sw/rxe/rxe_hdr.h b/drivers/infiniband/sw/rxe/rxe_hdr.h
new file mode 100644 (file)
index 0000000..d57b5e9
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_HDR_H
+#define RXE_HDR_H
+
+/* extracted information about a packet carried in an sk_buff struct fits in
+ * the skbuff cb array. Must be at most 48 bytes. stored in control block of
+ * sk_buff for received packets.
+ */
+struct rxe_pkt_info {
+       struct rxe_dev          *rxe;           /* device that owns packet */
+       struct rxe_qp           *qp;            /* qp that owns packet */
+       struct rxe_send_wqe     *wqe;           /* send wqe */
+       u8                      *hdr;           /* points to bth */
+       u32                     mask;           /* useful info about pkt */
+       u32                     psn;            /* bth psn of packet */
+       u16                     pkey_index;     /* partition of pkt */
+       u16                     paylen;         /* length of bth - icrc */
+       u8                      port_num;       /* port pkt received on */
+       u8                      opcode;         /* bth opcode of packet */
+       u8                      offset;         /* bth offset from pkt->hdr */
+};
+
+/* Macros should be used only for received skb */
+#define SKB_TO_PKT(skb) ((struct rxe_pkt_info *)(skb)->cb)
+#define PKT_TO_SKB(pkt) container_of((void *)(pkt), struct sk_buff, cb)
+
+/*
+ * IBA header types and methods
+ *
+ * Some of these are for reference and completeness only since
+ * rxe does not currently support RD transport
+ * most of this could be moved into IB core. ib_pack.h has
+ * part of this but is incomplete
+ *
+ * Header specific routines to insert/extract values to/from headers
+ * the routines that are named __hhh_(set_)fff() take a pointer to a
+ * hhh header and get(set) the fff field. The routines named
+ * hhh_(set_)fff take a packet info struct and find the
+ * header and field based on the opcode in the packet.
+ * Conversion to/from network byte order from cpu order is also done.
+ */
+
+#define RXE_ICRC_SIZE          (4)
+#define RXE_MAX_HDR_LENGTH     (80)
+
+/******************************************************************************
+ * Base Transport Header
+ ******************************************************************************/
+struct rxe_bth {
+       u8                      opcode;
+       u8                      flags;
+       __be16                  pkey;
+       __be32                  qpn;
+       __be32                  apsn;
+};
+
+#define BTH_TVER               (0)
+#define BTH_DEF_PKEY           (0xffff)
+
+#define BTH_SE_MASK            (0x80)
+#define BTH_MIG_MASK           (0x40)
+#define BTH_PAD_MASK           (0x30)
+#define BTH_TVER_MASK          (0x0f)
+#define BTH_FECN_MASK          (0x80000000)
+#define BTH_BECN_MASK          (0x40000000)
+#define BTH_RESV6A_MASK                (0x3f000000)
+#define BTH_QPN_MASK           (0x00ffffff)
+#define BTH_ACK_MASK           (0x80000000)
+#define BTH_RESV7_MASK         (0x7f000000)
+#define BTH_PSN_MASK           (0x00ffffff)
+
+static inline u8 __bth_opcode(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return bth->opcode;
+}
+
+static inline void __bth_set_opcode(void *arg, u8 opcode)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->opcode = opcode;
+}
+
+static inline u8 __bth_se(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return 0 != (BTH_SE_MASK & bth->flags);
+}
+
+static inline void __bth_set_se(void *arg, int se)
+{
+       struct rxe_bth *bth = arg;
+
+       if (se)
+               bth->flags |= BTH_SE_MASK;
+       else
+               bth->flags &= ~BTH_SE_MASK;
+}
+
+static inline u8 __bth_mig(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return 0 != (BTH_MIG_MASK & bth->flags);
+}
+
+static inline void __bth_set_mig(void *arg, u8 mig)
+{
+       struct rxe_bth *bth = arg;
+
+       if (mig)
+               bth->flags |= BTH_MIG_MASK;
+       else
+               bth->flags &= ~BTH_MIG_MASK;
+}
+
+static inline u8 __bth_pad(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return (BTH_PAD_MASK & bth->flags) >> 4;
+}
+
+static inline void __bth_set_pad(void *arg, u8 pad)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->flags = (BTH_PAD_MASK & (pad << 4)) |
+                       (~BTH_PAD_MASK & bth->flags);
+}
+
+static inline u8 __bth_tver(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return BTH_TVER_MASK & bth->flags;
+}
+
+static inline void __bth_set_tver(void *arg, u8 tver)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->flags = (BTH_TVER_MASK & tver) |
+                       (~BTH_TVER_MASK & bth->flags);
+}
+
+static inline u16 __bth_pkey(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return be16_to_cpu(bth->pkey);
+}
+
+static inline void __bth_set_pkey(void *arg, u16 pkey)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->pkey = cpu_to_be16(pkey);
+}
+
+static inline u32 __bth_qpn(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return BTH_QPN_MASK & be32_to_cpu(bth->qpn);
+}
+
+static inline void __bth_set_qpn(void *arg, u32 qpn)
+{
+       struct rxe_bth *bth = arg;
+       u32 resvqpn = be32_to_cpu(bth->qpn);
+
+       bth->qpn = cpu_to_be32((BTH_QPN_MASK & qpn) |
+                              (~BTH_QPN_MASK & resvqpn));
+}
+
+static inline int __bth_fecn(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return 0 != (cpu_to_be32(BTH_FECN_MASK) & bth->qpn);
+}
+
+static inline void __bth_set_fecn(void *arg, int fecn)
+{
+       struct rxe_bth *bth = arg;
+
+       if (fecn)
+               bth->qpn |= cpu_to_be32(BTH_FECN_MASK);
+       else
+               bth->qpn &= ~cpu_to_be32(BTH_FECN_MASK);
+}
+
+static inline int __bth_becn(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return 0 != (cpu_to_be32(BTH_BECN_MASK) & bth->qpn);
+}
+
+static inline void __bth_set_becn(void *arg, int becn)
+{
+       struct rxe_bth *bth = arg;
+
+       if (becn)
+               bth->qpn |= cpu_to_be32(BTH_BECN_MASK);
+       else
+               bth->qpn &= ~cpu_to_be32(BTH_BECN_MASK);
+}
+
+static inline u8 __bth_resv6a(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return (BTH_RESV6A_MASK & be32_to_cpu(bth->qpn)) >> 24;
+}
+
+static inline void __bth_set_resv6a(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->qpn = cpu_to_be32(~BTH_RESV6A_MASK);
+}
+
+static inline int __bth_ack(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return 0 != (cpu_to_be32(BTH_ACK_MASK) & bth->apsn);
+}
+
+static inline void __bth_set_ack(void *arg, int ack)
+{
+       struct rxe_bth *bth = arg;
+
+       if (ack)
+               bth->apsn |= cpu_to_be32(BTH_ACK_MASK);
+       else
+               bth->apsn &= ~cpu_to_be32(BTH_ACK_MASK);
+}
+
+static inline void __bth_set_resv7(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       bth->apsn &= ~cpu_to_be32(BTH_RESV7_MASK);
+}
+
+static inline u32 __bth_psn(void *arg)
+{
+       struct rxe_bth *bth = arg;
+
+       return BTH_PSN_MASK & be32_to_cpu(bth->apsn);
+}
+
+static inline void __bth_set_psn(void *arg, u32 psn)
+{
+       struct rxe_bth *bth = arg;
+       u32 apsn = be32_to_cpu(bth->apsn);
+
+       bth->apsn = cpu_to_be32((BTH_PSN_MASK & psn) |
+                       (~BTH_PSN_MASK & apsn));
+}
+
+static inline u8 bth_opcode(struct rxe_pkt_info *pkt)
+{
+       return __bth_opcode(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_opcode(struct rxe_pkt_info *pkt, u8 opcode)
+{
+       __bth_set_opcode(pkt->hdr + pkt->offset, opcode);
+}
+
+static inline u8 bth_se(struct rxe_pkt_info *pkt)
+{
+       return __bth_se(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_se(struct rxe_pkt_info *pkt, int se)
+{
+       __bth_set_se(pkt->hdr + pkt->offset, se);
+}
+
+static inline u8 bth_mig(struct rxe_pkt_info *pkt)
+{
+       return __bth_mig(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_mig(struct rxe_pkt_info *pkt, u8 mig)
+{
+       __bth_set_mig(pkt->hdr + pkt->offset, mig);
+}
+
+static inline u8 bth_pad(struct rxe_pkt_info *pkt)
+{
+       return __bth_pad(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_pad(struct rxe_pkt_info *pkt, u8 pad)
+{
+       __bth_set_pad(pkt->hdr + pkt->offset, pad);
+}
+
+static inline u8 bth_tver(struct rxe_pkt_info *pkt)
+{
+       return __bth_tver(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_tver(struct rxe_pkt_info *pkt, u8 tver)
+{
+       __bth_set_tver(pkt->hdr + pkt->offset, tver);
+}
+
+static inline u16 bth_pkey(struct rxe_pkt_info *pkt)
+{
+       return __bth_pkey(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_pkey(struct rxe_pkt_info *pkt, u16 pkey)
+{
+       __bth_set_pkey(pkt->hdr + pkt->offset, pkey);
+}
+
+static inline u32 bth_qpn(struct rxe_pkt_info *pkt)
+{
+       return __bth_qpn(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_qpn(struct rxe_pkt_info *pkt, u32 qpn)
+{
+       __bth_set_qpn(pkt->hdr + pkt->offset, qpn);
+}
+
+static inline int bth_fecn(struct rxe_pkt_info *pkt)
+{
+       return __bth_fecn(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_fecn(struct rxe_pkt_info *pkt, int fecn)
+{
+       __bth_set_fecn(pkt->hdr + pkt->offset, fecn);
+}
+
+static inline int bth_becn(struct rxe_pkt_info *pkt)
+{
+       return __bth_becn(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_becn(struct rxe_pkt_info *pkt, int becn)
+{
+       __bth_set_becn(pkt->hdr + pkt->offset, becn);
+}
+
+static inline u8 bth_resv6a(struct rxe_pkt_info *pkt)
+{
+       return __bth_resv6a(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_resv6a(struct rxe_pkt_info *pkt)
+{
+       __bth_set_resv6a(pkt->hdr + pkt->offset);
+}
+
+static inline int bth_ack(struct rxe_pkt_info *pkt)
+{
+       return __bth_ack(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_ack(struct rxe_pkt_info *pkt, int ack)
+{
+       __bth_set_ack(pkt->hdr + pkt->offset, ack);
+}
+
+static inline void bth_set_resv7(struct rxe_pkt_info *pkt)
+{
+       __bth_set_resv7(pkt->hdr + pkt->offset);
+}
+
+static inline u32 bth_psn(struct rxe_pkt_info *pkt)
+{
+       return __bth_psn(pkt->hdr + pkt->offset);
+}
+
+static inline void bth_set_psn(struct rxe_pkt_info *pkt, u32 psn)
+{
+       __bth_set_psn(pkt->hdr + pkt->offset, psn);
+}
+
+static inline void bth_init(struct rxe_pkt_info *pkt, u8 opcode, int se,
+                           int mig, int pad, u16 pkey, u32 qpn, int ack_req,
+                           u32 psn)
+{
+       struct rxe_bth *bth = (struct rxe_bth *)(pkt->hdr + pkt->offset);
+
+       bth->opcode = opcode;
+       bth->flags = (pad << 4) & BTH_PAD_MASK;
+       if (se)
+               bth->flags |= BTH_SE_MASK;
+       if (mig)
+               bth->flags |= BTH_MIG_MASK;
+       bth->pkey = cpu_to_be16(pkey);
+       bth->qpn = cpu_to_be32(qpn & BTH_QPN_MASK);
+       psn &= BTH_PSN_MASK;
+       if (ack_req)
+               psn |= BTH_ACK_MASK;
+       bth->apsn = cpu_to_be32(psn);
+}
+
+/******************************************************************************
+ * Reliable Datagram Extended Transport Header
+ ******************************************************************************/
+struct rxe_rdeth {
+       __be32                  een;
+};
+
+#define RDETH_EEN_MASK         (0x00ffffff)
+
+static inline u8 __rdeth_een(void *arg)
+{
+       struct rxe_rdeth *rdeth = arg;
+
+       return RDETH_EEN_MASK & be32_to_cpu(rdeth->een);
+}
+
+static inline void __rdeth_set_een(void *arg, u32 een)
+{
+       struct rxe_rdeth *rdeth = arg;
+
+       rdeth->een = cpu_to_be32(RDETH_EEN_MASK & een);
+}
+
+static inline u8 rdeth_een(struct rxe_pkt_info *pkt)
+{
+       return __rdeth_een(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RDETH]);
+}
+
+static inline void rdeth_set_een(struct rxe_pkt_info *pkt, u32 een)
+{
+       __rdeth_set_een(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RDETH], een);
+}
+
+/******************************************************************************
+ * Datagram Extended Transport Header
+ ******************************************************************************/
+struct rxe_deth {
+       __be32                  qkey;
+       __be32                  sqp;
+};
+
+#define GSI_QKEY               (0x80010000)
+#define DETH_SQP_MASK          (0x00ffffff)
+
+static inline u32 __deth_qkey(void *arg)
+{
+       struct rxe_deth *deth = arg;
+
+       return be32_to_cpu(deth->qkey);
+}
+
+static inline void __deth_set_qkey(void *arg, u32 qkey)
+{
+       struct rxe_deth *deth = arg;
+
+       deth->qkey = cpu_to_be32(qkey);
+}
+
+static inline u32 __deth_sqp(void *arg)
+{
+       struct rxe_deth *deth = arg;
+
+       return DETH_SQP_MASK & be32_to_cpu(deth->sqp);
+}
+
+static inline void __deth_set_sqp(void *arg, u32 sqp)
+{
+       struct rxe_deth *deth = arg;
+
+       deth->sqp = cpu_to_be32(DETH_SQP_MASK & sqp);
+}
+
+static inline u32 deth_qkey(struct rxe_pkt_info *pkt)
+{
+       return __deth_qkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_DETH]);
+}
+
+static inline void deth_set_qkey(struct rxe_pkt_info *pkt, u32 qkey)
+{
+       __deth_set_qkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_DETH], qkey);
+}
+
+static inline u32 deth_sqp(struct rxe_pkt_info *pkt)
+{
+       return __deth_sqp(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_DETH]);
+}
+
+static inline void deth_set_sqp(struct rxe_pkt_info *pkt, u32 sqp)
+{
+       __deth_set_sqp(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_DETH], sqp);
+}
+
+/******************************************************************************
+ * RDMA Extended Transport Header
+ ******************************************************************************/
+struct rxe_reth {
+       __be64                  va;
+       __be32                  rkey;
+       __be32                  len;
+};
+
+static inline u64 __reth_va(void *arg)
+{
+       struct rxe_reth *reth = arg;
+
+       return be64_to_cpu(reth->va);
+}
+
+static inline void __reth_set_va(void *arg, u64 va)
+{
+       struct rxe_reth *reth = arg;
+
+       reth->va = cpu_to_be64(va);
+}
+
+static inline u32 __reth_rkey(void *arg)
+{
+       struct rxe_reth *reth = arg;
+
+       return be32_to_cpu(reth->rkey);
+}
+
+static inline void __reth_set_rkey(void *arg, u32 rkey)
+{
+       struct rxe_reth *reth = arg;
+
+       reth->rkey = cpu_to_be32(rkey);
+}
+
+static inline u32 __reth_len(void *arg)
+{
+       struct rxe_reth *reth = arg;
+
+       return be32_to_cpu(reth->len);
+}
+
+static inline void __reth_set_len(void *arg, u32 len)
+{
+       struct rxe_reth *reth = arg;
+
+       reth->len = cpu_to_be32(len);
+}
+
+static inline u64 reth_va(struct rxe_pkt_info *pkt)
+{
+       return __reth_va(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH]);
+}
+
+static inline void reth_set_va(struct rxe_pkt_info *pkt, u64 va)
+{
+       __reth_set_va(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH], va);
+}
+
+static inline u32 reth_rkey(struct rxe_pkt_info *pkt)
+{
+       return __reth_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH]);
+}
+
+static inline void reth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
+{
+       __reth_set_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH], rkey);
+}
+
+static inline u32 reth_len(struct rxe_pkt_info *pkt)
+{
+       return __reth_len(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH]);
+}
+
+static inline void reth_set_len(struct rxe_pkt_info *pkt, u32 len)
+{
+       __reth_set_len(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_RETH], len);
+}
+
+/******************************************************************************
+ * Atomic Extended Transport Header
+ ******************************************************************************/
+struct rxe_atmeth {
+       __be64                  va;
+       __be32                  rkey;
+       __be64                  swap_add;
+       __be64                  comp;
+} __attribute__((__packed__));
+
+static inline u64 __atmeth_va(void *arg)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       return be64_to_cpu(atmeth->va);
+}
+
+static inline void __atmeth_set_va(void *arg, u64 va)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       atmeth->va = cpu_to_be64(va);
+}
+
+static inline u32 __atmeth_rkey(void *arg)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       return be32_to_cpu(atmeth->rkey);
+}
+
+static inline void __atmeth_set_rkey(void *arg, u32 rkey)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       atmeth->rkey = cpu_to_be32(rkey);
+}
+
+static inline u64 __atmeth_swap_add(void *arg)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       return be64_to_cpu(atmeth->swap_add);
+}
+
+static inline void __atmeth_set_swap_add(void *arg, u64 swap_add)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       atmeth->swap_add = cpu_to_be64(swap_add);
+}
+
+static inline u64 __atmeth_comp(void *arg)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       return be64_to_cpu(atmeth->comp);
+}
+
+static inline void __atmeth_set_comp(void *arg, u64 comp)
+{
+       struct rxe_atmeth *atmeth = arg;
+
+       atmeth->comp = cpu_to_be64(comp);
+}
+
+static inline u64 atmeth_va(struct rxe_pkt_info *pkt)
+{
+       return __atmeth_va(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
+}
+
+static inline void atmeth_set_va(struct rxe_pkt_info *pkt, u64 va)
+{
+       __atmeth_set_va(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH], va);
+}
+
+static inline u32 atmeth_rkey(struct rxe_pkt_info *pkt)
+{
+       return __atmeth_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
+}
+
+static inline void atmeth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
+{
+       __atmeth_set_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH], rkey);
+}
+
+static inline u64 atmeth_swap_add(struct rxe_pkt_info *pkt)
+{
+       return __atmeth_swap_add(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
+}
+
+static inline void atmeth_set_swap_add(struct rxe_pkt_info *pkt, u64 swap_add)
+{
+       __atmeth_set_swap_add(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH], swap_add);
+}
+
+static inline u64 atmeth_comp(struct rxe_pkt_info *pkt)
+{
+       return __atmeth_comp(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
+}
+
+static inline void atmeth_set_comp(struct rxe_pkt_info *pkt, u64 comp)
+{
+       __atmeth_set_comp(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMETH], comp);
+}
+
+/******************************************************************************
+ * Ack Extended Transport Header
+ ******************************************************************************/
+struct rxe_aeth {
+       __be32                  smsn;
+};
+
+#define AETH_SYN_MASK          (0xff000000)
+#define AETH_MSN_MASK          (0x00ffffff)
+
+enum aeth_syndrome {
+       AETH_TYPE_MASK          = 0xe0,
+       AETH_ACK                = 0x00,
+       AETH_RNR_NAK            = 0x20,
+       AETH_RSVD               = 0x40,
+       AETH_NAK                = 0x60,
+       AETH_ACK_UNLIMITED      = 0x1f,
+       AETH_NAK_PSN_SEQ_ERROR  = 0x60,
+       AETH_NAK_INVALID_REQ    = 0x61,
+       AETH_NAK_REM_ACC_ERR    = 0x62,
+       AETH_NAK_REM_OP_ERR     = 0x63,
+       AETH_NAK_INV_RD_REQ     = 0x64,
+};
+
+static inline u8 __aeth_syn(void *arg)
+{
+       struct rxe_aeth *aeth = arg;
+
+       return (AETH_SYN_MASK & be32_to_cpu(aeth->smsn)) >> 24;
+}
+
+static inline void __aeth_set_syn(void *arg, u8 syn)
+{
+       struct rxe_aeth *aeth = arg;
+       u32 smsn = be32_to_cpu(aeth->smsn);
+
+       aeth->smsn = cpu_to_be32((AETH_SYN_MASK & (syn << 24)) |
+                        (~AETH_SYN_MASK & smsn));
+}
+
+static inline u32 __aeth_msn(void *arg)
+{
+       struct rxe_aeth *aeth = arg;
+
+       return AETH_MSN_MASK & be32_to_cpu(aeth->smsn);
+}
+
+static inline void __aeth_set_msn(void *arg, u32 msn)
+{
+       struct rxe_aeth *aeth = arg;
+       u32 smsn = be32_to_cpu(aeth->smsn);
+
+       aeth->smsn = cpu_to_be32((AETH_MSN_MASK & msn) |
+                        (~AETH_MSN_MASK & smsn));
+}
+
+static inline u8 aeth_syn(struct rxe_pkt_info *pkt)
+{
+       return __aeth_syn(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_AETH]);
+}
+
+static inline void aeth_set_syn(struct rxe_pkt_info *pkt, u8 syn)
+{
+       __aeth_set_syn(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_AETH], syn);
+}
+
+static inline u32 aeth_msn(struct rxe_pkt_info *pkt)
+{
+       return __aeth_msn(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_AETH]);
+}
+
+static inline void aeth_set_msn(struct rxe_pkt_info *pkt, u32 msn)
+{
+       __aeth_set_msn(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_AETH], msn);
+}
+
+/******************************************************************************
+ * Atomic Ack Extended Transport Header
+ ******************************************************************************/
+struct rxe_atmack {
+       __be64                  orig;
+};
+
+static inline u64 __atmack_orig(void *arg)
+{
+       struct rxe_atmack *atmack = arg;
+
+       return be64_to_cpu(atmack->orig);
+}
+
+static inline void __atmack_set_orig(void *arg, u64 orig)
+{
+       struct rxe_atmack *atmack = arg;
+
+       atmack->orig = cpu_to_be64(orig);
+}
+
+static inline u64 atmack_orig(struct rxe_pkt_info *pkt)
+{
+       return __atmack_orig(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMACK]);
+}
+
+static inline void atmack_set_orig(struct rxe_pkt_info *pkt, u64 orig)
+{
+       __atmack_set_orig(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_ATMACK], orig);
+}
+
+/******************************************************************************
+ * Immediate Extended Transport Header
+ ******************************************************************************/
+struct rxe_immdt {
+       __be32                  imm;
+};
+
+static inline __be32 __immdt_imm(void *arg)
+{
+       struct rxe_immdt *immdt = arg;
+
+       return immdt->imm;
+}
+
+static inline void __immdt_set_imm(void *arg, __be32 imm)
+{
+       struct rxe_immdt *immdt = arg;
+
+       immdt->imm = imm;
+}
+
+static inline __be32 immdt_imm(struct rxe_pkt_info *pkt)
+{
+       return __immdt_imm(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_IMMDT]);
+}
+
+static inline void immdt_set_imm(struct rxe_pkt_info *pkt, __be32 imm)
+{
+       __immdt_set_imm(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_IMMDT], imm);
+}
+
+/******************************************************************************
+ * Invalidate Extended Transport Header
+ ******************************************************************************/
+struct rxe_ieth {
+       __be32                  rkey;
+};
+
+static inline u32 __ieth_rkey(void *arg)
+{
+       struct rxe_ieth *ieth = arg;
+
+       return be32_to_cpu(ieth->rkey);
+}
+
+static inline void __ieth_set_rkey(void *arg, u32 rkey)
+{
+       struct rxe_ieth *ieth = arg;
+
+       ieth->rkey = cpu_to_be32(rkey);
+}
+
+static inline u32 ieth_rkey(struct rxe_pkt_info *pkt)
+{
+       return __ieth_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_IETH]);
+}
+
+static inline void ieth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
+{
+       __ieth_set_rkey(pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_IETH], rkey);
+}
+
+enum rxe_hdr_length {
+       RXE_BTH_BYTES           = sizeof(struct rxe_bth),
+       RXE_DETH_BYTES          = sizeof(struct rxe_deth),
+       RXE_IMMDT_BYTES         = sizeof(struct rxe_immdt),
+       RXE_RETH_BYTES          = sizeof(struct rxe_reth),
+       RXE_AETH_BYTES          = sizeof(struct rxe_aeth),
+       RXE_ATMACK_BYTES        = sizeof(struct rxe_atmack),
+       RXE_ATMETH_BYTES        = sizeof(struct rxe_atmeth),
+       RXE_IETH_BYTES          = sizeof(struct rxe_ieth),
+       RXE_RDETH_BYTES         = sizeof(struct rxe_rdeth),
+};
+
+static inline size_t header_size(struct rxe_pkt_info *pkt)
+{
+       return pkt->offset + rxe_opcode[pkt->opcode].length;
+}
+
+static inline void *payload_addr(struct rxe_pkt_info *pkt)
+{
+       return pkt->hdr + pkt->offset
+               + rxe_opcode[pkt->opcode].offset[RXE_PAYLOAD];
+}
+
+static inline size_t payload_size(struct rxe_pkt_info *pkt)
+{
+       return pkt->paylen - rxe_opcode[pkt->opcode].offset[RXE_PAYLOAD]
+               - bth_pad(pkt) - RXE_ICRC_SIZE;
+}
+
+#endif /* RXE_HDR_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_icrc.c b/drivers/infiniband/sw/rxe/rxe_icrc.c
new file mode 100644 (file)
index 0000000..413b56b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+/* Compute a partial ICRC for all the IB transport headers. */
+u32 rxe_icrc_hdr(struct rxe_pkt_info *pkt, struct sk_buff *skb)
+{
+       unsigned int bth_offset = 0;
+       struct iphdr *ip4h = NULL;
+       struct ipv6hdr *ip6h = NULL;
+       struct udphdr *udph;
+       struct rxe_bth *bth;
+       int crc;
+       int length;
+       int hdr_size = sizeof(struct udphdr) +
+               (skb->protocol == htons(ETH_P_IP) ?
+               sizeof(struct iphdr) : sizeof(struct ipv6hdr));
+       /* pseudo header buffer size is calculate using ipv6 header size since
+        * it is bigger than ipv4
+        */
+       u8 pshdr[sizeof(struct udphdr) +
+               sizeof(struct ipv6hdr) +
+               RXE_BTH_BYTES];
+
+       /* This seed is the result of computing a CRC with a seed of
+        * 0xfffffff and 8 bytes of 0xff representing a masked LRH.
+        */
+       crc = 0xdebb20e3;
+
+       if (skb->protocol == htons(ETH_P_IP)) { /* IPv4 */
+               memcpy(pshdr, ip_hdr(skb), hdr_size);
+               ip4h = (struct iphdr *)pshdr;
+               udph = (struct udphdr *)(ip4h + 1);
+
+               ip4h->ttl = 0xff;
+               ip4h->check = CSUM_MANGLED_0;
+               ip4h->tos = 0xff;
+       } else {                                /* IPv6 */
+               memcpy(pshdr, ipv6_hdr(skb), hdr_size);
+               ip6h = (struct ipv6hdr *)pshdr;
+               udph = (struct udphdr *)(ip6h + 1);
+
+               memset(ip6h->flow_lbl, 0xff, sizeof(ip6h->flow_lbl));
+               ip6h->priority = 0xf;
+               ip6h->hop_limit = 0xff;
+       }
+       udph->check = CSUM_MANGLED_0;
+
+       bth_offset += hdr_size;
+
+       memcpy(&pshdr[bth_offset], pkt->hdr, RXE_BTH_BYTES);
+       bth = (struct rxe_bth *)&pshdr[bth_offset];
+
+       /* exclude bth.resv8a */
+       bth->qpn |= cpu_to_be32(~BTH_QPN_MASK);
+
+       length = hdr_size + RXE_BTH_BYTES;
+       crc = crc32_le(crc, pshdr, length);
+
+       /* And finish to compute the CRC on the remainder of the headers. */
+       crc = crc32_le(crc, pkt->hdr + RXE_BTH_BYTES,
+                      rxe_opcode[pkt->opcode].length - RXE_BTH_BYTES);
+       return crc;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
new file mode 100644 (file)
index 0000000..4a5484e
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_LOC_H
+#define RXE_LOC_H
+
+/* rxe_av.c */
+
+int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr);
+
+int rxe_av_from_attr(struct rxe_dev *rxe, u8 port_num,
+                    struct rxe_av *av, struct ib_ah_attr *attr);
+
+int rxe_av_to_attr(struct rxe_dev *rxe, struct rxe_av *av,
+                  struct ib_ah_attr *attr);
+
+int rxe_av_fill_ip_info(struct rxe_dev *rxe,
+                       struct rxe_av *av,
+                       struct ib_ah_attr *attr,
+                       struct ib_gid_attr *sgid_attr,
+                       union ib_gid *sgid);
+
+struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt);
+
+/* rxe_cq.c */
+int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
+                   int cqe, int comp_vector, struct ib_udata *udata);
+
+int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
+                    int comp_vector, struct ib_ucontext *context,
+                    struct ib_udata *udata);
+
+int rxe_cq_resize_queue(struct rxe_cq *cq, int new_cqe, struct ib_udata *udata);
+
+int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited);
+
+void rxe_cq_cleanup(void *arg);
+
+/* rxe_mcast.c */
+int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid,
+                     struct rxe_mc_grp **grp_p);
+
+int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
+                          struct rxe_mc_grp *grp);
+
+int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
+                           union ib_gid *mgid);
+
+void rxe_drop_all_mcast_groups(struct rxe_qp *qp);
+
+void rxe_mc_cleanup(void *arg);
+
+/* rxe_mmap.c */
+struct rxe_mmap_info {
+       struct list_head        pending_mmaps;
+       struct ib_ucontext      *context;
+       struct kref             ref;
+       void                    *obj;
+
+       struct mminfo info;
+};
+
+void rxe_mmap_release(struct kref *ref);
+
+struct rxe_mmap_info *rxe_create_mmap_info(struct rxe_dev *dev,
+                                          u32 size,
+                                          struct ib_ucontext *context,
+                                          void *obj);
+
+int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+/* rxe_mr.c */
+enum copy_direction {
+       to_mem_obj,
+       from_mem_obj,
+};
+
+int rxe_mem_init_dma(struct rxe_dev *rxe, struct rxe_pd *pd,
+                    int access, struct rxe_mem *mem);
+
+int rxe_mem_init_user(struct rxe_dev *rxe, struct rxe_pd *pd, u64 start,
+                     u64 length, u64 iova, int access, struct ib_udata *udata,
+                     struct rxe_mem *mr);
+
+int rxe_mem_init_fast(struct rxe_dev *rxe, struct rxe_pd *pd,
+                     int max_pages, struct rxe_mem *mem);
+
+int rxe_mem_copy(struct rxe_mem *mem, u64 iova, void *addr,
+                int length, enum copy_direction dir, u32 *crcp);
+
+int copy_data(struct rxe_dev *rxe, struct rxe_pd *pd, int access,
+             struct rxe_dma_info *dma, void *addr, int length,
+             enum copy_direction dir, u32 *crcp);
+
+void *iova_to_vaddr(struct rxe_mem *mem, u64 iova, int length);
+
+enum lookup_type {
+       lookup_local,
+       lookup_remote,
+};
+
+struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key,
+                          enum lookup_type type);
+
+int mem_check_range(struct rxe_mem *mem, u64 iova, size_t length);
+
+int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem,
+                     u64 *page, int num_pages, u64 iova);
+
+void rxe_mem_cleanup(void *arg);
+
+int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);
+
+/* rxe_qp.c */
+int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init);
+
+int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
+                    struct ib_qp_init_attr *init, struct ib_udata *udata,
+                    struct ib_pd *ibpd);
+
+int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init);
+
+int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
+                   struct ib_qp_attr *attr, int mask);
+
+int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr,
+                    int mask, struct ib_udata *udata);
+
+int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask);
+
+void rxe_qp_error(struct rxe_qp *qp);
+
+void rxe_qp_destroy(struct rxe_qp *qp);
+
+void rxe_qp_cleanup(void *arg);
+
+static inline int qp_num(struct rxe_qp *qp)
+{
+       return qp->ibqp.qp_num;
+}
+
+static inline enum ib_qp_type qp_type(struct rxe_qp *qp)
+{
+       return qp->ibqp.qp_type;
+}
+
+static inline enum ib_qp_state qp_state(struct rxe_qp *qp)
+{
+       return qp->attr.qp_state;
+}
+
+static inline int qp_mtu(struct rxe_qp *qp)
+{
+       if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC)
+               return qp->attr.path_mtu;
+       else
+               return RXE_PORT_MAX_MTU;
+}
+
+static inline int rcv_wqe_size(int max_sge)
+{
+       return sizeof(struct rxe_recv_wqe) +
+               max_sge * sizeof(struct ib_sge);
+}
+
+void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res);
+
+static inline void rxe_advance_resp_resource(struct rxe_qp *qp)
+{
+       qp->resp.res_head++;
+       if (unlikely(qp->resp.res_head == qp->attr.max_rd_atomic))
+               qp->resp.res_head = 0;
+}
+
+void retransmit_timer(unsigned long data);
+void rnr_nak_timer(unsigned long data);
+
+void dump_qp(struct rxe_qp *qp);
+
+/* rxe_srq.c */
+#define IB_SRQ_INIT_MASK (~IB_SRQ_LIMIT)
+
+int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
+                    struct ib_srq_attr *attr, enum ib_srq_attr_mask mask);
+
+int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
+                     struct ib_srq_init_attr *init,
+                     struct ib_ucontext *context, struct ib_udata *udata);
+
+int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
+                     struct ib_srq_attr *attr, enum ib_srq_attr_mask mask,
+                     struct ib_udata *udata);
+
+extern struct ib_dma_mapping_ops rxe_dma_mapping_ops;
+
+void rxe_release(struct kref *kref);
+
+int rxe_completer(void *arg);
+int rxe_requester(void *arg);
+int rxe_responder(void *arg);
+
+u32 rxe_icrc_hdr(struct rxe_pkt_info *pkt, struct sk_buff *skb);
+
+void rxe_resp_queue_pkt(struct rxe_dev *rxe,
+                       struct rxe_qp *qp, struct sk_buff *skb);
+
+void rxe_comp_queue_pkt(struct rxe_dev *rxe,
+                       struct rxe_qp *qp, struct sk_buff *skb);
+
+static inline unsigned wr_opcode_mask(int opcode, struct rxe_qp *qp)
+{
+       return rxe_wr_opcode_info[opcode].mask[qp->ibqp.qp_type];
+}
+
+static inline int rxe_xmit_packet(struct rxe_dev *rxe, struct rxe_qp *qp,
+                                 struct rxe_pkt_info *pkt, struct sk_buff *skb)
+{
+       int err;
+       int is_request = pkt->mask & RXE_REQ_MASK;
+
+       if ((is_request && (qp->req.state != QP_STATE_READY)) ||
+           (!is_request && (qp->resp.state != QP_STATE_READY))) {
+               pr_info("Packet dropped. QP is not in ready state\n");
+               goto drop;
+       }
+
+       if (pkt->mask & RXE_LOOPBACK_MASK) {
+               memcpy(SKB_TO_PKT(skb), pkt, sizeof(*pkt));
+               err = rxe->ifc_ops->loopback(skb);
+       } else {
+               err = rxe->ifc_ops->send(rxe, pkt, skb);
+       }
+
+       if (err) {
+               rxe->xmit_errors++;
+               return err;
+       }
+
+       atomic_inc(&qp->skb_out);
+
+       if ((qp_type(qp) != IB_QPT_RC) &&
+           (pkt->mask & RXE_END_MASK)) {
+               pkt->wqe->state = wqe_state_done;
+               rxe_run_task(&qp->comp.task, 1);
+       }
+
+       goto done;
+
+drop:
+       kfree_skb(skb);
+       err = 0;
+done:
+       return err;
+}
+
+#endif /* RXE_LOC_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_mcast.c b/drivers/infiniband/sw/rxe/rxe_mcast.c
new file mode 100644 (file)
index 0000000..fa95544
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid,
+                     struct rxe_mc_grp **grp_p)
+{
+       int err;
+       struct rxe_mc_grp *grp;
+
+       if (rxe->attr.max_mcast_qp_attach == 0) {
+               err = -EINVAL;
+               goto err1;
+       }
+
+       grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
+       if (grp)
+               goto done;
+
+       grp = rxe_alloc(&rxe->mc_grp_pool);
+       if (!grp) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       INIT_LIST_HEAD(&grp->qp_list);
+       spin_lock_init(&grp->mcg_lock);
+       grp->rxe = rxe;
+
+       rxe_add_key(grp, mgid);
+
+       err = rxe->ifc_ops->mcast_add(rxe, mgid);
+       if (err)
+               goto err2;
+
+done:
+       *grp_p = grp;
+       return 0;
+
+err2:
+       rxe_drop_ref(grp);
+err1:
+       return err;
+}
+
+int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
+                          struct rxe_mc_grp *grp)
+{
+       int err;
+       struct rxe_mc_elem *elem;
+
+       /* check to see of the qp is already a member of the group */
+       spin_lock_bh(&qp->grp_lock);
+       spin_lock_bh(&grp->mcg_lock);
+       list_for_each_entry(elem, &grp->qp_list, qp_list) {
+               if (elem->qp == qp) {
+                       err = 0;
+                       goto out;
+               }
+       }
+
+       if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       elem = rxe_alloc(&rxe->mc_elem_pool);
+       if (!elem) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* each qp holds a ref on the grp */
+       rxe_add_ref(grp);
+
+       grp->num_qp++;
+       elem->qp = qp;
+       elem->grp = grp;
+
+       list_add(&elem->qp_list, &grp->qp_list);
+       list_add(&elem->grp_list, &qp->grp_list);
+
+       err = 0;
+out:
+       spin_unlock_bh(&grp->mcg_lock);
+       spin_unlock_bh(&qp->grp_lock);
+       return err;
+}
+
+int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
+                           union ib_gid *mgid)
+{
+       struct rxe_mc_grp *grp;
+       struct rxe_mc_elem *elem, *tmp;
+
+       grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
+       if (!grp)
+               goto err1;
+
+       spin_lock_bh(&qp->grp_lock);
+       spin_lock_bh(&grp->mcg_lock);
+
+       list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) {
+               if (elem->qp == qp) {
+                       list_del(&elem->qp_list);
+                       list_del(&elem->grp_list);
+                       grp->num_qp--;
+
+                       spin_unlock_bh(&grp->mcg_lock);
+                       spin_unlock_bh(&qp->grp_lock);
+                       rxe_drop_ref(elem);
+                       rxe_drop_ref(grp);      /* ref held by QP */
+                       rxe_drop_ref(grp);      /* ref from get_key */
+                       return 0;
+               }
+       }
+
+       spin_unlock_bh(&grp->mcg_lock);
+       spin_unlock_bh(&qp->grp_lock);
+       rxe_drop_ref(grp);                      /* ref from get_key */
+err1:
+       return -EINVAL;
+}
+
+void rxe_drop_all_mcast_groups(struct rxe_qp *qp)
+{
+       struct rxe_mc_grp *grp;
+       struct rxe_mc_elem *elem;
+
+       while (1) {
+               spin_lock_bh(&qp->grp_lock);
+               if (list_empty(&qp->grp_list)) {
+                       spin_unlock_bh(&qp->grp_lock);
+                       break;
+               }
+               elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem,
+                                       grp_list);
+               list_del(&elem->grp_list);
+               spin_unlock_bh(&qp->grp_lock);
+
+               grp = elem->grp;
+               spin_lock_bh(&grp->mcg_lock);
+               list_del(&elem->qp_list);
+               grp->num_qp--;
+               spin_unlock_bh(&grp->mcg_lock);
+               rxe_drop_ref(grp);
+               rxe_drop_ref(elem);
+       }
+}
+
+void rxe_mc_cleanup(void *arg)
+{
+       struct rxe_mc_grp *grp = arg;
+       struct rxe_dev *rxe = grp->rxe;
+
+       rxe_drop_key(grp);
+       rxe->ifc_ops->mcast_delete(rxe, &grp->mgid);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_mmap.c b/drivers/infiniband/sw/rxe/rxe_mmap.c
new file mode 100644 (file)
index 0000000..54b3c7c
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <asm/pgtable.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+void rxe_mmap_release(struct kref *ref)
+{
+       struct rxe_mmap_info *ip = container_of(ref,
+                                       struct rxe_mmap_info, ref);
+       struct rxe_dev *rxe = to_rdev(ip->context->device);
+
+       spin_lock_bh(&rxe->pending_lock);
+
+       if (!list_empty(&ip->pending_mmaps))
+               list_del(&ip->pending_mmaps);
+
+       spin_unlock_bh(&rxe->pending_lock);
+
+       vfree(ip->obj);         /* buf */
+       kfree(ip);
+}
+
+/*
+ * open and close keep track of how many times the memory region is mapped,
+ * to avoid releasing it.
+ */
+static void rxe_vma_open(struct vm_area_struct *vma)
+{
+       struct rxe_mmap_info *ip = vma->vm_private_data;
+
+       kref_get(&ip->ref);
+}
+
+static void rxe_vma_close(struct vm_area_struct *vma)
+{
+       struct rxe_mmap_info *ip = vma->vm_private_data;
+
+       kref_put(&ip->ref, rxe_mmap_release);
+}
+
+static struct vm_operations_struct rxe_vm_ops = {
+       .open = rxe_vma_open,
+       .close = rxe_vma_close,
+};
+
+/**
+ * rxe_mmap - create a new mmap region
+ * @context: the IB user context of the process making the mmap() call
+ * @vma: the VMA to be initialized
+ * Return zero if the mmap is OK. Otherwise, return an errno.
+ */
+int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+       struct rxe_dev *rxe = to_rdev(context->device);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long size = vma->vm_end - vma->vm_start;
+       struct rxe_mmap_info *ip, *pp;
+       int ret;
+
+       /*
+        * Search the device's list of objects waiting for a mmap call.
+        * Normally, this list is very short since a call to create a
+        * CQ, QP, or SRQ is soon followed by a call to mmap().
+        */
+       spin_lock_bh(&rxe->pending_lock);
+       list_for_each_entry_safe(ip, pp, &rxe->pending_mmaps, pending_mmaps) {
+               if (context != ip->context || (__u64)offset != ip->info.offset)
+                       continue;
+
+               /* Don't allow a mmap larger than the object. */
+               if (size > ip->info.size) {
+                       pr_err("mmap region is larger than the object!\n");
+                       spin_unlock_bh(&rxe->pending_lock);
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               goto found_it;
+       }
+       pr_warn("unable to find pending mmap info\n");
+       spin_unlock_bh(&rxe->pending_lock);
+       ret = -EINVAL;
+       goto done;
+
+found_it:
+       list_del_init(&ip->pending_mmaps);
+       spin_unlock_bh(&rxe->pending_lock);
+
+       ret = remap_vmalloc_range(vma, ip->obj, 0);
+       if (ret) {
+               pr_err("rxe: err %d from remap_vmalloc_range\n", ret);
+               goto done;
+       }
+
+       vma->vm_ops = &rxe_vm_ops;
+       vma->vm_private_data = ip;
+       rxe_vma_open(vma);
+done:
+       return ret;
+}
+
+/*
+ * Allocate information for rxe_mmap
+ */
+struct rxe_mmap_info *rxe_create_mmap_info(struct rxe_dev *rxe,
+                                          u32 size,
+                                          struct ib_ucontext *context,
+                                          void *obj)
+{
+       struct rxe_mmap_info *ip;
+
+       ip = kmalloc(sizeof(*ip), GFP_KERNEL);
+       if (!ip)
+               return NULL;
+
+       size = PAGE_ALIGN(size);
+
+       spin_lock_bh(&rxe->mmap_offset_lock);
+
+       if (rxe->mmap_offset == 0)
+               rxe->mmap_offset = PAGE_SIZE;
+
+       ip->info.offset = rxe->mmap_offset;
+       rxe->mmap_offset += size;
+
+       spin_unlock_bh(&rxe->mmap_offset_lock);
+
+       INIT_LIST_HEAD(&ip->pending_mmaps);
+       ip->info.size = size;
+       ip->context = context;
+       ip->obj = obj;
+       kref_init(&ip->ref);
+
+       return ip;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
new file mode 100644 (file)
index 0000000..f3dab65
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+/*
+ * lfsr (linear feedback shift register) with period 255
+ */
+static u8 rxe_get_key(void)
+{
+       static unsigned key = 1;
+
+       key = key << 1;
+
+       key |= (0 != (key & 0x100)) ^ (0 != (key & 0x10))
+               ^ (0 != (key & 0x80)) ^ (0 != (key & 0x40));
+
+       key &= 0xff;
+
+       return key;
+}
+
+int mem_check_range(struct rxe_mem *mem, u64 iova, size_t length)
+{
+       switch (mem->type) {
+       case RXE_MEM_TYPE_DMA:
+               return 0;
+
+       case RXE_MEM_TYPE_MR:
+       case RXE_MEM_TYPE_FMR:
+               return ((iova < mem->iova) ||
+                       ((iova + length) > (mem->iova + mem->length))) ?
+                       -EFAULT : 0;
+
+       default:
+               return -EFAULT;
+       }
+}
+
+#define IB_ACCESS_REMOTE       (IB_ACCESS_REMOTE_READ          \
+                               | IB_ACCESS_REMOTE_WRITE        \
+                               | IB_ACCESS_REMOTE_ATOMIC)
+
+static void rxe_mem_init(int access, struct rxe_mem *mem)
+{
+       u32 lkey = mem->pelem.index << 8 | rxe_get_key();
+       u32 rkey = (access & IB_ACCESS_REMOTE) ? lkey : 0;
+
+       if (mem->pelem.pool->type == RXE_TYPE_MR) {
+               mem->ibmr.lkey          = lkey;
+               mem->ibmr.rkey          = rkey;
+       }
+
+       mem->lkey               = lkey;
+       mem->rkey               = rkey;
+       mem->state              = RXE_MEM_STATE_INVALID;
+       mem->type               = RXE_MEM_TYPE_NONE;
+       mem->map_shift          = ilog2(RXE_BUF_PER_MAP);
+}
+
+void rxe_mem_cleanup(void *arg)
+{
+       struct rxe_mem *mem = arg;
+       int i;
+
+       if (mem->umem)
+               ib_umem_release(mem->umem);
+
+       if (mem->map) {
+               for (i = 0; i < mem->num_map; i++)
+                       kfree(mem->map[i]);
+
+               kfree(mem->map);
+       }
+}
+
+static int rxe_mem_alloc(struct rxe_dev *rxe, struct rxe_mem *mem, int num_buf)
+{
+       int i;
+       int num_map;
+       struct rxe_map **map = mem->map;
+
+       num_map = (num_buf + RXE_BUF_PER_MAP - 1) / RXE_BUF_PER_MAP;
+
+       mem->map = kmalloc_array(num_map, sizeof(*map), GFP_KERNEL);
+       if (!mem->map)
+               goto err1;
+
+       for (i = 0; i < num_map; i++) {
+               mem->map[i] = kmalloc(sizeof(**map), GFP_KERNEL);
+               if (!mem->map[i])
+                       goto err2;
+       }
+
+       WARN_ON(!is_power_of_2(RXE_BUF_PER_MAP));
+
+       mem->map_shift  = ilog2(RXE_BUF_PER_MAP);
+       mem->map_mask   = RXE_BUF_PER_MAP - 1;
+
+       mem->num_buf = num_buf;
+       mem->num_map = num_map;
+       mem->max_buf = num_map * RXE_BUF_PER_MAP;
+
+       return 0;
+
+err2:
+       for (i--; i >= 0; i--)
+               kfree(mem->map[i]);
+
+       kfree(mem->map);
+err1:
+       return -ENOMEM;
+}
+
+int rxe_mem_init_dma(struct rxe_dev *rxe, struct rxe_pd *pd,
+                    int access, struct rxe_mem *mem)
+{
+       rxe_mem_init(access, mem);
+
+       mem->pd                 = pd;
+       mem->access             = access;
+       mem->state              = RXE_MEM_STATE_VALID;
+       mem->type               = RXE_MEM_TYPE_DMA;
+
+       return 0;
+}
+
+int rxe_mem_init_user(struct rxe_dev *rxe, struct rxe_pd *pd, u64 start,
+                     u64 length, u64 iova, int access, struct ib_udata *udata,
+                     struct rxe_mem *mem)
+{
+       int                     entry;
+       struct rxe_map          **map;
+       struct rxe_phys_buf     *buf = NULL;
+       struct ib_umem          *umem;
+       struct scatterlist      *sg;
+       int                     num_buf;
+       void                    *vaddr;
+       int err;
+
+       umem = ib_umem_get(pd->ibpd.uobject->context, start, length, access, 0);
+       if (IS_ERR(umem)) {
+               pr_warn("err %d from rxe_umem_get\n",
+                       (int)PTR_ERR(umem));
+               err = -EINVAL;
+               goto err1;
+       }
+
+       mem->umem = umem;
+       num_buf = umem->nmap;
+
+       rxe_mem_init(access, mem);
+
+       err = rxe_mem_alloc(rxe, mem, num_buf);
+       if (err) {
+               pr_warn("err %d from rxe_mem_alloc\n", err);
+               ib_umem_release(umem);
+               goto err1;
+       }
+
+       WARN_ON(!is_power_of_2(umem->page_size));
+
+       mem->page_shift         = ilog2(umem->page_size);
+       mem->page_mask          = umem->page_size - 1;
+
+       num_buf                 = 0;
+       map                     = mem->map;
+       if (length > 0) {
+               buf = map[0]->buf;
+
+               for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
+                       vaddr = page_address(sg_page(sg));
+                       if (!vaddr) {
+                               pr_warn("null vaddr\n");
+                               err = -ENOMEM;
+                               goto err1;
+                       }
+
+                       buf->addr = (uintptr_t)vaddr;
+                       buf->size = umem->page_size;
+                       num_buf++;
+                       buf++;
+
+                       if (num_buf >= RXE_BUF_PER_MAP) {
+                               map++;
+                               buf = map[0]->buf;
+                               num_buf = 0;
+                       }
+               }
+       }
+
+       mem->pd                 = pd;
+       mem->umem               = umem;
+       mem->access             = access;
+       mem->length             = length;
+       mem->iova               = iova;
+       mem->va                 = start;
+       mem->offset             = ib_umem_offset(umem);
+       mem->state              = RXE_MEM_STATE_VALID;
+       mem->type               = RXE_MEM_TYPE_MR;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+int rxe_mem_init_fast(struct rxe_dev *rxe, struct rxe_pd *pd,
+                     int max_pages, struct rxe_mem *mem)
+{
+       int err;
+
+       rxe_mem_init(0, mem);
+
+       /* In fastreg, we also set the rkey */
+       mem->ibmr.rkey = mem->ibmr.lkey;
+
+       err = rxe_mem_alloc(rxe, mem, max_pages);
+       if (err)
+               goto err1;
+
+       mem->pd                 = pd;
+       mem->max_buf            = max_pages;
+       mem->state              = RXE_MEM_STATE_FREE;
+       mem->type               = RXE_MEM_TYPE_MR;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+static void lookup_iova(
+       struct rxe_mem  *mem,
+       u64                     iova,
+       int                     *m_out,
+       int                     *n_out,
+       size_t                  *offset_out)
+{
+       size_t                  offset = iova - mem->iova + mem->offset;
+       int                     map_index;
+       int                     buf_index;
+       u64                     length;
+
+       if (likely(mem->page_shift)) {
+               *offset_out = offset & mem->page_mask;
+               offset >>= mem->page_shift;
+               *n_out = offset & mem->map_mask;
+               *m_out = offset >> mem->map_shift;
+       } else {
+               map_index = 0;
+               buf_index = 0;
+
+               length = mem->map[map_index]->buf[buf_index].size;
+
+               while (offset >= length) {
+                       offset -= length;
+                       buf_index++;
+
+                       if (buf_index == RXE_BUF_PER_MAP) {
+                               map_index++;
+                               buf_index = 0;
+                       }
+                       length = mem->map[map_index]->buf[buf_index].size;
+               }
+
+               *m_out = map_index;
+               *n_out = buf_index;
+               *offset_out = offset;
+       }
+}
+
+void *iova_to_vaddr(struct rxe_mem *mem, u64 iova, int length)
+{
+       size_t offset;
+       int m, n;
+       void *addr;
+
+       if (mem->state != RXE_MEM_STATE_VALID) {
+               pr_warn("mem not in valid state\n");
+               addr = NULL;
+               goto out;
+       }
+
+       if (!mem->map) {
+               addr = (void *)(uintptr_t)iova;
+               goto out;
+       }
+
+       if (mem_check_range(mem, iova, length)) {
+               pr_warn("range violation\n");
+               addr = NULL;
+               goto out;
+       }
+
+       lookup_iova(mem, iova, &m, &n, &offset);
+
+       if (offset + length > mem->map[m]->buf[n].size) {
+               pr_warn("crosses page boundary\n");
+               addr = NULL;
+               goto out;
+       }
+
+       addr = (void *)(uintptr_t)mem->map[m]->buf[n].addr + offset;
+
+out:
+       return addr;
+}
+
+/* copy data from a range (vaddr, vaddr+length-1) to or from
+ * a mem object starting at iova. Compute incremental value of
+ * crc32 if crcp is not zero. caller must hold a reference to mem
+ */
+int rxe_mem_copy(struct rxe_mem *mem, u64 iova, void *addr, int length,
+                enum copy_direction dir, u32 *crcp)
+{
+       int                     err;
+       int                     bytes;
+       u8                      *va;
+       struct rxe_map          **map;
+       struct rxe_phys_buf     *buf;
+       int                     m;
+       int                     i;
+       size_t                  offset;
+       u32                     crc = crcp ? (*crcp) : 0;
+
+       if (mem->type == RXE_MEM_TYPE_DMA) {
+               u8 *src, *dest;
+
+               src  = (dir == to_mem_obj) ?
+                       addr : ((void *)(uintptr_t)iova);
+
+               dest = (dir == to_mem_obj) ?
+                       ((void *)(uintptr_t)iova) : addr;
+
+               if (crcp)
+                       *crcp = crc32_le(*crcp, src, length);
+
+               memcpy(dest, src, length);
+
+               return 0;
+       }
+
+       WARN_ON(!mem->map);
+
+       err = mem_check_range(mem, iova, length);
+       if (err) {
+               err = -EFAULT;
+               goto err1;
+       }
+
+       lookup_iova(mem, iova, &m, &i, &offset);
+
+       map     = mem->map + m;
+       buf     = map[0]->buf + i;
+
+       while (length > 0) {
+               u8 *src, *dest;
+
+               va      = (u8 *)(uintptr_t)buf->addr + offset;
+               src  = (dir == to_mem_obj) ? addr : va;
+               dest = (dir == to_mem_obj) ? va : addr;
+
+               bytes   = buf->size - offset;
+
+               if (bytes > length)
+                       bytes = length;
+
+               if (crcp)
+                       crc = crc32_le(crc, src, bytes);
+
+               memcpy(dest, src, bytes);
+
+               length  -= bytes;
+               addr    += bytes;
+
+               offset  = 0;
+               buf++;
+               i++;
+
+               if (i == RXE_BUF_PER_MAP) {
+                       i = 0;
+                       map++;
+                       buf = map[0]->buf;
+               }
+       }
+
+       if (crcp)
+               *crcp = crc;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+/* copy data in or out of a wqe, i.e. sg list
+ * under the control of a dma descriptor
+ */
+int copy_data(
+       struct rxe_dev          *rxe,
+       struct rxe_pd           *pd,
+       int                     access,
+       struct rxe_dma_info     *dma,
+       void                    *addr,
+       int                     length,
+       enum copy_direction     dir,
+       u32                     *crcp)
+{
+       int                     bytes;
+       struct rxe_sge          *sge    = &dma->sge[dma->cur_sge];
+       int                     offset  = dma->sge_offset;
+       int                     resid   = dma->resid;
+       struct rxe_mem          *mem    = NULL;
+       u64                     iova;
+       int                     err;
+
+       if (length == 0)
+               return 0;
+
+       if (length > resid) {
+               err = -EINVAL;
+               goto err2;
+       }
+
+       if (sge->length && (offset < sge->length)) {
+               mem = lookup_mem(pd, access, sge->lkey, lookup_local);
+               if (!mem) {
+                       err = -EINVAL;
+                       goto err1;
+               }
+       }
+
+       while (length > 0) {
+               bytes = length;
+
+               if (offset >= sge->length) {
+                       if (mem) {
+                               rxe_drop_ref(mem);
+                               mem = NULL;
+                       }
+                       sge++;
+                       dma->cur_sge++;
+                       offset = 0;
+
+                       if (dma->cur_sge >= dma->num_sge) {
+                               err = -ENOSPC;
+                               goto err2;
+                       }
+
+                       if (sge->length) {
+                               mem = lookup_mem(pd, access, sge->lkey,
+                                                lookup_local);
+                               if (!mem) {
+                                       err = -EINVAL;
+                                       goto err1;
+                               }
+                       } else {
+                               continue;
+                       }
+               }
+
+               if (bytes > sge->length - offset)
+                       bytes = sge->length - offset;
+
+               if (bytes > 0) {
+                       iova = sge->addr + offset;
+
+                       err = rxe_mem_copy(mem, iova, addr, bytes, dir, crcp);
+                       if (err)
+                               goto err2;
+
+                       offset  += bytes;
+                       resid   -= bytes;
+                       length  -= bytes;
+                       addr    += bytes;
+               }
+       }
+
+       dma->sge_offset = offset;
+       dma->resid      = resid;
+
+       if (mem)
+               rxe_drop_ref(mem);
+
+       return 0;
+
+err2:
+       if (mem)
+               rxe_drop_ref(mem);
+err1:
+       return err;
+}
+
+int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
+{
+       struct rxe_sge          *sge    = &dma->sge[dma->cur_sge];
+       int                     offset  = dma->sge_offset;
+       int                     resid   = dma->resid;
+
+       while (length) {
+               unsigned int bytes;
+
+               if (offset >= sge->length) {
+                       sge++;
+                       dma->cur_sge++;
+                       offset = 0;
+                       if (dma->cur_sge >= dma->num_sge)
+                               return -ENOSPC;
+               }
+
+               bytes = length;
+
+               if (bytes > sge->length - offset)
+                       bytes = sge->length - offset;
+
+               offset  += bytes;
+               resid   -= bytes;
+               length  -= bytes;
+       }
+
+       dma->sge_offset = offset;
+       dma->resid      = resid;
+
+       return 0;
+}
+
+/* (1) find the mem (mr or mw) corresponding to lkey/rkey
+ *     depending on lookup_type
+ * (2) verify that the (qp) pd matches the mem pd
+ * (3) verify that the mem can support the requested access
+ * (4) verify that mem state is valid
+ */
+struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key,
+                          enum lookup_type type)
+{
+       struct rxe_mem *mem;
+       struct rxe_dev *rxe = to_rdev(pd->ibpd.device);
+       int index = key >> 8;
+
+       if (index >= RXE_MIN_MR_INDEX && index <= RXE_MAX_MR_INDEX) {
+               mem = rxe_pool_get_index(&rxe->mr_pool, index);
+               if (!mem)
+                       goto err1;
+       } else {
+               goto err1;
+       }
+
+       if ((type == lookup_local && mem->lkey != key) ||
+           (type == lookup_remote && mem->rkey != key))
+               goto err2;
+
+       if (mem->pd != pd)
+               goto err2;
+
+       if (access && !(access & mem->access))
+               goto err2;
+
+       if (mem->state != RXE_MEM_STATE_VALID)
+               goto err2;
+
+       return mem;
+
+err2:
+       rxe_drop_ref(mem);
+err1:
+       return NULL;
+}
+
+int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem,
+                     u64 *page, int num_pages, u64 iova)
+{
+       int i;
+       int num_buf;
+       int err;
+       struct rxe_map **map;
+       struct rxe_phys_buf *buf;
+       int page_size;
+
+       if (num_pages > mem->max_buf) {
+               err = -EINVAL;
+               goto err1;
+       }
+
+       num_buf         = 0;
+       page_size       = 1 << mem->page_shift;
+       map             = mem->map;
+       buf             = map[0]->buf;
+
+       for (i = 0; i < num_pages; i++) {
+               buf->addr = *page++;
+               buf->size = page_size;
+               buf++;
+               num_buf++;
+
+               if (num_buf == RXE_BUF_PER_MAP) {
+                       map++;
+                       buf = map[0]->buf;
+                       num_buf = 0;
+               }
+       }
+
+       mem->iova       = iova;
+       mem->va         = iova;
+       mem->length     = num_pages << mem->page_shift;
+       mem->state      = RXE_MEM_STATE_VALID;
+
+       return 0;
+
+err1:
+       return err;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c
new file mode 100644 (file)
index 0000000..0b8d2ea
--- /dev/null
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <net/udp_tunnel.h>
+#include <net/sch_generic.h>
+#include <linux/netfilter.h>
+#include <rdma/ib_addr.h>
+
+#include "rxe.h"
+#include "rxe_net.h"
+#include "rxe_loc.h"
+
+static LIST_HEAD(rxe_dev_list);
+static spinlock_t dev_list_lock; /* spinlock for device list */
+
+struct rxe_dev *net_to_rxe(struct net_device *ndev)
+{
+       struct rxe_dev *rxe;
+       struct rxe_dev *found = NULL;
+
+       spin_lock_bh(&dev_list_lock);
+       list_for_each_entry(rxe, &rxe_dev_list, list) {
+               if (rxe->ndev == ndev) {
+                       found = rxe;
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev_list_lock);
+
+       return found;
+}
+
+struct rxe_dev *get_rxe_by_name(const char* name)
+{
+       struct rxe_dev *rxe;
+       struct rxe_dev *found = NULL;
+
+       spin_lock_bh(&dev_list_lock);
+       list_for_each_entry(rxe, &rxe_dev_list, list) {
+               if (!strcmp(name, rxe->ib_dev.name)) {
+                       found = rxe;
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev_list_lock);
+       return found;
+}
+
+
+struct rxe_recv_sockets recv_sockets;
+
+static __be64 rxe_mac_to_eui64(struct net_device *ndev)
+{
+       unsigned char *mac_addr = ndev->dev_addr;
+       __be64 eui64;
+       unsigned char *dst = (unsigned char *)&eui64;
+
+       dst[0] = mac_addr[0] ^ 2;
+       dst[1] = mac_addr[1];
+       dst[2] = mac_addr[2];
+       dst[3] = 0xff;
+       dst[4] = 0xfe;
+       dst[5] = mac_addr[3];
+       dst[6] = mac_addr[4];
+       dst[7] = mac_addr[5];
+
+       return eui64;
+}
+
+static __be64 node_guid(struct rxe_dev *rxe)
+{
+       return rxe_mac_to_eui64(rxe->ndev);
+}
+
+static __be64 port_guid(struct rxe_dev *rxe)
+{
+       return rxe_mac_to_eui64(rxe->ndev);
+}
+
+static struct device *dma_device(struct rxe_dev *rxe)
+{
+       struct net_device *ndev;
+
+       ndev = rxe->ndev;
+
+       if (ndev->priv_flags & IFF_802_1Q_VLAN)
+               ndev = vlan_dev_real_dev(ndev);
+
+       return ndev->dev.parent;
+}
+
+static int mcast_add(struct rxe_dev *rxe, union ib_gid *mgid)
+{
+       int err;
+       unsigned char ll_addr[ETH_ALEN];
+
+       ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
+       err = dev_mc_add(rxe->ndev, ll_addr);
+
+       return err;
+}
+
+static int mcast_delete(struct rxe_dev *rxe, union ib_gid *mgid)
+{
+       int err;
+       unsigned char ll_addr[ETH_ALEN];
+
+       ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
+       err = dev_mc_del(rxe->ndev, ll_addr);
+
+       return err;
+}
+
+static struct dst_entry *rxe_find_route4(struct net_device *ndev,
+                                 struct in_addr *saddr,
+                                 struct in_addr *daddr)
+{
+       struct rtable *rt;
+       struct flowi4 fl = { { 0 } };
+
+       memset(&fl, 0, sizeof(fl));
+       fl.flowi4_oif = ndev->ifindex;
+       memcpy(&fl.saddr, saddr, sizeof(*saddr));
+       memcpy(&fl.daddr, daddr, sizeof(*daddr));
+       fl.flowi4_proto = IPPROTO_UDP;
+
+       rt = ip_route_output_key(&init_net, &fl);
+       if (IS_ERR(rt)) {
+               pr_err_ratelimited("no route to %pI4\n", &daddr->s_addr);
+               return NULL;
+       }
+
+       return &rt->dst;
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static struct dst_entry *rxe_find_route6(struct net_device *ndev,
+                                        struct in6_addr *saddr,
+                                        struct in6_addr *daddr)
+{
+       struct dst_entry *ndst;
+       struct flowi6 fl6 = { { 0 } };
+
+       memset(&fl6, 0, sizeof(fl6));
+       fl6.flowi6_oif = ndev->ifindex;
+       memcpy(&fl6.saddr, saddr, sizeof(*saddr));
+       memcpy(&fl6.daddr, daddr, sizeof(*daddr));
+       fl6.flowi6_proto = IPPROTO_UDP;
+
+       if (unlikely(ipv6_stub->ipv6_dst_lookup(sock_net(recv_sockets.sk6->sk),
+                                               recv_sockets.sk6->sk, &ndst, &fl6))) {
+               pr_err_ratelimited("no route to %pI6\n", daddr);
+               goto put;
+       }
+
+       if (unlikely(ndst->error)) {
+               pr_err("no route to %pI6\n", daddr);
+               goto put;
+       }
+
+       return ndst;
+put:
+       dst_release(ndst);
+       return NULL;
+}
+
+#else
+
+static struct dst_entry *rxe_find_route6(struct net_device *ndev,
+                                        struct in6_addr *saddr,
+                                        struct in6_addr *daddr)
+{
+       return NULL;
+}
+
+#endif
+
+static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct udphdr *udph;
+       struct net_device *ndev = skb->dev;
+       struct rxe_dev *rxe = net_to_rxe(ndev);
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+
+       if (!rxe)
+               goto drop;
+
+       if (skb_linearize(skb)) {
+               pr_err("skb_linearize failed\n");
+               goto drop;
+       }
+
+       udph = udp_hdr(skb);
+       pkt->rxe = rxe;
+       pkt->port_num = 1;
+       pkt->hdr = (u8 *)(udph + 1);
+       pkt->mask = RXE_GRH_MASK;
+       pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
+
+       return rxe_rcv(skb);
+drop:
+       kfree_skb(skb);
+       return 0;
+}
+
+static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
+                                          bool ipv6)
+{
+       int err;
+       struct socket *sock;
+       struct udp_port_cfg udp_cfg;
+       struct udp_tunnel_sock_cfg tnl_cfg;
+
+       memset(&udp_cfg, 0, sizeof(udp_cfg));
+
+       if (ipv6) {
+               udp_cfg.family = AF_INET6;
+               udp_cfg.ipv6_v6only = 1;
+       } else {
+               udp_cfg.family = AF_INET;
+       }
+
+       udp_cfg.local_udp_port = port;
+
+       /* Create UDP socket */
+       err = udp_sock_create(net, &udp_cfg, &sock);
+       if (err < 0) {
+               pr_err("failed to create udp socket. err = %d\n", err);
+               return ERR_PTR(err);
+       }
+
+       tnl_cfg.sk_user_data = NULL;
+       tnl_cfg.encap_type = 1;
+       tnl_cfg.encap_rcv = rxe_udp_encap_recv;
+       tnl_cfg.encap_destroy = NULL;
+
+       /* Setup UDP tunnel */
+       setup_udp_tunnel_sock(net, sock, &tnl_cfg);
+
+       return sock;
+}
+
+static void rxe_release_udp_tunnel(struct socket *sk)
+{
+       udp_tunnel_sock_release(sk);
+}
+
+static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port,
+                           __be16 dst_port)
+{
+       struct udphdr *udph;
+
+       __skb_push(skb, sizeof(*udph));
+       skb_reset_transport_header(skb);
+       udph = udp_hdr(skb);
+
+       udph->dest = dst_port;
+       udph->source = src_port;
+       udph->len = htons(skb->len);
+       udph->check = 0;
+}
+
+static void prepare_ipv4_hdr(struct dst_entry *dst, struct sk_buff *skb,
+                            __be32 saddr, __be32 daddr, __u8 proto,
+                            __u8 tos, __u8 ttl, __be16 df, bool xnet)
+{
+       struct iphdr *iph;
+
+       skb_scrub_packet(skb, xnet);
+
+       skb_clear_hash(skb);
+       skb_dst_set(skb, dst);
+       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+
+       skb_push(skb, sizeof(struct iphdr));
+       skb_reset_network_header(skb);
+
+       iph = ip_hdr(skb);
+
+       iph->version    =       IPVERSION;
+       iph->ihl        =       sizeof(struct iphdr) >> 2;
+       iph->frag_off   =       df;
+       iph->protocol   =       proto;
+       iph->tos        =       tos;
+       iph->daddr      =       daddr;
+       iph->saddr      =       saddr;
+       iph->ttl        =       ttl;
+       __ip_select_ident(dev_net(dst->dev), iph,
+                         skb_shinfo(skb)->gso_segs ?: 1);
+       iph->tot_len = htons(skb->len);
+       ip_send_check(iph);
+}
+
+static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
+                            struct in6_addr *saddr, struct in6_addr *daddr,
+                            __u8 proto, __u8 prio, __u8 ttl)
+{
+       struct ipv6hdr *ip6h;
+
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
+                           | IPSKB_REROUTED);
+       skb_dst_set(skb, dst);
+
+       __skb_push(skb, sizeof(*ip6h));
+       skb_reset_network_header(skb);
+       ip6h              = ipv6_hdr(skb);
+       ip6_flow_hdr(ip6h, prio, htonl(0));
+       ip6h->payload_len = htons(skb->len);
+       ip6h->nexthdr     = proto;
+       ip6h->hop_limit   = ttl;
+       ip6h->daddr       = *daddr;
+       ip6h->saddr       = *saddr;
+       ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
+}
+
+static int prepare4(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
+{
+       struct dst_entry *dst;
+       bool xnet = false;
+       __be16 df = htons(IP_DF);
+       struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
+       struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+
+       dst = rxe_find_route4(rxe->ndev, saddr, daddr);
+       if (!dst) {
+               pr_err("Host not reachable\n");
+               return -EHOSTUNREACH;
+       }
+
+       if (!memcmp(saddr, daddr, sizeof(*daddr)))
+               pkt->mask |= RXE_LOOPBACK_MASK;
+
+       prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
+                       htons(ROCE_V2_UDP_DPORT));
+
+       prepare_ipv4_hdr(dst, skb, saddr->s_addr, daddr->s_addr, IPPROTO_UDP,
+                        av->grh.traffic_class, av->grh.hop_limit, df, xnet);
+       return 0;
+}
+
+static int prepare6(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
+{
+       struct dst_entry *dst;
+       struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
+       struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+
+       dst = rxe_find_route6(rxe->ndev, saddr, daddr);
+       if (!dst) {
+               pr_err("Host not reachable\n");
+               return -EHOSTUNREACH;
+       }
+
+       if (!memcmp(saddr, daddr, sizeof(*daddr)))
+               pkt->mask |= RXE_LOOPBACK_MASK;
+
+       prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
+                       htons(ROCE_V2_UDP_DPORT));
+
+       prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP,
+                        av->grh.traffic_class,
+                        av->grh.hop_limit);
+       return 0;
+}
+
+static int prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                  struct sk_buff *skb, u32 *crc)
+{
+       int err = 0;
+       struct rxe_av *av = rxe_get_av(pkt);
+
+       if (av->network_type == RDMA_NETWORK_IPV4)
+               err = prepare4(rxe, skb, av);
+       else if (av->network_type == RDMA_NETWORK_IPV6)
+               err = prepare6(rxe, skb, av);
+
+       *crc = rxe_icrc_hdr(pkt, skb);
+
+       return err;
+}
+
+static void rxe_skb_tx_dtor(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct rxe_qp *qp = sk->sk_user_data;
+       int skb_out = atomic_dec_return(&qp->skb_out);
+
+       if (unlikely(qp->need_req_skb &&
+                    skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW))
+               rxe_run_task(&qp->req.task, 1);
+}
+
+static int send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+               struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+       struct rxe_av *av;
+       int err;
+
+       av = rxe_get_av(pkt);
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               return -ENOMEM;
+
+       nskb->destructor = rxe_skb_tx_dtor;
+       nskb->sk = pkt->qp->sk->sk;
+
+       if (av->network_type == RDMA_NETWORK_IPV4) {
+               err = ip_local_out(dev_net(skb_dst(skb)->dev), nskb->sk, nskb);
+       } else if (av->network_type == RDMA_NETWORK_IPV6) {
+               err = ip6_local_out(dev_net(skb_dst(skb)->dev), nskb->sk, nskb);
+       } else {
+               pr_err("Unknown layer 3 protocol: %d\n", av->network_type);
+               kfree_skb(nskb);
+               return -EINVAL;
+       }
+
+       if (unlikely(net_xmit_eval(err))) {
+               pr_debug("error sending packet: %d\n", err);
+               return -EAGAIN;
+       }
+
+       kfree_skb(skb);
+
+       return 0;
+}
+
+static int loopback(struct sk_buff *skb)
+{
+       return rxe_rcv(skb);
+}
+
+static inline int addr_same(struct rxe_dev *rxe, struct rxe_av *av)
+{
+       return rxe->port.port_guid == av->grh.dgid.global.interface_id;
+}
+
+static struct sk_buff *init_packet(struct rxe_dev *rxe, struct rxe_av *av,
+                                  int paylen, struct rxe_pkt_info *pkt)
+{
+       unsigned int hdr_len;
+       struct sk_buff *skb;
+
+       if (av->network_type == RDMA_NETWORK_IPV4)
+               hdr_len = ETH_HLEN + sizeof(struct udphdr) +
+                       sizeof(struct iphdr);
+       else
+               hdr_len = ETH_HLEN + sizeof(struct udphdr) +
+                       sizeof(struct ipv6hdr);
+
+       skb = alloc_skb(paylen + hdr_len + LL_RESERVED_SPACE(rxe->ndev),
+                       GFP_ATOMIC);
+       if (unlikely(!skb))
+               return NULL;
+
+       skb_reserve(skb, hdr_len + LL_RESERVED_SPACE(rxe->ndev));
+
+       skb->dev        = rxe->ndev;
+       if (av->network_type == RDMA_NETWORK_IPV4)
+               skb->protocol = htons(ETH_P_IP);
+       else
+               skb->protocol = htons(ETH_P_IPV6);
+
+       pkt->rxe        = rxe;
+       pkt->port_num   = 1;
+       pkt->hdr        = skb_put(skb, paylen);
+       pkt->mask       |= RXE_GRH_MASK;
+
+       memset(pkt->hdr, 0, paylen);
+
+       return skb;
+}
+
+/*
+ * this is required by rxe_cfg to match rxe devices in
+ * /sys/class/infiniband up with their underlying ethernet devices
+ */
+static char *parent_name(struct rxe_dev *rxe, unsigned int port_num)
+{
+       return rxe->ndev->name;
+}
+
+static enum rdma_link_layer link_layer(struct rxe_dev *rxe,
+                                      unsigned int port_num)
+{
+       return IB_LINK_LAYER_ETHERNET;
+}
+
+static struct rxe_ifc_ops ifc_ops = {
+       .node_guid      = node_guid,
+       .port_guid      = port_guid,
+       .dma_device     = dma_device,
+       .mcast_add      = mcast_add,
+       .mcast_delete   = mcast_delete,
+       .prepare        = prepare,
+       .send           = send,
+       .loopback       = loopback,
+       .init_packet    = init_packet,
+       .parent_name    = parent_name,
+       .link_layer     = link_layer,
+};
+
+struct rxe_dev *rxe_net_add(struct net_device *ndev)
+{
+       int err;
+       struct rxe_dev *rxe = NULL;
+
+       rxe = (struct rxe_dev *)ib_alloc_device(sizeof(*rxe));
+       if (!rxe)
+               return NULL;
+
+       rxe->ifc_ops = &ifc_ops;
+       rxe->ndev = ndev;
+
+       err = rxe_add(rxe, ndev->mtu);
+       if (err) {
+               ib_dealloc_device(&rxe->ib_dev);
+               return NULL;
+       }
+
+       spin_lock_bh(&dev_list_lock);
+       list_add_tail(&rxe_dev_list, &rxe->list);
+       spin_unlock_bh(&dev_list_lock);
+       return rxe;
+}
+
+void rxe_remove_all(void)
+{
+       spin_lock_bh(&dev_list_lock);
+       while (!list_empty(&rxe_dev_list)) {
+               struct rxe_dev *rxe =
+                       list_first_entry(&rxe_dev_list, struct rxe_dev, list);
+
+               list_del(&rxe->list);
+               spin_unlock_bh(&dev_list_lock);
+               rxe_remove(rxe);
+               spin_lock_bh(&dev_list_lock);
+       }
+       spin_unlock_bh(&dev_list_lock);
+}
+EXPORT_SYMBOL(rxe_remove_all);
+
+static void rxe_port_event(struct rxe_dev *rxe,
+                          enum ib_event_type event)
+{
+       struct ib_event ev;
+
+       ev.device = &rxe->ib_dev;
+       ev.element.port_num = 1;
+       ev.event = event;
+
+       ib_dispatch_event(&ev);
+}
+
+/* Caller must hold net_info_lock */
+void rxe_port_up(struct rxe_dev *rxe)
+{
+       struct rxe_port *port;
+
+       port = &rxe->port;
+       port->attr.state = IB_PORT_ACTIVE;
+       port->attr.phys_state = IB_PHYS_STATE_LINK_UP;
+
+       rxe_port_event(rxe, IB_EVENT_PORT_ACTIVE);
+       pr_info("rxe: set %s active\n", rxe->ib_dev.name);
+       return;
+}
+
+/* Caller must hold net_info_lock */
+void rxe_port_down(struct rxe_dev *rxe)
+{
+       struct rxe_port *port;
+
+       port = &rxe->port;
+       port->attr.state = IB_PORT_DOWN;
+       port->attr.phys_state = IB_PHYS_STATE_LINK_DOWN;
+
+       rxe_port_event(rxe, IB_EVENT_PORT_ERR);
+       pr_info("rxe: set %s down\n", rxe->ib_dev.name);
+       return;
+}
+
+static int rxe_notify(struct notifier_block *not_blk,
+                     unsigned long event,
+                     void *arg)
+{
+       struct net_device *ndev = netdev_notifier_info_to_dev(arg);
+       struct rxe_dev *rxe = net_to_rxe(ndev);
+
+       if (!rxe)
+               goto out;
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
+               list_del(&rxe->list);
+               rxe_remove(rxe);
+               break;
+       case NETDEV_UP:
+               rxe_port_up(rxe);
+               break;
+       case NETDEV_DOWN:
+               rxe_port_down(rxe);
+               break;
+       case NETDEV_CHANGEMTU:
+               pr_info("rxe: %s changed mtu to %d\n", ndev->name, ndev->mtu);
+               rxe_set_mtu(rxe, ndev->mtu);
+               break;
+       case NETDEV_REBOOT:
+       case NETDEV_CHANGE:
+       case NETDEV_GOING_DOWN:
+       case NETDEV_CHANGEADDR:
+       case NETDEV_CHANGENAME:
+       case NETDEV_FEAT_CHANGE:
+       default:
+               pr_info("rxe: ignoring netdev event = %ld for %s\n",
+                       event, ndev->name);
+               break;
+       }
+out:
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rxe_net_notifier = {
+       .notifier_call = rxe_notify,
+};
+
+int rxe_net_init(void)
+{
+       int err;
+
+       spin_lock_init(&dev_list_lock);
+
+       recv_sockets.sk6 = rxe_setup_udp_tunnel(&init_net,
+                       htons(ROCE_V2_UDP_DPORT), true);
+       if (IS_ERR(recv_sockets.sk6)) {
+               recv_sockets.sk6 = NULL;
+               pr_err("rxe: Failed to create IPv6 UDP tunnel\n");
+               return -1;
+       }
+
+       recv_sockets.sk4 = rxe_setup_udp_tunnel(&init_net,
+                       htons(ROCE_V2_UDP_DPORT), false);
+       if (IS_ERR(recv_sockets.sk4)) {
+               rxe_release_udp_tunnel(recv_sockets.sk6);
+               recv_sockets.sk4 = NULL;
+               recv_sockets.sk6 = NULL;
+               pr_err("rxe: Failed to create IPv4 UDP tunnel\n");
+               return -1;
+       }
+
+       err = register_netdevice_notifier(&rxe_net_notifier);
+       if (err) {
+               rxe_release_udp_tunnel(recv_sockets.sk6);
+               rxe_release_udp_tunnel(recv_sockets.sk4);
+               pr_err("rxe: Failed to rigister netdev notifier\n");
+       }
+
+       return err;
+}
+
+void rxe_net_exit(void)
+{
+       if (recv_sockets.sk6)
+               rxe_release_udp_tunnel(recv_sockets.sk6);
+
+       if (recv_sockets.sk4)
+               rxe_release_udp_tunnel(recv_sockets.sk4);
+
+       unregister_netdevice_notifier(&rxe_net_notifier);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_net.h b/drivers/infiniband/sw/rxe/rxe_net.h
new file mode 100644 (file)
index 0000000..7b06f76
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_NET_H
+#define RXE_NET_H
+
+#include <net/sock.h>
+#include <net/if_inet6.h>
+#include <linux/module.h>
+
+struct rxe_recv_sockets {
+       struct socket *sk4;
+       struct socket *sk6;
+};
+
+extern struct rxe_recv_sockets recv_sockets;
+
+struct rxe_dev *rxe_net_add(struct net_device *ndev);
+
+int rxe_net_init(void);
+void rxe_net_exit(void);
+
+#endif /* RXE_NET_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_opcode.c b/drivers/infiniband/sw/rxe/rxe_opcode.c
new file mode 100644 (file)
index 0000000..61927c1
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 <rdma/ib_pack.h>
+#include "rxe_opcode.h"
+#include "rxe_hdr.h"
+
+/* useful information about work request opcodes and pkt opcodes in
+ * table form
+ */
+struct rxe_wr_opcode_info rxe_wr_opcode_info[] = {
+       [IB_WR_RDMA_WRITE]                              = {
+               .name   = "IB_WR_RDMA_WRITE",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_INLINE_MASK | WR_WRITE_MASK,
+                       [IB_QPT_UC]     = WR_INLINE_MASK | WR_WRITE_MASK,
+               },
+       },
+       [IB_WR_RDMA_WRITE_WITH_IMM]                     = {
+               .name   = "IB_WR_RDMA_WRITE_WITH_IMM",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_INLINE_MASK | WR_WRITE_MASK,
+                       [IB_QPT_UC]     = WR_INLINE_MASK | WR_WRITE_MASK,
+               },
+       },
+       [IB_WR_SEND]                                    = {
+               .name   = "IB_WR_SEND",
+               .mask   = {
+                       [IB_QPT_SMI]    = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_GSI]    = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_RC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UD]     = WR_INLINE_MASK | WR_SEND_MASK,
+               },
+       },
+       [IB_WR_SEND_WITH_IMM]                           = {
+               .name   = "IB_WR_SEND_WITH_IMM",
+               .mask   = {
+                       [IB_QPT_SMI]    = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_GSI]    = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_RC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UD]     = WR_INLINE_MASK | WR_SEND_MASK,
+               },
+       },
+       [IB_WR_RDMA_READ]                               = {
+               .name   = "IB_WR_RDMA_READ",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_READ_MASK,
+               },
+       },
+       [IB_WR_ATOMIC_CMP_AND_SWP]                      = {
+               .name   = "IB_WR_ATOMIC_CMP_AND_SWP",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_ATOMIC_MASK,
+               },
+       },
+       [IB_WR_ATOMIC_FETCH_AND_ADD]                    = {
+               .name   = "IB_WR_ATOMIC_FETCH_AND_ADD",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_ATOMIC_MASK,
+               },
+       },
+       [IB_WR_LSO]                                     = {
+               .name   = "IB_WR_LSO",
+               .mask   = {
+                       /* not supported */
+               },
+       },
+       [IB_WR_SEND_WITH_INV]                           = {
+               .name   = "IB_WR_SEND_WITH_INV",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UC]     = WR_INLINE_MASK | WR_SEND_MASK,
+                       [IB_QPT_UD]     = WR_INLINE_MASK | WR_SEND_MASK,
+               },
+       },
+       [IB_WR_RDMA_READ_WITH_INV]                      = {
+               .name   = "IB_WR_RDMA_READ_WITH_INV",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_READ_MASK,
+               },
+       },
+       [IB_WR_LOCAL_INV]                               = {
+               .name   = "IB_WR_LOCAL_INV",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_REG_MASK,
+               },
+       },
+       [IB_WR_REG_MR]                                  = {
+               .name   = "IB_WR_REG_MR",
+               .mask   = {
+                       [IB_QPT_RC]     = WR_REG_MASK,
+               },
+       },
+};
+
+struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE] = {
+       [IB_OPCODE_RC_SEND_FIRST]                       = {
+               .name   = "IB_OPCODE_RC_SEND_FIRST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_RWR_MASK
+                               | RXE_SEND_MASK | RXE_START_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_MIDDLE]              = {
+               .name   = "IB_OPCODE_RC_SEND_MIDDLE]",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_SEND_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_LAST]                        = {
+               .name   = "IB_OPCODE_RC_SEND_LAST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
+                               | RXE_SEND_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_ONLY]                        = {
+               .name   = "IB_OPCODE_RC_SEND_ONLY",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
+                               | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_FIRST]         = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_FIRST",
+               .mask   = RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_MIDDLE]                = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_MIDDLE",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_LAST]                  = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_LAST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_ONLY]                  = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_ONLY",
+               .mask   = RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_RETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_READ_REQUEST]                        = {
+               .name   = "IB_OPCODE_RC_RDMA_READ_REQUEST",
+               .mask   = RXE_RETH_MASK | RXE_REQ_MASK | RXE_READ_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST]         = {
+               .name   = "IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST",
+               .mask   = RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
+                               | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_AETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE]                = {
+               .name   = "IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE",
+               .mask   = RXE_PAYLOAD_MASK | RXE_ACK_MASK | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST]          = {
+               .name   = "IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST",
+               .mask   = RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_AETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY]          = {
+               .name   = "IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY",
+               .mask   = RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_AETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_ACKNOWLEDGE]                      = {
+               .name   = "IB_OPCODE_RC_ACKNOWLEDGE",
+               .mask   = RXE_AETH_MASK | RXE_ACK_MASK | RXE_START_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_AETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE]                       = {
+               .name   = "IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE",
+               .mask   = RXE_AETH_MASK | RXE_ATMACK_MASK | RXE_ACK_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMACK_BYTES + RXE_AETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_AETH]      = RXE_BTH_BYTES,
+                       [RXE_ATMACK]    = RXE_BTH_BYTES
+                                               + RXE_AETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                       + RXE_ATMACK_BYTES + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_COMPARE_SWAP]                     = {
+               .name   = "IB_OPCODE_RC_COMPARE_SWAP",
+               .mask   = RXE_ATMETH_MASK | RXE_REQ_MASK | RXE_ATOMIC_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_ATMETH]    = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_ATMETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_FETCH_ADD]                        = {
+               .name   = "IB_OPCODE_RC_FETCH_ADD",
+               .mask   = RXE_ATMETH_MASK | RXE_REQ_MASK | RXE_ATOMIC_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_ATMETH]    = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_ATMETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE]                = {
+               .name   = "IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE",
+               .mask   = RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE]                = {
+               .name   = "IB_OPCODE_RC_SEND_ONLY_INV",
+               .mask   = RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IETH_BYTES,
+               }
+       },
+
+       /* UC */
+       [IB_OPCODE_UC_SEND_FIRST]                       = {
+               .name   = "IB_OPCODE_UC_SEND_FIRST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_RWR_MASK
+                               | RXE_SEND_MASK | RXE_START_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_SEND_MIDDLE]              = {
+               .name   = "IB_OPCODE_UC_SEND_MIDDLE",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_SEND_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_SEND_LAST]                        = {
+               .name   = "IB_OPCODE_UC_SEND_LAST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
+                               | RXE_SEND_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_SEND_ONLY]                        = {
+               .name   = "IB_OPCODE_UC_SEND_ONLY",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
+                               | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_FIRST]         = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_FIRST",
+               .mask   = RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_MIDDLE]                = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_MIDDLE",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_LAST]                  = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_LAST",
+               .mask   = RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_ONLY]                  = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_ONLY",
+               .mask   = RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_RETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RETH]      = RXE_BTH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+
+       /* RD */
+       [IB_OPCODE_RD_SEND_FIRST]                       = {
+               .name   = "IB_OPCODE_RD_SEND_FIRST",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_SEND_MIDDLE]              = {
+               .name   = "IB_OPCODE_RD_SEND_MIDDLE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_SEND_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_SEND_LAST]                        = {
+               .name   = "IB_OPCODE_RD_SEND_LAST",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_COMP_MASK | RXE_SEND_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_SEND_LAST_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_RD_SEND_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
+                               | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_SEND_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_SEND_ONLY]                        = {
+               .name   = "IB_OPCODE_RD_SEND_ONLY",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_SEND_MASK | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_SEND_ONLY_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_RD_SEND_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
+                               | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_FIRST]         = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_FIRST",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
+                               | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_RETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_MIDDLE]                = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_MIDDLE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_LAST]                  = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_LAST",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_LAST_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_LAST_WITH_IMMEDIATE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
+                               | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_ONLY]                  = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_ONLY",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
+                               | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_WRITE_MASK | RXE_START_MASK
+                               | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_RETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_RETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_WRITE_ONLY_WITH_IMMEDIATE]           = {
+               .name   = "IB_OPCODE_RD_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
+                               | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_WRITE_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES
+                               + RXE_DETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_RETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_RETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_RETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_READ_REQUEST]                        = {
+               .name   = "IB_OPCODE_RD_RDMA_READ_REQUEST",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
+                               | RXE_REQ_MASK | RXE_READ_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_RETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RETH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_RDETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_READ_RESPONSE_FIRST]         = {
+               .name   = "IB_OPCODE_RD_RDMA_READ_RESPONSE_FIRST",
+               .mask   = RXE_RDETH_MASK | RXE_AETH_MASK
+                               | RXE_PAYLOAD_MASK | RXE_ACK_MASK
+                               | RXE_START_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_AETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_READ_RESPONSE_MIDDLE]                = {
+               .name   = "IB_OPCODE_RD_RDMA_READ_RESPONSE_MIDDLE",
+               .mask   = RXE_RDETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
+                               | RXE_MIDDLE_MASK,
+               .length = RXE_BTH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_READ_RESPONSE_LAST]          = {
+               .name   = "IB_OPCODE_RD_RDMA_READ_RESPONSE_LAST",
+               .mask   = RXE_RDETH_MASK | RXE_AETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_ACK_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_AETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_RDMA_READ_RESPONSE_ONLY]          = {
+               .name   = "IB_OPCODE_RD_RDMA_READ_RESPONSE_ONLY",
+               .mask   = RXE_RDETH_MASK | RXE_AETH_MASK | RXE_PAYLOAD_MASK
+                               | RXE_ACK_MASK | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_AETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_ACKNOWLEDGE]                      = {
+               .name   = "IB_OPCODE_RD_ACKNOWLEDGE",
+               .mask   = RXE_RDETH_MASK | RXE_AETH_MASK | RXE_ACK_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_AETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_ATOMIC_ACKNOWLEDGE]                       = {
+               .name   = "IB_OPCODE_RD_ATOMIC_ACKNOWLEDGE",
+               .mask   = RXE_RDETH_MASK | RXE_AETH_MASK | RXE_ATMACK_MASK
+                               | RXE_ACK_MASK | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMACK_BYTES + RXE_AETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_AETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_ATMACK]    = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_AETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_COMPARE_SWAP]                     = {
+               .name   = "RD_COMPARE_SWAP",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_ATMETH_MASK
+                               | RXE_REQ_MASK | RXE_ATOMIC_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMETH_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_ATMETH]    = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES +
+                                               + RXE_ATMETH_BYTES
+                                               + RXE_DETH_BYTES +
+                                               + RXE_RDETH_BYTES,
+               }
+       },
+       [IB_OPCODE_RD_FETCH_ADD]                        = {
+               .name   = "IB_OPCODE_RD_FETCH_ADD",
+               .mask   = RXE_RDETH_MASK | RXE_DETH_MASK | RXE_ATMETH_MASK
+                               | RXE_REQ_MASK | RXE_ATOMIC_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_ATMETH_BYTES + RXE_DETH_BYTES
+                               + RXE_RDETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_RDETH]     = RXE_BTH_BYTES,
+                       [RXE_DETH]      = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES,
+                       [RXE_ATMETH]    = RXE_BTH_BYTES
+                                               + RXE_RDETH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES +
+                                               + RXE_ATMETH_BYTES
+                                               + RXE_DETH_BYTES +
+                                               + RXE_RDETH_BYTES,
+               }
+       },
+
+       /* UD */
+       [IB_OPCODE_UD_SEND_ONLY]                        = {
+               .name   = "IB_OPCODE_UD_SEND_ONLY",
+               .mask   = RXE_DETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
+                               | RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
+                               | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_DETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_DETH]      = RXE_BTH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_DETH_BYTES,
+               }
+       },
+       [IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE]         = {
+               .name   = "IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE",
+               .mask   = RXE_DETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
+                               | RXE_REQ_MASK | RXE_COMP_MASK | RXE_RWR_MASK
+                               | RXE_SEND_MASK | RXE_START_MASK | RXE_END_MASK,
+               .length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES,
+               .offset = {
+                       [RXE_BTH]       = 0,
+                       [RXE_DETH]      = RXE_BTH_BYTES,
+                       [RXE_IMMDT]     = RXE_BTH_BYTES
+                                               + RXE_DETH_BYTES,
+                       [RXE_PAYLOAD]   = RXE_BTH_BYTES
+                                               + RXE_DETH_BYTES
+                                               + RXE_IMMDT_BYTES,
+               }
+       },
+
+};
diff --git a/drivers/infiniband/sw/rxe/rxe_opcode.h b/drivers/infiniband/sw/rxe/rxe_opcode.h
new file mode 100644 (file)
index 0000000..307604e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_OPCODE_H
+#define RXE_OPCODE_H
+
+/*
+ * contains header bit mask definitions and header lengths
+ * declaration of the rxe_opcode_info struct and
+ * rxe_wr_opcode_info struct
+ */
+
+enum rxe_wr_mask {
+       WR_INLINE_MASK                  = BIT(0),
+       WR_ATOMIC_MASK                  = BIT(1),
+       WR_SEND_MASK                    = BIT(2),
+       WR_READ_MASK                    = BIT(3),
+       WR_WRITE_MASK                   = BIT(4),
+       WR_LOCAL_MASK                   = BIT(5),
+       WR_REG_MASK                     = BIT(6),
+
+       WR_READ_OR_WRITE_MASK           = WR_READ_MASK | WR_WRITE_MASK,
+       WR_READ_WRITE_OR_SEND_MASK      = WR_READ_OR_WRITE_MASK | WR_SEND_MASK,
+       WR_WRITE_OR_SEND_MASK           = WR_WRITE_MASK | WR_SEND_MASK,
+       WR_ATOMIC_OR_READ_MASK          = WR_ATOMIC_MASK | WR_READ_MASK,
+};
+
+#define WR_MAX_QPT             (8)
+
+struct rxe_wr_opcode_info {
+       char                    *name;
+       enum rxe_wr_mask        mask[WR_MAX_QPT];
+};
+
+extern struct rxe_wr_opcode_info rxe_wr_opcode_info[];
+
+enum rxe_hdr_type {
+       RXE_LRH,
+       RXE_GRH,
+       RXE_BTH,
+       RXE_RETH,
+       RXE_AETH,
+       RXE_ATMETH,
+       RXE_ATMACK,
+       RXE_IETH,
+       RXE_RDETH,
+       RXE_DETH,
+       RXE_IMMDT,
+       RXE_PAYLOAD,
+       NUM_HDR_TYPES
+};
+
+enum rxe_hdr_mask {
+       RXE_LRH_MASK            = BIT(RXE_LRH),
+       RXE_GRH_MASK            = BIT(RXE_GRH),
+       RXE_BTH_MASK            = BIT(RXE_BTH),
+       RXE_IMMDT_MASK          = BIT(RXE_IMMDT),
+       RXE_RETH_MASK           = BIT(RXE_RETH),
+       RXE_AETH_MASK           = BIT(RXE_AETH),
+       RXE_ATMETH_MASK         = BIT(RXE_ATMETH),
+       RXE_ATMACK_MASK         = BIT(RXE_ATMACK),
+       RXE_IETH_MASK           = BIT(RXE_IETH),
+       RXE_RDETH_MASK          = BIT(RXE_RDETH),
+       RXE_DETH_MASK           = BIT(RXE_DETH),
+       RXE_PAYLOAD_MASK        = BIT(RXE_PAYLOAD),
+
+       RXE_REQ_MASK            = BIT(NUM_HDR_TYPES + 0),
+       RXE_ACK_MASK            = BIT(NUM_HDR_TYPES + 1),
+       RXE_SEND_MASK           = BIT(NUM_HDR_TYPES + 2),
+       RXE_WRITE_MASK          = BIT(NUM_HDR_TYPES + 3),
+       RXE_READ_MASK           = BIT(NUM_HDR_TYPES + 4),
+       RXE_ATOMIC_MASK         = BIT(NUM_HDR_TYPES + 5),
+
+       RXE_RWR_MASK            = BIT(NUM_HDR_TYPES + 6),
+       RXE_COMP_MASK           = BIT(NUM_HDR_TYPES + 7),
+
+       RXE_START_MASK          = BIT(NUM_HDR_TYPES + 8),
+       RXE_MIDDLE_MASK         = BIT(NUM_HDR_TYPES + 9),
+       RXE_END_MASK            = BIT(NUM_HDR_TYPES + 10),
+
+       RXE_LOOPBACK_MASK       = BIT(NUM_HDR_TYPES + 12),
+
+       RXE_READ_OR_ATOMIC      = (RXE_READ_MASK | RXE_ATOMIC_MASK),
+       RXE_WRITE_OR_SEND       = (RXE_WRITE_MASK | RXE_SEND_MASK),
+};
+
+#define OPCODE_NONE            (-1)
+#define RXE_NUM_OPCODE         256
+
+struct rxe_opcode_info {
+       char                    *name;
+       enum rxe_hdr_mask       mask;
+       int                     length;
+       int                     offset[NUM_HDR_TYPES];
+};
+
+extern struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE];
+
+#endif /* RXE_OPCODE_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h
new file mode 100644 (file)
index 0000000..f459c43
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_PARAM_H
+#define RXE_PARAM_H
+
+static inline enum ib_mtu rxe_mtu_int_to_enum(int mtu)
+{
+       if (mtu < 256)
+               return 0;
+       else if (mtu < 512)
+               return IB_MTU_256;
+       else if (mtu < 1024)
+               return IB_MTU_512;
+       else if (mtu < 2048)
+               return IB_MTU_1024;
+       else if (mtu < 4096)
+               return IB_MTU_2048;
+       else
+               return IB_MTU_4096;
+}
+
+/* Find the IB mtu for a given network MTU. */
+static inline enum ib_mtu eth_mtu_int_to_enum(int mtu)
+{
+       mtu -= RXE_MAX_HDR_LENGTH;
+
+       return rxe_mtu_int_to_enum(mtu);
+}
+
+/* default/initial rxe device parameter settings */
+enum rxe_device_param {
+       RXE_FW_VER                      = 0,
+       RXE_MAX_MR_SIZE                 = -1ull,
+       RXE_PAGE_SIZE_CAP               = 0xfffff000,
+       RXE_VENDOR_ID                   = 0,
+       RXE_VENDOR_PART_ID              = 0,
+       RXE_HW_VER                      = 0,
+       RXE_MAX_QP                      = 0x10000,
+       RXE_MAX_QP_WR                   = 0x4000,
+       RXE_MAX_INLINE_DATA             = 400,
+       RXE_DEVICE_CAP_FLAGS            = IB_DEVICE_BAD_PKEY_CNTR
+                                       | IB_DEVICE_BAD_QKEY_CNTR
+                                       | IB_DEVICE_AUTO_PATH_MIG
+                                       | IB_DEVICE_CHANGE_PHY_PORT
+                                       | IB_DEVICE_UD_AV_PORT_ENFORCE
+                                       | IB_DEVICE_PORT_ACTIVE_EVENT
+                                       | IB_DEVICE_SYS_IMAGE_GUID
+                                       | IB_DEVICE_RC_RNR_NAK_GEN
+                                       | IB_DEVICE_SRQ_RESIZE
+                                       | IB_DEVICE_MEM_MGT_EXTENSIONS,
+       RXE_MAX_SGE                     = 32,
+       RXE_MAX_SGE_RD                  = 32,
+       RXE_MAX_CQ                      = 16384,
+       RXE_MAX_LOG_CQE                 = 13,
+       RXE_MAX_MR                      = 2 * 1024,
+       RXE_MAX_PD                      = 0x7ffc,
+       RXE_MAX_QP_RD_ATOM              = 128,
+       RXE_MAX_EE_RD_ATOM              = 0,
+       RXE_MAX_RES_RD_ATOM             = 0x3f000,
+       RXE_MAX_QP_INIT_RD_ATOM         = 128,
+       RXE_MAX_EE_INIT_RD_ATOM         = 0,
+       RXE_ATOMIC_CAP                  = 1,
+       RXE_MAX_EE                      = 0,
+       RXE_MAX_RDD                     = 0,
+       RXE_MAX_MW                      = 0,
+       RXE_MAX_RAW_IPV6_QP             = 0,
+       RXE_MAX_RAW_ETHY_QP             = 0,
+       RXE_MAX_MCAST_GRP               = 8192,
+       RXE_MAX_MCAST_QP_ATTACH         = 56,
+       RXE_MAX_TOT_MCAST_QP_ATTACH     = 0x70000,
+       RXE_MAX_AH                      = 100,
+       RXE_MAX_FMR                     = 0,
+       RXE_MAX_MAP_PER_FMR             = 0,
+       RXE_MAX_SRQ                     = 960,
+       RXE_MAX_SRQ_WR                  = 0x4000,
+       RXE_MIN_SRQ_WR                  = 1,
+       RXE_MAX_SRQ_SGE                 = 27,
+       RXE_MIN_SRQ_SGE                 = 1,
+       RXE_MAX_FMR_PAGE_LIST_LEN       = 512,
+       RXE_MAX_PKEYS                   = 64,
+       RXE_LOCAL_CA_ACK_DELAY          = 15,
+
+       RXE_MAX_UCONTEXT                = 512,
+
+       RXE_NUM_PORT                    = 1,
+       RXE_NUM_COMP_VECTORS            = 1,
+
+       RXE_MIN_QP_INDEX                = 16,
+       RXE_MAX_QP_INDEX                = 0x00020000,
+
+       RXE_MIN_SRQ_INDEX               = 0x00020001,
+       RXE_MAX_SRQ_INDEX               = 0x00040000,
+
+       RXE_MIN_MR_INDEX                = 0x00000001,
+       RXE_MAX_MR_INDEX                = 0x00040000,
+       RXE_MIN_MW_INDEX                = 0x00040001,
+       RXE_MAX_MW_INDEX                = 0x00060000,
+       RXE_MAX_PKT_PER_ACK             = 64,
+
+       RXE_MAX_UNACKED_PSNS            = 128,
+
+       /* Max inflight SKBs per queue pair */
+       RXE_INFLIGHT_SKBS_PER_QP_HIGH   = 64,
+       RXE_INFLIGHT_SKBS_PER_QP_LOW    = 16,
+
+       /* Delay before calling arbiter timer */
+       RXE_NSEC_ARB_TIMER_DELAY        = 200,
+};
+
+/* default/initial rxe port parameters */
+enum rxe_port_param {
+       RXE_PORT_STATE                  = IB_PORT_DOWN,
+       RXE_PORT_MAX_MTU                = IB_MTU_4096,
+       RXE_PORT_ACTIVE_MTU             = IB_MTU_256,
+       RXE_PORT_GID_TBL_LEN            = 1024,
+       RXE_PORT_PORT_CAP_FLAGS         = RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP,
+       RXE_PORT_MAX_MSG_SZ             = 0x800000,
+       RXE_PORT_BAD_PKEY_CNTR          = 0,
+       RXE_PORT_QKEY_VIOL_CNTR         = 0,
+       RXE_PORT_LID                    = 0,
+       RXE_PORT_SM_LID                 = 0,
+       RXE_PORT_SM_SL                  = 0,
+       RXE_PORT_LMC                    = 0,
+       RXE_PORT_MAX_VL_NUM             = 1,
+       RXE_PORT_SUBNET_TIMEOUT         = 0,
+       RXE_PORT_INIT_TYPE_REPLY        = 0,
+       RXE_PORT_ACTIVE_WIDTH           = IB_WIDTH_1X,
+       RXE_PORT_ACTIVE_SPEED           = 1,
+       RXE_PORT_PKEY_TBL_LEN           = 64,
+       RXE_PORT_PHYS_STATE             = 2,
+       RXE_PORT_SUBNET_PREFIX          = 0xfe80000000000000ULL,
+};
+
+/* default/initial port info parameters */
+enum rxe_port_info_param {
+       RXE_PORT_INFO_VL_CAP            = 4,    /* 1-8 */
+       RXE_PORT_INFO_MTU_CAP           = 5,    /* 4096 */
+       RXE_PORT_INFO_OPER_VL           = 1,    /* 1 */
+};
+
+#endif /* RXE_PARAM_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c
new file mode 100644 (file)
index 0000000..6bac071
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+
+/* info about object pools
+ * note that mr and mw share a single index space
+ * so that one can map an lkey to the correct type of object
+ */
+struct rxe_type_info rxe_type_info[RXE_NUM_TYPES] = {
+       [RXE_TYPE_UC] = {
+               .name           = "rxe-uc",
+               .size           = sizeof(struct rxe_ucontext),
+       },
+       [RXE_TYPE_PD] = {
+               .name           = "rxe-pd",
+               .size           = sizeof(struct rxe_pd),
+       },
+       [RXE_TYPE_AH] = {
+               .name           = "rxe-ah",
+               .size           = sizeof(struct rxe_ah),
+               .flags          = RXE_POOL_ATOMIC,
+       },
+       [RXE_TYPE_SRQ] = {
+               .name           = "rxe-srq",
+               .size           = sizeof(struct rxe_srq),
+               .flags          = RXE_POOL_INDEX,
+               .min_index      = RXE_MIN_SRQ_INDEX,
+               .max_index      = RXE_MAX_SRQ_INDEX,
+       },
+       [RXE_TYPE_QP] = {
+               .name           = "rxe-qp",
+               .size           = sizeof(struct rxe_qp),
+               .cleanup        = rxe_qp_cleanup,
+               .flags          = RXE_POOL_INDEX,
+               .min_index      = RXE_MIN_QP_INDEX,
+               .max_index      = RXE_MAX_QP_INDEX,
+       },
+       [RXE_TYPE_CQ] = {
+               .name           = "rxe-cq",
+               .size           = sizeof(struct rxe_cq),
+               .cleanup        = rxe_cq_cleanup,
+       },
+       [RXE_TYPE_MR] = {
+               .name           = "rxe-mr",
+               .size           = sizeof(struct rxe_mem),
+               .cleanup        = rxe_mem_cleanup,
+               .flags          = RXE_POOL_INDEX,
+               .max_index      = RXE_MAX_MR_INDEX,
+               .min_index      = RXE_MIN_MR_INDEX,
+       },
+       [RXE_TYPE_MW] = {
+               .name           = "rxe-mw",
+               .size           = sizeof(struct rxe_mem),
+               .flags          = RXE_POOL_INDEX,
+               .max_index      = RXE_MAX_MW_INDEX,
+               .min_index      = RXE_MIN_MW_INDEX,
+       },
+       [RXE_TYPE_MC_GRP] = {
+               .name           = "rxe-mc_grp",
+               .size           = sizeof(struct rxe_mc_grp),
+               .cleanup        = rxe_mc_cleanup,
+               .flags          = RXE_POOL_KEY,
+               .key_offset     = offsetof(struct rxe_mc_grp, mgid),
+               .key_size       = sizeof(union ib_gid),
+       },
+       [RXE_TYPE_MC_ELEM] = {
+               .name           = "rxe-mc_elem",
+               .size           = sizeof(struct rxe_mc_elem),
+               .flags          = RXE_POOL_ATOMIC,
+       },
+};
+
+static inline char *pool_name(struct rxe_pool *pool)
+{
+       return rxe_type_info[pool->type].name;
+}
+
+static inline struct kmem_cache *pool_cache(struct rxe_pool *pool)
+{
+       return rxe_type_info[pool->type].cache;
+}
+
+static inline enum rxe_elem_type rxe_type(void *arg)
+{
+       struct rxe_pool_entry *elem = arg;
+
+       return elem->pool->type;
+}
+
+int rxe_cache_init(void)
+{
+       int err;
+       int i;
+       size_t size;
+       struct rxe_type_info *type;
+
+       for (i = 0; i < RXE_NUM_TYPES; i++) {
+               type = &rxe_type_info[i];
+               size = ALIGN(type->size, RXE_POOL_ALIGN);
+               type->cache = kmem_cache_create(type->name, size,
+                               RXE_POOL_ALIGN,
+                               RXE_POOL_CACHE_FLAGS, NULL);
+               if (!type->cache) {
+                       pr_err("Unable to init kmem cache for %s\n",
+                              type->name);
+                       err = -ENOMEM;
+                       goto err1;
+               }
+       }
+
+       return 0;
+
+err1:
+       while (--i >= 0) {
+               kmem_cache_destroy(type->cache);
+               type->cache = NULL;
+       }
+
+       return err;
+}
+
+void rxe_cache_exit(void)
+{
+       int i;
+       struct rxe_type_info *type;
+
+       for (i = 0; i < RXE_NUM_TYPES; i++) {
+               type = &rxe_type_info[i];
+               kmem_cache_destroy(type->cache);
+               type->cache = NULL;
+       }
+}
+
+static int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min)
+{
+       int err = 0;
+       size_t size;
+
+       if ((max - min + 1) < pool->max_elem) {
+               pr_warn("not enough indices for max_elem\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       pool->max_index = max;
+       pool->min_index = min;
+
+       size = BITS_TO_LONGS(max - min + 1) * sizeof(long);
+       pool->table = kmalloc(size, GFP_KERNEL);
+       if (!pool->table) {
+               pr_warn("no memory for bit table\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       pool->table_size = size;
+       bitmap_zero(pool->table, max - min + 1);
+
+out:
+       return err;
+}
+
+int rxe_pool_init(
+       struct rxe_dev          *rxe,
+       struct rxe_pool         *pool,
+       enum rxe_elem_type      type,
+       unsigned                max_elem)
+{
+       int                     err = 0;
+       size_t                  size = rxe_type_info[type].size;
+
+       memset(pool, 0, sizeof(*pool));
+
+       pool->rxe               = rxe;
+       pool->type              = type;
+       pool->max_elem          = max_elem;
+       pool->elem_size         = ALIGN(size, RXE_POOL_ALIGN);
+       pool->flags             = rxe_type_info[type].flags;
+       pool->tree              = RB_ROOT;
+       pool->cleanup           = rxe_type_info[type].cleanup;
+
+       atomic_set(&pool->num_elem, 0);
+
+       kref_init(&pool->ref_cnt);
+
+       spin_lock_init(&pool->pool_lock);
+
+       if (rxe_type_info[type].flags & RXE_POOL_INDEX) {
+               err = rxe_pool_init_index(pool,
+                                         rxe_type_info[type].max_index,
+                                         rxe_type_info[type].min_index);
+               if (err)
+                       goto out;
+       }
+
+       if (rxe_type_info[type].flags & RXE_POOL_KEY) {
+               pool->key_offset = rxe_type_info[type].key_offset;
+               pool->key_size = rxe_type_info[type].key_size;
+       }
+
+       pool->state = rxe_pool_valid;
+
+out:
+       return err;
+}
+
+static void rxe_pool_release(struct kref *kref)
+{
+       struct rxe_pool *pool = container_of(kref, struct rxe_pool, ref_cnt);
+
+       pool->state = rxe_pool_invalid;
+       kfree(pool->table);
+}
+
+static void rxe_pool_put(struct rxe_pool *pool)
+{
+       kref_put(&pool->ref_cnt, rxe_pool_release);
+}
+
+int rxe_pool_cleanup(struct rxe_pool *pool)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       pool->state = rxe_pool_invalid;
+       if (atomic_read(&pool->num_elem) > 0)
+               pr_warn("%s pool destroyed with unfree'd elem\n",
+                       pool_name(pool));
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+
+       rxe_pool_put(pool);
+
+       return 0;
+}
+
+static u32 alloc_index(struct rxe_pool *pool)
+{
+       u32 index;
+       u32 range = pool->max_index - pool->min_index + 1;
+
+       index = find_next_zero_bit(pool->table, range, pool->last);
+       if (index >= range)
+               index = find_first_zero_bit(pool->table, range);
+
+       set_bit(index, pool->table);
+       pool->last = index;
+       return index + pool->min_index;
+}
+
+static void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
+{
+       struct rb_node **link = &pool->tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct rxe_pool_entry *elem;
+
+       while (*link) {
+               parent = *link;
+               elem = rb_entry(parent, struct rxe_pool_entry, node);
+
+               if (elem->index == new->index) {
+                       pr_warn("element already exists!\n");
+                       goto out;
+               }
+
+               if (elem->index > new->index)
+                       link = &(*link)->rb_left;
+               else
+                       link = &(*link)->rb_right;
+       }
+
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, &pool->tree);
+out:
+       return;
+}
+
+static void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
+{
+       struct rb_node **link = &pool->tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct rxe_pool_entry *elem;
+       int cmp;
+
+       while (*link) {
+               parent = *link;
+               elem = rb_entry(parent, struct rxe_pool_entry, node);
+
+               cmp = memcmp((u8 *)elem + pool->key_offset,
+                            (u8 *)new + pool->key_offset, pool->key_size);
+
+               if (cmp == 0) {
+                       pr_warn("key already exists!\n");
+                       goto out;
+               }
+
+               if (cmp > 0)
+                       link = &(*link)->rb_left;
+               else
+                       link = &(*link)->rb_right;
+       }
+
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, &pool->tree);
+out:
+       return;
+}
+
+void rxe_add_key(void *arg, void *key)
+{
+       struct rxe_pool_entry *elem = arg;
+       struct rxe_pool *pool = elem->pool;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       memcpy((u8 *)elem + pool->key_offset, key, pool->key_size);
+       insert_key(pool, elem);
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+}
+
+void rxe_drop_key(void *arg)
+{
+       struct rxe_pool_entry *elem = arg;
+       struct rxe_pool *pool = elem->pool;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       rb_erase(&elem->node, &pool->tree);
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+}
+
+void rxe_add_index(void *arg)
+{
+       struct rxe_pool_entry *elem = arg;
+       struct rxe_pool *pool = elem->pool;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       elem->index = alloc_index(pool);
+       insert_index(pool, elem);
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+}
+
+void rxe_drop_index(void *arg)
+{
+       struct rxe_pool_entry *elem = arg;
+       struct rxe_pool *pool = elem->pool;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       clear_bit(elem->index - pool->min_index, pool->table);
+       rb_erase(&elem->node, &pool->tree);
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+}
+
+void *rxe_alloc(struct rxe_pool *pool)
+{
+       struct rxe_pool_entry *elem;
+       unsigned long flags;
+
+       might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC));
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+       if (pool->state != rxe_pool_valid) {
+               spin_unlock_irqrestore(&pool->pool_lock, flags);
+               return NULL;
+       }
+       kref_get(&pool->ref_cnt);
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+
+       kref_get(&pool->rxe->ref_cnt);
+
+       if (atomic_inc_return(&pool->num_elem) > pool->max_elem) {
+               atomic_dec(&pool->num_elem);
+               rxe_dev_put(pool->rxe);
+               rxe_pool_put(pool);
+               return NULL;
+       }
+
+       elem = kmem_cache_zalloc(pool_cache(pool),
+                                (pool->flags & RXE_POOL_ATOMIC) ?
+                                GFP_ATOMIC : GFP_KERNEL);
+
+       elem->pool = pool;
+       kref_init(&elem->ref_cnt);
+
+       return elem;
+}
+
+void rxe_elem_release(struct kref *kref)
+{
+       struct rxe_pool_entry *elem =
+               container_of(kref, struct rxe_pool_entry, ref_cnt);
+       struct rxe_pool *pool = elem->pool;
+
+       if (pool->cleanup)
+               pool->cleanup(elem);
+
+       kmem_cache_free(pool_cache(pool), elem);
+       atomic_dec(&pool->num_elem);
+       rxe_dev_put(pool->rxe);
+       rxe_pool_put(pool);
+}
+
+void *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
+{
+       struct rb_node *node = NULL;
+       struct rxe_pool_entry *elem = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+
+       if (pool->state != rxe_pool_valid)
+               goto out;
+
+       node = pool->tree.rb_node;
+
+       while (node) {
+               elem = rb_entry(node, struct rxe_pool_entry, node);
+
+               if (elem->index > index)
+                       node = node->rb_left;
+               else if (elem->index < index)
+                       node = node->rb_right;
+               else
+                       break;
+       }
+
+       if (node)
+               kref_get(&elem->ref_cnt);
+
+out:
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+       return node ? (void *)elem : NULL;
+}
+
+void *rxe_pool_get_key(struct rxe_pool *pool, void *key)
+{
+       struct rb_node *node = NULL;
+       struct rxe_pool_entry *elem = NULL;
+       int cmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->pool_lock, flags);
+
+       if (pool->state != rxe_pool_valid)
+               goto out;
+
+       node = pool->tree.rb_node;
+
+       while (node) {
+               elem = rb_entry(node, struct rxe_pool_entry, node);
+
+               cmp = memcmp((u8 *)elem + pool->key_offset,
+                            key, pool->key_size);
+
+               if (cmp > 0)
+                       node = node->rb_left;
+               else if (cmp < 0)
+                       node = node->rb_right;
+               else
+                       break;
+       }
+
+       if (node)
+               kref_get(&elem->ref_cnt);
+
+out:
+       spin_unlock_irqrestore(&pool->pool_lock, flags);
+       return node ? ((void *)elem) : NULL;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h
new file mode 100644 (file)
index 0000000..4d04830
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_POOL_H
+#define RXE_POOL_H
+
+#define RXE_POOL_ALIGN         (16)
+#define RXE_POOL_CACHE_FLAGS   (0)
+
+enum rxe_pool_flags {
+       RXE_POOL_ATOMIC         = BIT(0),
+       RXE_POOL_INDEX          = BIT(1),
+       RXE_POOL_KEY            = BIT(2),
+};
+
+enum rxe_elem_type {
+       RXE_TYPE_UC,
+       RXE_TYPE_PD,
+       RXE_TYPE_AH,
+       RXE_TYPE_SRQ,
+       RXE_TYPE_QP,
+       RXE_TYPE_CQ,
+       RXE_TYPE_MR,
+       RXE_TYPE_MW,
+       RXE_TYPE_MC_GRP,
+       RXE_TYPE_MC_ELEM,
+       RXE_NUM_TYPES,          /* keep me last */
+};
+
+struct rxe_type_info {
+       char                    *name;
+       size_t                  size;
+       void                    (*cleanup)(void *obj);
+       enum rxe_pool_flags     flags;
+       u32                     max_index;
+       u32                     min_index;
+       size_t                  key_offset;
+       size_t                  key_size;
+       struct kmem_cache       *cache;
+};
+
+extern struct rxe_type_info rxe_type_info[];
+
+enum rxe_pool_state {
+       rxe_pool_invalid,
+       rxe_pool_valid,
+};
+
+struct rxe_pool_entry {
+       struct rxe_pool         *pool;
+       struct kref             ref_cnt;
+       struct list_head        list;
+
+       /* only used if indexed or keyed */
+       struct rb_node          node;
+       u32                     index;
+};
+
+struct rxe_pool {
+       struct rxe_dev          *rxe;
+       spinlock_t              pool_lock; /* pool spinlock */
+       size_t                  elem_size;
+       struct kref             ref_cnt;
+       void                    (*cleanup)(void *obj);
+       enum rxe_pool_state     state;
+       enum rxe_pool_flags     flags;
+       enum rxe_elem_type      type;
+
+       unsigned int            max_elem;
+       atomic_t                num_elem;
+
+       /* only used if indexed or keyed */
+       struct rb_root          tree;
+       unsigned long           *table;
+       size_t                  table_size;
+       u32                     max_index;
+       u32                     min_index;
+       u32                     last;
+       size_t                  key_offset;
+       size_t                  key_size;
+};
+
+/* initialize slab caches for managed objects */
+int rxe_cache_init(void);
+
+/* cleanup slab caches for managed objects */
+void rxe_cache_exit(void);
+
+/* initialize a pool of objects with given limit on
+ * number of elements. gets parameters from rxe_type_info
+ * pool elements will be allocated out of a slab cache
+ */
+int rxe_pool_init(struct rxe_dev *rxe, struct rxe_pool *pool,
+                 enum rxe_elem_type type, u32 max_elem);
+
+/* free resources from object pool */
+int rxe_pool_cleanup(struct rxe_pool *pool);
+
+/* allocate an object from pool */
+void *rxe_alloc(struct rxe_pool *pool);
+
+/* assign an index to an indexed object and insert object into
+ *  pool's rb tree
+ */
+void rxe_add_index(void *elem);
+
+/* drop an index and remove object from rb tree */
+void rxe_drop_index(void *elem);
+
+/* assign a key to a keyed object and insert object into
+ *  pool's rb tree
+ */
+void rxe_add_key(void *elem, void *key);
+
+/* remove elem from rb tree */
+void rxe_drop_key(void *elem);
+
+/* lookup an indexed object from index. takes a reference on object */
+void *rxe_pool_get_index(struct rxe_pool *pool, u32 index);
+
+/* lookup keyed object from key. takes a reference on the object */
+void *rxe_pool_get_key(struct rxe_pool *pool, void *key);
+
+/* cleanup an object when all references are dropped */
+void rxe_elem_release(struct kref *kref);
+
+/* take a reference on an object */
+#define rxe_add_ref(elem) kref_get(&(elem)->pelem.ref_cnt)
+
+/* drop a reference on an object */
+#define rxe_drop_ref(elem) kref_put(&(elem)->pelem.ref_cnt, rxe_elem_release)
+
+#endif /* RXE_POOL_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
new file mode 100644 (file)
index 0000000..22ba24f
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+#include "rxe_task.h"
+
+char *rxe_qp_state_name[] = {
+       [QP_STATE_RESET]        = "RESET",
+       [QP_STATE_INIT]         = "INIT",
+       [QP_STATE_READY]        = "READY",
+       [QP_STATE_DRAIN]        = "DRAIN",
+       [QP_STATE_DRAINED]      = "DRAINED",
+       [QP_STATE_ERROR]        = "ERROR",
+};
+
+static int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap,
+                         int has_srq)
+{
+       if (cap->max_send_wr > rxe->attr.max_qp_wr) {
+               pr_warn("invalid send wr = %d > %d\n",
+                       cap->max_send_wr, rxe->attr.max_qp_wr);
+               goto err1;
+       }
+
+       if (cap->max_send_sge > rxe->attr.max_sge) {
+               pr_warn("invalid send sge = %d > %d\n",
+                       cap->max_send_sge, rxe->attr.max_sge);
+               goto err1;
+       }
+
+       if (!has_srq) {
+               if (cap->max_recv_wr > rxe->attr.max_qp_wr) {
+                       pr_warn("invalid recv wr = %d > %d\n",
+                               cap->max_recv_wr, rxe->attr.max_qp_wr);
+                       goto err1;
+               }
+
+               if (cap->max_recv_sge > rxe->attr.max_sge) {
+                       pr_warn("invalid recv sge = %d > %d\n",
+                               cap->max_recv_sge, rxe->attr.max_sge);
+                       goto err1;
+               }
+       }
+
+       if (cap->max_inline_data > rxe->max_inline_data) {
+               pr_warn("invalid max inline data = %d > %d\n",
+                       cap->max_inline_data, rxe->max_inline_data);
+               goto err1;
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init)
+{
+       struct ib_qp_cap *cap = &init->cap;
+       struct rxe_port *port;
+       int port_num = init->port_num;
+
+       if (!init->recv_cq || !init->send_cq) {
+               pr_warn("missing cq\n");
+               goto err1;
+       }
+
+       if (rxe_qp_chk_cap(rxe, cap, !!init->srq))
+               goto err1;
+
+       if (init->qp_type == IB_QPT_SMI || init->qp_type == IB_QPT_GSI) {
+               if (port_num != 1) {
+                       pr_warn("invalid port = %d\n", port_num);
+                       goto err1;
+               }
+
+               port = &rxe->port;
+
+               if (init->qp_type == IB_QPT_SMI && port->qp_smi_index) {
+                       pr_warn("SMI QP exists for port %d\n", port_num);
+                       goto err1;
+               }
+
+               if (init->qp_type == IB_QPT_GSI && port->qp_gsi_index) {
+                       pr_warn("GSI QP exists for port %d\n", port_num);
+                       goto err1;
+               }
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static int alloc_rd_atomic_resources(struct rxe_qp *qp, unsigned int n)
+{
+       qp->resp.res_head = 0;
+       qp->resp.res_tail = 0;
+       qp->resp.resources = kcalloc(n, sizeof(struct resp_res), GFP_KERNEL);
+
+       if (!qp->resp.resources)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void free_rd_atomic_resources(struct rxe_qp *qp)
+{
+       if (qp->resp.resources) {
+               int i;
+
+               for (i = 0; i < qp->attr.max_rd_atomic; i++) {
+                       struct resp_res *res = &qp->resp.resources[i];
+
+                       free_rd_atomic_resource(qp, res);
+               }
+               kfree(qp->resp.resources);
+               qp->resp.resources = NULL;
+       }
+}
+
+void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res)
+{
+       if (res->type == RXE_ATOMIC_MASK) {
+               rxe_drop_ref(qp);
+               kfree_skb(res->atomic.skb);
+       } else if (res->type == RXE_READ_MASK) {
+               if (res->read.mr)
+                       rxe_drop_ref(res->read.mr);
+       }
+       res->type = 0;
+}
+
+static void cleanup_rd_atomic_resources(struct rxe_qp *qp)
+{
+       int i;
+       struct resp_res *res;
+
+       if (qp->resp.resources) {
+               for (i = 0; i < qp->attr.max_rd_atomic; i++) {
+                       res = &qp->resp.resources[i];
+                       free_rd_atomic_resource(qp, res);
+               }
+       }
+}
+
+static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp,
+                            struct ib_qp_init_attr *init)
+{
+       struct rxe_port *port;
+       u32 qpn;
+
+       qp->sq_sig_type         = init->sq_sig_type;
+       qp->attr.path_mtu       = 1;
+       qp->mtu                 = ib_mtu_enum_to_int(qp->attr.path_mtu);
+
+       qpn                     = qp->pelem.index;
+       port                    = &rxe->port;
+
+       switch (init->qp_type) {
+       case IB_QPT_SMI:
+               qp->ibqp.qp_num         = 0;
+               port->qp_smi_index      = qpn;
+               qp->attr.port_num       = init->port_num;
+               break;
+
+       case IB_QPT_GSI:
+               qp->ibqp.qp_num         = 1;
+               port->qp_gsi_index      = qpn;
+               qp->attr.port_num       = init->port_num;
+               break;
+
+       default:
+               qp->ibqp.qp_num         = qpn;
+               break;
+       }
+
+       INIT_LIST_HEAD(&qp->grp_list);
+
+       skb_queue_head_init(&qp->send_pkts);
+
+       spin_lock_init(&qp->grp_lock);
+       spin_lock_init(&qp->state_lock);
+
+       atomic_set(&qp->ssn, 0);
+       atomic_set(&qp->skb_out, 0);
+}
+
+static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
+                          struct ib_qp_init_attr *init,
+                          struct ib_ucontext *context, struct ib_udata *udata)
+{
+       int err;
+       int wqe_size;
+
+       err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk);
+       if (err < 0)
+               return err;
+       qp->sk->sk->sk_user_data = qp;
+
+       qp->sq.max_wr           = init->cap.max_send_wr;
+       qp->sq.max_sge          = init->cap.max_send_sge;
+       qp->sq.max_inline       = init->cap.max_inline_data;
+
+       wqe_size = max_t(int, sizeof(struct rxe_send_wqe) +
+                        qp->sq.max_sge * sizeof(struct ib_sge),
+                        sizeof(struct rxe_send_wqe) +
+                        qp->sq.max_inline);
+
+       qp->sq.queue = rxe_queue_init(rxe,
+                                     &qp->sq.max_wr,
+                                     wqe_size);
+       if (!qp->sq.queue)
+               return -ENOMEM;
+
+       err = do_mmap_info(rxe, udata, true,
+                          context, qp->sq.queue->buf,
+                          qp->sq.queue->buf_size, &qp->sq.queue->ip);
+
+       if (err) {
+               kvfree(qp->sq.queue->buf);
+               kfree(qp->sq.queue);
+               return err;
+       }
+
+       qp->req.wqe_index       = producer_index(qp->sq.queue);
+       qp->req.state           = QP_STATE_RESET;
+       qp->req.opcode          = -1;
+       qp->comp.opcode         = -1;
+
+       spin_lock_init(&qp->sq.sq_lock);
+       skb_queue_head_init(&qp->req_pkts);
+
+       rxe_init_task(rxe, &qp->req.task, qp,
+                     rxe_requester, "req");
+       rxe_init_task(rxe, &qp->comp.task, qp,
+                     rxe_completer, "comp");
+
+       init_timer(&qp->rnr_nak_timer);
+       qp->rnr_nak_timer.function = rnr_nak_timer;
+       qp->rnr_nak_timer.data = (unsigned long)qp;
+
+       init_timer(&qp->retrans_timer);
+       qp->retrans_timer.function = retransmit_timer;
+       qp->retrans_timer.data = (unsigned long)qp;
+       qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */
+
+       return 0;
+}
+
+static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
+                           struct ib_qp_init_attr *init,
+                           struct ib_ucontext *context, struct ib_udata *udata)
+{
+       int err;
+       int wqe_size;
+
+       if (!qp->srq) {
+               qp->rq.max_wr           = init->cap.max_recv_wr;
+               qp->rq.max_sge          = init->cap.max_recv_sge;
+
+               wqe_size = rcv_wqe_size(qp->rq.max_sge);
+
+               pr_debug("max_wr = %d, max_sge = %d, wqe_size = %d\n",
+                        qp->rq.max_wr, qp->rq.max_sge, wqe_size);
+
+               qp->rq.queue = rxe_queue_init(rxe,
+                                             &qp->rq.max_wr,
+                                             wqe_size);
+               if (!qp->rq.queue)
+                       return -ENOMEM;
+
+               err = do_mmap_info(rxe, udata, false, context,
+                                  qp->rq.queue->buf,
+                                  qp->rq.queue->buf_size,
+                                  &qp->rq.queue->ip);
+               if (err) {
+                       kvfree(qp->rq.queue->buf);
+                       kfree(qp->rq.queue);
+                       return err;
+               }
+       }
+
+       spin_lock_init(&qp->rq.producer_lock);
+       spin_lock_init(&qp->rq.consumer_lock);
+
+       skb_queue_head_init(&qp->resp_pkts);
+
+       rxe_init_task(rxe, &qp->resp.task, qp,
+                     rxe_responder, "resp");
+
+       qp->resp.opcode         = OPCODE_NONE;
+       qp->resp.msn            = 0;
+       qp->resp.state          = QP_STATE_RESET;
+
+       return 0;
+}
+
+/* called by the create qp verb */
+int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
+                    struct ib_qp_init_attr *init, struct ib_udata *udata,
+                    struct ib_pd *ibpd)
+{
+       int err;
+       struct rxe_cq *rcq = to_rcq(init->recv_cq);
+       struct rxe_cq *scq = to_rcq(init->send_cq);
+       struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL;
+       struct ib_ucontext *context = udata ? ibpd->uobject->context : NULL;
+
+       rxe_add_ref(pd);
+       rxe_add_ref(rcq);
+       rxe_add_ref(scq);
+       if (srq)
+               rxe_add_ref(srq);
+
+       qp->pd                  = pd;
+       qp->rcq                 = rcq;
+       qp->scq                 = scq;
+       qp->srq                 = srq;
+
+       rxe_qp_init_misc(rxe, qp, init);
+
+       err = rxe_qp_init_req(rxe, qp, init, context, udata);
+       if (err)
+               goto err1;
+
+       err = rxe_qp_init_resp(rxe, qp, init, context, udata);
+       if (err)
+               goto err2;
+
+       qp->attr.qp_state = IB_QPS_RESET;
+       qp->valid = 1;
+
+       return 0;
+
+err2:
+       rxe_queue_cleanup(qp->sq.queue);
+err1:
+       if (srq)
+               rxe_drop_ref(srq);
+       rxe_drop_ref(scq);
+       rxe_drop_ref(rcq);
+       rxe_drop_ref(pd);
+
+       return err;
+}
+
+/* called by the query qp verb */
+int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init)
+{
+       init->event_handler             = qp->ibqp.event_handler;
+       init->qp_context                = qp->ibqp.qp_context;
+       init->send_cq                   = qp->ibqp.send_cq;
+       init->recv_cq                   = qp->ibqp.recv_cq;
+       init->srq                       = qp->ibqp.srq;
+
+       init->cap.max_send_wr           = qp->sq.max_wr;
+       init->cap.max_send_sge          = qp->sq.max_sge;
+       init->cap.max_inline_data       = qp->sq.max_inline;
+
+       if (!qp->srq) {
+               init->cap.max_recv_wr           = qp->rq.max_wr;
+               init->cap.max_recv_sge          = qp->rq.max_sge;
+       }
+
+       init->sq_sig_type               = qp->sq_sig_type;
+
+       init->qp_type                   = qp->ibqp.qp_type;
+       init->port_num                  = 1;
+
+       return 0;
+}
+
+/* called by the modify qp verb, this routine checks all the parameters before
+ * making any changes
+ */
+int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
+                   struct ib_qp_attr *attr, int mask)
+{
+       enum ib_qp_state cur_state = (mask & IB_QP_CUR_STATE) ?
+                                       attr->cur_qp_state : qp->attr.qp_state;
+       enum ib_qp_state new_state = (mask & IB_QP_STATE) ?
+                                       attr->qp_state : cur_state;
+
+       if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask,
+                               IB_LINK_LAYER_ETHERNET)) {
+               pr_warn("invalid mask or state for qp\n");
+               goto err1;
+       }
+
+       if (mask & IB_QP_STATE) {
+               if (cur_state == IB_QPS_SQD) {
+                       if (qp->req.state == QP_STATE_DRAIN &&
+                           new_state != IB_QPS_ERR)
+                               goto err1;
+               }
+       }
+
+       if (mask & IB_QP_PORT) {
+               if (attr->port_num != 1) {
+                       pr_warn("invalid port %d\n", attr->port_num);
+                       goto err1;
+               }
+       }
+
+       if (mask & IB_QP_CAP && rxe_qp_chk_cap(rxe, &attr->cap, !!qp->srq))
+               goto err1;
+
+       if (mask & IB_QP_AV && rxe_av_chk_attr(rxe, &attr->ah_attr))
+               goto err1;
+
+       if (mask & IB_QP_ALT_PATH) {
+               if (rxe_av_chk_attr(rxe, &attr->alt_ah_attr))
+                       goto err1;
+               if (attr->alt_port_num != 1) {
+                       pr_warn("invalid alt port %d\n", attr->alt_port_num);
+                       goto err1;
+               }
+               if (attr->alt_timeout > 31) {
+                       pr_warn("invalid QP alt timeout %d > 31\n",
+                               attr->alt_timeout);
+                       goto err1;
+               }
+       }
+
+       if (mask & IB_QP_PATH_MTU) {
+               struct rxe_port *port = &rxe->port;
+
+               enum ib_mtu max_mtu = port->attr.max_mtu;
+               enum ib_mtu mtu = attr->path_mtu;
+
+               if (mtu > max_mtu) {
+                       pr_debug("invalid mtu (%d) > (%d)\n",
+                                ib_mtu_enum_to_int(mtu),
+                                ib_mtu_enum_to_int(max_mtu));
+                       goto err1;
+               }
+       }
+
+       if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
+               if (attr->max_rd_atomic > rxe->attr.max_qp_rd_atom) {
+                       pr_warn("invalid max_rd_atomic %d > %d\n",
+                               attr->max_rd_atomic,
+                               rxe->attr.max_qp_rd_atom);
+                       goto err1;
+               }
+       }
+
+       if (mask & IB_QP_TIMEOUT) {
+               if (attr->timeout > 31) {
+                       pr_warn("invalid QP timeout %d > 31\n",
+                               attr->timeout);
+                       goto err1;
+               }
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+/* move the qp to the reset state */
+static void rxe_qp_reset(struct rxe_qp *qp)
+{
+       /* stop tasks from running */
+       rxe_disable_task(&qp->resp.task);
+
+       /* stop request/comp */
+       if (qp->sq.queue) {
+               if (qp_type(qp) == IB_QPT_RC)
+                       rxe_disable_task(&qp->comp.task);
+               rxe_disable_task(&qp->req.task);
+       }
+
+       /* move qp to the reset state */
+       qp->req.state = QP_STATE_RESET;
+       qp->resp.state = QP_STATE_RESET;
+
+       /* let state machines reset themselves drain work and packet queues
+        * etc.
+        */
+       __rxe_do_task(&qp->resp.task);
+
+       if (qp->sq.queue) {
+               __rxe_do_task(&qp->comp.task);
+               __rxe_do_task(&qp->req.task);
+       }
+
+       /* cleanup attributes */
+       atomic_set(&qp->ssn, 0);
+       qp->req.opcode = -1;
+       qp->req.need_retry = 0;
+       qp->req.noack_pkts = 0;
+       qp->resp.msn = 0;
+       qp->resp.opcode = -1;
+       qp->resp.drop_msg = 0;
+       qp->resp.goto_error = 0;
+       qp->resp.sent_psn_nak = 0;
+
+       if (qp->resp.mr) {
+               rxe_drop_ref(qp->resp.mr);
+               qp->resp.mr = NULL;
+       }
+
+       cleanup_rd_atomic_resources(qp);
+
+       /* reenable tasks */
+       rxe_enable_task(&qp->resp.task);
+
+       if (qp->sq.queue) {
+               if (qp_type(qp) == IB_QPT_RC)
+                       rxe_enable_task(&qp->comp.task);
+
+               rxe_enable_task(&qp->req.task);
+       }
+}
+
+/* drain the send queue */
+static void rxe_qp_drain(struct rxe_qp *qp)
+{
+       if (qp->sq.queue) {
+               if (qp->req.state != QP_STATE_DRAINED) {
+                       qp->req.state = QP_STATE_DRAIN;
+                       if (qp_type(qp) == IB_QPT_RC)
+                               rxe_run_task(&qp->comp.task, 1);
+                       else
+                               __rxe_do_task(&qp->comp.task);
+                       rxe_run_task(&qp->req.task, 1);
+               }
+       }
+}
+
+/* move the qp to the error state */
+void rxe_qp_error(struct rxe_qp *qp)
+{
+       qp->req.state = QP_STATE_ERROR;
+       qp->resp.state = QP_STATE_ERROR;
+
+       /* drain work and packet queues */
+       rxe_run_task(&qp->resp.task, 1);
+
+       if (qp_type(qp) == IB_QPT_RC)
+               rxe_run_task(&qp->comp.task, 1);
+       else
+               __rxe_do_task(&qp->comp.task);
+       rxe_run_task(&qp->req.task, 1);
+}
+
+/* called by the modify qp verb */
+int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
+                    struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       union ib_gid sgid;
+       struct ib_gid_attr sgid_attr;
+
+       if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
+               int max_rd_atomic = __roundup_pow_of_two(attr->max_rd_atomic);
+
+               free_rd_atomic_resources(qp);
+
+               err = alloc_rd_atomic_resources(qp, max_rd_atomic);
+               if (err)
+                       return err;
+
+               qp->attr.max_rd_atomic = max_rd_atomic;
+               atomic_set(&qp->req.rd_atomic, max_rd_atomic);
+       }
+
+       if (mask & IB_QP_CUR_STATE)
+               qp->attr.cur_qp_state = attr->qp_state;
+
+       if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
+               qp->attr.en_sqd_async_notify = attr->en_sqd_async_notify;
+
+       if (mask & IB_QP_ACCESS_FLAGS)
+               qp->attr.qp_access_flags = attr->qp_access_flags;
+
+       if (mask & IB_QP_PKEY_INDEX)
+               qp->attr.pkey_index = attr->pkey_index;
+
+       if (mask & IB_QP_PORT)
+               qp->attr.port_num = attr->port_num;
+
+       if (mask & IB_QP_QKEY)
+               qp->attr.qkey = attr->qkey;
+
+       if (mask & IB_QP_AV) {
+               ib_get_cached_gid(&rxe->ib_dev, 1,
+                                 attr->ah_attr.grh.sgid_index, &sgid,
+                                 &sgid_attr);
+               rxe_av_from_attr(rxe, attr->port_num, &qp->pri_av,
+                                &attr->ah_attr);
+               rxe_av_fill_ip_info(rxe, &qp->pri_av, &attr->ah_attr,
+                                   &sgid_attr, &sgid);
+               if (sgid_attr.ndev)
+                       dev_put(sgid_attr.ndev);
+       }
+
+       if (mask & IB_QP_ALT_PATH) {
+               ib_get_cached_gid(&rxe->ib_dev, 1,
+                                 attr->alt_ah_attr.grh.sgid_index, &sgid,
+                                 &sgid_attr);
+
+               rxe_av_from_attr(rxe, attr->alt_port_num, &qp->alt_av,
+                                &attr->alt_ah_attr);
+               rxe_av_fill_ip_info(rxe, &qp->alt_av, &attr->alt_ah_attr,
+                                   &sgid_attr, &sgid);
+               if (sgid_attr.ndev)
+                       dev_put(sgid_attr.ndev);
+
+               qp->attr.alt_port_num = attr->alt_port_num;
+               qp->attr.alt_pkey_index = attr->alt_pkey_index;
+               qp->attr.alt_timeout = attr->alt_timeout;
+       }
+
+       if (mask & IB_QP_PATH_MTU) {
+               qp->attr.path_mtu = attr->path_mtu;
+               qp->mtu = ib_mtu_enum_to_int(attr->path_mtu);
+       }
+
+       if (mask & IB_QP_TIMEOUT) {
+               qp->attr.timeout = attr->timeout;
+               if (attr->timeout == 0) {
+                       qp->qp_timeout_jiffies = 0;
+               } else {
+                       /* According to the spec, timeout = 4.096 * 2 ^ attr->timeout [us] */
+                       int j = nsecs_to_jiffies(4096ULL << attr->timeout);
+
+                       qp->qp_timeout_jiffies = j ? j : 1;
+               }
+       }
+
+       if (mask & IB_QP_RETRY_CNT) {
+               qp->attr.retry_cnt = attr->retry_cnt;
+               qp->comp.retry_cnt = attr->retry_cnt;
+               pr_debug("set retry count = %d\n", attr->retry_cnt);
+       }
+
+       if (mask & IB_QP_RNR_RETRY) {
+               qp->attr.rnr_retry = attr->rnr_retry;
+               qp->comp.rnr_retry = attr->rnr_retry;
+               pr_debug("set rnr retry count = %d\n", attr->rnr_retry);
+       }
+
+       if (mask & IB_QP_RQ_PSN) {
+               qp->attr.rq_psn = (attr->rq_psn & BTH_PSN_MASK);
+               qp->resp.psn = qp->attr.rq_psn;
+               pr_debug("set resp psn = 0x%x\n", qp->resp.psn);
+       }
+
+       if (mask & IB_QP_MIN_RNR_TIMER) {
+               qp->attr.min_rnr_timer = attr->min_rnr_timer;
+               pr_debug("set min rnr timer = 0x%x\n",
+                        attr->min_rnr_timer);
+       }
+
+       if (mask & IB_QP_SQ_PSN) {
+               qp->attr.sq_psn = (attr->sq_psn & BTH_PSN_MASK);
+               qp->req.psn = qp->attr.sq_psn;
+               qp->comp.psn = qp->attr.sq_psn;
+               pr_debug("set req psn = 0x%x\n", qp->req.psn);
+       }
+
+       if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+               qp->attr.max_dest_rd_atomic =
+                       __roundup_pow_of_two(attr->max_dest_rd_atomic);
+       }
+
+       if (mask & IB_QP_PATH_MIG_STATE)
+               qp->attr.path_mig_state = attr->path_mig_state;
+
+       if (mask & IB_QP_DEST_QPN)
+               qp->attr.dest_qp_num = attr->dest_qp_num;
+
+       if (mask & IB_QP_STATE) {
+               qp->attr.qp_state = attr->qp_state;
+
+               switch (attr->qp_state) {
+               case IB_QPS_RESET:
+                       pr_debug("qp state -> RESET\n");
+                       rxe_qp_reset(qp);
+                       break;
+
+               case IB_QPS_INIT:
+                       pr_debug("qp state -> INIT\n");
+                       qp->req.state = QP_STATE_INIT;
+                       qp->resp.state = QP_STATE_INIT;
+                       break;
+
+               case IB_QPS_RTR:
+                       pr_debug("qp state -> RTR\n");
+                       qp->resp.state = QP_STATE_READY;
+                       break;
+
+               case IB_QPS_RTS:
+                       pr_debug("qp state -> RTS\n");
+                       qp->req.state = QP_STATE_READY;
+                       break;
+
+               case IB_QPS_SQD:
+                       pr_debug("qp state -> SQD\n");
+                       rxe_qp_drain(qp);
+                       break;
+
+               case IB_QPS_SQE:
+                       pr_warn("qp state -> SQE !!?\n");
+                       /* Not possible from modify_qp. */
+                       break;
+
+               case IB_QPS_ERR:
+                       pr_debug("qp state -> ERR\n");
+                       rxe_qp_error(qp);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/* called by the query qp verb */
+int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+
+       *attr = qp->attr;
+
+       attr->rq_psn                            = qp->resp.psn;
+       attr->sq_psn                            = qp->req.psn;
+
+       attr->cap.max_send_wr                   = qp->sq.max_wr;
+       attr->cap.max_send_sge                  = qp->sq.max_sge;
+       attr->cap.max_inline_data               = qp->sq.max_inline;
+
+       if (!qp->srq) {
+               attr->cap.max_recv_wr           = qp->rq.max_wr;
+               attr->cap.max_recv_sge          = qp->rq.max_sge;
+       }
+
+       rxe_av_to_attr(rxe, &qp->pri_av, &attr->ah_attr);
+       rxe_av_to_attr(rxe, &qp->alt_av, &attr->alt_ah_attr);
+
+       if (qp->req.state == QP_STATE_DRAIN) {
+               attr->sq_draining = 1;
+               /* applications that get this state
+                * typically spin on it. yield the
+                * processor
+                */
+               cond_resched();
+       } else {
+               attr->sq_draining = 0;
+       }
+
+       pr_debug("attr->sq_draining = %d\n", attr->sq_draining);
+
+       return 0;
+}
+
+/* called by the destroy qp verb */
+void rxe_qp_destroy(struct rxe_qp *qp)
+{
+       qp->valid = 0;
+       qp->qp_timeout_jiffies = 0;
+       rxe_cleanup_task(&qp->resp.task);
+
+       del_timer_sync(&qp->retrans_timer);
+       del_timer_sync(&qp->rnr_nak_timer);
+
+       rxe_cleanup_task(&qp->req.task);
+       if (qp_type(qp) == IB_QPT_RC)
+               rxe_cleanup_task(&qp->comp.task);
+
+       /* flush out any receive wr's or pending requests */
+       __rxe_do_task(&qp->req.task);
+       if (qp->sq.queue) {
+               __rxe_do_task(&qp->comp.task);
+               __rxe_do_task(&qp->req.task);
+       }
+}
+
+/* called when the last reference to the qp is dropped */
+void rxe_qp_cleanup(void *arg)
+{
+       struct rxe_qp *qp = arg;
+
+       rxe_drop_all_mcast_groups(qp);
+
+       if (qp->sq.queue)
+               rxe_queue_cleanup(qp->sq.queue);
+
+       if (qp->srq)
+               rxe_drop_ref(qp->srq);
+
+       if (qp->rq.queue)
+               rxe_queue_cleanup(qp->rq.queue);
+
+       if (qp->scq)
+               rxe_drop_ref(qp->scq);
+       if (qp->rcq)
+               rxe_drop_ref(qp->rcq);
+       if (qp->pd)
+               rxe_drop_ref(qp->pd);
+
+       if (qp->resp.mr) {
+               rxe_drop_ref(qp->resp.mr);
+               qp->resp.mr = NULL;
+       }
+
+       free_rd_atomic_resources(qp);
+
+       kernel_sock_shutdown(qp->sk, SHUT_RDWR);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_queue.c b/drivers/infiniband/sw/rxe/rxe_queue.c
new file mode 100644 (file)
index 0000000..0827425
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 retailuce 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/vmalloc.h>
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+int do_mmap_info(struct rxe_dev *rxe,
+                struct ib_udata *udata,
+                bool is_req,
+                struct ib_ucontext *context,
+                struct rxe_queue_buf *buf,
+                size_t buf_size,
+                struct rxe_mmap_info **ip_p)
+{
+       int err;
+       u32 len, offset;
+       struct rxe_mmap_info *ip = NULL;
+
+       if (udata) {
+               if (is_req) {
+                       len = udata->outlen - sizeof(struct mminfo);
+                       offset = sizeof(struct mminfo);
+               } else {
+                       len = udata->outlen;
+                       offset = 0;
+               }
+
+               if (len < sizeof(ip->info))
+                       goto err1;
+
+               ip = rxe_create_mmap_info(rxe, buf_size, context, buf);
+               if (!ip)
+                       goto err1;
+
+               err = copy_to_user(udata->outbuf + offset, &ip->info,
+                                  sizeof(ip->info));
+               if (err)
+                       goto err2;
+
+               spin_lock_bh(&rxe->pending_lock);
+               list_add(&ip->pending_mmaps, &rxe->pending_mmaps);
+               spin_unlock_bh(&rxe->pending_lock);
+       }
+
+       *ip_p = ip;
+
+       return 0;
+
+err2:
+       kfree(ip);
+err1:
+       return -EINVAL;
+}
+
+struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
+                                int *num_elem,
+                                unsigned int elem_size)
+{
+       struct rxe_queue *q;
+       size_t buf_size;
+       unsigned int num_slots;
+
+       /* num_elem == 0 is allowed, but uninteresting */
+       if (*num_elem < 0)
+               goto err1;
+
+       q = kmalloc(sizeof(*q), GFP_KERNEL);
+       if (!q)
+               goto err1;
+
+       q->rxe = rxe;
+
+       /* used in resize, only need to copy used part of queue */
+       q->elem_size = elem_size;
+
+       /* pad element up to at least a cacheline and always a power of 2 */
+       if (elem_size < cache_line_size())
+               elem_size = cache_line_size();
+       elem_size = roundup_pow_of_two(elem_size);
+
+       q->log2_elem_size = order_base_2(elem_size);
+
+       num_slots = *num_elem + 1;
+       num_slots = roundup_pow_of_two(num_slots);
+       q->index_mask = num_slots - 1;
+
+       buf_size = sizeof(struct rxe_queue_buf) + num_slots * elem_size;
+
+       q->buf = vmalloc_user(buf_size);
+       if (!q->buf)
+               goto err2;
+
+       q->buf->log2_elem_size = q->log2_elem_size;
+       q->buf->index_mask = q->index_mask;
+
+       q->buf_size = buf_size;
+
+       *num_elem = num_slots - 1;
+       return q;
+
+err2:
+       kfree(q);
+err1:
+       return NULL;
+}
+
+/* copies elements from original q to new q and then swaps the contents of the
+ * two q headers. This is so that if anyone is holding a pointer to q it will
+ * still work
+ */
+static int resize_finish(struct rxe_queue *q, struct rxe_queue *new_q,
+                        unsigned int num_elem)
+{
+       if (!queue_empty(q) && (num_elem < queue_count(q)))
+               return -EINVAL;
+
+       while (!queue_empty(q)) {
+               memcpy(producer_addr(new_q), consumer_addr(q),
+                      new_q->elem_size);
+               advance_producer(new_q);
+               advance_consumer(q);
+       }
+
+       swap(*q, *new_q);
+
+       return 0;
+}
+
+int rxe_queue_resize(struct rxe_queue *q,
+                    unsigned int *num_elem_p,
+                    unsigned int elem_size,
+                    struct ib_ucontext *context,
+                    struct ib_udata *udata,
+                    spinlock_t *producer_lock,
+                    spinlock_t *consumer_lock)
+{
+       struct rxe_queue *new_q;
+       unsigned int num_elem = *num_elem_p;
+       int err;
+       unsigned long flags = 0, flags1;
+
+       new_q = rxe_queue_init(q->rxe, &num_elem, elem_size);
+       if (!new_q)
+               return -ENOMEM;
+
+       err = do_mmap_info(new_q->rxe, udata, false, context, new_q->buf,
+                          new_q->buf_size, &new_q->ip);
+       if (err) {
+               vfree(new_q->buf);
+               kfree(new_q);
+               goto err1;
+       }
+
+       spin_lock_irqsave(consumer_lock, flags1);
+
+       if (producer_lock) {
+               spin_lock_irqsave(producer_lock, flags);
+               err = resize_finish(q, new_q, num_elem);
+               spin_unlock_irqrestore(producer_lock, flags);
+       } else {
+               err = resize_finish(q, new_q, num_elem);
+       }
+
+       spin_unlock_irqrestore(consumer_lock, flags1);
+
+       rxe_queue_cleanup(new_q);       /* new/old dep on err */
+       if (err)
+               goto err1;
+
+       *num_elem_p = num_elem;
+       return 0;
+
+err1:
+       return err;
+}
+
+void rxe_queue_cleanup(struct rxe_queue *q)
+{
+       if (q->ip)
+               kref_put(&q->ip->ref, rxe_mmap_release);
+       else
+               vfree(q->buf);
+
+       kfree(q);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_queue.h b/drivers/infiniband/sw/rxe/rxe_queue.h
new file mode 100644 (file)
index 0000000..239fd60
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_QUEUE_H
+#define RXE_QUEUE_H
+
+/* implements a simple circular buffer that can optionally be
+ * shared between user space and the kernel and can be resized
+
+ * the requested element size is rounded up to a power of 2
+ * and the number of elements in the buffer is also rounded
+ * up to a power of 2. Since the queue is empty when the
+ * producer and consumer indices match the maximum capacity
+ * of the queue is one less than the number of element slots
+ */
+
+/* this data structure is shared between user space and kernel
+ * space for those cases where the queue is shared. It contains
+ * the producer and consumer indices. Is also contains a copy
+ * of the queue size parameters for user space to use but the
+ * kernel must use the parameters in the rxe_queue struct
+ * this MUST MATCH the corresponding librxe struct
+ * for performance reasons arrange to have producer and consumer
+ * pointers in separate cache lines
+ * the kernel should always mask the indices to avoid accessing
+ * memory outside of the data area
+ */
+struct rxe_queue_buf {
+       __u32                   log2_elem_size;
+       __u32                   index_mask;
+       __u32                   pad_1[30];
+       __u32                   producer_index;
+       __u32                   pad_2[31];
+       __u32                   consumer_index;
+       __u32                   pad_3[31];
+       __u8                    data[0];
+};
+
+struct rxe_queue {
+       struct rxe_dev          *rxe;
+       struct rxe_queue_buf    *buf;
+       struct rxe_mmap_info    *ip;
+       size_t                  buf_size;
+       size_t                  elem_size;
+       unsigned int            log2_elem_size;
+       unsigned int            index_mask;
+};
+
+int do_mmap_info(struct rxe_dev *rxe,
+                struct ib_udata *udata,
+                bool is_req,
+                struct ib_ucontext *context,
+                struct rxe_queue_buf *buf,
+                size_t buf_size,
+                struct rxe_mmap_info **ip_p);
+
+struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
+                                int *num_elem,
+                                unsigned int elem_size);
+
+int rxe_queue_resize(struct rxe_queue *q,
+                    unsigned int *num_elem_p,
+                    unsigned int elem_size,
+                    struct ib_ucontext *context,
+                    struct ib_udata *udata,
+                    /* Protect producers while resizing queue */
+                    spinlock_t *producer_lock,
+                    /* Protect consumers while resizing queue */
+                    spinlock_t *consumer_lock);
+
+void rxe_queue_cleanup(struct rxe_queue *queue);
+
+static inline int next_index(struct rxe_queue *q, int index)
+{
+       return (index + 1) & q->buf->index_mask;
+}
+
+static inline int queue_empty(struct rxe_queue *q)
+{
+       return ((q->buf->producer_index - q->buf->consumer_index)
+                       & q->index_mask) == 0;
+}
+
+static inline int queue_full(struct rxe_queue *q)
+{
+       return ((q->buf->producer_index + 1 - q->buf->consumer_index)
+                       & q->index_mask) == 0;
+}
+
+static inline void advance_producer(struct rxe_queue *q)
+{
+       q->buf->producer_index = (q->buf->producer_index + 1)
+                       & q->index_mask;
+}
+
+static inline void advance_consumer(struct rxe_queue *q)
+{
+       q->buf->consumer_index = (q->buf->consumer_index + 1)
+                       & q->index_mask;
+}
+
+static inline void *producer_addr(struct rxe_queue *q)
+{
+       return q->buf->data + ((q->buf->producer_index & q->index_mask)
+                               << q->log2_elem_size);
+}
+
+static inline void *consumer_addr(struct rxe_queue *q)
+{
+       return q->buf->data + ((q->buf->consumer_index & q->index_mask)
+                               << q->log2_elem_size);
+}
+
+static inline unsigned int producer_index(struct rxe_queue *q)
+{
+       return q->buf->producer_index;
+}
+
+static inline unsigned int consumer_index(struct rxe_queue *q)
+{
+       return q->buf->consumer_index;
+}
+
+static inline void *addr_from_index(struct rxe_queue *q, unsigned int index)
+{
+       return q->buf->data + ((index & q->index_mask)
+                               << q->buf->log2_elem_size);
+}
+
+static inline unsigned int index_from_addr(const struct rxe_queue *q,
+                                          const void *addr)
+{
+       return (((u8 *)addr - q->buf->data) >> q->log2_elem_size)
+               & q->index_mask;
+}
+
+static inline unsigned int queue_count(const struct rxe_queue *q)
+{
+       return (q->buf->producer_index - q->buf->consumer_index)
+               & q->index_mask;
+}
+
+static inline void *queue_head(struct rxe_queue *q)
+{
+       return queue_empty(q) ? NULL : consumer_addr(q);
+}
+
+#endif /* RXE_QUEUE_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
new file mode 100644 (file)
index 0000000..3d464c2
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+
+static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                           struct rxe_qp *qp)
+{
+       if (unlikely(!qp->valid))
+               goto err1;
+
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               if (unlikely((pkt->opcode & IB_OPCODE_RC) != 0)) {
+                       pr_warn_ratelimited("bad qp type\n");
+                       goto err1;
+               }
+               break;
+       case IB_QPT_UC:
+               if (unlikely(!(pkt->opcode & IB_OPCODE_UC))) {
+                       pr_warn_ratelimited("bad qp type\n");
+                       goto err1;
+               }
+               break;
+       case IB_QPT_UD:
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               if (unlikely(!(pkt->opcode & IB_OPCODE_UD))) {
+                       pr_warn_ratelimited("bad qp type\n");
+                       goto err1;
+               }
+               break;
+       default:
+               pr_warn_ratelimited("unsupported qp type\n");
+               goto err1;
+       }
+
+       if (pkt->mask & RXE_REQ_MASK) {
+               if (unlikely(qp->resp.state != QP_STATE_READY))
+                       goto err1;
+       } else if (unlikely(qp->req.state < QP_STATE_READY ||
+                               qp->req.state > QP_STATE_DRAINED)) {
+               goto err1;
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static void set_bad_pkey_cntr(struct rxe_port *port)
+{
+       spin_lock_bh(&port->port_lock);
+       port->attr.bad_pkey_cntr = min((u32)0xffff,
+                                      port->attr.bad_pkey_cntr + 1);
+       spin_unlock_bh(&port->port_lock);
+}
+
+static void set_qkey_viol_cntr(struct rxe_port *port)
+{
+       spin_lock_bh(&port->port_lock);
+       port->attr.qkey_viol_cntr = min((u32)0xffff,
+                                       port->attr.qkey_viol_cntr + 1);
+       spin_unlock_bh(&port->port_lock);
+}
+
+static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                     u32 qpn, struct rxe_qp *qp)
+{
+       int i;
+       int found_pkey = 0;
+       struct rxe_port *port = &rxe->port;
+       u16 pkey = bth_pkey(pkt);
+
+       pkt->pkey_index = 0;
+
+       if (qpn == 1) {
+               for (i = 0; i < port->attr.pkey_tbl_len; i++) {
+                       if (pkey_match(pkey, port->pkey_tbl[i])) {
+                               pkt->pkey_index = i;
+                               found_pkey = 1;
+                               break;
+                       }
+               }
+
+               if (!found_pkey) {
+                       pr_warn_ratelimited("bad pkey = 0x%x\n", pkey);
+                       set_bad_pkey_cntr(port);
+                       goto err1;
+               }
+       } else if (qpn != 0) {
+               if (unlikely(!pkey_match(pkey,
+                                        port->pkey_tbl[qp->attr.pkey_index]
+                                       ))) {
+                       pr_warn_ratelimited("bad pkey = 0x%0x\n", pkey);
+                       set_bad_pkey_cntr(port);
+                       goto err1;
+               }
+               pkt->pkey_index = qp->attr.pkey_index;
+       }
+
+       if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) &&
+           qpn != 0 && pkt->mask) {
+               u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey;
+
+               if (unlikely(deth_qkey(pkt) != qkey)) {
+                       pr_warn_ratelimited("bad qkey, got 0x%x expected 0x%x for qpn 0x%x\n",
+                                           deth_qkey(pkt), qkey, qpn);
+                       set_qkey_viol_cntr(port);
+                       goto err1;
+               }
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static int check_addr(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                     struct rxe_qp *qp)
+{
+       struct sk_buff *skb = PKT_TO_SKB(pkt);
+
+       if (qp_type(qp) != IB_QPT_RC && qp_type(qp) != IB_QPT_UC)
+               goto done;
+
+       if (unlikely(pkt->port_num != qp->attr.port_num)) {
+               pr_warn_ratelimited("port %d != qp port %d\n",
+                                   pkt->port_num, qp->attr.port_num);
+               goto err1;
+       }
+
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct in_addr *saddr =
+                       &qp->pri_av.sgid_addr._sockaddr_in.sin_addr;
+               struct in_addr *daddr =
+                       &qp->pri_av.dgid_addr._sockaddr_in.sin_addr;
+
+               if (ip_hdr(skb)->daddr != saddr->s_addr) {
+                       pr_warn_ratelimited("dst addr %pI4 != qp source addr %pI4\n",
+                                           &ip_hdr(skb)->daddr,
+                                           &saddr->s_addr);
+                       goto err1;
+               }
+
+               if (ip_hdr(skb)->saddr != daddr->s_addr) {
+                       pr_warn_ratelimited("source addr %pI4 != qp dst addr %pI4\n",
+                                           &ip_hdr(skb)->saddr,
+                                           &daddr->s_addr);
+                       goto err1;
+               }
+
+       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               struct in6_addr *saddr =
+                       &qp->pri_av.sgid_addr._sockaddr_in6.sin6_addr;
+               struct in6_addr *daddr =
+                       &qp->pri_av.dgid_addr._sockaddr_in6.sin6_addr;
+
+               if (memcmp(&ipv6_hdr(skb)->daddr, saddr, sizeof(*saddr))) {
+                       pr_warn_ratelimited("dst addr %pI6 != qp source addr %pI6\n",
+                                           &ipv6_hdr(skb)->daddr, saddr);
+                       goto err1;
+               }
+
+               if (memcmp(&ipv6_hdr(skb)->saddr, daddr, sizeof(*daddr))) {
+                       pr_warn_ratelimited("source addr %pI6 != qp dst addr %pI6\n",
+                                           &ipv6_hdr(skb)->saddr, daddr);
+                       goto err1;
+               }
+       }
+
+done:
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static int hdr_check(struct rxe_pkt_info *pkt)
+{
+       struct rxe_dev *rxe = pkt->rxe;
+       struct rxe_port *port = &rxe->port;
+       struct rxe_qp *qp = NULL;
+       u32 qpn = bth_qpn(pkt);
+       int index;
+       int err;
+
+       if (unlikely(bth_tver(pkt) != BTH_TVER)) {
+               pr_warn_ratelimited("bad tver\n");
+               goto err1;
+       }
+
+       if (qpn != IB_MULTICAST_QPN) {
+               index = (qpn == 0) ? port->qp_smi_index :
+                       ((qpn == 1) ? port->qp_gsi_index : qpn);
+               qp = rxe_pool_get_index(&rxe->qp_pool, index);
+               if (unlikely(!qp)) {
+                       pr_warn_ratelimited("no qp matches qpn 0x%x\n", qpn);
+                       goto err1;
+               }
+
+               err = check_type_state(rxe, pkt, qp);
+               if (unlikely(err))
+                       goto err2;
+
+               err = check_addr(rxe, pkt, qp);
+               if (unlikely(err))
+                       goto err2;
+
+               err = check_keys(rxe, pkt, qpn, qp);
+               if (unlikely(err))
+                       goto err2;
+       } else {
+               if (unlikely((pkt->mask & RXE_GRH_MASK) == 0)) {
+                       pr_warn_ratelimited("no grh for mcast qpn\n");
+                       goto err1;
+               }
+       }
+
+       pkt->qp = qp;
+       return 0;
+
+err2:
+       if (qp)
+               rxe_drop_ref(qp);
+err1:
+       return -EINVAL;
+}
+
+static inline void rxe_rcv_pkt(struct rxe_dev *rxe,
+                              struct rxe_pkt_info *pkt,
+                              struct sk_buff *skb)
+{
+       if (pkt->mask & RXE_REQ_MASK)
+               rxe_resp_queue_pkt(rxe, pkt->qp, skb);
+       else
+               rxe_comp_queue_pkt(rxe, pkt->qp, skb);
+}
+
+static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
+{
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+       struct rxe_mc_grp *mcg;
+       struct sk_buff *skb_copy;
+       struct rxe_mc_elem *mce;
+       struct rxe_qp *qp;
+       union ib_gid dgid;
+       int err;
+
+       if (skb->protocol == htons(ETH_P_IP))
+               ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
+                                      (struct in6_addr *)&dgid);
+       else if (skb->protocol == htons(ETH_P_IPV6))
+               memcpy(&dgid, &ipv6_hdr(skb)->daddr, sizeof(dgid));
+
+       /* lookup mcast group corresponding to mgid, takes a ref */
+       mcg = rxe_pool_get_key(&rxe->mc_grp_pool, &dgid);
+       if (!mcg)
+               goto err1;      /* mcast group not registered */
+
+       spin_lock_bh(&mcg->mcg_lock);
+
+       list_for_each_entry(mce, &mcg->qp_list, qp_list) {
+               qp = mce->qp;
+               pkt = SKB_TO_PKT(skb);
+
+               /* validate qp for incoming packet */
+               err = check_type_state(rxe, pkt, qp);
+               if (err)
+                       continue;
+
+               err = check_keys(rxe, pkt, bth_qpn(pkt), qp);
+               if (err)
+                       continue;
+
+               /* if *not* the last qp in the list
+                * make a copy of the skb to post to the next qp
+                */
+               skb_copy = (mce->qp_list.next != &mcg->qp_list) ?
+                               skb_clone(skb, GFP_KERNEL) : NULL;
+
+               pkt->qp = qp;
+               rxe_add_ref(qp);
+               rxe_rcv_pkt(rxe, pkt, skb);
+
+               skb = skb_copy;
+               if (!skb)
+                       break;
+       }
+
+       spin_unlock_bh(&mcg->mcg_lock);
+
+       rxe_drop_ref(mcg);      /* drop ref from rxe_pool_get_key. */
+
+err1:
+       if (skb)
+               kfree_skb(skb);
+}
+
+static int rxe_match_dgid(struct rxe_dev *rxe, struct sk_buff *skb)
+{
+       union ib_gid dgid;
+       union ib_gid *pdgid;
+       u16 index;
+
+       if (skb->protocol == htons(ETH_P_IP)) {
+               ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
+                                      (struct in6_addr *)&dgid);
+               pdgid = &dgid;
+       } else {
+               pdgid = (union ib_gid *)&ipv6_hdr(skb)->daddr;
+       }
+
+       return ib_find_cached_gid_by_port(&rxe->ib_dev, pdgid,
+                                         IB_GID_TYPE_ROCE_UDP_ENCAP,
+                                         1, rxe->ndev, &index);
+}
+
+/* rxe_rcv is called from the interface driver */
+int rxe_rcv(struct sk_buff *skb)
+{
+       int err;
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+       struct rxe_dev *rxe = pkt->rxe;
+       __be32 *icrcp;
+       u32 calc_icrc, pack_icrc;
+
+       pkt->offset = 0;
+
+       if (unlikely(skb->len < pkt->offset + RXE_BTH_BYTES))
+               goto drop;
+
+       if (unlikely(rxe_match_dgid(rxe, skb) < 0)) {
+               pr_warn_ratelimited("failed matching dgid\n");
+               goto drop;
+       }
+
+       pkt->opcode = bth_opcode(pkt);
+       pkt->psn = bth_psn(pkt);
+       pkt->qp = NULL;
+       pkt->mask |= rxe_opcode[pkt->opcode].mask;
+
+       if (unlikely(skb->len < header_size(pkt)))
+               goto drop;
+
+       err = hdr_check(pkt);
+       if (unlikely(err))
+               goto drop;
+
+       /* Verify ICRC */
+       icrcp = (__be32 *)(pkt->hdr + pkt->paylen - RXE_ICRC_SIZE);
+       pack_icrc = be32_to_cpu(*icrcp);
+
+       calc_icrc = rxe_icrc_hdr(pkt, skb);
+       calc_icrc = crc32_le(calc_icrc, (u8 *)payload_addr(pkt), payload_size(pkt));
+       calc_icrc = cpu_to_be32(~calc_icrc);
+       if (unlikely(calc_icrc != pack_icrc)) {
+               char saddr[sizeof(struct in6_addr)];
+
+               if (skb->protocol == htons(ETH_P_IPV6))
+                       sprintf(saddr, "%pI6", &ipv6_hdr(skb)->saddr);
+               else if (skb->protocol == htons(ETH_P_IP))
+                       sprintf(saddr, "%pI4", &ip_hdr(skb)->saddr);
+               else
+                       sprintf(saddr, "unknown");
+
+               pr_warn_ratelimited("bad ICRC from %s\n", saddr);
+               goto drop;
+       }
+
+       if (unlikely(bth_qpn(pkt) == IB_MULTICAST_QPN))
+               rxe_rcv_mcast_pkt(rxe, skb);
+       else
+               rxe_rcv_pkt(rxe, pkt, skb);
+
+       return 0;
+
+drop:
+       if (pkt->qp)
+               rxe_drop_ref(pkt->qp);
+
+       kfree_skb(skb);
+       return 0;
+}
+EXPORT_SYMBOL(rxe_rcv);
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
new file mode 100644 (file)
index 0000000..33b2d9d
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+                      unsigned opcode);
+
+static inline void retry_first_write_send(struct rxe_qp *qp,
+                                         struct rxe_send_wqe *wqe,
+                                         unsigned mask, int npsn)
+{
+       int i;
+
+       for (i = 0; i < npsn; i++) {
+               int to_send = (wqe->dma.resid > qp->mtu) ?
+                               qp->mtu : wqe->dma.resid;
+
+               qp->req.opcode = next_opcode(qp, wqe,
+                                            wqe->wr.opcode);
+
+               if (wqe->wr.send_flags & IB_SEND_INLINE) {
+                       wqe->dma.resid -= to_send;
+                       wqe->dma.sge_offset += to_send;
+               } else {
+                       advance_dma_data(&wqe->dma, to_send);
+               }
+               if (mask & WR_WRITE_MASK)
+                       wqe->iova += qp->mtu;
+       }
+}
+
+static void req_retry(struct rxe_qp *qp)
+{
+       struct rxe_send_wqe *wqe;
+       unsigned int wqe_index;
+       unsigned int mask;
+       int npsn;
+       int first = 1;
+
+       wqe = queue_head(qp->sq.queue);
+       npsn = (qp->comp.psn - wqe->first_psn) & BTH_PSN_MASK;
+
+       qp->req.wqe_index       = consumer_index(qp->sq.queue);
+       qp->req.psn             = qp->comp.psn;
+       qp->req.opcode          = -1;
+
+       for (wqe_index = consumer_index(qp->sq.queue);
+               wqe_index != producer_index(qp->sq.queue);
+               wqe_index = next_index(qp->sq.queue, wqe_index)) {
+               wqe = addr_from_index(qp->sq.queue, wqe_index);
+               mask = wr_opcode_mask(wqe->wr.opcode, qp);
+
+               if (wqe->state == wqe_state_posted)
+                       break;
+
+               if (wqe->state == wqe_state_done)
+                       continue;
+
+               wqe->iova = (mask & WR_ATOMIC_MASK) ?
+                            wqe->wr.wr.atomic.remote_addr :
+                            (mask & WR_READ_OR_WRITE_MASK) ?
+                            wqe->wr.wr.rdma.remote_addr :
+                            0;
+
+               if (!first || (mask & WR_READ_MASK) == 0) {
+                       wqe->dma.resid = wqe->dma.length;
+                       wqe->dma.cur_sge = 0;
+                       wqe->dma.sge_offset = 0;
+               }
+
+               if (first) {
+                       first = 0;
+
+                       if (mask & WR_WRITE_OR_SEND_MASK)
+                               retry_first_write_send(qp, wqe, mask, npsn);
+
+                       if (mask & WR_READ_MASK)
+                               wqe->iova += npsn * qp->mtu;
+               }
+
+               wqe->state = wqe_state_posted;
+       }
+}
+
+void rnr_nak_timer(unsigned long data)
+{
+       struct rxe_qp *qp = (struct rxe_qp *)data;
+
+       pr_debug("rnr nak timer fired\n");
+       rxe_run_task(&qp->req.task, 1);
+}
+
+static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
+{
+       struct rxe_send_wqe *wqe = queue_head(qp->sq.queue);
+       unsigned long flags;
+
+       if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
+               /* check to see if we are drained;
+                * state_lock used by requester and completer
+                */
+               spin_lock_irqsave(&qp->state_lock, flags);
+               do {
+                       if (qp->req.state != QP_STATE_DRAIN) {
+                               /* comp just finished */
+                               spin_unlock_irqrestore(&qp->state_lock,
+                                                      flags);
+                               break;
+                       }
+
+                       if (wqe && ((qp->req.wqe_index !=
+                               consumer_index(qp->sq.queue)) ||
+                               (wqe->state != wqe_state_posted))) {
+                               /* comp not done yet */
+                               spin_unlock_irqrestore(&qp->state_lock,
+                                                      flags);
+                               break;
+                       }
+
+                       qp->req.state = QP_STATE_DRAINED;
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
+
+                       if (qp->ibqp.event_handler) {
+                               struct ib_event ev;
+
+                               ev.device = qp->ibqp.device;
+                               ev.element.qp = &qp->ibqp;
+                               ev.event = IB_EVENT_SQ_DRAINED;
+                               qp->ibqp.event_handler(&ev,
+                                       qp->ibqp.qp_context);
+                       }
+               } while (0);
+       }
+
+       if (qp->req.wqe_index == producer_index(qp->sq.queue))
+               return NULL;
+
+       wqe = addr_from_index(qp->sq.queue, qp->req.wqe_index);
+
+       if (unlikely((qp->req.state == QP_STATE_DRAIN ||
+                     qp->req.state == QP_STATE_DRAINED) &&
+                    (wqe->state != wqe_state_processing)))
+               return NULL;
+
+       if (unlikely((wqe->wr.send_flags & IB_SEND_FENCE) &&
+                    (qp->req.wqe_index != consumer_index(qp->sq.queue)))) {
+               qp->req.wait_fence = 1;
+               return NULL;
+       }
+
+       wqe->mask = wr_opcode_mask(wqe->wr.opcode, qp);
+       return wqe;
+}
+
+static int next_opcode_rc(struct rxe_qp *qp, unsigned opcode, int fits)
+{
+       switch (opcode) {
+       case IB_WR_RDMA_WRITE:
+               if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST ||
+                   qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_RC_RDMA_WRITE_LAST :
+                               IB_OPCODE_RC_RDMA_WRITE_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_RC_RDMA_WRITE_ONLY :
+                               IB_OPCODE_RC_RDMA_WRITE_FIRST;
+
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+               if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST ||
+                   qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE :
+                               IB_OPCODE_RC_RDMA_WRITE_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE :
+                               IB_OPCODE_RC_RDMA_WRITE_FIRST;
+
+       case IB_WR_SEND:
+               if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
+                   qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_RC_SEND_LAST :
+                               IB_OPCODE_RC_SEND_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_RC_SEND_ONLY :
+                               IB_OPCODE_RC_SEND_FIRST;
+
+       case IB_WR_SEND_WITH_IMM:
+               if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
+                   qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE :
+                               IB_OPCODE_RC_SEND_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE :
+                               IB_OPCODE_RC_SEND_FIRST;
+
+       case IB_WR_RDMA_READ:
+               return IB_OPCODE_RC_RDMA_READ_REQUEST;
+
+       case IB_WR_ATOMIC_CMP_AND_SWP:
+               return IB_OPCODE_RC_COMPARE_SWAP;
+
+       case IB_WR_ATOMIC_FETCH_AND_ADD:
+               return IB_OPCODE_RC_FETCH_ADD;
+
+       case IB_WR_SEND_WITH_INV:
+               if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
+                   qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
+                       return fits ? IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE :
+                               IB_OPCODE_RC_SEND_MIDDLE;
+               else
+                       return fits ? IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE :
+                               IB_OPCODE_RC_SEND_FIRST;
+       case IB_WR_REG_MR:
+       case IB_WR_LOCAL_INV:
+               return opcode;
+       }
+
+       return -EINVAL;
+}
+
+static int next_opcode_uc(struct rxe_qp *qp, unsigned opcode, int fits)
+{
+       switch (opcode) {
+       case IB_WR_RDMA_WRITE:
+               if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST ||
+                   qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_UC_RDMA_WRITE_LAST :
+                               IB_OPCODE_UC_RDMA_WRITE_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_UC_RDMA_WRITE_ONLY :
+                               IB_OPCODE_UC_RDMA_WRITE_FIRST;
+
+       case IB_WR_RDMA_WRITE_WITH_IMM:
+               if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST ||
+                   qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE :
+                               IB_OPCODE_UC_RDMA_WRITE_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE :
+                               IB_OPCODE_UC_RDMA_WRITE_FIRST;
+
+       case IB_WR_SEND:
+               if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST ||
+                   qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_UC_SEND_LAST :
+                               IB_OPCODE_UC_SEND_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_UC_SEND_ONLY :
+                               IB_OPCODE_UC_SEND_FIRST;
+
+       case IB_WR_SEND_WITH_IMM:
+               if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST ||
+                   qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE)
+                       return fits ?
+                               IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE :
+                               IB_OPCODE_UC_SEND_MIDDLE;
+               else
+                       return fits ?
+                               IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE :
+                               IB_OPCODE_UC_SEND_FIRST;
+       }
+
+       return -EINVAL;
+}
+
+static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+                      unsigned opcode)
+{
+       int fits = (wqe->dma.resid <= qp->mtu);
+
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               return next_opcode_rc(qp, opcode, fits);
+
+       case IB_QPT_UC:
+               return next_opcode_uc(qp, opcode, fits);
+
+       case IB_QPT_SMI:
+       case IB_QPT_UD:
+       case IB_QPT_GSI:
+               switch (opcode) {
+               case IB_WR_SEND:
+                       return IB_OPCODE_UD_SEND_ONLY;
+
+               case IB_WR_SEND_WITH_IMM:
+                       return IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static inline int check_init_depth(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+{
+       int depth;
+
+       if (wqe->has_rd_atomic)
+               return 0;
+
+       qp->req.need_rd_atomic = 1;
+       depth = atomic_dec_return(&qp->req.rd_atomic);
+
+       if (depth >= 0) {
+               qp->req.need_rd_atomic = 0;
+               wqe->has_rd_atomic = 1;
+               return 0;
+       }
+
+       atomic_inc(&qp->req.rd_atomic);
+       return -EAGAIN;
+}
+
+static inline int get_mtu(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       struct rxe_port *port;
+       struct rxe_av *av;
+
+       if ((qp_type(qp) == IB_QPT_RC) || (qp_type(qp) == IB_QPT_UC))
+               return qp->mtu;
+
+       av = &wqe->av;
+       port = &rxe->port;
+
+       return port->mtu_cap;
+}
+
+static struct sk_buff *init_req_packet(struct rxe_qp *qp,
+                                      struct rxe_send_wqe *wqe,
+                                      int opcode, int payload,
+                                      struct rxe_pkt_info *pkt)
+{
+       struct rxe_dev          *rxe = to_rdev(qp->ibqp.device);
+       struct rxe_port         *port = &rxe->port;
+       struct sk_buff          *skb;
+       struct rxe_send_wr      *ibwr = &wqe->wr;
+       struct rxe_av           *av;
+       int                     pad = (-payload) & 0x3;
+       int                     paylen;
+       int                     solicited;
+       u16                     pkey;
+       u32                     qp_num;
+       int                     ack_req;
+
+       /* length from start of bth to end of icrc */
+       paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE;
+
+       /* pkt->hdr, rxe, port_num and mask are initialized in ifc
+        * layer
+        */
+       pkt->opcode     = opcode;
+       pkt->qp         = qp;
+       pkt->psn        = qp->req.psn;
+       pkt->mask       = rxe_opcode[opcode].mask;
+       pkt->paylen     = paylen;
+       pkt->offset     = 0;
+       pkt->wqe        = wqe;
+
+       /* init skb */
+       av = rxe_get_av(pkt);
+       skb = rxe->ifc_ops->init_packet(rxe, av, paylen, pkt);
+       if (unlikely(!skb))
+               return NULL;
+
+       /* init bth */
+       solicited = (ibwr->send_flags & IB_SEND_SOLICITED) &&
+                       (pkt->mask & RXE_END_MASK) &&
+                       ((pkt->mask & (RXE_SEND_MASK)) ||
+                       (pkt->mask & (RXE_WRITE_MASK | RXE_IMMDT_MASK)) ==
+                       (RXE_WRITE_MASK | RXE_IMMDT_MASK));
+
+       pkey = (qp_type(qp) == IB_QPT_GSI) ?
+                port->pkey_tbl[ibwr->wr.ud.pkey_index] :
+                port->pkey_tbl[qp->attr.pkey_index];
+
+       qp_num = (pkt->mask & RXE_DETH_MASK) ? ibwr->wr.ud.remote_qpn :
+                                        qp->attr.dest_qp_num;
+
+       ack_req = ((pkt->mask & RXE_END_MASK) ||
+               (qp->req.noack_pkts++ > RXE_MAX_PKT_PER_ACK));
+       if (ack_req)
+               qp->req.noack_pkts = 0;
+
+       bth_init(pkt, pkt->opcode, solicited, 0, pad, pkey, qp_num,
+                ack_req, pkt->psn);
+
+       /* init optional headers */
+       if (pkt->mask & RXE_RETH_MASK) {
+               reth_set_rkey(pkt, ibwr->wr.rdma.rkey);
+               reth_set_va(pkt, wqe->iova);
+               reth_set_len(pkt, wqe->dma.length);
+       }
+
+       if (pkt->mask & RXE_IMMDT_MASK)
+               immdt_set_imm(pkt, ibwr->ex.imm_data);
+
+       if (pkt->mask & RXE_IETH_MASK)
+               ieth_set_rkey(pkt, ibwr->ex.invalidate_rkey);
+
+       if (pkt->mask & RXE_ATMETH_MASK) {
+               atmeth_set_va(pkt, wqe->iova);
+               if (opcode == IB_OPCODE_RC_COMPARE_SWAP ||
+                   opcode == IB_OPCODE_RD_COMPARE_SWAP) {
+                       atmeth_set_swap_add(pkt, ibwr->wr.atomic.swap);
+                       atmeth_set_comp(pkt, ibwr->wr.atomic.compare_add);
+               } else {
+                       atmeth_set_swap_add(pkt, ibwr->wr.atomic.compare_add);
+               }
+               atmeth_set_rkey(pkt, ibwr->wr.atomic.rkey);
+       }
+
+       if (pkt->mask & RXE_DETH_MASK) {
+               if (qp->ibqp.qp_num == 1)
+                       deth_set_qkey(pkt, GSI_QKEY);
+               else
+                       deth_set_qkey(pkt, ibwr->wr.ud.remote_qkey);
+               deth_set_sqp(pkt, qp->ibqp.qp_num);
+       }
+
+       return skb;
+}
+
+static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+                      struct rxe_pkt_info *pkt, struct sk_buff *skb,
+                      int paylen)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       u32 crc = 0;
+       u32 *p;
+       int err;
+
+       err = rxe->ifc_ops->prepare(rxe, pkt, skb, &crc);
+       if (err)
+               return err;
+
+       if (pkt->mask & RXE_WRITE_OR_SEND) {
+               if (wqe->wr.send_flags & IB_SEND_INLINE) {
+                       u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset];
+
+                       crc = crc32_le(crc, tmp, paylen);
+
+                       memcpy(payload_addr(pkt), tmp, paylen);
+
+                       wqe->dma.resid -= paylen;
+                       wqe->dma.sge_offset += paylen;
+               } else {
+                       err = copy_data(rxe, qp->pd, 0, &wqe->dma,
+                                       payload_addr(pkt), paylen,
+                                       from_mem_obj,
+                                       &crc);
+                       if (err)
+                               return err;
+               }
+       }
+       p = payload_addr(pkt) + paylen + bth_pad(pkt);
+
+       *p = ~crc;
+
+       return 0;
+}
+
+static void update_wqe_state(struct rxe_qp *qp,
+                            struct rxe_send_wqe *wqe,
+                            struct rxe_pkt_info *pkt,
+                            enum wqe_state *prev_state)
+{
+       enum wqe_state prev_state_ = wqe->state;
+
+       if (pkt->mask & RXE_END_MASK) {
+               if (qp_type(qp) == IB_QPT_RC)
+                       wqe->state = wqe_state_pending;
+       } else {
+               wqe->state = wqe_state_processing;
+       }
+
+       *prev_state = prev_state_;
+}
+
+static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
+                        struct rxe_pkt_info *pkt, int payload)
+{
+       /* number of packets left to send including current one */
+       int num_pkt = (wqe->dma.resid + payload + qp->mtu - 1) / qp->mtu;
+
+       /* handle zero length packet case */
+       if (num_pkt == 0)
+               num_pkt = 1;
+
+       if (pkt->mask & RXE_START_MASK) {
+               wqe->first_psn = qp->req.psn;
+               wqe->last_psn = (qp->req.psn + num_pkt - 1) & BTH_PSN_MASK;
+       }
+
+       if (pkt->mask & RXE_READ_MASK)
+               qp->req.psn = (wqe->first_psn + num_pkt) & BTH_PSN_MASK;
+       else
+               qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK;
+
+       qp->req.opcode = pkt->opcode;
+
+
+       if (pkt->mask & RXE_END_MASK)
+               qp->req.wqe_index = next_index(qp->sq.queue, qp->req.wqe_index);
+
+       qp->need_req_skb = 0;
+
+       if (qp->qp_timeout_jiffies && !timer_pending(&qp->retrans_timer))
+               mod_timer(&qp->retrans_timer,
+                         jiffies + qp->qp_timeout_jiffies);
+}
+
+int rxe_requester(void *arg)
+{
+       struct rxe_qp *qp = (struct rxe_qp *)arg;
+       struct rxe_pkt_info pkt;
+       struct sk_buff *skb;
+       struct rxe_send_wqe *wqe;
+       unsigned mask;
+       int payload;
+       int mtu;
+       int opcode;
+       int ret;
+       enum wqe_state prev_state;
+
+next_wqe:
+       if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR))
+               goto exit;
+
+       if (unlikely(qp->req.state == QP_STATE_RESET)) {
+               qp->req.wqe_index = consumer_index(qp->sq.queue);
+               qp->req.opcode = -1;
+               qp->req.need_rd_atomic = 0;
+               qp->req.wait_psn = 0;
+               qp->req.need_retry = 0;
+               goto exit;
+       }
+
+       if (unlikely(qp->req.need_retry)) {
+               req_retry(qp);
+               qp->req.need_retry = 0;
+       }
+
+       wqe = req_next_wqe(qp);
+       if (unlikely(!wqe))
+               goto exit;
+
+       if (wqe->mask & WR_REG_MASK) {
+               if (wqe->wr.opcode == IB_WR_LOCAL_INV) {
+                       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+                       struct rxe_mem *rmr;
+
+                       rmr = rxe_pool_get_index(&rxe->mr_pool,
+                                                wqe->wr.ex.invalidate_rkey >> 8);
+                       if (!rmr) {
+                               pr_err("No mr for key %#x\n", wqe->wr.ex.invalidate_rkey);
+                               wqe->state = wqe_state_error;
+                               wqe->status = IB_WC_MW_BIND_ERR;
+                               goto exit;
+                       }
+                       rmr->state = RXE_MEM_STATE_FREE;
+                       wqe->state = wqe_state_done;
+                       wqe->status = IB_WC_SUCCESS;
+               } else if (wqe->wr.opcode == IB_WR_REG_MR) {
+                       struct rxe_mem *rmr = to_rmr(wqe->wr.wr.reg.mr);
+
+                       rmr->state = RXE_MEM_STATE_VALID;
+                       rmr->access = wqe->wr.wr.reg.access;
+                       rmr->lkey = wqe->wr.wr.reg.key;
+                       rmr->rkey = wqe->wr.wr.reg.key;
+                       wqe->state = wqe_state_done;
+                       wqe->status = IB_WC_SUCCESS;
+               } else {
+                       goto exit;
+               }
+               qp->req.wqe_index = next_index(qp->sq.queue,
+                                               qp->req.wqe_index);
+               goto next_wqe;
+       }
+
+       if (unlikely(qp_type(qp) == IB_QPT_RC &&
+                    qp->req.psn > (qp->comp.psn + RXE_MAX_UNACKED_PSNS))) {
+               qp->req.wait_psn = 1;
+               goto exit;
+       }
+
+       /* Limit the number of inflight SKBs per QP */
+       if (unlikely(atomic_read(&qp->skb_out) >
+                    RXE_INFLIGHT_SKBS_PER_QP_HIGH)) {
+               qp->need_req_skb = 1;
+               goto exit;
+       }
+
+       opcode = next_opcode(qp, wqe, wqe->wr.opcode);
+       if (unlikely(opcode < 0)) {
+               wqe->status = IB_WC_LOC_QP_OP_ERR;
+               goto exit;
+       }
+
+       mask = rxe_opcode[opcode].mask;
+       if (unlikely(mask & RXE_READ_OR_ATOMIC)) {
+               if (check_init_depth(qp, wqe))
+                       goto exit;
+       }
+
+       mtu = get_mtu(qp, wqe);
+       payload = (mask & RXE_WRITE_OR_SEND) ? wqe->dma.resid : 0;
+       if (payload > mtu) {
+               if (qp_type(qp) == IB_QPT_UD) {
+                       /* C10-93.1.1: If the total sum of all the buffer lengths specified for a
+                        * UD message exceeds the MTU of the port as returned by QueryHCA, the CI
+                        * shall not emit any packets for this message. Further, the CI shall not
+                        * generate an error due to this condition.
+                        */
+
+                       /* fake a successful UD send */
+                       wqe->first_psn = qp->req.psn;
+                       wqe->last_psn = qp->req.psn;
+                       qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK;
+                       qp->req.opcode = IB_OPCODE_UD_SEND_ONLY;
+                       qp->req.wqe_index = next_index(qp->sq.queue,
+                                                      qp->req.wqe_index);
+                       wqe->state = wqe_state_done;
+                       wqe->status = IB_WC_SUCCESS;
+                       goto complete;
+               }
+               payload = mtu;
+       }
+
+       skb = init_req_packet(qp, wqe, opcode, payload, &pkt);
+       if (unlikely(!skb)) {
+               pr_err("Failed allocating skb\n");
+               goto err;
+       }
+
+       if (fill_packet(qp, wqe, &pkt, skb, payload)) {
+               pr_debug("Error during fill packet\n");
+               goto err;
+       }
+
+       update_wqe_state(qp, wqe, &pkt, &prev_state);
+       ret = rxe_xmit_packet(to_rdev(qp->ibqp.device), qp, &pkt, skb);
+       if (ret) {
+               qp->need_req_skb = 1;
+               kfree_skb(skb);
+
+               wqe->state = prev_state;
+
+               if (ret == -EAGAIN) {
+                       rxe_run_task(&qp->req.task, 1);
+                       goto exit;
+               }
+
+               goto err;
+       }
+
+       update_state(qp, wqe, &pkt, payload);
+
+       goto next_wqe;
+
+err:
+       kfree_skb(skb);
+       wqe->status = IB_WC_LOC_PROT_ERR;
+       wqe->state = wqe_state_error;
+
+complete:
+       if (qp_type(qp) != IB_QPT_RC) {
+               while (rxe_completer(qp) == 0)
+                       ;
+       }
+
+       return 0;
+
+exit:
+       return -EAGAIN;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
new file mode 100644 (file)
index 0000000..ebb03b4
--- /dev/null
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/skbuff.h>
+
+#include "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+enum resp_states {
+       RESPST_NONE,
+       RESPST_GET_REQ,
+       RESPST_CHK_PSN,
+       RESPST_CHK_OP_SEQ,
+       RESPST_CHK_OP_VALID,
+       RESPST_CHK_RESOURCE,
+       RESPST_CHK_LENGTH,
+       RESPST_CHK_RKEY,
+       RESPST_EXECUTE,
+       RESPST_READ_REPLY,
+       RESPST_COMPLETE,
+       RESPST_ACKNOWLEDGE,
+       RESPST_CLEANUP,
+       RESPST_DUPLICATE_REQUEST,
+       RESPST_ERR_MALFORMED_WQE,
+       RESPST_ERR_UNSUPPORTED_OPCODE,
+       RESPST_ERR_MISALIGNED_ATOMIC,
+       RESPST_ERR_PSN_OUT_OF_SEQ,
+       RESPST_ERR_MISSING_OPCODE_FIRST,
+       RESPST_ERR_MISSING_OPCODE_LAST_C,
+       RESPST_ERR_MISSING_OPCODE_LAST_D1E,
+       RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
+       RESPST_ERR_RNR,
+       RESPST_ERR_RKEY_VIOLATION,
+       RESPST_ERR_LENGTH,
+       RESPST_ERR_CQ_OVERFLOW,
+       RESPST_ERROR,
+       RESPST_RESET,
+       RESPST_DONE,
+       RESPST_EXIT,
+};
+
+static char *resp_state_name[] = {
+       [RESPST_NONE]                           = "NONE",
+       [RESPST_GET_REQ]                        = "GET_REQ",
+       [RESPST_CHK_PSN]                        = "CHK_PSN",
+       [RESPST_CHK_OP_SEQ]                     = "CHK_OP_SEQ",
+       [RESPST_CHK_OP_VALID]                   = "CHK_OP_VALID",
+       [RESPST_CHK_RESOURCE]                   = "CHK_RESOURCE",
+       [RESPST_CHK_LENGTH]                     = "CHK_LENGTH",
+       [RESPST_CHK_RKEY]                       = "CHK_RKEY",
+       [RESPST_EXECUTE]                        = "EXECUTE",
+       [RESPST_READ_REPLY]                     = "READ_REPLY",
+       [RESPST_COMPLETE]                       = "COMPLETE",
+       [RESPST_ACKNOWLEDGE]                    = "ACKNOWLEDGE",
+       [RESPST_CLEANUP]                        = "CLEANUP",
+       [RESPST_DUPLICATE_REQUEST]              = "DUPLICATE_REQUEST",
+       [RESPST_ERR_MALFORMED_WQE]              = "ERR_MALFORMED_WQE",
+       [RESPST_ERR_UNSUPPORTED_OPCODE]         = "ERR_UNSUPPORTED_OPCODE",
+       [RESPST_ERR_MISALIGNED_ATOMIC]          = "ERR_MISALIGNED_ATOMIC",
+       [RESPST_ERR_PSN_OUT_OF_SEQ]             = "ERR_PSN_OUT_OF_SEQ",
+       [RESPST_ERR_MISSING_OPCODE_FIRST]       = "ERR_MISSING_OPCODE_FIRST",
+       [RESPST_ERR_MISSING_OPCODE_LAST_C]      = "ERR_MISSING_OPCODE_LAST_C",
+       [RESPST_ERR_MISSING_OPCODE_LAST_D1E]    = "ERR_MISSING_OPCODE_LAST_D1E",
+       [RESPST_ERR_TOO_MANY_RDMA_ATM_REQ]      = "ERR_TOO_MANY_RDMA_ATM_REQ",
+       [RESPST_ERR_RNR]                        = "ERR_RNR",
+       [RESPST_ERR_RKEY_VIOLATION]             = "ERR_RKEY_VIOLATION",
+       [RESPST_ERR_LENGTH]                     = "ERR_LENGTH",
+       [RESPST_ERR_CQ_OVERFLOW]                = "ERR_CQ_OVERFLOW",
+       [RESPST_ERROR]                          = "ERROR",
+       [RESPST_RESET]                          = "RESET",
+       [RESPST_DONE]                           = "DONE",
+       [RESPST_EXIT]                           = "EXIT",
+};
+
+/* rxe_recv calls here to add a request packet to the input queue */
+void rxe_resp_queue_pkt(struct rxe_dev *rxe, struct rxe_qp *qp,
+                       struct sk_buff *skb)
+{
+       int must_sched;
+       struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
+
+       skb_queue_tail(&qp->req_pkts, skb);
+
+       must_sched = (pkt->opcode == IB_OPCODE_RC_RDMA_READ_REQUEST) ||
+                       (skb_queue_len(&qp->req_pkts) > 1);
+
+       rxe_run_task(&qp->resp.task, must_sched);
+}
+
+static inline enum resp_states get_req(struct rxe_qp *qp,
+                                      struct rxe_pkt_info **pkt_p)
+{
+       struct sk_buff *skb;
+
+       if (qp->resp.state == QP_STATE_ERROR) {
+               skb = skb_dequeue(&qp->req_pkts);
+               if (skb) {
+                       /* drain request packet queue */
+                       rxe_drop_ref(qp);
+                       kfree_skb(skb);
+                       return RESPST_GET_REQ;
+               }
+
+               /* go drain recv wr queue */
+               return RESPST_CHK_RESOURCE;
+       }
+
+       skb = skb_peek(&qp->req_pkts);
+       if (!skb)
+               return RESPST_EXIT;
+
+       *pkt_p = SKB_TO_PKT(skb);
+
+       return (qp->resp.res) ? RESPST_READ_REPLY : RESPST_CHK_PSN;
+}
+
+static enum resp_states check_psn(struct rxe_qp *qp,
+                                 struct rxe_pkt_info *pkt)
+{
+       int diff = psn_compare(pkt->psn, qp->resp.psn);
+
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               if (diff > 0) {
+                       if (qp->resp.sent_psn_nak)
+                               return RESPST_CLEANUP;
+
+                       qp->resp.sent_psn_nak = 1;
+                       return RESPST_ERR_PSN_OUT_OF_SEQ;
+
+               } else if (diff < 0) {
+                       return RESPST_DUPLICATE_REQUEST;
+               }
+
+               if (qp->resp.sent_psn_nak)
+                       qp->resp.sent_psn_nak = 0;
+
+               break;
+
+       case IB_QPT_UC:
+               if (qp->resp.drop_msg || diff != 0) {
+                       if (pkt->mask & RXE_START_MASK) {
+                               qp->resp.drop_msg = 0;
+                               return RESPST_CHK_OP_SEQ;
+                       }
+
+                       qp->resp.drop_msg = 1;
+                       return RESPST_CLEANUP;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return RESPST_CHK_OP_SEQ;
+}
+
+static enum resp_states check_op_seq(struct rxe_qp *qp,
+                                    struct rxe_pkt_info *pkt)
+{
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               switch (qp->resp.opcode) {
+               case IB_OPCODE_RC_SEND_FIRST:
+               case IB_OPCODE_RC_SEND_MIDDLE:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_RC_SEND_MIDDLE:
+                       case IB_OPCODE_RC_SEND_LAST:
+                       case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE:
+                       case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE:
+                               return RESPST_CHK_OP_VALID;
+                       default:
+                               return RESPST_ERR_MISSING_OPCODE_LAST_C;
+                       }
+
+               case IB_OPCODE_RC_RDMA_WRITE_FIRST:
+               case IB_OPCODE_RC_RDMA_WRITE_MIDDLE:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_RC_RDMA_WRITE_MIDDLE:
+                       case IB_OPCODE_RC_RDMA_WRITE_LAST:
+                       case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE:
+                               return RESPST_CHK_OP_VALID;
+                       default:
+                               return RESPST_ERR_MISSING_OPCODE_LAST_C;
+                       }
+
+               default:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_RC_SEND_MIDDLE:
+                       case IB_OPCODE_RC_SEND_LAST:
+                       case IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE:
+                       case IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE:
+                       case IB_OPCODE_RC_RDMA_WRITE_MIDDLE:
+                       case IB_OPCODE_RC_RDMA_WRITE_LAST:
+                       case IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE:
+                               return RESPST_ERR_MISSING_OPCODE_FIRST;
+                       default:
+                               return RESPST_CHK_OP_VALID;
+                       }
+               }
+               break;
+
+       case IB_QPT_UC:
+               switch (qp->resp.opcode) {
+               case IB_OPCODE_UC_SEND_FIRST:
+               case IB_OPCODE_UC_SEND_MIDDLE:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_UC_SEND_MIDDLE:
+                       case IB_OPCODE_UC_SEND_LAST:
+                       case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE:
+                               return RESPST_CHK_OP_VALID;
+                       default:
+                               return RESPST_ERR_MISSING_OPCODE_LAST_D1E;
+                       }
+
+               case IB_OPCODE_UC_RDMA_WRITE_FIRST:
+               case IB_OPCODE_UC_RDMA_WRITE_MIDDLE:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_UC_RDMA_WRITE_MIDDLE:
+                       case IB_OPCODE_UC_RDMA_WRITE_LAST:
+                       case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE:
+                               return RESPST_CHK_OP_VALID;
+                       default:
+                               return RESPST_ERR_MISSING_OPCODE_LAST_D1E;
+                       }
+
+               default:
+                       switch (pkt->opcode) {
+                       case IB_OPCODE_UC_SEND_MIDDLE:
+                       case IB_OPCODE_UC_SEND_LAST:
+                       case IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE:
+                       case IB_OPCODE_UC_RDMA_WRITE_MIDDLE:
+                       case IB_OPCODE_UC_RDMA_WRITE_LAST:
+                       case IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE:
+                               qp->resp.drop_msg = 1;
+                               return RESPST_CLEANUP;
+                       default:
+                               return RESPST_CHK_OP_VALID;
+                       }
+               }
+               break;
+
+       default:
+               return RESPST_CHK_OP_VALID;
+       }
+}
+
+static enum resp_states check_op_valid(struct rxe_qp *qp,
+                                      struct rxe_pkt_info *pkt)
+{
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               if (((pkt->mask & RXE_READ_MASK) &&
+                    !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_READ)) ||
+                   ((pkt->mask & RXE_WRITE_MASK) &&
+                    !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) ||
+                   ((pkt->mask & RXE_ATOMIC_MASK) &&
+                    !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) {
+                       return RESPST_ERR_UNSUPPORTED_OPCODE;
+               }
+
+               break;
+
+       case IB_QPT_UC:
+               if ((pkt->mask & RXE_WRITE_MASK) &&
+                   !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) {
+                       qp->resp.drop_msg = 1;
+                       return RESPST_CLEANUP;
+               }
+
+               break;
+
+       case IB_QPT_UD:
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               break;
+
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return RESPST_CHK_RESOURCE;
+}
+
+static enum resp_states get_srq_wqe(struct rxe_qp *qp)
+{
+       struct rxe_srq *srq = qp->srq;
+       struct rxe_queue *q = srq->rq.queue;
+       struct rxe_recv_wqe *wqe;
+       struct ib_event ev;
+
+       if (srq->error)
+               return RESPST_ERR_RNR;
+
+       spin_lock_bh(&srq->rq.consumer_lock);
+
+       wqe = queue_head(q);
+       if (!wqe) {
+               spin_unlock_bh(&srq->rq.consumer_lock);
+               return RESPST_ERR_RNR;
+       }
+
+       /* note kernel and user space recv wqes have same size */
+       memcpy(&qp->resp.srq_wqe, wqe, sizeof(qp->resp.srq_wqe));
+
+       qp->resp.wqe = &qp->resp.srq_wqe.wqe;
+       advance_consumer(q);
+
+       if (srq->limit && srq->ibsrq.event_handler &&
+           (queue_count(q) < srq->limit)) {
+               srq->limit = 0;
+               goto event;
+       }
+
+       spin_unlock_bh(&srq->rq.consumer_lock);
+       return RESPST_CHK_LENGTH;
+
+event:
+       spin_unlock_bh(&srq->rq.consumer_lock);
+       ev.device = qp->ibqp.device;
+       ev.element.srq = qp->ibqp.srq;
+       ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
+       srq->ibsrq.event_handler(&ev, srq->ibsrq.srq_context);
+       return RESPST_CHK_LENGTH;
+}
+
+static enum resp_states check_resource(struct rxe_qp *qp,
+                                      struct rxe_pkt_info *pkt)
+{
+       struct rxe_srq *srq = qp->srq;
+
+       if (qp->resp.state == QP_STATE_ERROR) {
+               if (qp->resp.wqe) {
+                       qp->resp.status = IB_WC_WR_FLUSH_ERR;
+                       return RESPST_COMPLETE;
+               } else if (!srq) {
+                       qp->resp.wqe = queue_head(qp->rq.queue);
+                       if (qp->resp.wqe) {
+                               qp->resp.status = IB_WC_WR_FLUSH_ERR;
+                               return RESPST_COMPLETE;
+                       } else {
+                               return RESPST_EXIT;
+                       }
+               } else {
+                       return RESPST_EXIT;
+               }
+       }
+
+       if (pkt->mask & RXE_READ_OR_ATOMIC) {
+               /* it is the requesters job to not send
+                * too many read/atomic ops, we just
+                * recycle the responder resource queue
+                */
+               if (likely(qp->attr.max_rd_atomic > 0))
+                       return RESPST_CHK_LENGTH;
+               else
+                       return RESPST_ERR_TOO_MANY_RDMA_ATM_REQ;
+       }
+
+       if (pkt->mask & RXE_RWR_MASK) {
+               if (srq)
+                       return get_srq_wqe(qp);
+
+               qp->resp.wqe = queue_head(qp->rq.queue);
+               return (qp->resp.wqe) ? RESPST_CHK_LENGTH : RESPST_ERR_RNR;
+       }
+
+       return RESPST_CHK_LENGTH;
+}
+
+static enum resp_states check_length(struct rxe_qp *qp,
+                                    struct rxe_pkt_info *pkt)
+{
+       switch (qp_type(qp)) {
+       case IB_QPT_RC:
+               return RESPST_CHK_RKEY;
+
+       case IB_QPT_UC:
+               return RESPST_CHK_RKEY;
+
+       default:
+               return RESPST_CHK_RKEY;
+       }
+}
+
+static enum resp_states check_rkey(struct rxe_qp *qp,
+                                  struct rxe_pkt_info *pkt)
+{
+       struct rxe_mem *mem;
+       u64 va;
+       u32 rkey;
+       u32 resid;
+       u32 pktlen;
+       int mtu = qp->mtu;
+       enum resp_states state;
+       int access;
+
+       if (pkt->mask & (RXE_READ_MASK | RXE_WRITE_MASK)) {
+               if (pkt->mask & RXE_RETH_MASK) {
+                       qp->resp.va = reth_va(pkt);
+                       qp->resp.rkey = reth_rkey(pkt);
+                       qp->resp.resid = reth_len(pkt);
+               }
+               access = (pkt->mask & RXE_READ_MASK) ? IB_ACCESS_REMOTE_READ
+                                                    : IB_ACCESS_REMOTE_WRITE;
+       } else if (pkt->mask & RXE_ATOMIC_MASK) {
+               qp->resp.va = atmeth_va(pkt);
+               qp->resp.rkey = atmeth_rkey(pkt);
+               qp->resp.resid = sizeof(u64);
+               access = IB_ACCESS_REMOTE_ATOMIC;
+       } else {
+               return RESPST_EXECUTE;
+       }
+
+       va      = qp->resp.va;
+       rkey    = qp->resp.rkey;
+       resid   = qp->resp.resid;
+       pktlen  = payload_size(pkt);
+
+       mem = lookup_mem(qp->pd, access, rkey, lookup_remote);
+       if (!mem) {
+               state = RESPST_ERR_RKEY_VIOLATION;
+               goto err1;
+       }
+
+       if (unlikely(mem->state == RXE_MEM_STATE_FREE)) {
+               state = RESPST_ERR_RKEY_VIOLATION;
+               goto err1;
+       }
+
+       if (mem_check_range(mem, va, resid)) {
+               state = RESPST_ERR_RKEY_VIOLATION;
+               goto err2;
+       }
+
+       if (pkt->mask & RXE_WRITE_MASK)  {
+               if (resid > mtu) {
+                       if (pktlen != mtu || bth_pad(pkt)) {
+                               state = RESPST_ERR_LENGTH;
+                               goto err2;
+                       }
+
+                       resid = mtu;
+               } else {
+                       if (pktlen != resid) {
+                               state = RESPST_ERR_LENGTH;
+                               goto err2;
+                       }
+                       if ((bth_pad(pkt) != (0x3 & (-resid)))) {
+                               /* This case may not be exactly that
+                                * but nothing else fits.
+                                */
+                               state = RESPST_ERR_LENGTH;
+                               goto err2;
+                       }
+               }
+       }
+
+       WARN_ON(qp->resp.mr);
+
+       qp->resp.mr = mem;
+       return RESPST_EXECUTE;
+
+err2:
+       rxe_drop_ref(mem);
+err1:
+       return state;
+}
+
+static enum resp_states send_data_in(struct rxe_qp *qp, void *data_addr,
+                                    int data_len)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+
+       err = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE, &qp->resp.wqe->dma,
+                       data_addr, data_len, to_mem_obj, NULL);
+       if (unlikely(err))
+               return (err == -ENOSPC) ? RESPST_ERR_LENGTH
+                                       : RESPST_ERR_MALFORMED_WQE;
+
+       return RESPST_NONE;
+}
+
+static enum resp_states write_data_in(struct rxe_qp *qp,
+                                     struct rxe_pkt_info *pkt)
+{
+       enum resp_states rc = RESPST_NONE;
+       int     err;
+       int data_len = payload_size(pkt);
+
+       err = rxe_mem_copy(qp->resp.mr, qp->resp.va, payload_addr(pkt),
+                          data_len, to_mem_obj, NULL);
+       if (err) {
+               rc = RESPST_ERR_RKEY_VIOLATION;
+               goto out;
+       }
+
+       qp->resp.va += data_len;
+       qp->resp.resid -= data_len;
+
+out:
+       return rc;
+}
+
+/* Guarantee atomicity of atomic operations at the machine level. */
+static DEFINE_SPINLOCK(atomic_ops_lock);
+
+static enum resp_states process_atomic(struct rxe_qp *qp,
+                                      struct rxe_pkt_info *pkt)
+{
+       u64 iova = atmeth_va(pkt);
+       u64 *vaddr;
+       enum resp_states ret;
+       struct rxe_mem *mr = qp->resp.mr;
+
+       if (mr->state != RXE_MEM_STATE_VALID) {
+               ret = RESPST_ERR_RKEY_VIOLATION;
+               goto out;
+       }
+
+       vaddr = iova_to_vaddr(mr, iova, sizeof(u64));
+
+       /* check vaddr is 8 bytes aligned. */
+       if (!vaddr || (uintptr_t)vaddr & 7) {
+               ret = RESPST_ERR_MISALIGNED_ATOMIC;
+               goto out;
+       }
+
+       spin_lock_bh(&atomic_ops_lock);
+
+       qp->resp.atomic_orig = *vaddr;
+
+       if (pkt->opcode == IB_OPCODE_RC_COMPARE_SWAP ||
+           pkt->opcode == IB_OPCODE_RD_COMPARE_SWAP) {
+               if (*vaddr == atmeth_comp(pkt))
+                       *vaddr = atmeth_swap_add(pkt);
+       } else {
+               *vaddr += atmeth_swap_add(pkt);
+       }
+
+       spin_unlock_bh(&atomic_ops_lock);
+
+       ret = RESPST_NONE;
+out:
+       return ret;
+}
+
+static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
+                                         struct rxe_pkt_info *pkt,
+                                         struct rxe_pkt_info *ack,
+                                         int opcode,
+                                         int payload,
+                                         u32 psn,
+                                         u8 syndrome,
+                                         u32 *crcp)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       struct sk_buff *skb;
+       u32 crc = 0;
+       u32 *p;
+       int paylen;
+       int pad;
+       int err;
+
+       /*
+        * allocate packet
+        */
+       pad = (-payload) & 0x3;
+       paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE;
+
+       skb = rxe->ifc_ops->init_packet(rxe, &qp->pri_av, paylen, ack);
+       if (!skb)
+               return NULL;
+
+       ack->qp = qp;
+       ack->opcode = opcode;
+       ack->mask = rxe_opcode[opcode].mask;
+       ack->offset = pkt->offset;
+       ack->paylen = paylen;
+
+       /* fill in bth using the request packet headers */
+       memcpy(ack->hdr, pkt->hdr, pkt->offset + RXE_BTH_BYTES);
+
+       bth_set_opcode(ack, opcode);
+       bth_set_qpn(ack, qp->attr.dest_qp_num);
+       bth_set_pad(ack, pad);
+       bth_set_se(ack, 0);
+       bth_set_psn(ack, psn);
+       bth_set_ack(ack, 0);
+       ack->psn = psn;
+
+       if (ack->mask & RXE_AETH_MASK) {
+               aeth_set_syn(ack, syndrome);
+               aeth_set_msn(ack, qp->resp.msn);
+       }
+
+       if (ack->mask & RXE_ATMACK_MASK)
+               atmack_set_orig(ack, qp->resp.atomic_orig);
+
+       err = rxe->ifc_ops->prepare(rxe, ack, skb, &crc);
+       if (err) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       if (crcp) {
+               /* CRC computation will be continued by the caller */
+               *crcp = crc;
+       } else {
+               p = payload_addr(ack) + payload + bth_pad(ack);
+               *p = ~crc;
+       }
+
+       return skb;
+}
+
+/* RDMA read response. If res is not NULL, then we have a current RDMA request
+ * being processed or replayed.
+ */
+static enum resp_states read_reply(struct rxe_qp *qp,
+                                  struct rxe_pkt_info *req_pkt)
+{
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       struct rxe_pkt_info ack_pkt;
+       struct sk_buff *skb;
+       int mtu = qp->mtu;
+       enum resp_states state;
+       int payload;
+       int opcode;
+       int err;
+       struct resp_res *res = qp->resp.res;
+       u32 icrc;
+       u32 *p;
+
+       if (!res) {
+               /* This is the first time we process that request. Get a
+                * resource
+                */
+               res = &qp->resp.resources[qp->resp.res_head];
+
+               free_rd_atomic_resource(qp, res);
+               rxe_advance_resp_resource(qp);
+
+               res->type               = RXE_READ_MASK;
+
+               res->read.va            = qp->resp.va;
+               res->read.va_org        = qp->resp.va;
+
+               res->first_psn          = req_pkt->psn;
+               res->last_psn           = req_pkt->psn +
+                                         (reth_len(req_pkt) + mtu - 1) /
+                                         mtu - 1;
+               res->cur_psn            = req_pkt->psn;
+
+               res->read.resid         = qp->resp.resid;
+               res->read.length        = qp->resp.resid;
+               res->read.rkey          = qp->resp.rkey;
+
+               /* note res inherits the reference to mr from qp */
+               res->read.mr            = qp->resp.mr;
+               qp->resp.mr             = NULL;
+
+               qp->resp.res            = res;
+               res->state              = rdatm_res_state_new;
+       }
+
+       if (res->state == rdatm_res_state_new) {
+               if (res->read.resid <= mtu)
+                       opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY;
+               else
+                       opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST;
+       } else {
+               if (res->read.resid > mtu)
+                       opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE;
+               else
+                       opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST;
+       }
+
+       res->state = rdatm_res_state_next;
+
+       payload = min_t(int, res->read.resid, mtu);
+
+       skb = prepare_ack_packet(qp, req_pkt, &ack_pkt, opcode, payload,
+                                res->cur_psn, AETH_ACK_UNLIMITED, &icrc);
+       if (!skb)
+               return RESPST_ERR_RNR;
+
+       err = rxe_mem_copy(res->read.mr, res->read.va, payload_addr(&ack_pkt),
+                          payload, from_mem_obj, &icrc);
+       if (err)
+               pr_err("Failed copying memory\n");
+
+       p = payload_addr(&ack_pkt) + payload + bth_pad(&ack_pkt);
+       *p = ~icrc;
+
+       err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb);
+       if (err) {
+               pr_err("Failed sending RDMA reply.\n");
+               kfree_skb(skb);
+               return RESPST_ERR_RNR;
+       }
+
+       res->read.va += payload;
+       res->read.resid -= payload;
+       res->cur_psn = (res->cur_psn + 1) & BTH_PSN_MASK;
+
+       if (res->read.resid > 0) {
+               state = RESPST_DONE;
+       } else {
+               qp->resp.res = NULL;
+               qp->resp.opcode = -1;
+               qp->resp.psn = res->cur_psn;
+               state = RESPST_CLEANUP;
+       }
+
+       return state;
+}
+
+/* Executes a new request. A retried request never reach that function (send
+ * and writes are discarded, and reads and atomics are retried elsewhere.
+ */
+static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
+{
+       enum resp_states err;
+
+       if (pkt->mask & RXE_SEND_MASK) {
+               if (qp_type(qp) == IB_QPT_UD ||
+                   qp_type(qp) == IB_QPT_SMI ||
+                   qp_type(qp) == IB_QPT_GSI) {
+                       union rdma_network_hdr hdr;
+                       struct sk_buff *skb = PKT_TO_SKB(pkt);
+
+                       memset(&hdr, 0, sizeof(hdr));
+                       if (skb->protocol == htons(ETH_P_IP))
+                               memcpy(&hdr.roce4grh, ip_hdr(skb), sizeof(hdr.roce4grh));
+                       else if (skb->protocol == htons(ETH_P_IPV6))
+                               memcpy(&hdr.ibgrh, ipv6_hdr(skb), sizeof(hdr.ibgrh));
+
+                       err = send_data_in(qp, &hdr, sizeof(hdr));
+                       if (err)
+                               return err;
+               }
+               err = send_data_in(qp, payload_addr(pkt), payload_size(pkt));
+               if (err)
+                       return err;
+       } else if (pkt->mask & RXE_WRITE_MASK) {
+               err = write_data_in(qp, pkt);
+               if (err)
+                       return err;
+       } else if (pkt->mask & RXE_READ_MASK) {
+               /* For RDMA Read we can increment the msn now. See C9-148. */
+               qp->resp.msn++;
+               return RESPST_READ_REPLY;
+       } else if (pkt->mask & RXE_ATOMIC_MASK) {
+               err = process_atomic(qp, pkt);
+               if (err)
+                       return err;
+       } else
+               /* Unreachable */
+               WARN_ON(1);
+
+       /* We successfully processed this new request. */
+       qp->resp.msn++;
+
+       /* next expected psn, read handles this separately */
+       qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
+
+       qp->resp.opcode = pkt->opcode;
+       qp->resp.status = IB_WC_SUCCESS;
+
+       if (pkt->mask & RXE_COMP_MASK)
+               return RESPST_COMPLETE;
+       else if (qp_type(qp) == IB_QPT_RC)
+               return RESPST_ACKNOWLEDGE;
+       else
+               return RESPST_CLEANUP;
+}
+
+static enum resp_states do_complete(struct rxe_qp *qp,
+                                   struct rxe_pkt_info *pkt)
+{
+       struct rxe_cqe cqe;
+       struct ib_wc *wc = &cqe.ibwc;
+       struct ib_uverbs_wc *uwc = &cqe.uibwc;
+       struct rxe_recv_wqe *wqe = qp->resp.wqe;
+
+       if (unlikely(!wqe))
+               return RESPST_CLEANUP;
+
+       memset(&cqe, 0, sizeof(cqe));
+
+       wc->wr_id               = wqe->wr_id;
+       wc->status              = qp->resp.status;
+       wc->qp                  = &qp->ibqp;
+
+       /* fields after status are not required for errors */
+       if (wc->status == IB_WC_SUCCESS) {
+               wc->opcode = (pkt->mask & RXE_IMMDT_MASK &&
+                               pkt->mask & RXE_WRITE_MASK) ?
+                                       IB_WC_RECV_RDMA_WITH_IMM : IB_WC_RECV;
+               wc->vendor_err = 0;
+               wc->byte_len = wqe->dma.length - wqe->dma.resid;
+
+               /* fields after byte_len are different between kernel and user
+                * space
+                */
+               if (qp->rcq->is_user) {
+                       uwc->wc_flags = IB_WC_GRH;
+
+                       if (pkt->mask & RXE_IMMDT_MASK) {
+                               uwc->wc_flags |= IB_WC_WITH_IMM;
+                               uwc->ex.imm_data =
+                                       (__u32 __force)immdt_imm(pkt);
+                       }
+
+                       if (pkt->mask & RXE_IETH_MASK) {
+                               uwc->wc_flags |= IB_WC_WITH_INVALIDATE;
+                               uwc->ex.invalidate_rkey = ieth_rkey(pkt);
+                       }
+
+                       uwc->qp_num             = qp->ibqp.qp_num;
+
+                       if (pkt->mask & RXE_DETH_MASK)
+                               uwc->src_qp = deth_sqp(pkt);
+
+                       uwc->port_num           = qp->attr.port_num;
+               } else {
+                       struct sk_buff *skb = PKT_TO_SKB(pkt);
+
+                       wc->wc_flags = IB_WC_GRH | IB_WC_WITH_NETWORK_HDR_TYPE;
+                       if (skb->protocol == htons(ETH_P_IP))
+                               wc->network_hdr_type = RDMA_NETWORK_IPV4;
+                       else
+                               wc->network_hdr_type = RDMA_NETWORK_IPV6;
+
+                       if (pkt->mask & RXE_IMMDT_MASK) {
+                               wc->wc_flags |= IB_WC_WITH_IMM;
+                               wc->ex.imm_data = immdt_imm(pkt);
+                       }
+
+                       if (pkt->mask & RXE_IETH_MASK) {
+                               struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+                               struct rxe_mem *rmr;
+
+                               wc->wc_flags |= IB_WC_WITH_INVALIDATE;
+                               wc->ex.invalidate_rkey = ieth_rkey(pkt);
+
+                               rmr = rxe_pool_get_index(&rxe->mr_pool,
+                                                        wc->ex.invalidate_rkey >> 8);
+                               if (unlikely(!rmr)) {
+                                       pr_err("Bad rkey %#x invalidation\n", wc->ex.invalidate_rkey);
+                                       return RESPST_ERROR;
+                               }
+                               rmr->state = RXE_MEM_STATE_FREE;
+                       }
+
+                       wc->qp                  = &qp->ibqp;
+
+                       if (pkt->mask & RXE_DETH_MASK)
+                               wc->src_qp = deth_sqp(pkt);
+
+                       wc->port_num            = qp->attr.port_num;
+               }
+       }
+
+       /* have copy for srq and reference for !srq */
+       if (!qp->srq)
+               advance_consumer(qp->rq.queue);
+
+       qp->resp.wqe = NULL;
+
+       if (rxe_cq_post(qp->rcq, &cqe, pkt ? bth_se(pkt) : 1))
+               return RESPST_ERR_CQ_OVERFLOW;
+
+       if (qp->resp.state == QP_STATE_ERROR)
+               return RESPST_CHK_RESOURCE;
+
+       if (!pkt)
+               return RESPST_DONE;
+       else if (qp_type(qp) == IB_QPT_RC)
+               return RESPST_ACKNOWLEDGE;
+       else
+               return RESPST_CLEANUP;
+}
+
+static int send_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
+                   u8 syndrome, u32 psn)
+{
+       int err = 0;
+       struct rxe_pkt_info ack_pkt;
+       struct sk_buff *skb;
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+
+       skb = prepare_ack_packet(qp, pkt, &ack_pkt, IB_OPCODE_RC_ACKNOWLEDGE,
+                                0, psn, syndrome, NULL);
+       if (!skb) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       err = rxe_xmit_packet(rxe, qp, &ack_pkt, skb);
+       if (err) {
+               pr_err_ratelimited("Failed sending ack\n");
+               kfree_skb(skb);
+       }
+
+err1:
+       return err;
+}
+
+static int send_atomic_ack(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
+                          u8 syndrome)
+{
+       int rc = 0;
+       struct rxe_pkt_info ack_pkt;
+       struct sk_buff *skb;
+       struct sk_buff *skb_copy;
+       struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       struct resp_res *res;
+
+       skb = prepare_ack_packet(qp, pkt, &ack_pkt,
+                                IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE, 0, pkt->psn,
+                                syndrome, NULL);
+       if (!skb) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       skb_copy = skb_clone(skb, GFP_ATOMIC);
+       if (skb_copy)
+               rxe_add_ref(qp); /* for the new SKB */
+       else {
+               pr_warn("Could not clone atomic response\n");
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       res = &qp->resp.resources[qp->resp.res_head];
+       free_rd_atomic_resource(qp, res);
+       rxe_advance_resp_resource(qp);
+
+       res->type = RXE_ATOMIC_MASK;
+       res->atomic.skb = skb;
+       res->first_psn = qp->resp.psn;
+       res->last_psn = qp->resp.psn;
+       res->cur_psn = qp->resp.psn;
+
+       rc = rxe_xmit_packet(rxe, qp, &ack_pkt, skb_copy);
+       if (rc) {
+               pr_err_ratelimited("Failed sending ack\n");
+               rxe_drop_ref(qp);
+               kfree_skb(skb_copy);
+       }
+
+out:
+       return rc;
+}
+
+static enum resp_states acknowledge(struct rxe_qp *qp,
+                                   struct rxe_pkt_info *pkt)
+{
+       if (qp_type(qp) != IB_QPT_RC)
+               return RESPST_CLEANUP;
+
+       if (qp->resp.aeth_syndrome != AETH_ACK_UNLIMITED)
+               send_ack(qp, pkt, qp->resp.aeth_syndrome, pkt->psn);
+       else if (pkt->mask & RXE_ATOMIC_MASK)
+               send_atomic_ack(qp, pkt, AETH_ACK_UNLIMITED);
+       else if (bth_ack(pkt))
+               send_ack(qp, pkt, AETH_ACK_UNLIMITED, pkt->psn);
+
+       return RESPST_CLEANUP;
+}
+
+static enum resp_states cleanup(struct rxe_qp *qp,
+                               struct rxe_pkt_info *pkt)
+{
+       struct sk_buff *skb;
+
+       if (pkt) {
+               skb = skb_dequeue(&qp->req_pkts);
+               rxe_drop_ref(qp);
+               kfree_skb(skb);
+       }
+
+       if (qp->resp.mr) {
+               rxe_drop_ref(qp->resp.mr);
+               qp->resp.mr = NULL;
+       }
+
+       return RESPST_DONE;
+}
+
+static struct resp_res *find_resource(struct rxe_qp *qp, u32 psn)
+{
+       int i;
+
+       for (i = 0; i < qp->attr.max_rd_atomic; i++) {
+               struct resp_res *res = &qp->resp.resources[i];
+
+               if (res->type == 0)
+                       continue;
+
+               if (psn_compare(psn, res->first_psn) >= 0 &&
+                   psn_compare(psn, res->last_psn) <= 0) {
+                       return res;
+               }
+       }
+
+       return NULL;
+}
+
+static enum resp_states duplicate_request(struct rxe_qp *qp,
+                                         struct rxe_pkt_info *pkt)
+{
+       enum resp_states rc;
+
+       if (pkt->mask & RXE_SEND_MASK ||
+           pkt->mask & RXE_WRITE_MASK) {
+               /* SEND. Ack again and cleanup. C9-105. */
+               if (bth_ack(pkt))
+                       send_ack(qp, pkt, AETH_ACK_UNLIMITED, qp->resp.psn - 1);
+               rc = RESPST_CLEANUP;
+               goto out;
+       } else if (pkt->mask & RXE_READ_MASK) {
+               struct resp_res *res;
+
+               res = find_resource(qp, pkt->psn);
+               if (!res) {
+                       /* Resource not found. Class D error.  Drop the
+                        * request.
+                        */
+                       rc = RESPST_CLEANUP;
+                       goto out;
+               } else {
+                       /* Ensure this new request is the same as the previous
+                        * one or a subset of it.
+                        */
+                       u64 iova = reth_va(pkt);
+                       u32 resid = reth_len(pkt);
+
+                       if (iova < res->read.va_org ||
+                           resid > res->read.length ||
+                           (iova + resid) > (res->read.va_org +
+                                             res->read.length)) {
+                               rc = RESPST_CLEANUP;
+                               goto out;
+                       }
+
+                       if (reth_rkey(pkt) != res->read.rkey) {
+                               rc = RESPST_CLEANUP;
+                               goto out;
+                       }
+
+                       res->cur_psn = pkt->psn;
+                       res->state = (pkt->psn == res->first_psn) ?
+                                       rdatm_res_state_new :
+                                       rdatm_res_state_replay;
+
+                       /* Reset the resource, except length. */
+                       res->read.va_org = iova;
+                       res->read.va = iova;
+                       res->read.resid = resid;
+
+                       /* Replay the RDMA read reply. */
+                       qp->resp.res = res;
+                       rc = RESPST_READ_REPLY;
+                       goto out;
+               }
+       } else {
+               struct resp_res *res;
+
+               /* Find the operation in our list of responder resources. */
+               res = find_resource(qp, pkt->psn);
+               if (res) {
+                       struct sk_buff *skb_copy;
+
+                       skb_copy = skb_clone(res->atomic.skb, GFP_ATOMIC);
+                       if (skb_copy) {
+                               rxe_add_ref(qp); /* for the new SKB */
+                       } else {
+                               pr_warn("Couldn't clone atomic resp\n");
+                               rc = RESPST_CLEANUP;
+                               goto out;
+                       }
+                       bth_set_psn(SKB_TO_PKT(skb_copy),
+                                   qp->resp.psn - 1);
+                       /* Resend the result. */
+                       rc = rxe_xmit_packet(to_rdev(qp->ibqp.device), qp,
+                                            pkt, skb_copy);
+                       if (rc) {
+                               pr_err("Failed resending result. This flow is not handled - skb ignored\n");
+                               kfree_skb(skb_copy);
+                               rc = RESPST_CLEANUP;
+                               goto out;
+                       }
+               }
+
+               /* Resource not found. Class D error. Drop the request. */
+               rc = RESPST_CLEANUP;
+               goto out;
+       }
+out:
+       return rc;
+}
+
+/* Process a class A or C. Both are treated the same in this implementation. */
+static void do_class_ac_error(struct rxe_qp *qp, u8 syndrome,
+                             enum ib_wc_status status)
+{
+       qp->resp.aeth_syndrome  = syndrome;
+       qp->resp.status         = status;
+
+       /* indicate that we should go through the ERROR state */
+       qp->resp.goto_error     = 1;
+}
+
+static enum resp_states do_class_d1e_error(struct rxe_qp *qp)
+{
+       /* UC */
+       if (qp->srq) {
+               /* Class E */
+               qp->resp.drop_msg = 1;
+               if (qp->resp.wqe) {
+                       qp->resp.status = IB_WC_REM_INV_REQ_ERR;
+                       return RESPST_COMPLETE;
+               } else {
+                       return RESPST_CLEANUP;
+               }
+       } else {
+               /* Class D1. This packet may be the start of a
+                * new message and could be valid. The previous
+                * message is invalid and ignored. reset the
+                * recv wr to its original state
+                */
+               if (qp->resp.wqe) {
+                       qp->resp.wqe->dma.resid = qp->resp.wqe->dma.length;
+                       qp->resp.wqe->dma.cur_sge = 0;
+                       qp->resp.wqe->dma.sge_offset = 0;
+                       qp->resp.opcode = -1;
+               }
+
+               if (qp->resp.mr) {
+                       rxe_drop_ref(qp->resp.mr);
+                       qp->resp.mr = NULL;
+               }
+
+               return RESPST_CLEANUP;
+       }
+}
+
+int rxe_responder(void *arg)
+{
+       struct rxe_qp *qp = (struct rxe_qp *)arg;
+       enum resp_states state;
+       struct rxe_pkt_info *pkt = NULL;
+       int ret = 0;
+
+       qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED;
+
+       if (!qp->valid) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       switch (qp->resp.state) {
+       case QP_STATE_RESET:
+               state = RESPST_RESET;
+               break;
+
+       default:
+               state = RESPST_GET_REQ;
+               break;
+       }
+
+       while (1) {
+               pr_debug("state = %s\n", resp_state_name[state]);
+               switch (state) {
+               case RESPST_GET_REQ:
+                       state = get_req(qp, &pkt);
+                       break;
+               case RESPST_CHK_PSN:
+                       state = check_psn(qp, pkt);
+                       break;
+               case RESPST_CHK_OP_SEQ:
+                       state = check_op_seq(qp, pkt);
+                       break;
+               case RESPST_CHK_OP_VALID:
+                       state = check_op_valid(qp, pkt);
+                       break;
+               case RESPST_CHK_RESOURCE:
+                       state = check_resource(qp, pkt);
+                       break;
+               case RESPST_CHK_LENGTH:
+                       state = check_length(qp, pkt);
+                       break;
+               case RESPST_CHK_RKEY:
+                       state = check_rkey(qp, pkt);
+                       break;
+               case RESPST_EXECUTE:
+                       state = execute(qp, pkt);
+                       break;
+               case RESPST_COMPLETE:
+                       state = do_complete(qp, pkt);
+                       break;
+               case RESPST_READ_REPLY:
+                       state = read_reply(qp, pkt);
+                       break;
+               case RESPST_ACKNOWLEDGE:
+                       state = acknowledge(qp, pkt);
+                       break;
+               case RESPST_CLEANUP:
+                       state = cleanup(qp, pkt);
+                       break;
+               case RESPST_DUPLICATE_REQUEST:
+                       state = duplicate_request(qp, pkt);
+                       break;
+               case RESPST_ERR_PSN_OUT_OF_SEQ:
+                       /* RC only - Class B. Drop packet. */
+                       send_ack(qp, pkt, AETH_NAK_PSN_SEQ_ERROR, qp->resp.psn);
+                       state = RESPST_CLEANUP;
+                       break;
+
+               case RESPST_ERR_TOO_MANY_RDMA_ATM_REQ:
+               case RESPST_ERR_MISSING_OPCODE_FIRST:
+               case RESPST_ERR_MISSING_OPCODE_LAST_C:
+               case RESPST_ERR_UNSUPPORTED_OPCODE:
+               case RESPST_ERR_MISALIGNED_ATOMIC:
+                       /* RC Only - Class C. */
+                       do_class_ac_error(qp, AETH_NAK_INVALID_REQ,
+                                         IB_WC_REM_INV_REQ_ERR);
+                       state = RESPST_COMPLETE;
+                       break;
+
+               case RESPST_ERR_MISSING_OPCODE_LAST_D1E:
+                       state = do_class_d1e_error(qp);
+                       break;
+               case RESPST_ERR_RNR:
+                       if (qp_type(qp) == IB_QPT_RC) {
+                               /* RC - class B */
+                               send_ack(qp, pkt, AETH_RNR_NAK |
+                                        (~AETH_TYPE_MASK &
+                                        qp->attr.min_rnr_timer),
+                                        pkt->psn);
+                       } else {
+                               /* UD/UC - class D */
+                               qp->resp.drop_msg = 1;
+                       }
+                       state = RESPST_CLEANUP;
+                       break;
+
+               case RESPST_ERR_RKEY_VIOLATION:
+                       if (qp_type(qp) == IB_QPT_RC) {
+                               /* Class C */
+                               do_class_ac_error(qp, AETH_NAK_REM_ACC_ERR,
+                                                 IB_WC_REM_ACCESS_ERR);
+                               state = RESPST_COMPLETE;
+                       } else {
+                               qp->resp.drop_msg = 1;
+                               if (qp->srq) {
+                                       /* UC/SRQ Class D */
+                                       qp->resp.status = IB_WC_REM_ACCESS_ERR;
+                                       state = RESPST_COMPLETE;
+                               } else {
+                                       /* UC/non-SRQ Class E. */
+                                       state = RESPST_CLEANUP;
+                               }
+                       }
+                       break;
+
+               case RESPST_ERR_LENGTH:
+                       if (qp_type(qp) == IB_QPT_RC) {
+                               /* Class C */
+                               do_class_ac_error(qp, AETH_NAK_INVALID_REQ,
+                                                 IB_WC_REM_INV_REQ_ERR);
+                               state = RESPST_COMPLETE;
+                       } else if (qp->srq) {
+                               /* UC/UD - class E */
+                               qp->resp.status = IB_WC_REM_INV_REQ_ERR;
+                               state = RESPST_COMPLETE;
+                       } else {
+                               /* UC/UD - class D */
+                               qp->resp.drop_msg = 1;
+                               state = RESPST_CLEANUP;
+                       }
+                       break;
+
+               case RESPST_ERR_MALFORMED_WQE:
+                       /* All, Class A. */
+                       do_class_ac_error(qp, AETH_NAK_REM_OP_ERR,
+                                         IB_WC_LOC_QP_OP_ERR);
+                       state = RESPST_COMPLETE;
+                       break;
+
+               case RESPST_ERR_CQ_OVERFLOW:
+                       /* All - Class G */
+                       state = RESPST_ERROR;
+                       break;
+
+               case RESPST_DONE:
+                       if (qp->resp.goto_error) {
+                               state = RESPST_ERROR;
+                               break;
+                       }
+
+                       goto done;
+
+               case RESPST_EXIT:
+                       if (qp->resp.goto_error) {
+                               state = RESPST_ERROR;
+                               break;
+                       }
+
+                       goto exit;
+
+               case RESPST_RESET: {
+                       struct sk_buff *skb;
+
+                       while ((skb = skb_dequeue(&qp->req_pkts))) {
+                               rxe_drop_ref(qp);
+                               kfree_skb(skb);
+                       }
+
+                       while (!qp->srq && qp->rq.queue &&
+                              queue_head(qp->rq.queue))
+                               advance_consumer(qp->rq.queue);
+
+                       qp->resp.wqe = NULL;
+                       goto exit;
+               }
+
+               case RESPST_ERROR:
+                       qp->resp.goto_error = 0;
+                       pr_warn("qp#%d moved to error state\n", qp_num(qp));
+                       rxe_qp_error(qp);
+                       goto exit;
+
+               default:
+                       WARN_ON(1);
+               }
+       }
+
+exit:
+       ret = -EAGAIN;
+done:
+       return ret;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c
new file mode 100644 (file)
index 0000000..2a6e3cd
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
+                    struct ib_srq_attr *attr, enum ib_srq_attr_mask mask)
+{
+       if (srq && srq->error) {
+               pr_warn("srq in error state\n");
+               goto err1;
+       }
+
+       if (mask & IB_SRQ_MAX_WR) {
+               if (attr->max_wr > rxe->attr.max_srq_wr) {
+                       pr_warn("max_wr(%d) > max_srq_wr(%d)\n",
+                               attr->max_wr, rxe->attr.max_srq_wr);
+                       goto err1;
+               }
+
+               if (attr->max_wr <= 0) {
+                       pr_warn("max_wr(%d) <= 0\n", attr->max_wr);
+                       goto err1;
+               }
+
+               if (srq && srq->limit && (attr->max_wr < srq->limit)) {
+                       pr_warn("max_wr (%d) < srq->limit (%d)\n",
+                               attr->max_wr, srq->limit);
+                       goto err1;
+               }
+
+               if (attr->max_wr < RXE_MIN_SRQ_WR)
+                       attr->max_wr = RXE_MIN_SRQ_WR;
+       }
+
+       if (mask & IB_SRQ_LIMIT) {
+               if (attr->srq_limit > rxe->attr.max_srq_wr) {
+                       pr_warn("srq_limit(%d) > max_srq_wr(%d)\n",
+                               attr->srq_limit, rxe->attr.max_srq_wr);
+                       goto err1;
+               }
+
+               if (srq && (attr->srq_limit > srq->rq.queue->buf->index_mask)) {
+                       pr_warn("srq_limit (%d) > cur limit(%d)\n",
+                               attr->srq_limit,
+                                srq->rq.queue->buf->index_mask);
+                       goto err1;
+               }
+       }
+
+       if (mask == IB_SRQ_INIT_MASK) {
+               if (attr->max_sge > rxe->attr.max_srq_sge) {
+                       pr_warn("max_sge(%d) > max_srq_sge(%d)\n",
+                               attr->max_sge, rxe->attr.max_srq_sge);
+                       goto err1;
+               }
+
+               if (attr->max_sge < RXE_MIN_SRQ_SGE)
+                       attr->max_sge = RXE_MIN_SRQ_SGE;
+       }
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
+                     struct ib_srq_init_attr *init,
+                     struct ib_ucontext *context, struct ib_udata *udata)
+{
+       int err;
+       int srq_wqe_size;
+       struct rxe_queue *q;
+
+       srq->ibsrq.event_handler        = init->event_handler;
+       srq->ibsrq.srq_context          = init->srq_context;
+       srq->limit              = init->attr.srq_limit;
+       srq->srq_num            = srq->pelem.index;
+       srq->rq.max_wr          = init->attr.max_wr;
+       srq->rq.max_sge         = init->attr.max_sge;
+
+       srq_wqe_size            = rcv_wqe_size(srq->rq.max_sge);
+
+       spin_lock_init(&srq->rq.producer_lock);
+       spin_lock_init(&srq->rq.consumer_lock);
+
+       q = rxe_queue_init(rxe, &srq->rq.max_wr,
+                          srq_wqe_size);
+       if (!q) {
+               pr_warn("unable to allocate queue for srq\n");
+               return -ENOMEM;
+       }
+
+       srq->rq.queue = q;
+
+       err = do_mmap_info(rxe, udata, false, context, q->buf,
+                          q->buf_size, &q->ip);
+       if (err)
+               return err;
+
+       if (udata && udata->outlen >= sizeof(struct mminfo) + sizeof(u32)) {
+               if (copy_to_user(udata->outbuf + sizeof(struct mminfo),
+                                &srq->srq_num, sizeof(u32)))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
+int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
+                     struct ib_srq_attr *attr, enum ib_srq_attr_mask mask,
+                     struct ib_udata *udata)
+{
+       int err;
+       struct rxe_queue *q = srq->rq.queue;
+       struct mminfo mi = { .offset = 1, .size = 0};
+
+       if (mask & IB_SRQ_MAX_WR) {
+               /* Check that we can write the mminfo struct to user space */
+               if (udata && udata->inlen >= sizeof(__u64)) {
+                       __u64 mi_addr;
+
+                       /* Get address of user space mminfo struct */
+                       err = ib_copy_from_udata(&mi_addr, udata,
+                                                sizeof(mi_addr));
+                       if (err)
+                               goto err1;
+
+                       udata->outbuf = (void __user *)(unsigned long)mi_addr;
+                       udata->outlen = sizeof(mi);
+
+                       if (!access_ok(VERIFY_WRITE,
+                                      (void __user *)udata->outbuf,
+                                       udata->outlen)) {
+                               err = -EFAULT;
+                               goto err1;
+                       }
+               }
+
+               err = rxe_queue_resize(q, (unsigned int *)&attr->max_wr,
+                                      rcv_wqe_size(srq->rq.max_sge),
+                                      srq->rq.queue->ip ?
+                                               srq->rq.queue->ip->context :
+                                               NULL,
+                                      udata, &srq->rq.producer_lock,
+                                      &srq->rq.consumer_lock);
+               if (err)
+                       goto err2;
+       }
+
+       if (mask & IB_SRQ_LIMIT)
+               srq->limit = attr->srq_limit;
+
+       return 0;
+
+err2:
+       rxe_queue_cleanup(q);
+       srq->rq.queue = NULL;
+err1:
+       return err;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_sysfs.c b/drivers/infiniband/sw/rxe/rxe_sysfs.c
new file mode 100644 (file)
index 0000000..cf8e778
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_net.h"
+
+/* Copy argument and remove trailing CR. Return the new length. */
+static int sanitize_arg(const char *val, char *intf, int intf_len)
+{
+       int len;
+
+       if (!val)
+               return 0;
+
+       /* Remove newline. */
+       for (len = 0; len < intf_len - 1 && val[len] && val[len] != '\n'; len++)
+               intf[len] = val[len];
+       intf[len] = 0;
+
+       if (len == 0 || (val[len] != 0 && val[len] != '\n'))
+               return 0;
+
+       return len;
+}
+
+static void rxe_set_port_state(struct net_device *ndev)
+{
+       struct rxe_dev *rxe = net_to_rxe(ndev);
+       bool is_up = netif_running(ndev) && netif_carrier_ok(ndev);
+
+       if (!rxe)
+               goto out;
+
+       if (is_up)
+               rxe_port_up(rxe);
+       else
+               rxe_port_down(rxe); /* down for unknown state */
+out:
+       return;
+}
+
+static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
+{
+       int len;
+       int err = 0;
+       char intf[32];
+       struct net_device *ndev = NULL;
+       struct rxe_dev *rxe;
+
+       len = sanitize_arg(val, intf, sizeof(intf));
+       if (!len) {
+               pr_err("rxe: add: invalid interface name\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       ndev = dev_get_by_name(&init_net, intf);
+       if (!ndev) {
+               pr_err("interface %s not found\n", intf);
+               err = -EINVAL;
+               goto err;
+       }
+
+       if (net_to_rxe(ndev)) {
+               pr_err("rxe: already configured on %s\n", intf);
+               err = -EINVAL;
+               goto err;
+       }
+
+       rxe = rxe_net_add(ndev);
+       if (!rxe) {
+               pr_err("rxe: failed to add %s\n", intf);
+               err = -EINVAL;
+               goto err;
+       }
+
+       rxe_set_port_state(ndev);
+       pr_info("rxe: added %s to %s\n", rxe->ib_dev.name, intf);
+err:
+       if (ndev)
+               dev_put(ndev);
+       return err;
+}
+
+static int rxe_param_set_remove(const char *val, const struct kernel_param *kp)
+{
+       int len;
+       char intf[32];
+       struct rxe_dev *rxe;
+
+       len = sanitize_arg(val, intf, sizeof(intf));
+       if (!len) {
+               pr_err("rxe: add: invalid interface name\n");
+               return -EINVAL;
+       }
+
+       if (strncmp("all", intf, len) == 0) {
+               pr_info("rxe_sys: remove all");
+               rxe_remove_all();
+               return 0;
+       }
+
+       rxe = get_rxe_by_name(intf);
+
+       if (!rxe) {
+               pr_err("rxe: not configured on %s\n", intf);
+               return -EINVAL;
+       }
+
+       list_del(&rxe->list);
+       rxe_remove(rxe);
+
+       return 0;
+}
+
+static const struct kernel_param_ops rxe_add_ops = {
+       .set = rxe_param_set_add,
+};
+
+static const struct kernel_param_ops rxe_remove_ops = {
+       .set = rxe_param_set_remove,
+};
+
+module_param_cb(add, &rxe_add_ops, NULL, 0200);
+MODULE_PARM_DESC(add, "Create RXE device over network interface");
+module_param_cb(remove, &rxe_remove_ops, NULL, 0200);
+MODULE_PARM_DESC(remove, "Remove RXE device over network interface");
diff --git a/drivers/infiniband/sw/rxe/rxe_task.c b/drivers/infiniband/sw/rxe/rxe_task.c
new file mode 100644 (file)
index 0000000..1e19bf8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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/interrupt.h>
+#include <linux/hardirq.h>
+
+#include "rxe_task.h"
+
+int __rxe_do_task(struct rxe_task *task)
+
+{
+       int ret;
+
+       while ((ret = task->func(task->arg)) == 0)
+               ;
+
+       task->ret = ret;
+
+       return ret;
+}
+
+/*
+ * this locking is due to a potential race where
+ * a second caller finds the task already running
+ * but looks just after the last call to func
+ */
+void rxe_do_task(unsigned long data)
+{
+       int cont;
+       int ret;
+       unsigned long flags;
+       struct rxe_task *task = (struct rxe_task *)data;
+
+       spin_lock_irqsave(&task->state_lock, flags);
+       switch (task->state) {
+       case TASK_STATE_START:
+               task->state = TASK_STATE_BUSY;
+               spin_unlock_irqrestore(&task->state_lock, flags);
+               break;
+
+       case TASK_STATE_BUSY:
+               task->state = TASK_STATE_ARMED;
+               /* fall through to */
+       case TASK_STATE_ARMED:
+               spin_unlock_irqrestore(&task->state_lock, flags);
+               return;
+
+       default:
+               spin_unlock_irqrestore(&task->state_lock, flags);
+               pr_warn("bad state = %d in rxe_do_task\n", task->state);
+               return;
+       }
+
+       do {
+               cont = 0;
+               ret = task->func(task->arg);
+
+               spin_lock_irqsave(&task->state_lock, flags);
+               switch (task->state) {
+               case TASK_STATE_BUSY:
+                       if (ret)
+                               task->state = TASK_STATE_START;
+                       else
+                               cont = 1;
+                       break;
+
+               /* soneone tried to run the task since the last time we called
+                * func, so we will call one more time regardless of the
+                * return value
+                */
+               case TASK_STATE_ARMED:
+                       task->state = TASK_STATE_BUSY;
+                       cont = 1;
+                       break;
+
+               default:
+                       pr_warn("bad state = %d in rxe_do_task\n",
+                               task->state);
+               }
+               spin_unlock_irqrestore(&task->state_lock, flags);
+       } while (cont);
+
+       task->ret = ret;
+}
+
+int rxe_init_task(void *obj, struct rxe_task *task,
+                 void *arg, int (*func)(void *), char *name)
+{
+       task->obj       = obj;
+       task->arg       = arg;
+       task->func      = func;
+       snprintf(task->name, sizeof(task->name), "%s", name);
+
+       tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
+
+       task->state = TASK_STATE_START;
+       spin_lock_init(&task->state_lock);
+
+       return 0;
+}
+
+void rxe_cleanup_task(struct rxe_task *task)
+{
+       tasklet_kill(&task->tasklet);
+}
+
+void rxe_run_task(struct rxe_task *task, int sched)
+{
+       if (sched)
+               tasklet_schedule(&task->tasklet);
+       else
+               rxe_do_task((unsigned long)task);
+}
+
+void rxe_disable_task(struct rxe_task *task)
+{
+       tasklet_disable(&task->tasklet);
+}
+
+void rxe_enable_task(struct rxe_task *task)
+{
+       tasklet_enable(&task->tasklet);
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_task.h b/drivers/infiniband/sw/rxe/rxe_task.h
new file mode 100644 (file)
index 0000000..d14aa6d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_TASK_H
+#define RXE_TASK_H
+
+enum {
+       TASK_STATE_START        = 0,
+       TASK_STATE_BUSY         = 1,
+       TASK_STATE_ARMED        = 2,
+};
+
+/*
+ * data structure to describe a 'task' which is a short
+ * function that returns 0 as long as it needs to be
+ * called again.
+ */
+struct rxe_task {
+       void                    *obj;
+       struct tasklet_struct   tasklet;
+       int                     state;
+       spinlock_t              state_lock; /* spinlock for task state */
+       void                    *arg;
+       int                     (*func)(void *arg);
+       int                     ret;
+       char                    name[16];
+};
+
+/*
+ * init rxe_task structure
+ *     arg  => parameter to pass to fcn
+ *     fcn  => function to call until it returns != 0
+ */
+int rxe_init_task(void *obj, struct rxe_task *task,
+                 void *arg, int (*func)(void *), char *name);
+
+/* cleanup task */
+void rxe_cleanup_task(struct rxe_task *task);
+
+/*
+ * raw call to func in loop without any checking
+ * can call when tasklets are disabled
+ */
+int __rxe_do_task(struct rxe_task *task);
+
+/*
+ * common function called by any of the main tasklets
+ * If there is any chance that there is additional
+ * work to do someone must reschedule the task before
+ * leaving
+ */
+void rxe_do_task(unsigned long data);
+
+/* run a task, else schedule it to run as a tasklet, The decision
+ * to run or schedule tasklet is based on the parameter sched.
+ */
+void rxe_run_task(struct rxe_task *task, int sched);
+
+/* keep a task from scheduling */
+void rxe_disable_task(struct rxe_task *task);
+
+/* allow task to run */
+void rxe_enable_task(struct rxe_task *task);
+
+#endif /* RXE_TASK_H */
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
new file mode 100644 (file)
index 0000000..4552be9
--- /dev/null
@@ -0,0 +1,1330 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 "rxe.h"
+#include "rxe_loc.h"
+#include "rxe_queue.h"
+
+static int rxe_query_device(struct ib_device *dev,
+                           struct ib_device_attr *attr,
+                           struct ib_udata *uhw)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+
+       if (uhw->inlen || uhw->outlen)
+               return -EINVAL;
+
+       *attr = rxe->attr;
+       return 0;
+}
+
+static void rxe_eth_speed_to_ib_speed(int speed, u8 *active_speed,
+                                     u8 *active_width)
+{
+       if (speed <= 1000) {
+               *active_width = IB_WIDTH_1X;
+               *active_speed = IB_SPEED_SDR;
+       } else if (speed <= 10000) {
+               *active_width = IB_WIDTH_1X;
+               *active_speed = IB_SPEED_FDR10;
+       } else if (speed <= 20000) {
+               *active_width = IB_WIDTH_4X;
+               *active_speed = IB_SPEED_DDR;
+       } else if (speed <= 30000) {
+               *active_width = IB_WIDTH_4X;
+               *active_speed = IB_SPEED_QDR;
+       } else if (speed <= 40000) {
+               *active_width = IB_WIDTH_4X;
+               *active_speed = IB_SPEED_FDR10;
+       } else {
+               *active_width = IB_WIDTH_4X;
+               *active_speed = IB_SPEED_EDR;
+       }
+}
+
+static int rxe_query_port(struct ib_device *dev,
+                         u8 port_num, struct ib_port_attr *attr)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+       struct rxe_port *port;
+       u32 speed;
+
+       if (unlikely(port_num != 1)) {
+               pr_warn("invalid port_number %d\n", port_num);
+               goto err1;
+       }
+
+       port = &rxe->port;
+
+       *attr = port->attr;
+
+       mutex_lock(&rxe->usdev_lock);
+       if (rxe->ndev->ethtool_ops->get_link_ksettings) {
+               struct ethtool_link_ksettings ks;
+
+               rxe->ndev->ethtool_ops->get_link_ksettings(rxe->ndev, &ks);
+               speed = ks.base.speed;
+       } else if (rxe->ndev->ethtool_ops->get_settings) {
+               struct ethtool_cmd cmd;
+
+               rxe->ndev->ethtool_ops->get_settings(rxe->ndev, &cmd);
+               speed = cmd.speed;
+       } else {
+               pr_warn("%s speed is unknown, defaulting to 1000\n", rxe->ndev->name);
+               speed = 1000;
+       }
+       rxe_eth_speed_to_ib_speed(speed, &attr->active_speed, &attr->active_width);
+       mutex_unlock(&rxe->usdev_lock);
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static int rxe_query_gid(struct ib_device *device,
+                        u8 port_num, int index, union ib_gid *gid)
+{
+       int ret;
+
+       if (index > RXE_PORT_GID_TBL_LEN)
+               return -EINVAL;
+
+       ret = ib_get_cached_gid(device, port_num, index, gid, NULL);
+       if (ret == -EAGAIN) {
+               memcpy(gid, &zgid, sizeof(*gid));
+               return 0;
+       }
+
+       return ret;
+}
+
+static int rxe_add_gid(struct ib_device *device, u8 port_num, unsigned int
+                      index, const union ib_gid *gid,
+                      const struct ib_gid_attr *attr, void **context)
+{
+       if (index >= RXE_PORT_GID_TBL_LEN)
+               return -EINVAL;
+       return 0;
+}
+
+static int rxe_del_gid(struct ib_device *device, u8 port_num, unsigned int
+                      index, void **context)
+{
+       if (index >= RXE_PORT_GID_TBL_LEN)
+               return -EINVAL;
+       return 0;
+}
+
+static struct net_device *rxe_get_netdev(struct ib_device *device,
+                                        u8 port_num)
+{
+       struct rxe_dev *rxe = to_rdev(device);
+
+       if (rxe->ndev) {
+               dev_hold(rxe->ndev);
+               return rxe->ndev;
+       }
+
+       return NULL;
+}
+
+static int rxe_query_pkey(struct ib_device *device,
+                         u8 port_num, u16 index, u16 *pkey)
+{
+       struct rxe_dev *rxe = to_rdev(device);
+       struct rxe_port *port;
+
+       if (unlikely(port_num != 1)) {
+               dev_warn(device->dma_device, "invalid port_num = %d\n",
+                        port_num);
+               goto err1;
+       }
+
+       port = &rxe->port;
+
+       if (unlikely(index >= port->attr.pkey_tbl_len)) {
+               dev_warn(device->dma_device, "invalid index = %d\n",
+                        index);
+               goto err1;
+       }
+
+       *pkey = port->pkey_tbl[index];
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static int rxe_modify_device(struct ib_device *dev,
+                            int mask, struct ib_device_modify *attr)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+
+       if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID)
+               rxe->attr.sys_image_guid = cpu_to_be64(attr->sys_image_guid);
+
+       if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+               memcpy(rxe->ib_dev.node_desc,
+                      attr->node_desc, sizeof(rxe->ib_dev.node_desc));
+       }
+
+       return 0;
+}
+
+static int rxe_modify_port(struct ib_device *dev,
+                          u8 port_num, int mask, struct ib_port_modify *attr)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+       struct rxe_port *port;
+
+       if (unlikely(port_num != 1)) {
+               pr_warn("invalid port_num = %d\n", port_num);
+               goto err1;
+       }
+
+       port = &rxe->port;
+
+       port->attr.port_cap_flags |= attr->set_port_cap_mask;
+       port->attr.port_cap_flags &= ~attr->clr_port_cap_mask;
+
+       if (mask & IB_PORT_RESET_QKEY_CNTR)
+               port->attr.qkey_viol_cntr = 0;
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static enum rdma_link_layer rxe_get_link_layer(struct ib_device *dev,
+                                              u8 port_num)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+
+       return rxe->ifc_ops->link_layer(rxe, port_num);
+}
+
+static struct ib_ucontext *rxe_alloc_ucontext(struct ib_device *dev,
+                                             struct ib_udata *udata)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+       struct rxe_ucontext *uc;
+
+       uc = rxe_alloc(&rxe->uc_pool);
+       return uc ? &uc->ibuc : ERR_PTR(-ENOMEM);
+}
+
+static int rxe_dealloc_ucontext(struct ib_ucontext *ibuc)
+{
+       struct rxe_ucontext *uc = to_ruc(ibuc);
+
+       rxe_drop_ref(uc);
+       return 0;
+}
+
+static int rxe_port_immutable(struct ib_device *dev, u8 port_num,
+                             struct ib_port_immutable *immutable)
+{
+       int err;
+       struct ib_port_attr attr;
+
+       err = rxe_query_port(dev, port_num, &attr);
+       if (err)
+               return err;
+
+       immutable->pkey_tbl_len = attr.pkey_tbl_len;
+       immutable->gid_tbl_len = attr.gid_tbl_len;
+       immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
+       immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+
+       return 0;
+}
+
+static struct ib_pd *rxe_alloc_pd(struct ib_device *dev,
+                                 struct ib_ucontext *context,
+                                 struct ib_udata *udata)
+{
+       struct rxe_dev *rxe = to_rdev(dev);
+       struct rxe_pd *pd;
+
+       pd = rxe_alloc(&rxe->pd_pool);
+       return pd ? &pd->ibpd : ERR_PTR(-ENOMEM);
+}
+
+static int rxe_dealloc_pd(struct ib_pd *ibpd)
+{
+       struct rxe_pd *pd = to_rpd(ibpd);
+
+       rxe_drop_ref(pd);
+       return 0;
+}
+
+static int rxe_init_av(struct rxe_dev *rxe, struct ib_ah_attr *attr,
+                      struct rxe_av *av)
+{
+       int err;
+       union ib_gid sgid;
+       struct ib_gid_attr sgid_attr;
+
+       err = ib_get_cached_gid(&rxe->ib_dev, attr->port_num,
+                               attr->grh.sgid_index, &sgid,
+                               &sgid_attr);
+       if (err) {
+               pr_err("Failed to query sgid. err = %d\n", err);
+               return err;
+       }
+
+       err = rxe_av_from_attr(rxe, attr->port_num, av, attr);
+       if (!err)
+               err = rxe_av_fill_ip_info(rxe, av, attr, &sgid_attr, &sgid);
+
+       if (sgid_attr.ndev)
+               dev_put(sgid_attr.ndev);
+       return err;
+}
+
+static struct ib_ah *rxe_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_ah *ah;
+
+       err = rxe_av_chk_attr(rxe, attr);
+       if (err)
+               goto err1;
+
+       ah = rxe_alloc(&rxe->ah_pool);
+       if (!ah) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       rxe_add_ref(pd);
+       ah->pd = pd;
+
+       err = rxe_init_av(rxe, attr, &ah->av);
+       if (err)
+               goto err2;
+
+       return &ah->ibah;
+
+err2:
+       rxe_drop_ref(pd);
+       rxe_drop_ref(ah);
+err1:
+       return ERR_PTR(err);
+}
+
+static int rxe_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibah->device);
+       struct rxe_ah *ah = to_rah(ibah);
+
+       err = rxe_av_chk_attr(rxe, attr);
+       if (err)
+               return err;
+
+       err = rxe_init_av(rxe, attr, &ah->av);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int rxe_query_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)
+{
+       struct rxe_dev *rxe = to_rdev(ibah->device);
+       struct rxe_ah *ah = to_rah(ibah);
+
+       rxe_av_to_attr(rxe, &ah->av, attr);
+       return 0;
+}
+
+static int rxe_destroy_ah(struct ib_ah *ibah)
+{
+       struct rxe_ah *ah = to_rah(ibah);
+
+       rxe_drop_ref(ah->pd);
+       rxe_drop_ref(ah);
+       return 0;
+}
+
+static int post_one_recv(struct rxe_rq *rq, struct ib_recv_wr *ibwr)
+{
+       int err;
+       int i;
+       u32 length;
+       struct rxe_recv_wqe *recv_wqe;
+       int num_sge = ibwr->num_sge;
+
+       if (unlikely(queue_full(rq->queue))) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       if (unlikely(num_sge > rq->max_sge)) {
+               err = -EINVAL;
+               goto err1;
+       }
+
+       length = 0;
+       for (i = 0; i < num_sge; i++)
+               length += ibwr->sg_list[i].length;
+
+       recv_wqe = producer_addr(rq->queue);
+       recv_wqe->wr_id = ibwr->wr_id;
+       recv_wqe->num_sge = num_sge;
+
+       memcpy(recv_wqe->dma.sge, ibwr->sg_list,
+              num_sge * sizeof(struct ib_sge));
+
+       recv_wqe->dma.length            = length;
+       recv_wqe->dma.resid             = length;
+       recv_wqe->dma.num_sge           = num_sge;
+       recv_wqe->dma.cur_sge           = 0;
+       recv_wqe->dma.sge_offset        = 0;
+
+       /* make sure all changes to the work queue are written before we
+        * update the producer pointer
+        */
+       smp_wmb();
+
+       advance_producer(rq->queue);
+       return 0;
+
+err1:
+       return err;
+}
+
+static struct ib_srq *rxe_create_srq(struct ib_pd *ibpd,
+                                    struct ib_srq_init_attr *init,
+                                    struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_srq *srq;
+       struct ib_ucontext *context = udata ? ibpd->uobject->context : NULL;
+
+       err = rxe_srq_chk_attr(rxe, NULL, &init->attr, IB_SRQ_INIT_MASK);
+       if (err)
+               goto err1;
+
+       srq = rxe_alloc(&rxe->srq_pool);
+       if (!srq) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       rxe_add_index(srq);
+       rxe_add_ref(pd);
+       srq->pd = pd;
+
+       err = rxe_srq_from_init(rxe, srq, init, context, udata);
+       if (err)
+               goto err2;
+
+       return &srq->ibsrq;
+
+err2:
+       rxe_drop_ref(pd);
+       rxe_drop_index(srq);
+       rxe_drop_ref(srq);
+err1:
+       return ERR_PTR(err);
+}
+
+static int rxe_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                         enum ib_srq_attr_mask mask,
+                         struct ib_udata *udata)
+{
+       int err;
+       struct rxe_srq *srq = to_rsrq(ibsrq);
+       struct rxe_dev *rxe = to_rdev(ibsrq->device);
+
+       err = rxe_srq_chk_attr(rxe, srq, attr, mask);
+       if (err)
+               goto err1;
+
+       err = rxe_srq_from_attr(rxe, srq, attr, mask, udata);
+       if (err)
+               goto err1;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+static int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
+{
+       struct rxe_srq *srq = to_rsrq(ibsrq);
+
+       if (srq->error)
+               return -EINVAL;
+
+       attr->max_wr = srq->rq.queue->buf->index_mask;
+       attr->max_sge = srq->rq.max_sge;
+       attr->srq_limit = srq->limit;
+       return 0;
+}
+
+static int rxe_destroy_srq(struct ib_srq *ibsrq)
+{
+       struct rxe_srq *srq = to_rsrq(ibsrq);
+
+       if (srq->rq.queue)
+               rxe_queue_cleanup(srq->rq.queue);
+
+       rxe_drop_ref(srq->pd);
+       rxe_drop_index(srq);
+       rxe_drop_ref(srq);
+
+       return 0;
+}
+
+static int rxe_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                            struct ib_recv_wr **bad_wr)
+{
+       int err = 0;
+       unsigned long flags;
+       struct rxe_srq *srq = to_rsrq(ibsrq);
+
+       spin_lock_irqsave(&srq->rq.producer_lock, flags);
+
+       while (wr) {
+               err = post_one_recv(&srq->rq, wr);
+               if (unlikely(err))
+                       break;
+               wr = wr->next;
+       }
+
+       spin_unlock_irqrestore(&srq->rq.producer_lock, flags);
+
+       if (err)
+               *bad_wr = wr;
+
+       return err;
+}
+
+static struct ib_qp *rxe_create_qp(struct ib_pd *ibpd,
+                                  struct ib_qp_init_attr *init,
+                                  struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_qp *qp;
+
+       err = rxe_qp_chk_init(rxe, init);
+       if (err)
+               goto err1;
+
+       qp = rxe_alloc(&rxe->qp_pool);
+       if (!qp) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       if (udata) {
+               if (udata->inlen) {
+                       err = -EINVAL;
+                       goto err1;
+               }
+               qp->is_user = 1;
+       }
+
+       rxe_add_index(qp);
+
+       err = rxe_qp_from_init(rxe, qp, pd, init, udata, ibpd);
+       if (err)
+               goto err2;
+
+       return &qp->ibqp;
+
+err2:
+       rxe_drop_index(qp);
+       rxe_drop_ref(qp);
+err1:
+       return ERR_PTR(err);
+}
+
+static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                        int mask, struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibqp->device);
+       struct rxe_qp *qp = to_rqp(ibqp);
+
+       err = rxe_qp_chk_attr(rxe, qp, attr, mask);
+       if (err)
+               goto err1;
+
+       err = rxe_qp_from_attr(qp, attr, mask, udata);
+       if (err)
+               goto err1;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+static int rxe_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                       int mask, struct ib_qp_init_attr *init)
+{
+       struct rxe_qp *qp = to_rqp(ibqp);
+
+       rxe_qp_to_init(qp, init);
+       rxe_qp_to_attr(qp, attr, mask);
+
+       return 0;
+}
+
+static int rxe_destroy_qp(struct ib_qp *ibqp)
+{
+       struct rxe_qp *qp = to_rqp(ibqp);
+
+       rxe_qp_destroy(qp);
+       rxe_drop_index(qp);
+       rxe_drop_ref(qp);
+       return 0;
+}
+
+static int validate_send_wr(struct rxe_qp *qp, struct ib_send_wr *ibwr,
+                           unsigned int mask, unsigned int length)
+{
+       int num_sge = ibwr->num_sge;
+       struct rxe_sq *sq = &qp->sq;
+
+       if (unlikely(num_sge > sq->max_sge))
+               goto err1;
+
+       if (unlikely(mask & WR_ATOMIC_MASK)) {
+               if (length < 8)
+                       goto err1;
+
+               if (atomic_wr(ibwr)->remote_addr & 0x7)
+                       goto err1;
+       }
+
+       if (unlikely((ibwr->send_flags & IB_SEND_INLINE) &&
+                    (length > sq->max_inline)))
+               goto err1;
+
+       return 0;
+
+err1:
+       return -EINVAL;
+}
+
+static void init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr,
+                        struct ib_send_wr *ibwr)
+{
+       wr->wr_id = ibwr->wr_id;
+       wr->num_sge = ibwr->num_sge;
+       wr->opcode = ibwr->opcode;
+       wr->send_flags = ibwr->send_flags;
+
+       if (qp_type(qp) == IB_QPT_UD ||
+           qp_type(qp) == IB_QPT_SMI ||
+           qp_type(qp) == IB_QPT_GSI) {
+               wr->wr.ud.remote_qpn = ud_wr(ibwr)->remote_qpn;
+               wr->wr.ud.remote_qkey = ud_wr(ibwr)->remote_qkey;
+               if (qp_type(qp) == IB_QPT_GSI)
+                       wr->wr.ud.pkey_index = ud_wr(ibwr)->pkey_index;
+               if (wr->opcode == IB_WR_SEND_WITH_IMM)
+                       wr->ex.imm_data = ibwr->ex.imm_data;
+       } else {
+               switch (wr->opcode) {
+               case IB_WR_RDMA_WRITE_WITH_IMM:
+                       wr->ex.imm_data = ibwr->ex.imm_data;
+               case IB_WR_RDMA_READ:
+               case IB_WR_RDMA_WRITE:
+                       wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr;
+                       wr->wr.rdma.rkey        = rdma_wr(ibwr)->rkey;
+                       break;
+               case IB_WR_SEND_WITH_IMM:
+                       wr->ex.imm_data = ibwr->ex.imm_data;
+                       break;
+               case IB_WR_SEND_WITH_INV:
+                       wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey;
+                       break;
+               case IB_WR_ATOMIC_CMP_AND_SWP:
+               case IB_WR_ATOMIC_FETCH_AND_ADD:
+                       wr->wr.atomic.remote_addr =
+                               atomic_wr(ibwr)->remote_addr;
+                       wr->wr.atomic.compare_add =
+                               atomic_wr(ibwr)->compare_add;
+                       wr->wr.atomic.swap = atomic_wr(ibwr)->swap;
+                       wr->wr.atomic.rkey = atomic_wr(ibwr)->rkey;
+                       break;
+               case IB_WR_LOCAL_INV:
+                       wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey;
+               break;
+               case IB_WR_REG_MR:
+                       wr->wr.reg.mr = reg_wr(ibwr)->mr;
+                       wr->wr.reg.key = reg_wr(ibwr)->key;
+                       wr->wr.reg.access = reg_wr(ibwr)->access;
+               break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int init_send_wqe(struct rxe_qp *qp, struct ib_send_wr *ibwr,
+                        unsigned int mask, unsigned int length,
+                        struct rxe_send_wqe *wqe)
+{
+       int num_sge = ibwr->num_sge;
+       struct ib_sge *sge;
+       int i;
+       u8 *p;
+
+       init_send_wr(qp, &wqe->wr, ibwr);
+
+       if (qp_type(qp) == IB_QPT_UD ||
+           qp_type(qp) == IB_QPT_SMI ||
+           qp_type(qp) == IB_QPT_GSI)
+               memcpy(&wqe->av, &to_rah(ud_wr(ibwr)->ah)->av, sizeof(wqe->av));
+
+       if (unlikely(ibwr->send_flags & IB_SEND_INLINE)) {
+               p = wqe->dma.inline_data;
+
+               sge = ibwr->sg_list;
+               for (i = 0; i < num_sge; i++, sge++) {
+                       if (qp->is_user && copy_from_user(p, (__user void *)
+                                           (uintptr_t)sge->addr, sge->length))
+                               return -EFAULT;
+
+                       else if (!qp->is_user)
+                               memcpy(p, (void *)(uintptr_t)sge->addr,
+                                      sge->length);
+
+                       p += sge->length;
+               }
+       } else if (mask & WR_REG_MASK) {
+               wqe->mask = mask;
+               wqe->state = wqe_state_posted;
+               return 0;
+       } else
+               memcpy(wqe->dma.sge, ibwr->sg_list,
+                      num_sge * sizeof(struct ib_sge));
+
+       wqe->iova               = (mask & WR_ATOMIC_MASK) ?
+                                       atomic_wr(ibwr)->remote_addr :
+                                       rdma_wr(ibwr)->remote_addr;
+       wqe->mask               = mask;
+       wqe->dma.length         = length;
+       wqe->dma.resid          = length;
+       wqe->dma.num_sge        = num_sge;
+       wqe->dma.cur_sge        = 0;
+       wqe->dma.sge_offset     = 0;
+       wqe->state              = wqe_state_posted;
+       wqe->ssn                = atomic_add_return(1, &qp->ssn);
+
+       return 0;
+}
+
+static int post_one_send(struct rxe_qp *qp, struct ib_send_wr *ibwr,
+                        unsigned mask, u32 length)
+{
+       int err;
+       struct rxe_sq *sq = &qp->sq;
+       struct rxe_send_wqe *send_wqe;
+       unsigned long flags;
+
+       err = validate_send_wr(qp, ibwr, mask, length);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&qp->sq.sq_lock, flags);
+
+       if (unlikely(queue_full(sq->queue))) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       send_wqe = producer_addr(sq->queue);
+
+       err = init_send_wqe(qp, ibwr, mask, length, send_wqe);
+       if (unlikely(err))
+               goto err1;
+
+       /*
+        * make sure all changes to the work queue are
+        * written before we update the producer pointer
+        */
+       smp_wmb();
+
+       advance_producer(sq->queue);
+       spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
+
+       return 0;
+
+err1:
+       spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
+       return err;
+}
+
+static int rxe_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                        struct ib_send_wr **bad_wr)
+{
+       int err = 0;
+       struct rxe_qp *qp = to_rqp(ibqp);
+       unsigned int mask;
+       unsigned int length = 0;
+       int i;
+       int must_sched;
+
+       if (unlikely(!qp->valid)) {
+               *bad_wr = wr;
+               return -EINVAL;
+       }
+
+       if (unlikely(qp->req.state < QP_STATE_READY)) {
+               *bad_wr = wr;
+               return -EINVAL;
+       }
+
+       while (wr) {
+               mask = wr_opcode_mask(wr->opcode, qp);
+               if (unlikely(!mask)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
+
+               if (unlikely((wr->send_flags & IB_SEND_INLINE) &&
+                            !(mask & WR_INLINE_MASK))) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
+
+               length = 0;
+               for (i = 0; i < wr->num_sge; i++)
+                       length += wr->sg_list[i].length;
+
+               err = post_one_send(qp, wr, mask, length);
+
+               if (err) {
+                       *bad_wr = wr;
+                       break;
+               }
+               wr = wr->next;
+       }
+
+       /*
+        * Must sched in case of GSI QP because ib_send_mad() hold irq lock,
+        * and the requester call ip_local_out_sk() that takes spin_lock_bh.
+        */
+       must_sched = (qp_type(qp) == IB_QPT_GSI) ||
+                       (queue_count(qp->sq.queue) > 1);
+
+       rxe_run_task(&qp->req.task, must_sched);
+
+       return err;
+}
+
+static int rxe_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                        struct ib_recv_wr **bad_wr)
+{
+       int err = 0;
+       struct rxe_qp *qp = to_rqp(ibqp);
+       struct rxe_rq *rq = &qp->rq;
+       unsigned long flags;
+
+       if (unlikely((qp_state(qp) < IB_QPS_INIT) || !qp->valid)) {
+               *bad_wr = wr;
+               err = -EINVAL;
+               goto err1;
+       }
+
+       if (unlikely(qp->srq)) {
+               *bad_wr = wr;
+               err = -EINVAL;
+               goto err1;
+       }
+
+       spin_lock_irqsave(&rq->producer_lock, flags);
+
+       while (wr) {
+               err = post_one_recv(rq, wr);
+               if (unlikely(err)) {
+                       *bad_wr = wr;
+                       break;
+               }
+               wr = wr->next;
+       }
+
+       spin_unlock_irqrestore(&rq->producer_lock, flags);
+
+err1:
+       return err;
+}
+
+static struct ib_cq *rxe_create_cq(struct ib_device *dev,
+                                  const struct ib_cq_init_attr *attr,
+                                  struct ib_ucontext *context,
+                                  struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(dev);
+       struct rxe_cq *cq;
+
+       if (attr->flags)
+               return ERR_PTR(-EINVAL);
+
+       err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector, udata);
+       if (err)
+               goto err1;
+
+       cq = rxe_alloc(&rxe->cq_pool);
+       if (!cq) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector,
+                              context, udata);
+       if (err)
+               goto err2;
+
+       return &cq->ibcq;
+
+err2:
+       rxe_drop_ref(cq);
+err1:
+       return ERR_PTR(err);
+}
+
+static int rxe_destroy_cq(struct ib_cq *ibcq)
+{
+       struct rxe_cq *cq = to_rcq(ibcq);
+
+       rxe_drop_ref(cq);
+       return 0;
+}
+
+static int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
+{
+       int err;
+       struct rxe_cq *cq = to_rcq(ibcq);
+       struct rxe_dev *rxe = to_rdev(ibcq->device);
+
+       err = rxe_cq_chk_attr(rxe, cq, cqe, 0, udata);
+       if (err)
+               goto err1;
+
+       err = rxe_cq_resize_queue(cq, cqe, udata);
+       if (err)
+               goto err1;
+
+       return 0;
+
+err1:
+       return err;
+}
+
+static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+       int i;
+       struct rxe_cq *cq = to_rcq(ibcq);
+       struct rxe_cqe *cqe;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cq->cq_lock, flags);
+       for (i = 0; i < num_entries; i++) {
+               cqe = queue_head(cq->queue);
+               if (!cqe)
+                       break;
+
+               memcpy(wc++, &cqe->ibwc, sizeof(*wc));
+               advance_consumer(cq->queue);
+       }
+       spin_unlock_irqrestore(&cq->cq_lock, flags);
+
+       return i;
+}
+
+static int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt)
+{
+       struct rxe_cq *cq = to_rcq(ibcq);
+       int count = queue_count(cq->queue);
+
+       return (count > wc_cnt) ? wc_cnt : count;
+}
+
+static int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+       struct rxe_cq *cq = to_rcq(ibcq);
+
+       if (cq->notify != IB_CQ_NEXT_COMP)
+               cq->notify = flags & IB_CQ_SOLICITED_MASK;
+
+       return 0;
+}
+
+static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
+{
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_mem *mr;
+       int err;
+
+       mr = rxe_alloc(&rxe->mr_pool);
+       if (!mr) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       rxe_add_index(mr);
+
+       rxe_add_ref(pd);
+
+       err = rxe_mem_init_dma(rxe, pd, access, mr);
+       if (err)
+               goto err2;
+
+       return &mr->ibmr;
+
+err2:
+       rxe_drop_ref(pd);
+       rxe_drop_index(mr);
+       rxe_drop_ref(mr);
+err1:
+       return ERR_PTR(err);
+}
+
+static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
+                                    u64 start,
+                                    u64 length,
+                                    u64 iova,
+                                    int access, struct ib_udata *udata)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_mem *mr;
+
+       mr = rxe_alloc(&rxe->mr_pool);
+       if (!mr) {
+               err = -ENOMEM;
+               goto err2;
+       }
+
+       rxe_add_index(mr);
+
+       rxe_add_ref(pd);
+
+       err = rxe_mem_init_user(rxe, pd, start, length, iova,
+                               access, udata, mr);
+       if (err)
+               goto err3;
+
+       return &mr->ibmr;
+
+err3:
+       rxe_drop_ref(pd);
+       rxe_drop_index(mr);
+       rxe_drop_ref(mr);
+err2:
+       return ERR_PTR(err);
+}
+
+static int rxe_dereg_mr(struct ib_mr *ibmr)
+{
+       struct rxe_mem *mr = to_rmr(ibmr);
+
+       mr->state = RXE_MEM_STATE_ZOMBIE;
+       rxe_drop_ref(mr->pd);
+       rxe_drop_index(mr);
+       rxe_drop_ref(mr);
+       return 0;
+}
+
+static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd,
+                                 enum ib_mr_type mr_type,
+                                 u32 max_num_sg)
+{
+       struct rxe_dev *rxe = to_rdev(ibpd->device);
+       struct rxe_pd *pd = to_rpd(ibpd);
+       struct rxe_mem *mr;
+       int err;
+
+       if (mr_type != IB_MR_TYPE_MEM_REG)
+               return ERR_PTR(-EINVAL);
+
+       mr = rxe_alloc(&rxe->mr_pool);
+       if (!mr) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       rxe_add_index(mr);
+
+       rxe_add_ref(pd);
+
+       err = rxe_mem_init_fast(rxe, pd, max_num_sg, mr);
+       if (err)
+               goto err2;
+
+       return &mr->ibmr;
+
+err2:
+       rxe_drop_ref(pd);
+       rxe_drop_index(mr);
+       rxe_drop_ref(mr);
+err1:
+       return ERR_PTR(err);
+}
+
+static int rxe_set_page(struct ib_mr *ibmr, u64 addr)
+{
+       struct rxe_mem *mr = to_rmr(ibmr);
+       struct rxe_map *map;
+       struct rxe_phys_buf *buf;
+
+       if (unlikely(mr->nbuf == mr->num_buf))
+               return -ENOMEM;
+
+       map = mr->map[mr->nbuf / RXE_BUF_PER_MAP];
+       buf = &map->buf[mr->nbuf % RXE_BUF_PER_MAP];
+
+       buf->addr = addr;
+       buf->size = ibmr->page_size;
+       mr->nbuf++;
+
+       return 0;
+}
+
+static int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
+                        unsigned int *sg_offset)
+{
+       struct rxe_mem *mr = to_rmr(ibmr);
+       int n;
+
+       mr->nbuf = 0;
+
+       n = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, rxe_set_page);
+
+       mr->va = ibmr->iova;
+       mr->iova = ibmr->iova;
+       mr->length = ibmr->length;
+       mr->page_shift = ilog2(ibmr->page_size);
+       mr->page_mask = ibmr->page_size - 1;
+       mr->offset = mr->iova & mr->page_mask;
+
+       return n;
+}
+
+static int rxe_attach_mcast(struct ib_qp *ibqp, union ib_gid *mgid, u16 mlid)
+{
+       int err;
+       struct rxe_dev *rxe = to_rdev(ibqp->device);
+       struct rxe_qp *qp = to_rqp(ibqp);
+       struct rxe_mc_grp *grp;
+
+       /* takes a ref on grp if successful */
+       err = rxe_mcast_get_grp(rxe, mgid, &grp);
+       if (err)
+               return err;
+
+       err = rxe_mcast_add_grp_elem(rxe, qp, grp);
+
+       rxe_drop_ref(grp);
+       return err;
+}
+
+static int rxe_detach_mcast(struct ib_qp *ibqp, union ib_gid *mgid, u16 mlid)
+{
+       struct rxe_dev *rxe = to_rdev(ibqp->device);
+       struct rxe_qp *qp = to_rqp(ibqp);
+
+       return rxe_mcast_drop_grp_elem(rxe, qp, mgid);
+}
+
+static ssize_t rxe_show_parent(struct device *device,
+                              struct device_attribute *attr, char *buf)
+{
+       struct rxe_dev *rxe = container_of(device, struct rxe_dev,
+                                          ib_dev.dev);
+       char *name;
+
+       name = rxe->ifc_ops->parent_name(rxe, 1);
+       return snprintf(buf, 16, "%s\n", name);
+}
+
+static DEVICE_ATTR(parent, S_IRUGO, rxe_show_parent, NULL);
+
+static struct device_attribute *rxe_dev_attributes[] = {
+       &dev_attr_parent,
+};
+
+int rxe_register_device(struct rxe_dev *rxe)
+{
+       int err;
+       int i;
+       struct ib_device *dev = &rxe->ib_dev;
+
+       strlcpy(dev->name, "rxe%d", IB_DEVICE_NAME_MAX);
+       strlcpy(dev->node_desc, "rxe", sizeof(dev->node_desc));
+
+       dev->owner = THIS_MODULE;
+       dev->node_type = RDMA_NODE_IB_CA;
+       dev->phys_port_cnt = 1;
+       dev->num_comp_vectors = RXE_NUM_COMP_VECTORS;
+       dev->dma_device = rxe->ifc_ops->dma_device(rxe);
+       dev->local_dma_lkey = 0;
+       dev->node_guid = rxe->ifc_ops->node_guid(rxe);
+       dev->dma_ops = &rxe_dma_mapping_ops;
+
+       dev->uverbs_abi_ver = RXE_UVERBS_ABI_VERSION;
+       dev->uverbs_cmd_mask = BIT_ULL(IB_USER_VERBS_CMD_GET_CONTEXT)
+           | BIT_ULL(IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL)
+           | BIT_ULL(IB_USER_VERBS_CMD_QUERY_DEVICE)
+           | BIT_ULL(IB_USER_VERBS_CMD_QUERY_PORT)
+           | BIT_ULL(IB_USER_VERBS_CMD_ALLOC_PD)
+           | BIT_ULL(IB_USER_VERBS_CMD_DEALLOC_PD)
+           | BIT_ULL(IB_USER_VERBS_CMD_CREATE_SRQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_MODIFY_SRQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_QUERY_SRQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_DESTROY_SRQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_POST_SRQ_RECV)
+           | BIT_ULL(IB_USER_VERBS_CMD_CREATE_QP)
+           | BIT_ULL(IB_USER_VERBS_CMD_MODIFY_QP)
+           | BIT_ULL(IB_USER_VERBS_CMD_QUERY_QP)
+           | BIT_ULL(IB_USER_VERBS_CMD_DESTROY_QP)
+           | BIT_ULL(IB_USER_VERBS_CMD_POST_SEND)
+           | BIT_ULL(IB_USER_VERBS_CMD_POST_RECV)
+           | BIT_ULL(IB_USER_VERBS_CMD_CREATE_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_RESIZE_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_DESTROY_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_POLL_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_PEEK_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_REQ_NOTIFY_CQ)
+           | BIT_ULL(IB_USER_VERBS_CMD_REG_MR)
+           | BIT_ULL(IB_USER_VERBS_CMD_DEREG_MR)
+           | BIT_ULL(IB_USER_VERBS_CMD_CREATE_AH)
+           | BIT_ULL(IB_USER_VERBS_CMD_MODIFY_AH)
+           | BIT_ULL(IB_USER_VERBS_CMD_QUERY_AH)
+           | BIT_ULL(IB_USER_VERBS_CMD_DESTROY_AH)
+           | BIT_ULL(IB_USER_VERBS_CMD_ATTACH_MCAST)
+           | BIT_ULL(IB_USER_VERBS_CMD_DETACH_MCAST)
+           ;
+
+       dev->query_device = rxe_query_device;
+       dev->modify_device = rxe_modify_device;
+       dev->query_port = rxe_query_port;
+       dev->modify_port = rxe_modify_port;
+       dev->get_link_layer = rxe_get_link_layer;
+       dev->query_gid = rxe_query_gid;
+       dev->get_netdev = rxe_get_netdev;
+       dev->add_gid = rxe_add_gid;
+       dev->del_gid = rxe_del_gid;
+       dev->query_pkey = rxe_query_pkey;
+       dev->alloc_ucontext = rxe_alloc_ucontext;
+       dev->dealloc_ucontext = rxe_dealloc_ucontext;
+       dev->mmap = rxe_mmap;
+       dev->get_port_immutable = rxe_port_immutable;
+       dev->alloc_pd = rxe_alloc_pd;
+       dev->dealloc_pd = rxe_dealloc_pd;
+       dev->create_ah = rxe_create_ah;
+       dev->modify_ah = rxe_modify_ah;
+       dev->query_ah = rxe_query_ah;
+       dev->destroy_ah = rxe_destroy_ah;
+       dev->create_srq = rxe_create_srq;
+       dev->modify_srq = rxe_modify_srq;
+       dev->query_srq = rxe_query_srq;
+       dev->destroy_srq = rxe_destroy_srq;
+       dev->post_srq_recv = rxe_post_srq_recv;
+       dev->create_qp = rxe_create_qp;
+       dev->modify_qp = rxe_modify_qp;
+       dev->query_qp = rxe_query_qp;
+       dev->destroy_qp = rxe_destroy_qp;
+       dev->post_send = rxe_post_send;
+       dev->post_recv = rxe_post_recv;
+       dev->create_cq = rxe_create_cq;
+       dev->destroy_cq = rxe_destroy_cq;
+       dev->resize_cq = rxe_resize_cq;
+       dev->poll_cq = rxe_poll_cq;
+       dev->peek_cq = rxe_peek_cq;
+       dev->req_notify_cq = rxe_req_notify_cq;
+       dev->get_dma_mr = rxe_get_dma_mr;
+       dev->reg_user_mr = rxe_reg_user_mr;
+       dev->dereg_mr = rxe_dereg_mr;
+       dev->alloc_mr = rxe_alloc_mr;
+       dev->map_mr_sg = rxe_map_mr_sg;
+       dev->attach_mcast = rxe_attach_mcast;
+       dev->detach_mcast = rxe_detach_mcast;
+
+       err = ib_register_device(dev, NULL);
+       if (err) {
+               pr_warn("rxe_register_device failed, err = %d\n", err);
+               goto err1;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i) {
+               err = device_create_file(&dev->dev, rxe_dev_attributes[i]);
+               if (err) {
+                       pr_warn("device_create_file failed, i = %d, err = %d\n",
+                               i, err);
+                       goto err2;
+               }
+       }
+
+       return 0;
+
+err2:
+       ib_unregister_device(dev);
+err1:
+       return err;
+}
+
+int rxe_unregister_device(struct rxe_dev *rxe)
+{
+       int i;
+       struct ib_device *dev = &rxe->ib_dev;
+
+       for (i = 0; i < ARRAY_SIZE(rxe_dev_attributes); ++i)
+               device_remove_file(&dev->dev, rxe_dev_attributes[i]);
+
+       ib_unregister_device(dev);
+
+       return 0;
+}
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
new file mode 100644 (file)
index 0000000..cac1d52
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
+ * Copyright (c) 2015 System Fabric Works, 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 RXE_VERBS_H
+#define RXE_VERBS_H
+
+#include <linux/interrupt.h>
+#include <rdma/rdma_user_rxe.h>
+#include "rxe_pool.h"
+#include "rxe_task.h"
+
+static inline int pkey_match(u16 key1, u16 key2)
+{
+       return (((key1 & 0x7fff) != 0) &&
+               ((key1 & 0x7fff) == (key2 & 0x7fff)) &&
+               ((key1 & 0x8000) || (key2 & 0x8000))) ? 1 : 0;
+}
+
+/* Return >0 if psn_a > psn_b
+ *        0 if psn_a == psn_b
+ *       <0 if psn_a < psn_b
+ */
+static inline int psn_compare(u32 psn_a, u32 psn_b)
+{
+       s32 diff;
+
+       diff = (psn_a - psn_b) << 8;
+       return diff;
+}
+
+struct rxe_ucontext {
+       struct rxe_pool_entry   pelem;
+       struct ib_ucontext      ibuc;
+};
+
+struct rxe_pd {
+       struct rxe_pool_entry   pelem;
+       struct ib_pd            ibpd;
+};
+
+struct rxe_ah {
+       struct rxe_pool_entry   pelem;
+       struct ib_ah            ibah;
+       struct rxe_pd           *pd;
+       struct rxe_av           av;
+};
+
+struct rxe_cqe {
+       union {
+               struct ib_wc            ibwc;
+               struct ib_uverbs_wc     uibwc;
+       };
+};
+
+struct rxe_cq {
+       struct rxe_pool_entry   pelem;
+       struct ib_cq            ibcq;
+       struct rxe_queue        *queue;
+       spinlock_t              cq_lock;
+       u8                      notify;
+       int                     is_user;
+       struct tasklet_struct   comp_task;
+};
+
+enum wqe_state {
+       wqe_state_posted,
+       wqe_state_processing,
+       wqe_state_pending,
+       wqe_state_done,
+       wqe_state_error,
+};
+
+struct rxe_sq {
+       int                     max_wr;
+       int                     max_sge;
+       int                     max_inline;
+       spinlock_t              sq_lock; /* guard queue */
+       struct rxe_queue        *queue;
+};
+
+struct rxe_rq {
+       int                     max_wr;
+       int                     max_sge;
+       spinlock_t              producer_lock; /* guard queue producer */
+       spinlock_t              consumer_lock; /* guard queue consumer */
+       struct rxe_queue        *queue;
+};
+
+struct rxe_srq {
+       struct rxe_pool_entry   pelem;
+       struct ib_srq           ibsrq;
+       struct rxe_pd           *pd;
+       struct rxe_rq           rq;
+       u32                     srq_num;
+
+       int                     limit;
+       int                     error;
+};
+
+enum rxe_qp_state {
+       QP_STATE_RESET,
+       QP_STATE_INIT,
+       QP_STATE_READY,
+       QP_STATE_DRAIN,         /* req only */
+       QP_STATE_DRAINED,       /* req only */
+       QP_STATE_ERROR
+};
+
+extern char *rxe_qp_state_name[];
+
+struct rxe_req_info {
+       enum rxe_qp_state       state;
+       int                     wqe_index;
+       u32                     psn;
+       int                     opcode;
+       atomic_t                rd_atomic;
+       int                     wait_fence;
+       int                     need_rd_atomic;
+       int                     wait_psn;
+       int                     need_retry;
+       int                     noack_pkts;
+       struct rxe_task         task;
+};
+
+struct rxe_comp_info {
+       u32                     psn;
+       int                     opcode;
+       int                     timeout;
+       int                     timeout_retry;
+       u32                     retry_cnt;
+       u32                     rnr_retry;
+       struct rxe_task         task;
+};
+
+enum rdatm_res_state {
+       rdatm_res_state_next,
+       rdatm_res_state_new,
+       rdatm_res_state_replay,
+};
+
+struct resp_res {
+       int                     type;
+       u32                     first_psn;
+       u32                     last_psn;
+       u32                     cur_psn;
+       enum rdatm_res_state    state;
+
+       union {
+               struct {
+                       struct sk_buff  *skb;
+               } atomic;
+               struct {
+                       struct rxe_mem  *mr;
+                       u64             va_org;
+                       u32             rkey;
+                       u32             length;
+                       u64             va;
+                       u32             resid;
+               } read;
+       };
+};
+
+struct rxe_resp_info {
+       enum rxe_qp_state       state;
+       u32                     msn;
+       u32                     psn;
+       int                     opcode;
+       int                     drop_msg;
+       int                     goto_error;
+       int                     sent_psn_nak;
+       enum ib_wc_status       status;
+       u8                      aeth_syndrome;
+
+       /* Receive only */
+       struct rxe_recv_wqe     *wqe;
+
+       /* RDMA read / atomic only */
+       u64                     va;
+       struct rxe_mem          *mr;
+       u32                     resid;
+       u32                     rkey;
+       u64                     atomic_orig;
+
+       /* SRQ only */
+       struct {
+               struct rxe_recv_wqe     wqe;
+               struct ib_sge           sge[RXE_MAX_SGE];
+       } srq_wqe;
+
+       /* Responder resources. It's a circular list where the oldest
+        * resource is dropped first.
+        */
+       struct resp_res         *resources;
+       unsigned int            res_head;
+       unsigned int            res_tail;
+       struct resp_res         *res;
+       struct rxe_task         task;
+};
+
+struct rxe_qp {
+       struct rxe_pool_entry   pelem;
+       struct ib_qp            ibqp;
+       struct ib_qp_attr       attr;
+       unsigned int            valid;
+       unsigned int            mtu;
+       int                     is_user;
+
+       struct rxe_pd           *pd;
+       struct rxe_srq          *srq;
+       struct rxe_cq           *scq;
+       struct rxe_cq           *rcq;
+
+       enum ib_sig_type        sq_sig_type;
+
+       struct rxe_sq           sq;
+       struct rxe_rq           rq;
+
+       struct socket           *sk;
+
+       struct rxe_av           pri_av;
+       struct rxe_av           alt_av;
+
+       /* list of mcast groups qp has joined (for cleanup) */
+       struct list_head        grp_list;
+       spinlock_t              grp_lock; /* guard grp_list */
+
+       struct sk_buff_head     req_pkts;
+       struct sk_buff_head     resp_pkts;
+       struct sk_buff_head     send_pkts;
+
+       struct rxe_req_info     req;
+       struct rxe_comp_info    comp;
+       struct rxe_resp_info    resp;
+
+       atomic_t                ssn;
+       atomic_t                skb_out;
+       int                     need_req_skb;
+
+       /* Timer for retranmitting packet when ACKs have been lost. RC
+        * only. The requester sets it when it is not already
+        * started. The responder resets it whenever an ack is
+        * received.
+        */
+       struct timer_list retrans_timer;
+       u64 qp_timeout_jiffies;
+
+       /* Timer for handling RNR NAKS. */
+       struct timer_list rnr_nak_timer;
+
+       spinlock_t              state_lock; /* guard requester and completer */
+};
+
+enum rxe_mem_state {
+       RXE_MEM_STATE_ZOMBIE,
+       RXE_MEM_STATE_INVALID,
+       RXE_MEM_STATE_FREE,
+       RXE_MEM_STATE_VALID,
+};
+
+enum rxe_mem_type {
+       RXE_MEM_TYPE_NONE,
+       RXE_MEM_TYPE_DMA,
+       RXE_MEM_TYPE_MR,
+       RXE_MEM_TYPE_FMR,
+       RXE_MEM_TYPE_MW,
+};
+
+#define RXE_BUF_PER_MAP                (PAGE_SIZE / sizeof(struct rxe_phys_buf))
+
+struct rxe_phys_buf {
+       u64      addr;
+       u64      size;
+};
+
+struct rxe_map {
+       struct rxe_phys_buf     buf[RXE_BUF_PER_MAP];
+};
+
+struct rxe_mem {
+       struct rxe_pool_entry   pelem;
+       union {
+               struct ib_mr            ibmr;
+               struct ib_mw            ibmw;
+       };
+
+       struct rxe_pd           *pd;
+       struct ib_umem          *umem;
+
+       u32                     lkey;
+       u32                     rkey;
+
+       enum rxe_mem_state      state;
+       enum rxe_mem_type       type;
+       u64                     va;
+       u64                     iova;
+       size_t                  length;
+       u32                     offset;
+       int                     access;
+
+       int                     page_shift;
+       int                     page_mask;
+       int                     map_shift;
+       int                     map_mask;
+
+       u32                     num_buf;
+       u32                     nbuf;
+
+       u32                     max_buf;
+       u32                     num_map;
+
+       struct rxe_map          **map;
+};
+
+struct rxe_mc_grp {
+       struct rxe_pool_entry   pelem;
+       spinlock_t              mcg_lock; /* guard group */
+       struct rxe_dev          *rxe;
+       struct list_head        qp_list;
+       union ib_gid            mgid;
+       int                     num_qp;
+       u32                     qkey;
+       u16                     pkey;
+};
+
+struct rxe_mc_elem {
+       struct rxe_pool_entry   pelem;
+       struct list_head        qp_list;
+       struct list_head        grp_list;
+       struct rxe_qp           *qp;
+       struct rxe_mc_grp       *grp;
+};
+
+struct rxe_port {
+       struct ib_port_attr     attr;
+       u16                     *pkey_tbl;
+       __be64                  port_guid;
+       __be64                  subnet_prefix;
+       spinlock_t              port_lock; /* guard port */
+       unsigned int            mtu_cap;
+       /* special QPs */
+       u32                     qp_smi_index;
+       u32                     qp_gsi_index;
+};
+
+/* callbacks from rdma_rxe to network interface layer */
+struct rxe_ifc_ops {
+       void (*release)(struct rxe_dev *rxe);
+       __be64 (*node_guid)(struct rxe_dev *rxe);
+       __be64 (*port_guid)(struct rxe_dev *rxe);
+       struct device *(*dma_device)(struct rxe_dev *rxe);
+       int (*mcast_add)(struct rxe_dev *rxe, union ib_gid *mgid);
+       int (*mcast_delete)(struct rxe_dev *rxe, union ib_gid *mgid);
+       int (*prepare)(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                      struct sk_buff *skb, u32 *crc);
+       int (*send)(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
+                   struct sk_buff *skb);
+       int (*loopback)(struct sk_buff *skb);
+       struct sk_buff *(*init_packet)(struct rxe_dev *rxe, struct rxe_av *av,
+                                      int paylen, struct rxe_pkt_info *pkt);
+       char *(*parent_name)(struct rxe_dev *rxe, unsigned int port_num);
+       enum rdma_link_layer (*link_layer)(struct rxe_dev *rxe,
+                                          unsigned int port_num);
+};
+
+struct rxe_dev {
+       struct ib_device        ib_dev;
+       struct ib_device_attr   attr;
+       int                     max_ucontext;
+       int                     max_inline_data;
+       struct kref             ref_cnt;
+       struct mutex    usdev_lock;
+
+       struct rxe_ifc_ops      *ifc_ops;
+
+       struct net_device       *ndev;
+
+       int                     xmit_errors;
+
+       struct rxe_pool         uc_pool;
+       struct rxe_pool         pd_pool;
+       struct rxe_pool         ah_pool;
+       struct rxe_pool         srq_pool;
+       struct rxe_pool         qp_pool;
+       struct rxe_pool         cq_pool;
+       struct rxe_pool         mr_pool;
+       struct rxe_pool         mw_pool;
+       struct rxe_pool         mc_grp_pool;
+       struct rxe_pool         mc_elem_pool;
+
+       spinlock_t              pending_lock; /* guard pending_mmaps */
+       struct list_head        pending_mmaps;
+
+       spinlock_t              mmap_offset_lock; /* guard mmap_offset */
+       int                     mmap_offset;
+
+       struct rxe_port         port;
+       struct list_head        list;
+};
+
+static inline struct rxe_dev *to_rdev(struct ib_device *dev)
+{
+       return dev ? container_of(dev, struct rxe_dev, ib_dev) : NULL;
+}
+
+static inline struct rxe_ucontext *to_ruc(struct ib_ucontext *uc)
+{
+       return uc ? container_of(uc, struct rxe_ucontext, ibuc) : NULL;
+}
+
+static inline struct rxe_pd *to_rpd(struct ib_pd *pd)
+{
+       return pd ? container_of(pd, struct rxe_pd, ibpd) : NULL;
+}
+
+static inline struct rxe_ah *to_rah(struct ib_ah *ah)
+{
+       return ah ? container_of(ah, struct rxe_ah, ibah) : NULL;
+}
+
+static inline struct rxe_srq *to_rsrq(struct ib_srq *srq)
+{
+       return srq ? container_of(srq, struct rxe_srq, ibsrq) : NULL;
+}
+
+static inline struct rxe_qp *to_rqp(struct ib_qp *qp)
+{
+       return qp ? container_of(qp, struct rxe_qp, ibqp) : NULL;
+}
+
+static inline struct rxe_cq *to_rcq(struct ib_cq *cq)
+{
+       return cq ? container_of(cq, struct rxe_cq, ibcq) : NULL;
+}
+
+static inline struct rxe_mem *to_rmr(struct ib_mr *mr)
+{
+       return mr ? container_of(mr, struct rxe_mem, ibmr) : NULL;
+}
+
+static inline struct rxe_mem *to_rmw(struct ib_mw *mw)
+{
+       return mw ? container_of(mw, struct rxe_mem, ibmw) : NULL;
+}
+
+int rxe_register_device(struct rxe_dev *rxe);
+int rxe_unregister_device(struct rxe_dev *rxe);
+
+void rxe_mc_cleanup(void *arg);
+
+#endif /* RXE_VERBS_H */
index 1502199..7b6d40f 100644 (file)
@@ -62,10 +62,8 @@ static void ipoib_get_drvinfo(struct net_device *netdev,
 {
        struct ipoib_dev_priv *priv = netdev_priv(netdev);
 
-       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
-                "%d.%d.%d", (int)(priv->ca->attrs.fw_ver >> 32),
-                (int)(priv->ca->attrs.fw_ver >> 16) & 0xffff,
-                (int)priv->ca->attrs.fw_ver & 0xffff);
+       ib_get_device_fw_str(priv->ca, drvinfo->fw_version,
+                            sizeof(drvinfo->fw_version));
 
        strlcpy(drvinfo->bus_info, dev_name(priv->ca->dma_device),
                sizeof(drvinfo->bus_info));
index 5f58c41..74bcaa0 100644 (file)
@@ -1967,8 +1967,7 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca)
        priv->hca_caps = hca->attrs.device_cap_flags;
 
        if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) {
-               priv->dev->hw_features = NETIF_F_SG |
-                       NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+               priv->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
 
                if (priv->hca_caps & IB_DEVICE_UD_TSO)
                        priv->dev->hw_features |= NETIF_F_TSO;
index 1e7cbba..c55ecb2 100644 (file)
@@ -135,7 +135,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
                .cap = {
                        .max_send_wr  = ipoib_sendq_size,
                        .max_recv_wr  = ipoib_recvq_size,
-                       .max_send_sge = 1,
+                       .max_send_sge = min_t(u32, priv->ca->attrs.max_sge,
+                                             MAX_SKB_FRAGS + 1),
                        .max_recv_sge = IPOIB_UD_RX_SG
                },
                .sq_sig_type = IB_SIGNAL_ALL_WR,
@@ -205,10 +206,6 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
        if (priv->hca_caps & IB_DEVICE_MANAGED_FLOW_STEERING)
                init_attr.create_flags |= IB_QP_CREATE_NETIF_QP;
 
-       if (dev->features & NETIF_F_SG)
-               init_attr.cap.max_send_sge =
-                       min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
-
        priv->qp = ib_create_qp(priv->pd, &init_attr);
        if (IS_ERR(priv->qp)) {
                printk(KERN_WARNING "%s: failed to create QP\n", ca->name);
@@ -234,6 +231,9 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
        priv->rx_wr.next = NULL;
        priv->rx_wr.sg_list = priv->rx_sge;
 
+       if (init_attr.cap.max_send_sge > 1)
+               dev->features |= NETIF_F_SG;
+
        priv->max_send_sge = init_attr.cap.max_send_sge;
 
        return 0;
index a990c04..ba6be06 100644 (file)
@@ -137,8 +137,6 @@ isert_create_qp(struct isert_conn *isert_conn,
        attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1;
        attr.cap.max_rdma_ctxs = ISCSI_DEF_XMIT_CMDS_MAX;
        attr.cap.max_send_sge = device->ib_device->attrs.max_sge;
-       isert_conn->max_sge = min(device->ib_device->attrs.max_sge,
-                                 device->ib_device->attrs.max_sge_rd);
        attr.cap.max_recv_sge = 1;
        attr.sq_sig_type = IB_SIGNAL_REQ_WR;
        attr.qp_type = IB_QPT_RC;
index e512ba9..fc791ef 100644 (file)
@@ -138,7 +138,6 @@ struct isert_conn {
        u32                     responder_resources;
        u32                     initiator_depth;
        bool                    pi_support;
-       u32                     max_sge;
        struct iser_rx_desc     *login_req_buf;
        char                    *login_rsp_buf;
        u64                     login_req_dma;
index 4a41556..dfa23b0 100644 (file)
@@ -1601,6 +1601,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
        struct ib_qp_init_attr *qp_init;
        struct srpt_port *sport = ch->sport;
        struct srpt_device *sdev = sport->sdev;
+       const struct ib_device_attr *attrs = &sdev->device->attrs;
        u32 srp_sq_size = sport->port_attrib.srp_sq_size;
        int ret;
 
@@ -1638,7 +1639,7 @@ retry:
         */
        qp_init->cap.max_send_wr = srp_sq_size / 2;
        qp_init->cap.max_rdma_ctxs = srp_sq_size / 2;
-       qp_init->cap.max_send_sge = SRPT_DEF_SG_PER_WQE;
+       qp_init->cap.max_send_sge = min(attrs->max_sge, SRPT_MAX_SG_PER_WQE);
        qp_init->port_num = ch->sport->port;
 
        ch->qp = ib_create_qp(sdev->pd, qp_init);
@@ -2261,7 +2262,7 @@ static void srpt_queue_response(struct se_cmd *cmd)
                container_of(cmd, struct srpt_send_ioctx, cmd);
        struct srpt_rdma_ch *ch = ioctx->ch;
        struct srpt_device *sdev = ch->sport->sdev;
-       struct ib_send_wr send_wr, *first_wr = NULL, *bad_wr;
+       struct ib_send_wr send_wr, *first_wr = &send_wr, *bad_wr;
        struct ib_sge sge;
        enum srpt_command_state state;
        unsigned long flags;
@@ -2302,11 +2303,8 @@ static void srpt_queue_response(struct se_cmd *cmd)
                        struct srpt_rw_ctx *ctx = &ioctx->rw_ctxs[i];
 
                        first_wr = rdma_rw_ctx_wrs(&ctx->rw, ch->qp,
-                                       ch->sport->port, NULL,
-                                       first_wr ? first_wr : &send_wr);
+                                       ch->sport->port, NULL, first_wr);
                }
-       } else {
-               first_wr = &send_wr;
        }
 
        if (state != SRPT_STATE_MGMT)
index 3890304..5818787 100644 (file)
@@ -106,7 +106,11 @@ enum {
        SRP_LOGIN_RSP_MULTICHAN_MAINTAINED = 0x2,
 
        SRPT_DEF_SG_TABLESIZE = 128,
-       SRPT_DEF_SG_PER_WQE = 16,
+       /*
+        * An experimentally determined value that avoids that QP creation
+        * fails due to "swiotlb buffer is full" on systems using the swiotlb.
+        */
+       SRPT_MAX_SG_PER_WQE = 16,
 
        MIN_SRPT_SQ_SIZE = 16,
        DEF_SRPT_SQ_SIZE = 4096,
index a529a45..83af17a 100644 (file)
@@ -115,6 +115,10 @@ static bool sticks_to_null;
 module_param(sticks_to_null, bool, S_IRUGO);
 MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
 
+static bool auto_poweroff = true;
+module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend");
+
 static const struct xpad_device {
        u16 idVendor;
        u16 idProduct;
@@ -1248,6 +1252,36 @@ static void xpad_stop_input(struct usb_xpad *xpad)
        usb_kill_urb(xpad->irq_in);
 }
 
+static void xpad360w_poweroff_controller(struct usb_xpad *xpad)
+{
+       unsigned long flags;
+       struct xpad_output_packet *packet =
+                       &xpad->out_packets[XPAD_OUT_CMD_IDX];
+
+       spin_lock_irqsave(&xpad->odata_lock, flags);
+
+       packet->data[0] = 0x00;
+       packet->data[1] = 0x00;
+       packet->data[2] = 0x08;
+       packet->data[3] = 0xC0;
+       packet->data[4] = 0x00;
+       packet->data[5] = 0x00;
+       packet->data[6] = 0x00;
+       packet->data[7] = 0x00;
+       packet->data[8] = 0x00;
+       packet->data[9] = 0x00;
+       packet->data[10] = 0x00;
+       packet->data[11] = 0x00;
+       packet->len = 12;
+       packet->pending = true;
+
+       /* Reset the sequence so we send out poweroff now */
+       xpad->last_out_packet = -1;
+       xpad_try_sending_next_out_packet(xpad);
+
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
+}
+
 static int xpad360w_start_input(struct usb_xpad *xpad)
 {
        int error;
@@ -1590,6 +1624,15 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
                 * or goes away.
                 */
                xpad360w_stop_input(xpad);
+
+               /*
+                * The wireless adapter is going off now, so the
+                * gamepads are going to become disconnected.
+                * Unless explicitly disabled, power them down
+                * so they don't just sit there flashing.
+                */
+               if (auto_poweroff && xpad->pad_present)
+                       xpad360w_poweroff_controller(xpad);
        } else {
                mutex_lock(&input->mutex);
                if (input->users)
index b01966d..4b0878f 100644 (file)
@@ -186,7 +186,7 @@ static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
        if (ret >= 0)
                cros_ec_keyb_process(ckdev, kb_state, ret);
        else
-               dev_err(ec->dev, "failed to get keyboard state: %d\n", ret);
+               dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret);
 
        return IRQ_HANDLED;
 }
@@ -236,7 +236,7 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev)
 static int cros_ec_keyb_probe(struct platform_device *pdev)
 {
        struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
-       struct device *dev = ec->dev;
+       struct device *dev = &pdev->dev;
        struct cros_ec_keyb *ckdev;
        struct input_dev *idev;
        struct device_node *np;
@@ -246,23 +246,22 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
        if (!np)
                return -ENODEV;
 
-       ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL);
+       ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
        if (!ckdev)
                return -ENOMEM;
-       err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows,
-                                           &ckdev->cols);
+       err = matrix_keypad_parse_of_params(dev, &ckdev->rows, &ckdev->cols);
        if (err)
                return err;
 
-       ckdev->valid_keys = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL);
+       ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL);
        if (!ckdev->valid_keys)
                return -ENOMEM;
 
-       ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL);
+       ckdev->old_kb_state = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL);
        if (!ckdev->old_kb_state)
                return -ENOMEM;
 
-       idev = devm_input_allocate_device(&pdev->dev);
+       idev = devm_input_allocate_device(dev);
        if (!idev)
                return -ENOMEM;
 
@@ -273,7 +272,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
 
        ckdev->ec = ec;
        ckdev->dev = dev;
-       dev_set_drvdata(&pdev->dev, ckdev);
+       dev_set_drvdata(dev, ckdev);
 
        idev->name = CROS_EC_DEV_NAME;
        idev->phys = ec->phys_name;
@@ -282,7 +281,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
        idev->id.bustype = BUS_VIRTUAL;
        idev->id.version = 1;
        idev->id.product = 0;
-       idev->dev.parent = &pdev->dev;
+       idev->dev.parent = dev;
        idev->open = cros_ec_keyb_open;
        idev->close = cros_ec_keyb_close;
 
index c7fc8d4..1588aec 100644 (file)
 
 #define DRV_NAME "rotary-encoder"
 
+enum rotary_encoder_encoding {
+       ROTENC_GRAY,
+       ROTENC_BINARY,
+};
+
 struct rotary_encoder {
        struct input_dev *input;
 
@@ -37,6 +42,7 @@ struct rotary_encoder {
        u32 axis;
        bool relative_axis;
        bool rollover;
+       enum rotary_encoder_encoding encoding;
 
        unsigned int pos;
 
@@ -57,8 +63,9 @@ static unsigned int rotary_encoder_get_state(struct rotary_encoder *encoder)
 
        for (i = 0; i < encoder->gpios->ndescs; ++i) {
                int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]);
+
                /* convert from gray encoding to normal */
-               if (ret & 1)
+               if (encoder->encoding == ROTENC_GRAY && ret & 1)
                        val = !val;
 
                ret = ret << 1 | val;
@@ -213,6 +220,20 @@ static int rotary_encoder_probe(struct platform_device *pdev)
        encoder->rollover =
                device_property_read_bool(dev, "rotary-encoder,rollover");
 
+       if (!device_property_present(dev, "rotary-encoder,encoding") ||
+           !device_property_match_string(dev, "rotary-encoder,encoding",
+                                         "gray")) {
+               dev_info(dev, "gray");
+               encoder->encoding = ROTENC_GRAY;
+       } else if (!device_property_match_string(dev, "rotary-encoder,encoding",
+                                                "binary")) {
+               dev_info(dev, "binary");
+               encoder->encoding = ROTENC_BINARY;
+       } else {
+               dev_err(dev, "unknown encoding setting\n");
+               return -EINVAL;
+       }
+
        device_property_read_u32(dev, "linux,axis", &encoder->axis);
        encoder->relative_axis =
                device_property_read_bool(dev, "rotary-encoder,relative-axis");
index 2f58985..d15b338 100644 (file)
@@ -4,7 +4,8 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.6.0
+ * Author: KT Liao <kt.liao@emc.com.tw>
+ * Version: 1.6.2
  *
  * Based on cyapa driver:
  * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +41,7 @@
 #include "elan_i2c.h"
 
 #define DRIVER_NAME            "elan_i2c"
-#define ELAN_DRIVER_VERSION    "1.6.1"
+#define ELAN_DRIVER_VERSION    "1.6.2"
 #define ELAN_VENDOR_ID         0x04f3
 #define ETP_MAX_PRESSURE       255
 #define ETP_FWIDTH_REDUCE      90
@@ -199,9 +200,41 @@ static int elan_sleep(struct elan_tp_data *data)
        return error;
 }
 
+static int elan_query_product(struct elan_tp_data *data)
+{
+       int error;
+
+       error = data->ops->get_product_id(data->client, &data->product_id);
+       if (error)
+               return error;
+
+       error = data->ops->get_sm_version(data->client, &data->ic_type,
+                                         &data->sm_version);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
+{
+       if (data->ic_type != 0x0E)
+               return false;
+
+       switch (data->product_id) {
+       case 0x05 ... 0x07:
+       case 0x09:
+       case 0x13:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int __elan_initialize(struct elan_tp_data *data)
 {
        struct i2c_client *client = data->client;
+       bool woken_up = false;
        int error;
 
        error = data->ops->initialize(client);
@@ -210,6 +243,27 @@ static int __elan_initialize(struct elan_tp_data *data)
                return error;
        }
 
+       error = elan_query_product(data);
+       if (error)
+               return error;
+
+       /*
+        * Some ASUS devices were shipped with firmware that requires
+        * touchpads to be woken up first, before attempting to switch
+        * them into absolute reporting mode.
+        */
+       if (elan_check_ASUS_special_fw(data)) {
+               error = data->ops->sleep_control(client, false);
+               if (error) {
+                       dev_err(&client->dev,
+                               "failed to wake device up: %d\n", error);
+                       return error;
+               }
+
+               msleep(200);
+               woken_up = true;
+       }
+
        data->mode |= ETP_ENABLE_ABS;
        error = data->ops->set_mode(client, data->mode);
        if (error) {
@@ -218,11 +272,13 @@ static int __elan_initialize(struct elan_tp_data *data)
                return error;
        }
 
-       error = data->ops->sleep_control(client, false);
-       if (error) {
-               dev_err(&client->dev,
-                       "failed to wake device up: %d\n", error);
-               return error;
+       if (!woken_up) {
+               error = data->ops->sleep_control(client, false);
+               if (error) {
+                       dev_err(&client->dev,
+                               "failed to wake device up: %d\n", error);
+                       return error;
+               }
        }
 
        return 0;
@@ -248,10 +304,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
 {
        int error;
 
-       error = data->ops->get_product_id(data->client, &data->product_id);
-       if (error)
-               return error;
-
        error = data->ops->get_version(data->client, false, &data->fw_version);
        if (error)
                return error;
@@ -261,11 +313,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
        if (error)
                return error;
 
-       error = data->ops->get_sm_version(data->client, &data->ic_type,
-                                         &data->sm_version);
-       if (error)
-               return error;
-
        error = data->ops->get_version(data->client, true, &data->iap_version);
        if (error)
                return error;
index 615d23e..08e252a 100644 (file)
@@ -222,12 +222,8 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
  */
 static void elantech_packet_dump(struct psmouse *psmouse)
 {
-       int     i;
-
-       psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet [");
-       for (i = 0; i < psmouse->pktsize; i++)
-               printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]);
-       printk("]\n");
+       psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet [%*ph]\n",
+                      psmouse->pktsize, psmouse->packet);
 }
 
 /*
index 253df96..a735806 100644 (file)
@@ -232,10 +232,7 @@ err_put_device:
 void rmi_unregister_function(struct rmi_function *fn)
 {
        device_del(&fn->dev);
-
-       if (fn->dev.of_node)
-               of_node_put(fn->dev.of_node);
-
+       of_node_put(fn->dev.of_node);
        put_device(&fn->dev);
 }
 
index 4541957..b4d3408 100644 (file)
@@ -1277,6 +1277,7 @@ static int __init i8042_create_kbd_port(void)
        serio->start            = i8042_start;
        serio->stop             = i8042_stop;
        serio->close            = i8042_port_close;
+       serio->ps2_cmd_mutex    = &i8042_mutex;
        serio->port_data        = port;
        serio->dev.parent       = &i8042_platform_device->dev;
        strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
@@ -1373,21 +1374,6 @@ static void i8042_unregister_ports(void)
        }
 }
 
-/*
- * Checks whether port belongs to i8042 controller.
- */
-bool i8042_check_port_owner(const struct serio *port)
-{
-       int i;
-
-       for (i = 0; i < I8042_NUM_PORTS; i++)
-               if (i8042_ports[i].serio == port)
-                       return true;
-
-       return false;
-}
-EXPORT_SYMBOL(i8042_check_port_owner);
-
 static void i8042_free_irqs(void)
 {
        if (i8042_aux_irq_registered)
index 316f2c8..83e9c66 100644 (file)
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte);
 
 void ps2_begin_command(struct ps2dev *ps2dev)
 {
-       mutex_lock(&ps2dev->cmd_mutex);
+       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-       if (i8042_check_port_owner(ps2dev->serio))
-               i8042_lock_chip();
+       mutex_lock(m);
 }
 EXPORT_SYMBOL(ps2_begin_command);
 
 void ps2_end_command(struct ps2dev *ps2dev)
 {
-       if (i8042_check_port_owner(ps2dev->serio))
-               i8042_unlock_chip();
+       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-       mutex_unlock(&ps2dev->cmd_mutex);
+       mutex_unlock(m);
 }
 EXPORT_SYMBOL(ps2_end_command);
 
index ee02dc7..2fb1f43 100644 (file)
@@ -1059,6 +1059,31 @@ config TOUCHSCREEN_RM_TS
          To compile this driver as a module, choose M here: the
          module will be called raydium_i2c_ts.
 
+config TOUCHSCREEN_SILEAD
+       tristate "Silead I2C touchscreen"
+       depends on I2C
+       help
+         Say Y here if you have the Silead touchscreen connected to
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called silead.
+
+config TOUCHSCREEN_SIS_I2C
+       tristate "SiS 9200 family I2C touchscreen"
+       depends on I2C
+       select CRC_ITU_T
+       depends on GPIOLIB || COMPILE_TEST
+       help
+         This enables support for SiS 9200 family over I2C based touchscreens.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sis_i2c.
+
 config TOUCHSCREEN_ST1232
        tristate "Sitronix ST1232 touchscreen controllers"
        depends on I2C
index 3315882..b4373d6 100644 (file)
@@ -64,6 +64,8 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)    += penmount.o
 obj-$(CONFIG_TOUCHSCREEN_PIXCIR)       += pixcir_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_RM_TS)                += raydium_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SILEAD)       += silead.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)      += sis_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)       += st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
 obj-$(CONFIG_TOUCHSCREEN_SUN4I)                += sun4i-ts.o
index ddf694b..fe4848b 100644 (file)
@@ -169,7 +169,7 @@ static ssize_t ili210x_calibrate(struct device *dev,
 
        return count;
 }
-static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
+static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
 
 static struct attribute *ili210x_attributes[] = {
        &dev_attr_calibrate.attr,
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
new file mode 100644 (file)
index 0000000..7379fe1
--- /dev/null
@@ -0,0 +1,565 @@
+/* -------------------------------------------------------------------------
+ * Copyright (C) 2014-2015, Intel Corporation
+ *
+ * Derived from:
+ *  gslX68X.c
+ *  Copyright (C) 2010-2015, Shanghai Sileadinc Co.Ltd
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * -------------------------------------------------------------------------
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/pm.h>
+#include <linux/irq.h>
+
+#include <asm/unaligned.h>
+
+#define SILEAD_TS_NAME         "silead_ts"
+
+#define SILEAD_REG_RESET       0xE0
+#define SILEAD_REG_DATA                0x80
+#define SILEAD_REG_TOUCH_NR    0x80
+#define SILEAD_REG_POWER       0xBC
+#define SILEAD_REG_CLOCK       0xE4
+#define SILEAD_REG_STATUS      0xB0
+#define SILEAD_REG_ID          0xFC
+#define SILEAD_REG_MEM_CHECK   0xB0
+
+#define SILEAD_STATUS_OK       0x5A5A5A5A
+#define SILEAD_TS_DATA_LEN     44
+#define SILEAD_CLOCK           0x04
+
+#define SILEAD_CMD_RESET       0x88
+#define SILEAD_CMD_START       0x00
+
+#define SILEAD_POINT_DATA_LEN  0x04
+#define SILEAD_POINT_Y_OFF      0x00
+#define SILEAD_POINT_Y_MSB_OFF 0x01
+#define SILEAD_POINT_X_OFF     0x02
+#define SILEAD_POINT_X_MSB_OFF 0x03
+#define SILEAD_TOUCH_ID_MASK   0xF0
+
+#define SILEAD_CMD_SLEEP_MIN   10000
+#define SILEAD_CMD_SLEEP_MAX   20000
+#define SILEAD_POWER_SLEEP     20
+#define SILEAD_STARTUP_SLEEP   30
+
+#define SILEAD_MAX_FINGERS     10
+
+enum silead_ts_power {
+       SILEAD_POWER_ON  = 1,
+       SILEAD_POWER_OFF = 0
+};
+
+struct silead_ts_data {
+       struct i2c_client *client;
+       struct gpio_desc *gpio_power;
+       struct input_dev *input;
+       char fw_name[64];
+       struct touchscreen_properties prop;
+       u32 max_fingers;
+       u32 chip_id;
+       struct input_mt_pos pos[SILEAD_MAX_FINGERS];
+       int slots[SILEAD_MAX_FINGERS];
+       int id[SILEAD_MAX_FINGERS];
+};
+
+struct silead_fw_data {
+       u32 offset;
+       u32 val;
+};
+
+static int silead_ts_request_input_dev(struct silead_ts_data *data)
+{
+       struct device *dev = &data->client->dev;
+       int error;
+
+       data->input = devm_input_allocate_device(dev);
+       if (!data->input) {
+               dev_err(dev,
+                       "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
+       input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
+       touchscreen_parse_properties(data->input, true, &data->prop);
+
+       input_mt_init_slots(data->input, data->max_fingers,
+                           INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
+                           INPUT_MT_TRACK);
+
+       data->input->name = SILEAD_TS_NAME;
+       data->input->phys = "input/ts";
+       data->input->id.bustype = BUS_I2C;
+
+       error = input_register_device(data->input);
+       if (error) {
+               dev_err(dev, "Failed to register input device: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static void silead_ts_set_power(struct i2c_client *client,
+                               enum silead_ts_power state)
+{
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+
+       if (data->gpio_power) {
+               gpiod_set_value_cansleep(data->gpio_power, state);
+               msleep(SILEAD_POWER_SLEEP);
+       }
+}
+
+static void silead_ts_read_data(struct i2c_client *client)
+{
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+       struct input_dev *input = data->input;
+       struct device *dev = &client->dev;
+       u8 *bufp, buf[SILEAD_TS_DATA_LEN];
+       int touch_nr, error, i;
+
+       error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA,
+                                             SILEAD_TS_DATA_LEN, buf);
+       if (error < 0) {
+               dev_err(dev, "Data read error %d\n", error);
+               return;
+       }
+
+       touch_nr = buf[0];
+       if (touch_nr > data->max_fingers) {
+               dev_warn(dev, "More touches reported then supported %d > %d\n",
+                        touch_nr, data->max_fingers);
+               touch_nr = data->max_fingers;
+       }
+
+       bufp = buf + SILEAD_POINT_DATA_LEN;
+       for (i = 0; i < touch_nr; i++, bufp += SILEAD_POINT_DATA_LEN) {
+               /* Bits 4-7 are the touch id */
+               data->id[i] = (bufp[SILEAD_POINT_X_MSB_OFF] &
+                              SILEAD_TOUCH_ID_MASK) >> 4;
+               touchscreen_set_mt_pos(&data->pos[i], &data->prop,
+                       get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff,
+                       get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff);
+       }
+
+       input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0);
+
+       for (i = 0; i < touch_nr; i++) {
+               input_mt_slot(input, data->slots[i]);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+               input_report_abs(input, ABS_MT_POSITION_X, data->pos[i].x);
+               input_report_abs(input, ABS_MT_POSITION_Y, data->pos[i].y);
+
+               dev_dbg(dev, "x=%d y=%d hw_id=%d sw_id=%d\n", data->pos[i].x,
+                       data->pos[i].y, data->id[i], data->slots[i]);
+       }
+
+       input_mt_sync_frame(input);
+       input_sync(input);
+}
+
+static int silead_ts_init(struct i2c_client *client)
+{
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+       int error;
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+                                         SILEAD_CMD_RESET);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
+                                       data->max_fingers);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
+                                         SILEAD_CLOCK);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+                                         SILEAD_CMD_START);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       return 0;
+
+i2c_write_err:
+       dev_err(&client->dev, "Registers clear error %d\n", error);
+       return error;
+}
+
+static int silead_ts_reset(struct i2c_client *client)
+{
+       int error;
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+                                         SILEAD_CMD_RESET);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
+                                         SILEAD_CLOCK);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_POWER,
+                                         SILEAD_CMD_START);
+       if (error)
+               goto i2c_write_err;
+       usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+       return 0;
+
+i2c_write_err:
+       dev_err(&client->dev, "Chip reset error %d\n", error);
+       return error;
+}
+
+static int silead_ts_startup(struct i2c_client *client)
+{
+       int error;
+
+       error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, 0x00);
+       if (error) {
+               dev_err(&client->dev, "Startup error %d\n", error);
+               return error;
+       }
+
+       msleep(SILEAD_STARTUP_SLEEP);
+
+       return 0;
+}
+
+static int silead_ts_load_fw(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+       unsigned int fw_size, i;
+       const struct firmware *fw;
+       struct silead_fw_data *fw_data;
+       int error;
+
+       dev_dbg(dev, "Firmware file name: %s", data->fw_name);
+
+       error = request_firmware(&fw, data->fw_name, dev);
+       if (error) {
+               dev_err(dev, "Firmware request error %d\n", error);
+               return error;
+       }
+
+       fw_size = fw->size / sizeof(*fw_data);
+       fw_data = (struct silead_fw_data *)fw->data;
+
+       for (i = 0; i < fw_size; i++) {
+               error = i2c_smbus_write_i2c_block_data(client,
+                                                      fw_data[i].offset,
+                                                      4,
+                                                      (u8 *)&fw_data[i].val);
+               if (error) {
+                       dev_err(dev, "Firmware load error %d\n", error);
+                       break;
+               }
+       }
+
+       release_firmware(fw);
+       return error ?: 0;
+}
+
+static u32 silead_ts_get_status(struct i2c_client *client)
+{
+       int error;
+       __le32 status;
+
+       error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_STATUS,
+                                             sizeof(status), (u8 *)&status);
+       if (error < 0) {
+               dev_err(&client->dev, "Status read error %d\n", error);
+               return error;
+       }
+
+       return le32_to_cpu(status);
+}
+
+static int silead_ts_get_id(struct i2c_client *client)
+{
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+       __le32 chip_id;
+       int error;
+
+       error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
+                                             sizeof(chip_id), (u8 *)&chip_id);
+       if (error < 0) {
+               dev_err(&client->dev, "Chip ID read error %d\n", error);
+               return error;
+       }
+
+       data->chip_id = le32_to_cpu(chip_id);
+       dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id);
+
+       return 0;
+}
+
+static int silead_ts_setup(struct i2c_client *client)
+{
+       int error;
+       u32 status;
+
+       silead_ts_set_power(client, SILEAD_POWER_OFF);
+       silead_ts_set_power(client, SILEAD_POWER_ON);
+
+       error = silead_ts_get_id(client);
+       if (error)
+               return error;
+
+       error = silead_ts_init(client);
+       if (error)
+               return error;
+
+       error = silead_ts_reset(client);
+       if (error)
+               return error;
+
+       error = silead_ts_load_fw(client);
+       if (error)
+               return error;
+
+       error = silead_ts_startup(client);
+       if (error)
+               return error;
+
+       status = silead_ts_get_status(client);
+       if (status != SILEAD_STATUS_OK) {
+               dev_err(&client->dev,
+                       "Initialization error, status: 0x%X\n", status);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static irqreturn_t silead_ts_threaded_irq_handler(int irq, void *id)
+{
+       struct silead_ts_data *data = id;
+       struct i2c_client *client = data->client;
+
+       silead_ts_read_data(client);
+
+       return IRQ_HANDLED;
+}
+
+static void silead_ts_read_props(struct i2c_client *client)
+{
+       struct silead_ts_data *data = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+       const char *str;
+       int error;
+
+       error = device_property_read_u32(dev, "silead,max-fingers",
+                                        &data->max_fingers);
+       if (error) {
+               dev_dbg(dev, "Max fingers read error %d\n", error);
+               data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
+       }
+
+       error = device_property_read_string(dev, "touchscreen-fw-name", &str);
+       if (!error)
+               snprintf(data->fw_name, sizeof(data->fw_name), "%s", str);
+       else
+               dev_dbg(dev, "Firmware file name read error. Using default.");
+}
+
+#ifdef CONFIG_ACPI
+static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
+                                        const struct i2c_device_id *id)
+{
+       const struct acpi_device_id *acpi_id;
+       struct device *dev = &data->client->dev;
+       int i;
+
+       if (ACPI_HANDLE(dev)) {
+               acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+               if (!acpi_id)
+                       return -ENODEV;
+
+               snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw",
+                       acpi_id->id);
+
+               for (i = 0; i < strlen(data->fw_name); i++)
+                       data->fw_name[i] = tolower(data->fw_name[i]);
+       } else {
+               snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw",
+                       id->name);
+       }
+
+       return 0;
+}
+#else
+static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
+                                        const struct i2c_device_id *id)
+{
+       snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw", id->name);
+       return 0;
+}
+#endif
+
+static int silead_ts_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       struct silead_ts_data *data;
+       struct device *dev = &client->dev;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_I2C |
+                                    I2C_FUNC_SMBUS_READ_I2C_BLOCK |
+                                    I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+               dev_err(dev, "I2C functionality check failed\n");
+               return -ENXIO;
+       }
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       data->client = client;
+
+       error = silead_ts_set_default_fw_name(data, id);
+       if (error)
+               return error;
+
+       silead_ts_read_props(client);
+
+       /* We must have the IRQ provided by DT or ACPI subsytem */
+       if (client->irq <= 0)
+               return -ENODEV;
+
+       /* Power GPIO pin */
+       data->gpio_power = gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
+       if (IS_ERR(data->gpio_power)) {
+               if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
+                       dev_err(dev, "Shutdown GPIO request failed\n");
+               return PTR_ERR(data->gpio_power);
+       }
+
+       error = silead_ts_setup(client);
+       if (error)
+               return error;
+
+       error = silead_ts_request_input_dev(data);
+       if (error)
+               return error;
+
+       error = devm_request_threaded_irq(dev, client->irq,
+                                         NULL, silead_ts_threaded_irq_handler,
+                                         IRQF_ONESHOT, client->name, data);
+       if (error) {
+               if (error != -EPROBE_DEFER)
+                       dev_err(dev, "IRQ request failed %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused silead_ts_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       silead_ts_set_power(client, SILEAD_POWER_OFF);
+       return 0;
+}
+
+static int __maybe_unused silead_ts_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int error, status;
+
+       silead_ts_set_power(client, SILEAD_POWER_ON);
+
+       error = silead_ts_reset(client);
+       if (error)
+               return error;
+
+       error = silead_ts_startup(client);
+       if (error)
+               return error;
+
+       status = silead_ts_get_status(client);
+       if (status != SILEAD_STATUS_OK) {
+               dev_err(dev, "Resume error, status: 0x%02x\n", status);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
+
+static const struct i2c_device_id silead_ts_id[] = {
+       { "gsl1680", 0 },
+       { "gsl1688", 0 },
+       { "gsl3670", 0 },
+       { "gsl3675", 0 },
+       { "gsl3692", 0 },
+       { "mssl1680", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, silead_ts_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id silead_ts_acpi_match[] = {
+       { "GSL1680", 0 },
+       { "GSL1688", 0 },
+       { "GSL3670", 0 },
+       { "GSL3675", 0 },
+       { "GSL3692", 0 },
+       { "MSSL1680", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
+#endif
+
+static struct i2c_driver silead_ts_driver = {
+       .probe = silead_ts_probe,
+       .id_table = silead_ts_id,
+       .driver = {
+               .name = SILEAD_TS_NAME,
+               .acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
+               .pm = &silead_ts_pm,
+       },
+};
+module_i2c_driver(silead_ts_driver);
+
+MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>");
+MODULE_DESCRIPTION("Silead I2C touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c
new file mode 100644 (file)
index 0000000..8d93f8c
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Touch Screen driver for SiS 9200 family I2C Touch panels
+ *
+ * Copyright (C) 2015 SiS, Inc.
+ * Copyright (C) 2016 Nextfour Group
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/crc-itu-t.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define SIS_I2C_NAME           "sis_i2c_ts"
+
+/*
+ * The I2C packet format:
+ * le16                byte count
+ * u8          Report ID
+ * <contact data - variable length>
+ * u8          Number of contacts
+ * le16                Scan Time (optional)
+ * le16                CRC
+ *
+ * One touch point information consists of 6+ bytes, the order is:
+ * u8          contact state
+ * u8          finger id
+ * le16                x axis
+ * le16                y axis
+ * u8          contact width (optional)
+ * u8          contact height (optional)
+ * u8          pressure (optional)
+ *
+ * Maximum amount of data transmitted in one shot is 64 bytes, if controller
+ * needs to report more contacts than fit in one packet it will send true
+ * number of contacts in first packet and 0 as number of contacts in second
+ * packet.
+ */
+
+#define SIS_MAX_PACKET_SIZE            64
+
+#define SIS_PKT_LEN_OFFSET             0
+#define SIS_PKT_REPORT_OFFSET          2 /* Report ID/type */
+#define SIS_PKT_CONTACT_OFFSET         3 /* First contact */
+
+#define SIS_SCAN_TIME_LEN              2
+
+/* Supported report types */
+#define SIS_ALL_IN_ONE_PACKAGE         0x10
+#define SIS_PKT_IS_TOUCH(x)            (((x) & 0x0f) == 0x01)
+#define SIS_PKT_IS_HIDI2C(x)           (((x) & 0x0f) == 0x06)
+
+/* Contact properties within report */
+#define SIS_PKT_HAS_AREA(x)            ((x) & BIT(4))
+#define SIS_PKT_HAS_PRESSURE(x)                ((x) & BIT(5))
+#define SIS_PKT_HAS_SCANTIME(x)                ((x) & BIT(6))
+
+/* Contact size */
+#define SIS_BASE_LEN_PER_CONTACT       6
+#define SIS_AREA_LEN_PER_CONTACT       2
+#define SIS_PRESSURE_LEN_PER_CONTACT   1
+
+/* Offsets within contact data */
+#define SIS_CONTACT_STATUS_OFFSET      0
+#define SIS_CONTACT_ID_OFFSET          1 /* Contact ID */
+#define SIS_CONTACT_X_OFFSET           2
+#define SIS_CONTACT_Y_OFFSET           4
+#define SIS_CONTACT_WIDTH_OFFSET       6
+#define SIS_CONTACT_HEIGHT_OFFSET      7
+#define SIS_CONTACT_PRESSURE_OFFSET(id)        (SIS_PKT_HAS_AREA(id) ? 8 : 6)
+
+/* Individual contact state */
+#define SIS_STATUS_UP                  0x0
+#define SIS_STATUS_DOWN                        0x3
+
+/* Touchscreen parameters */
+#define SIS_MAX_FINGERS                        10
+#define SIS_MAX_X                      4095
+#define SIS_MAX_Y                      4095
+#define SIS_MAX_PRESSURE               255
+
+/* Resolution diagonal */
+#define SIS_AREA_LENGTH_LONGER         5792
+/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
+#define SIS_AREA_LENGTH_SHORT          5792
+#define SIS_AREA_UNIT                  (5792 / 32)
+
+struct sis_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+
+       struct gpio_desc *attn_gpio;
+       struct gpio_desc *reset_gpio;
+
+       u8 packet[SIS_MAX_PACKET_SIZE];
+};
+
+static int sis_read_packet(struct i2c_client *client, u8 *buf,
+                          unsigned int *num_contacts,
+                          unsigned int *contact_size)
+{
+       int count_idx;
+       int ret;
+       u16 len;
+       u16 crc, pkg_crc;
+       u8 report_id;
+
+       ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE);
+       if (ret <= 0)
+               return -EIO;
+
+       len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]);
+       if (len > SIS_MAX_PACKET_SIZE) {
+               dev_err(&client->dev,
+                       "%s: invalid packet length (%d vs %d)\n",
+                       __func__, len, SIS_MAX_PACKET_SIZE);
+               return -E2BIG;
+       }
+
+       if (len < 10)
+               return -EINVAL;
+
+       report_id = buf[SIS_PKT_REPORT_OFFSET];
+       count_idx  = len - 1;
+       *contact_size = SIS_BASE_LEN_PER_CONTACT;
+
+       if (report_id != SIS_ALL_IN_ONE_PACKAGE) {
+               if (SIS_PKT_IS_TOUCH(report_id)) {
+                       /*
+                        * Calculate CRC ignoring packet length
+                        * in the beginning and CRC transmitted
+                        * at the end of the packet.
+                        */
+                       crc = crc_itu_t(0, buf + 2, len - 2 - 2);
+                       pkg_crc = get_unaligned_le16(&buf[len - 2]);
+
+                       if (crc != pkg_crc) {
+                               dev_err(&client->dev,
+                                       "%s: CRC Error (%d vs %d)\n",
+                                       __func__, crc, pkg_crc);
+                               return -EINVAL;
+                       }
+
+                       count_idx -= 2;
+
+               } else if (!SIS_PKT_IS_HIDI2C(report_id)) {
+                       dev_err(&client->dev,
+                               "%s: invalid packet ID %#02x\n",
+                               __func__, report_id);
+                       return -EINVAL;
+               }
+
+               if (SIS_PKT_HAS_SCANTIME(report_id))
+                       count_idx -= SIS_SCAN_TIME_LEN;
+
+               if (SIS_PKT_HAS_AREA(report_id))
+                       *contact_size += SIS_AREA_LEN_PER_CONTACT;
+               if (SIS_PKT_HAS_PRESSURE(report_id))
+                       *contact_size += SIS_PRESSURE_LEN_PER_CONTACT;
+       }
+
+       *num_contacts = buf[count_idx];
+       return 0;
+}
+
+static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id)
+{
+       struct input_dev *input = ts->input;
+       int slot;
+       u8 status = data[SIS_CONTACT_STATUS_OFFSET];
+       u8 pressure;
+       u8 height, width;
+       u16 x, y;
+
+       if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) {
+               dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n",
+                       data[SIS_CONTACT_STATUS_OFFSET]);
+               return -EINVAL;
+       }
+
+       slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]);
+       if (slot < 0)
+               return -ENOENT;
+
+       input_mt_slot(input, slot);
+       input_mt_report_slot_state(input, MT_TOOL_FINGER,
+                                  status == SIS_STATUS_DOWN);
+
+       if (status == SIS_STATUS_DOWN) {
+               pressure = height = width = 1;
+               if (id != SIS_ALL_IN_ONE_PACKAGE) {
+                       if (SIS_PKT_HAS_AREA(id)) {
+                               width = data[SIS_CONTACT_WIDTH_OFFSET];
+                               height = data[SIS_CONTACT_HEIGHT_OFFSET];
+                       }
+
+                       if (SIS_PKT_HAS_PRESSURE(id))
+                               pressure =
+                                       data[SIS_CONTACT_PRESSURE_OFFSET(id)];
+               }
+
+               x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]);
+               y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]);
+
+               input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+                                width * SIS_AREA_UNIT);
+               input_report_abs(input, ABS_MT_TOUCH_MINOR,
+                                height * SIS_AREA_UNIT);
+               input_report_abs(input, ABS_MT_PRESSURE, pressure);
+               input_report_abs(input, ABS_MT_POSITION_X, x);
+               input_report_abs(input, ABS_MT_POSITION_Y, y);
+       }
+
+       return 0;
+}
+
+static void sis_ts_handle_packet(struct sis_ts_data *ts)
+{
+       const u8 *contact;
+       unsigned int num_to_report = 0;
+       unsigned int num_contacts;
+       unsigned int num_reported;
+       unsigned int contact_size;
+       int error;
+       u8 report_id;
+
+       do {
+               error = sis_read_packet(ts->client, ts->packet,
+                                       &num_contacts, &contact_size);
+               if (error)
+                       break;
+
+               if (num_to_report == 0) {
+                       num_to_report = num_contacts;
+               } else if (num_contacts != 0) {
+                       dev_err(&ts->client->dev,
+                               "%s: nonzero (%d) point count in tail packet\n",
+                               __func__, num_contacts);
+                       break;
+               }
+
+               report_id = ts->packet[SIS_PKT_REPORT_OFFSET];
+               contact = &ts->packet[SIS_PKT_CONTACT_OFFSET];
+               num_reported = 0;
+
+               while (num_to_report > 0) {
+                       error = sis_ts_report_contact(ts, contact, report_id);
+                       if (error)
+                               break;
+
+                       contact += contact_size;
+                       num_to_report--;
+                       num_reported++;
+
+                       if (report_id != SIS_ALL_IN_ONE_PACKAGE &&
+                           num_reported >= 5) {
+                               /*
+                                * The remainder of contacts is sent
+                                * in the 2nd packet.
+                                */
+                               break;
+                       }
+               }
+       } while (num_to_report > 0);
+
+       input_mt_sync_frame(ts->input);
+       input_sync(ts->input);
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+       struct sis_ts_data *ts = dev_id;
+
+       do {
+               sis_ts_handle_packet(ts);
+       } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio));
+
+       return IRQ_HANDLED;
+}
+
+static void sis_ts_reset(struct sis_ts_data *ts)
+{
+       if (ts->reset_gpio) {
+               /* Get out of reset */
+               usleep_range(1000, 2000);
+               gpiod_set_value(ts->reset_gpio, 1);
+               usleep_range(1000, 2000);
+               gpiod_set_value(ts->reset_gpio, 0);
+               msleep(100);
+       }
+}
+
+static int sis_ts_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct sis_ts_data *ts;
+       struct input_dev *input;
+       int error;
+
+       ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       ts->client = client;
+       i2c_set_clientdata(client, ts);
+
+       ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
+                                               "attn", GPIOD_IN);
+       if (IS_ERR(ts->attn_gpio)) {
+               error = PTR_ERR(ts->attn_gpio);
+               if (error != -EPROBE_DEFER)
+                       dev_err(&client->dev,
+                               "Failed to get attention GPIO: %d\n", error);
+               return error;
+       }
+
+       ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
+                                                "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(ts->reset_gpio)) {
+               error = PTR_ERR(ts->reset_gpio);
+               if (error != -EPROBE_DEFER)
+                       dev_err(&client->dev,
+                               "Failed to get reset GPIO: %d\n", error);
+               return error;
+       }
+
+       sis_ts_reset(ts);
+
+       ts->input = input = devm_input_allocate_device(&client->dev);
+       if (!input) {
+               dev_err(&client->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       input->name = "SiS Touchscreen";
+       input->id.bustype = BUS_I2C;
+
+       input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+       input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+       input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0);
+       input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
+                            0, SIS_AREA_LENGTH_LONGER, 0, 0);
+       input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
+                            0, SIS_AREA_LENGTH_SHORT, 0, 0);
+
+       error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to initialize MT slots: %d\n", error);
+               return error;
+       }
+
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                         NULL, sis_ts_irq_handler,
+                                         IRQF_ONESHOT,
+                                         client->name, ts);
+       if (error) {
+               dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+               return error;
+       }
+
+       error = input_register_device(ts->input);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to register input device: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id sis_ts_dt_ids[] = {
+       { .compatible = "sis,9200-ts" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+       { SIS_I2C_NAME, 0 },
+       { "9200-ts",    0 },
+       { /* sentinel */  }
+};
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+       .driver = {
+               .name   = SIS_I2C_NAME,
+               .of_match_table = of_match_ptr(sis_ts_dt_ids),
+       },
+       .probe          = sis_ts_probe,
+       .id_table       = sis_ts_id,
+};
+module_i2c_driver(sis_ts_driver);
+
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>");
index 33c177b..96de97a 100644 (file)
@@ -2375,7 +2375,7 @@ static void __unmap_single(struct dma_ops_domain *dma_dom,
 static dma_addr_t map_page(struct device *dev, struct page *page,
                           unsigned long offset, size_t size,
                           enum dma_data_direction dir,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        phys_addr_t paddr = page_to_phys(page) + offset;
        struct protection_domain *domain;
@@ -2398,7 +2398,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page,
  * The exported unmap_single function for dma_ops.
  */
 static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-                      enum dma_data_direction dir, struct dma_attrs *attrs)
+                      enum dma_data_direction dir, unsigned long attrs)
 {
        struct protection_domain *domain;
        struct dma_ops_domain *dma_dom;
@@ -2444,7 +2444,7 @@ static int sg_num_pages(struct device *dev,
  */
 static int map_sg(struct device *dev, struct scatterlist *sglist,
                  int nelems, enum dma_data_direction direction,
-                 struct dma_attrs *attrs)
+                 unsigned long attrs)
 {
        int mapped_pages = 0, npages = 0, prot = 0, i;
        struct protection_domain *domain;
@@ -2525,7 +2525,7 @@ out_err:
  */
 static void unmap_sg(struct device *dev, struct scatterlist *sglist,
                     int nelems, enum dma_data_direction dir,
-                    struct dma_attrs *attrs)
+                    unsigned long attrs)
 {
        struct protection_domain *domain;
        struct dma_ops_domain *dma_dom;
@@ -2548,7 +2548,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
  */
 static void *alloc_coherent(struct device *dev, size_t size,
                            dma_addr_t *dma_addr, gfp_t flag,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        u64 dma_mask = dev->coherent_dma_mask;
        struct protection_domain *domain;
@@ -2604,7 +2604,7 @@ out_free:
  */
 static void free_coherent(struct device *dev, size_t size,
                          void *virt_addr, dma_addr_t dma_addr,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        struct protection_domain *domain;
        struct dma_ops_domain *dma_dom;
index ea5a9eb..08a1e2f 100644 (file)
@@ -286,7 +286,7 @@ void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
  *        or NULL on failure.
  */
 struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
-               struct dma_attrs *attrs, int prot, dma_addr_t *handle,
+               unsigned long attrs, int prot, dma_addr_t *handle,
                void (*flush_page)(struct device *, const void *, phys_addr_t))
 {
        struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
@@ -306,7 +306,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
        } else {
                size = ALIGN(size, min_size);
        }
-       if (dma_get_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, attrs))
+       if (attrs & DMA_ATTR_ALLOC_SINGLE_PAGES)
                alloc_sizes = min_size;
 
        count = PAGE_ALIGN(size) >> PAGE_SHIFT;
@@ -400,7 +400,7 @@ dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
 }
 
 void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
-               enum dma_data_direction dir, struct dma_attrs *attrs)
+               enum dma_data_direction dir, unsigned long attrs)
 {
        __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
 }
@@ -560,7 +560,7 @@ out_restore_sg:
 }
 
 void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-               enum dma_data_direction dir, struct dma_attrs *attrs)
+               enum dma_data_direction dir, unsigned long attrs)
 {
        /*
         * The scatterlist segments are mapped into a single
index afbaa2c..ebb5bf3 100644 (file)
@@ -3552,7 +3552,7 @@ error:
 static dma_addr_t intel_map_page(struct device *dev, struct page *page,
                                 unsigned long offset, size_t size,
                                 enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                                unsigned long attrs)
 {
        return __intel_map_single(dev, page_to_phys(page) + offset, size,
                                  dir, *dev->dma_mask);
@@ -3711,14 +3711,14 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
 
 static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
                             size_t size, enum dma_data_direction dir,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        intel_unmap(dev, dev_addr, size);
 }
 
 static void *intel_alloc_coherent(struct device *dev, size_t size,
                                  dma_addr_t *dma_handle, gfp_t flags,
-                                 struct dma_attrs *attrs)
+                                 unsigned long attrs)
 {
        struct page *page = NULL;
        int order;
@@ -3764,7 +3764,7 @@ static void *intel_alloc_coherent(struct device *dev, size_t size,
 }
 
 static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
-                               dma_addr_t dma_handle, struct dma_attrs *attrs)
+                               dma_addr_t dma_handle, unsigned long attrs)
 {
        int order;
        struct page *page = virt_to_page(vaddr);
@@ -3779,7 +3779,7 @@ static void intel_free_coherent(struct device *dev, size_t size, void *vaddr,
 
 static void intel_unmap_sg(struct device *dev, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction dir,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        dma_addr_t startaddr = sg_dma_address(sglist) & PAGE_MASK;
        unsigned long nrpages = 0;
@@ -3808,7 +3808,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 }
 
 static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nelems,
-                       enum dma_data_direction dir, struct dma_attrs *attrs)
+                       enum dma_data_direction dir, unsigned long attrs)
 {
        int i;
        struct dmar_domain *domain;
index 5495a5b..7f87289 100644 (file)
@@ -21,9 +21,9 @@ config ARM_GIC_MAX_NR
 
 config ARM_GIC_V2M
        bool
-       depends on ARM_GIC
-       depends on PCI && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI
+       select ARM_GIC
+       select PCI_MSI
 
 config GIC_NON_BANKED
        bool
@@ -37,7 +37,8 @@ config ARM_GIC_V3
 
 config ARM_GIC_V3_ITS
        bool
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI
+       depends on PCI_MSI
 
 config ARM_NVIC
        bool
@@ -62,13 +63,13 @@ config ARM_VIC_NR
 config ARMADA_370_XP_IRQ
        bool
        select GENERIC_IRQ_CHIP
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+       select PCI_MSI if PCI
 
 config ALPINE_MSI
        bool
-       depends on PCI && PCI_MSI
+       depends on PCI
+       select PCI_MSI
        select GENERIC_IRQ_CHIP
-       select PCI_MSI_IRQ_DOMAIN
 
 config ATMEL_AIC_IRQ
        bool
@@ -117,7 +118,6 @@ config HISILICON_IRQ_MBIGEN
        bool
        select ARM_GIC_V3
        select ARM_GIC_V3_ITS
-       select GENERIC_MSI_IRQ_DOMAIN
 
 config IMGPDC_IRQ
        bool
@@ -250,12 +250,10 @@ config IRQ_MXS
 
 config MVEBU_ODMI
        bool
-       select GENERIC_MSI_IRQ_DOMAIN
 
 config LS_SCFG_MSI
        def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
        depends on PCI && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
 
 config PARTITION_PERCPU
        bool
index 3786d0f..c5f33c3 100644 (file)
@@ -359,7 +359,7 @@ static void gic_handle_shared_int(bool chained)
                pending_reg += gic_reg_step;
                intrmask_reg += gic_reg_step;
 
-               if (!config_enabled(CONFIG_64BIT) || mips_cm_is64)
+               if (!IS_ENABLED(CONFIG_64BIT) || mips_cm_is64)
                        continue;
 
                pending[i] |= (u64)gic_read(pending_reg) << 32;
index 69f16f4..4b177fe 100644 (file)
@@ -208,7 +208,7 @@ static void bch_data_insert_start(struct closure *cl)
         * Journal writes are marked REQ_PREFLUSH; if the original write was a
         * flush, it'll wait on the journal write.
         */
-       bio->bi_rw &= ~(REQ_PREFLUSH|REQ_FUA);
+       bio->bi_opf &= ~(REQ_PREFLUSH|REQ_FUA);
 
        do {
                unsigned i;
@@ -405,7 +405,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
        if (!congested &&
            mode == CACHE_MODE_WRITEBACK &&
            op_is_write(bio_op(bio)) &&
-           (bio->bi_rw & REQ_SYNC))
+           (bio->bi_opf & REQ_SYNC))
                goto rescale;
 
        spin_lock(&dc->io_lock);
@@ -668,7 +668,7 @@ static inline struct search *search_alloc(struct bio *bio,
        s->iop.write_prio       = 0;
        s->iop.error            = 0;
        s->iop.flags            = 0;
-       s->iop.flush_journal    = (bio->bi_rw & (REQ_PREFLUSH|REQ_FUA)) != 0;
+       s->iop.flush_journal    = (bio->bi_opf & (REQ_PREFLUSH|REQ_FUA)) != 0;
        s->iop.wq               = bcache_wq;
 
        return s;
@@ -796,8 +796,8 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
                goto out_submit;
        }
 
-       if (!(bio->bi_rw & REQ_RAHEAD) &&
-           !(bio->bi_rw & REQ_META) &&
+       if (!(bio->bi_opf & REQ_RAHEAD) &&
+           !(bio->bi_opf & REQ_META) &&
            s->iop.c->gc_stats.in_use < CUTOFF_CACHE_READA)
                reada = min_t(sector_t, dc->readahead >> 9,
                              bdev_sectors(bio->bi_bdev) - bio_end_sector(bio));
@@ -920,7 +920,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s)
                bch_writeback_add(dc);
                s->iop.bio = bio;
 
-               if (bio->bi_rw & REQ_PREFLUSH) {
+               if (bio->bi_opf & REQ_PREFLUSH) {
                        /* Also need to send a flush to the backing device */
                        struct bio *flush = bio_alloc_bioset(GFP_NOIO, 0,
                                                             dc->disk.bio_split);
index 88ef6d1..95a4ca6 100644 (file)
@@ -347,7 +347,7 @@ static void uuid_io(struct cache_set *c, int op, unsigned long op_flags,
        for (i = 0; i < KEY_PTRS(k); i++) {
                struct bio *bio = bch_bbio_alloc(c);
 
-               bio->bi_rw      = REQ_SYNC|REQ_META|op_flags;
+               bio->bi_opf = REQ_SYNC | REQ_META | op_flags;
                bio->bi_iter.bi_size = KEY_SIZE(k) << 9;
 
                bio->bi_end_io  = uuid_endio;
index 073a042..301eaf5 100644 (file)
@@ -57,7 +57,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
        if (would_skip)
                return false;
 
-       return bio->bi_rw & REQ_SYNC ||
+       return bio->bi_opf & REQ_SYNC ||
                in_use <= CUTOFF_WRITEBACK;
 }
 
index 718744d..59b2c50 100644 (file)
@@ -788,7 +788,7 @@ static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio)
 
        spin_lock_irqsave(&cache->lock, flags);
        if (cache->need_tick_bio &&
-           !(bio->bi_rw & (REQ_FUA | REQ_PREFLUSH)) &&
+           !(bio->bi_opf & (REQ_FUA | REQ_PREFLUSH)) &&
            bio_op(bio) != REQ_OP_DISCARD) {
                pb->tick = true;
                cache->need_tick_bio = false;
@@ -830,7 +830,7 @@ static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio)
 
 static int bio_triggers_commit(struct cache *cache, struct bio *bio)
 {
-       return bio->bi_rw & (REQ_PREFLUSH | REQ_FUA);
+       return bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
 }
 
 /*
@@ -1069,7 +1069,7 @@ static void dec_io_migrations(struct cache *cache)
 static bool discard_or_flush(struct bio *bio)
 {
        return bio_op(bio) == REQ_OP_DISCARD ||
-              bio->bi_rw & (REQ_PREFLUSH | REQ_FUA);
+              bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
 }
 
 static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell)
@@ -1980,7 +1980,7 @@ static void process_deferred_bios(struct cache *cache)
 
                bio = bio_list_pop(&bios);
 
-               if (bio->bi_rw & REQ_PREFLUSH)
+               if (bio->bi_opf & REQ_PREFLUSH)
                        process_flush_bio(cache, bio);
                else if (bio_op(bio) == REQ_OP_DISCARD)
                        process_discard_bio(cache, &structs, bio);
index 8f2e3e2..4e9784b 100644 (file)
@@ -1136,7 +1136,7 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
        clone->bi_private = io;
        clone->bi_end_io  = crypt_endio;
        clone->bi_bdev    = cc->dev->bdev;
-       bio_set_op_attrs(clone, bio_op(io->base_bio), io->base_bio->bi_rw);
+       bio_set_op_attrs(clone, bio_op(io->base_bio), io->base_bio->bi_opf);
 }
 
 static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
@@ -1915,7 +1915,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
         * - for REQ_PREFLUSH device-mapper core ensures that no IO is in-flight
         * - for REQ_OP_DISCARD caller must use flush if IO ordering matters
         */
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH ||
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH ||
            bio_op(bio) == REQ_OP_DISCARD)) {
                bio->bi_bdev = cc->dev->bdev;
                if (bio_sectors(bio))
index 2faf49d..bf2b267 100644 (file)
@@ -1542,7 +1542,7 @@ static int era_map(struct dm_target *ti, struct bio *bio)
        /*
         * REQ_PREFLUSH bios carry no data, so we're not interested in them.
         */
-       if (!(bio->bi_rw & REQ_PREFLUSH) &&
+       if (!(bio->bi_opf & REQ_PREFLUSH) &&
            (bio_data_dir(bio) == WRITE) &&
            !metadata_current_marked(era->md, block)) {
                defer_bio(era, bio);
index 29b99fb..97e446d 100644 (file)
@@ -16,7 +16,7 @@
 #define DM_MSG_PREFIX "flakey"
 
 #define all_corrupt_bio_flags_match(bio, fc)   \
-       (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
+       (((bio)->bi_opf & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
 
 /*
  * Flakey: Used for testing only, simulates intermittent,
@@ -266,9 +266,9 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
                data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value;
 
                DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
-                       "(rw=%c bi_rw=%u bi_sector=%llu cur_bytes=%u)\n",
+                       "(rw=%c bi_opf=%u bi_sector=%llu cur_bytes=%u)\n",
                        bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
-                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_rw,
+                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
                        (unsigned long long)bio->bi_iter.bi_sector, bio_bytes);
        }
 }
@@ -289,10 +289,16 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
                pb->bio_submitted = true;
 
                /*
-                * Map reads as normal.
+                * Map reads as normal only if corrupt_bio_byte set.
                 */
-               if (bio_data_dir(bio) == READ)
-                       goto map_bio;
+               if (bio_data_dir(bio) == READ) {
+                       /* If flags were specified, only corrupt those that match. */
+                       if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
+                           all_corrupt_bio_flags_match(bio, fc))
+                               goto map_bio;
+                       else
+                               return -EIO;
+               }
 
                /*
                 * Drop writes?
@@ -330,12 +336,13 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
 
        /*
         * Corrupt successful READs while in down state.
-        * If flags were specified, only corrupt those that match.
         */
-       if (fc->corrupt_bio_byte && !error && pb->bio_submitted &&
-           (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
-           all_corrupt_bio_flags_match(bio, fc))
-               corrupt_bio_data(bio, fc);
+       if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
+               if (fc->corrupt_bio_byte)
+                       corrupt_bio_data(bio, fc);
+               else
+                       return -EIO;
+       }
 
        return error;
 }
index daa03e4..0bf1a12 100644 (file)
@@ -505,9 +505,9 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
  * New collapsed (a)synchronous interface.
  *
  * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug
- * the queue with blk_unplug() some time later or set REQ_SYNC in io_req->bi_rw.
- * If you fail to do one of these, the IO will be submitted to the disk after
- * q->unplug_delay, which defaults to 3ms in blk-settings.c.
+ * the queue with blk_unplug() some time later or set REQ_SYNC in
+ * io_req->bi_opf. If you fail to do one of these, the IO will be submitted to
+ * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c.
  */
 int dm_io(struct dm_io_request *io_req, unsigned num_regions,
          struct dm_io_region *where, unsigned long *sync_error_bits)
index b5dbf7a..4ab6803 100644 (file)
@@ -555,8 +555,8 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
        struct bio_vec bv;
        size_t alloc_size;
        int i = 0;
-       bool flush_bio = (bio->bi_rw & REQ_PREFLUSH);
-       bool fua_bio = (bio->bi_rw & REQ_FUA);
+       bool flush_bio = (bio->bi_opf & REQ_PREFLUSH);
+       bool fua_bio = (bio->bi_opf & REQ_FUA);
        bool discard_bio = (bio_op(bio) == REQ_OP_DISCARD);
 
        pb->block = NULL;
index 7eac080..ac734e5 100644 (file)
@@ -507,13 +507,27 @@ static bool __must_push_back(struct multipath *m)
 
 static bool must_push_back_rq(struct multipath *m)
 {
-       return (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) ||
-               __must_push_back(m));
+       bool r;
+       unsigned long flags;
+
+       spin_lock_irqsave(&m->lock, flags);
+       r = (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) ||
+            __must_push_back(m));
+       spin_unlock_irqrestore(&m->lock, flags);
+
+       return r;
 }
 
 static bool must_push_back_bio(struct multipath *m)
 {
-       return __must_push_back(m);
+       bool r;
+       unsigned long flags;
+
+       spin_lock_irqsave(&m->lock, flags);
+       r = __must_push_back(m);
+       spin_unlock_irqrestore(&m->lock, flags);
+
+       return r;
 }
 
 /*
@@ -647,7 +661,7 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio, struct dm_m
 
        bio->bi_error = 0;
        bio->bi_bdev = pgpath->path.dev->bdev;
-       bio->bi_rw |= REQ_FAILFAST_TRANSPORT;
+       bio->bi_opf |= REQ_FAILFAST_TRANSPORT;
 
        if (pgpath->pg->ps.type->start_io)
                pgpath->pg->ps.type->start_io(&pgpath->pg->ps,
@@ -1680,12 +1694,14 @@ static void multipath_postsuspend(struct dm_target *ti)
 static void multipath_resume(struct dm_target *ti)
 {
        struct multipath *m = ti->private;
+       unsigned long flags;
 
+       spin_lock_irqsave(&m->lock, flags);
        if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags))
                set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags);
        else
                clear_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags);
-       smp_mb__after_atomic();
+       spin_unlock_irqrestore(&m->lock, flags);
 }
 
 /*
index 8498354..1b9795d 100644 (file)
@@ -1270,7 +1270,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
                        }
                        rs->md.sync_speed_min = (int)value;
                } else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_MAX_RECOVERY_RATE))) {
-                       if (test_and_set_bit(__CTR_FLAG_MIN_RECOVERY_RATE, &rs->ctr_flags)) {
+                       if (test_and_set_bit(__CTR_FLAG_MAX_RECOVERY_RATE, &rs->ctr_flags)) {
                                rs->ti->error = "Only one max_recovery_rate argument pair allowed";
                                return -EINVAL;
                        }
@@ -1960,6 +1960,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
        sb->data_offset = cpu_to_le64(rdev->data_offset);
        sb->new_data_offset = cpu_to_le64(rdev->new_data_offset);
        sb->sectors = cpu_to_le64(rdev->sectors);
+       sb->incompat_features = cpu_to_le32(0);
 
        /* Zero out the rest of the payload after the size of the superblock */
        memset(sb + 1, 0, rdev->sb_size - sizeof(*sb));
@@ -3577,7 +3578,6 @@ static int raid_preresume(struct dm_target *ti)
        /* Be prepared for mddev_resume() in raid_resume() */
        set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
        if (mddev->recovery_cp && mddev->recovery_cp < MaxSector) {
-               set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
                set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                mddev->resync_min = mddev->recovery_cp;
        }
index dac55b2..bdf1606 100644 (file)
@@ -657,7 +657,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        struct mirror *m;
        struct dm_io_request io_req = {
                .bi_op = REQ_OP_WRITE,
-               .bi_op_flags = bio->bi_rw & WRITE_FLUSH_FUA,
+               .bi_op_flags = bio->bi_opf & WRITE_FLUSH_FUA,
                .mem.type = DM_IO_BIO,
                .mem.ptr.bio = bio,
                .notify.fn = write_callback,
@@ -704,7 +704,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
        bio_list_init(&requeue);
 
        while ((bio = bio_list_pop(writes))) {
-               if ((bio->bi_rw & REQ_PREFLUSH) ||
+               if ((bio->bi_opf & REQ_PREFLUSH) ||
                    (bio_op(bio) == REQ_OP_DISCARD)) {
                        bio_list_add(&sync, bio);
                        continue;
@@ -1217,7 +1217,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)
         * If region is not in-sync queue the bio.
         */
        if (!r || (r == -EWOULDBLOCK)) {
-               if (bio->bi_rw & REQ_RAHEAD)
+               if (bio->bi_opf & REQ_RAHEAD)
                        return -EWOULDBLOCK;
 
                queue_bio(ms, bio, rw);
@@ -1253,7 +1253,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
         * We need to dec pending if this was a write.
         */
        if (rw == WRITE) {
-               if (!(bio->bi_rw & REQ_PREFLUSH) &&
+               if (!(bio->bi_opf & REQ_PREFLUSH) &&
                    bio_op(bio) != REQ_OP_DISCARD)
                        dm_rh_dec(ms->rh, bio_record->write_region);
                return error;
@@ -1262,7 +1262,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
        if (error == -EOPNOTSUPP)
                goto out;
 
-       if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
+       if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
                goto out;
 
        if (unlikely(error)) {
index b118134..85c32b2 100644 (file)
@@ -398,7 +398,7 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio)
        region_t region = dm_rh_bio_to_region(rh, bio);
        int recovering = 0;
 
-       if (bio->bi_rw & REQ_PREFLUSH) {
+       if (bio->bi_opf & REQ_PREFLUSH) {
                rh->flush_failure = 1;
                return;
        }
@@ -526,7 +526,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios)
        struct bio *bio;
 
        for (bio = bios->head; bio; bio = bio->bi_next) {
-               if (bio->bi_rw & REQ_PREFLUSH || bio_op(bio) == REQ_OP_DISCARD)
+               if (bio->bi_opf & REQ_PREFLUSH || bio_op(bio) == REQ_OP_DISCARD)
                        continue;
                rh_inc(rh, dm_rh_bio_to_region(rh, bio));
        }
index 7a96618..1ca7463 100644 (file)
@@ -78,6 +78,7 @@ void dm_start_queue(struct request_queue *q)
        if (!q->mq_ops)
                dm_old_start_queue(q);
        else {
+               queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, q);
                blk_mq_start_stopped_hw_queues(q, true);
                blk_mq_kick_requeue_list(q);
        }
@@ -101,8 +102,14 @@ void dm_stop_queue(struct request_queue *q)
 {
        if (!q->mq_ops)
                dm_old_stop_queue(q);
-       else
+       else {
+               spin_lock_irq(q->queue_lock);
+               queue_flag_set(QUEUE_FLAG_STOPPED, q);
+               spin_unlock_irq(q->queue_lock);
+
+               blk_mq_cancel_requeue_work(q);
                blk_mq_stop_hw_queues(q);
+       }
 }
 
 static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md,
@@ -864,6 +871,17 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
                dm_put_live_table(md, srcu_idx);
        }
 
+       /*
+        * On suspend dm_stop_queue() handles stopping the blk-mq
+        * request_queue BUT: even though the hw_queues are marked
+        * BLK_MQ_S_STOPPED at that point there is still a race that
+        * is allowing block/blk-mq.c to call ->queue_rq against a
+        * hctx that it really shouldn't.  The following check guards
+        * against this rarity (albeit _not_ race-free).
+        */
+       if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
+               return BLK_MQ_RQ_QUEUE_BUSY;
+
        if (ti->type->busy && ti->type->busy(ti))
                return BLK_MQ_RQ_QUEUE_BUSY;
 
index ce2a910..c65feea 100644 (file)
@@ -1680,7 +1680,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
 
        init_tracked_chunk(bio);
 
-       if (bio->bi_rw & REQ_PREFLUSH) {
+       if (bio->bi_opf & REQ_PREFLUSH) {
                bio->bi_bdev = s->cow->bdev;
                return DM_MAPIO_REMAPPED;
        }
@@ -1800,7 +1800,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
 
        init_tracked_chunk(bio);
 
-       if (bio->bi_rw & REQ_PREFLUSH) {
+       if (bio->bi_opf & REQ_PREFLUSH) {
                if (!dm_bio_get_target_bio_nr(bio))
                        bio->bi_bdev = s->origin->bdev;
                else
@@ -2286,7 +2286,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio)
 
        bio->bi_bdev = o->dev->bdev;
 
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH))
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH))
                return DM_MAPIO_REMAPPED;
 
        if (bio_data_dir(bio) != WRITE)
index 83f1d46..28193a5 100644 (file)
@@ -286,7 +286,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
        uint32_t stripe;
        unsigned target_bio_nr;
 
-       if (bio->bi_rw & REQ_PREFLUSH) {
+       if (bio->bi_opf & REQ_PREFLUSH) {
                target_bio_nr = dm_bio_get_target_bio_nr(bio);
                BUG_ON(target_bio_nr >= sc->stripes);
                bio->bi_bdev = sc->stripe[target_bio_nr].dev->bdev;
@@ -383,7 +383,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
        if (!error)
                return 0; /* I/O complete */
 
-       if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD))
+       if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
                return error;
 
        if (error == -EOPNOTSUPP)
index 197ea20..d1c05c1 100644 (file)
@@ -699,7 +699,7 @@ static void remap_to_origin(struct thin_c *tc, struct bio *bio)
 
 static int bio_triggers_commit(struct thin_c *tc, struct bio *bio)
 {
-       return (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) &&
+       return (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) &&
                dm_thin_changed_this_transaction(tc->td);
 }
 
@@ -870,7 +870,7 @@ static void __inc_remap_and_issue_cell(void *context,
        struct bio *bio;
 
        while ((bio = bio_list_pop(&cell->bios))) {
-               if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) ||
+               if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
                    bio_op(bio) == REQ_OP_DISCARD)
                        bio_list_add(&info->defer_bios, bio);
                else {
@@ -1717,7 +1717,7 @@ static void __remap_and_issue_shared_cell(void *context,
 
        while ((bio = bio_list_pop(&cell->bios))) {
                if ((bio_data_dir(bio) == WRITE) ||
-                   (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) ||
+                   (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
                     bio_op(bio) == REQ_OP_DISCARD))
                        bio_list_add(&info->defer_bios, bio);
                else {
@@ -2635,7 +2635,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_SUBMITTED;
        }
 
-       if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) ||
+       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
            bio_op(bio) == REQ_OP_DISCARD) {
                thin_defer_bio_with_throttle(tc, bio);
                return DM_MAPIO_SUBMITTED;
index 618b875..b616f11 100644 (file)
@@ -37,7 +37,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio)
 {
        switch (bio_op(bio)) {
        case REQ_OP_READ:
-               if (bio->bi_rw & REQ_RAHEAD) {
+               if (bio->bi_opf & REQ_RAHEAD) {
                        /* readahead of null bytes only wastes buffer cache */
                        return -EIO;
                }
index 25d1d97..fa9b1cb 100644 (file)
@@ -798,12 +798,12 @@ static void dec_pending(struct dm_io *io, int error)
                if (io_error == DM_ENDIO_REQUEUE)
                        return;
 
-               if ((bio->bi_rw & REQ_PREFLUSH) && bio->bi_iter.bi_size) {
+               if ((bio->bi_opf & REQ_PREFLUSH) && bio->bi_iter.bi_size) {
                        /*
                         * Preflush done for flush with data, reissue
                         * without REQ_PREFLUSH.
                         */
-                       bio->bi_rw &= ~REQ_PREFLUSH;
+                       bio->bi_opf &= ~REQ_PREFLUSH;
                        queue_io(md, bio);
                } else {
                        /* done with normal IO or empty flush */
@@ -964,7 +964,7 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
 {
        struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
        unsigned bi_size = bio->bi_iter.bi_size >> SECTOR_SHIFT;
-       BUG_ON(bio->bi_rw & REQ_PREFLUSH);
+       BUG_ON(bio->bi_opf & REQ_PREFLUSH);
        BUG_ON(bi_size > *tio->len_ptr);
        BUG_ON(n_sectors > bi_size);
        *tio->len_ptr -= bi_size - n_sectors;
@@ -1252,7 +1252,7 @@ static void __split_and_process_bio(struct mapped_device *md,
 
        start_io_acct(ci.io);
 
-       if (bio->bi_rw & REQ_PREFLUSH) {
+       if (bio->bi_opf & REQ_PREFLUSH) {
                ci.bio = &ci.md->flush_bio;
                ci.sector_count = 0;
                error = __send_empty_flush(&ci);
@@ -1290,7 +1290,7 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
        if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) {
                dm_put_live_table(md, srcu_idx);
 
-               if (!(bio->bi_rw & REQ_RAHEAD))
+               if (!(bio->bi_opf & REQ_RAHEAD))
                        queue_io(md, bio);
                else
                        bio_io_error(bio);
@@ -2082,7 +2082,8 @@ static void unlock_fs(struct mapped_device *md)
  * Caller must hold md->suspend_lock
  */
 static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
-                       unsigned suspend_flags, int interruptible)
+                       unsigned suspend_flags, int interruptible,
+                       int dmf_suspended_flag)
 {
        bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
        bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
@@ -2149,6 +2150,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
         * to finish.
         */
        r = dm_wait_for_completion(md, interruptible);
+       if (!r)
+               set_bit(dmf_suspended_flag, &md->flags);
 
        if (noflush)
                clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
@@ -2210,12 +2213,10 @@ retry:
 
        map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
 
-       r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE);
+       r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED);
        if (r)
                goto out_unlock;
 
-       set_bit(DMF_SUSPENDED, &md->flags);
-
        dm_table_postsuspend_targets(map);
 
 out_unlock:
@@ -2309,9 +2310,8 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
         * would require changing .presuspend to return an error -- avoid this
         * until there is a need for more elaborate variants of internal suspend.
         */
-       (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE);
-
-       set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+       (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
+                           DMF_SUSPENDED_INTERNALLY);
 
        dm_table_postsuspend_targets(map);
 }
index 70ff888..86f5d43 100644 (file)
@@ -221,7 +221,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
        struct bio *split;
        sector_t start_sector, end_sector, data_offset;
 
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
index 2c3ab6f..d646f6e 100644 (file)
@@ -285,7 +285,7 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
         */
        sectors = bio_sectors(bio);
        /* bio could be mergeable after passing to underlayer */
-       bio->bi_rw &= ~REQ_NOMERGE;
+       bio->bi_opf &= ~REQ_NOMERGE;
        mddev->pers->make_request(mddev, bio);
 
        cpu = part_stat_lock();
@@ -414,7 +414,7 @@ static void md_submit_flush_data(struct work_struct *ws)
                /* an empty barrier - all done */
                bio_endio(bio);
        else {
-               bio->bi_rw &= ~REQ_PREFLUSH;
+               bio->bi_opf &= ~REQ_PREFLUSH;
                mddev->pers->make_request(mddev, bio);
        }
 
index 4974682..673efbd 100644 (file)
@@ -91,7 +91,7 @@ static void multipath_end_request(struct bio *bio)
 
        if (!bio->bi_error)
                multipath_end_bh_io(mp_bh, 0);
-       else if (!(bio->bi_rw & REQ_RAHEAD)) {
+       else if (!(bio->bi_opf & REQ_RAHEAD)) {
                /*
                 * oops, IO error:
                 */
@@ -112,7 +112,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
        struct multipath_bh * mp_bh;
        struct multipath_info *multipath;
 
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
@@ -135,7 +135,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
 
        mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset;
        mp_bh->bio.bi_bdev = multipath->rdev->bdev;
-       mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT;
+       mp_bh->bio.bi_opf |= REQ_FAILFAST_TRANSPORT;
        mp_bh->bio.bi_end_io = multipath_end_request;
        mp_bh->bio.bi_private = mp_bh;
        generic_make_request(&mp_bh->bio);
@@ -360,7 +360,7 @@ static void multipathd(struct md_thread *thread)
                        bio->bi_iter.bi_sector +=
                                conf->multipaths[mp_bh->path].rdev->data_offset;
                        bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev;
-                       bio->bi_rw |= REQ_FAILFAST_TRANSPORT;
+                       bio->bi_opf |= REQ_FAILFAST_TRANSPORT;
                        bio->bi_end_io = multipath_end_request;
                        bio->bi_private = mp_bh;
                        generic_make_request(bio);
index c3d4390..258986a 100644 (file)
@@ -458,7 +458,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
        struct md_rdev *tmp_dev;
        struct bio *split;
 
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
index 46168ef..21dc00e 100644 (file)
@@ -1043,8 +1043,8 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio)
        unsigned long flags;
        const int op = bio_op(bio);
        const int rw = bio_data_dir(bio);
-       const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
-       const unsigned long do_flush_fua = (bio->bi_rw &
+       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       const unsigned long do_flush_fua = (bio->bi_opf &
                                                (REQ_PREFLUSH | REQ_FUA));
        struct md_rdev *blocked_rdev;
        struct blk_plug_cb *cb;
@@ -2318,7 +2318,7 @@ read_more:
                raid_end_bio_io(r1_bio);
        } else {
                const unsigned long do_sync
-                       = r1_bio->master_bio->bi_rw & REQ_SYNC;
+                       = r1_bio->master_bio->bi_opf & REQ_SYNC;
                if (bio) {
                        r1_bio->bios[r1_bio->read_disk] =
                                mddev->ro ? IO_BLOCKED : NULL;
index ed29fc8..0e4efcd 100644 (file)
@@ -1054,8 +1054,8 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
        int i;
        const int op = bio_op(bio);
        const int rw = bio_data_dir(bio);
-       const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
-       const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
+       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+       const unsigned long do_fua = (bio->bi_opf & REQ_FUA);
        unsigned long flags;
        struct md_rdev *blocked_rdev;
        struct blk_plug_cb *cb;
@@ -1440,7 +1440,7 @@ static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 
        struct bio *split;
 
-       if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+       if (unlikely(bio->bi_opf & REQ_PREFLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
@@ -2533,7 +2533,7 @@ read_more:
                return;
        }
 
-       do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
+       do_sync = (r10_bio->master_bio->bi_opf & REQ_SYNC);
        slot = r10_bio->read_slot;
        printk_ratelimited(
                KERN_ERR
index 5504ce2..51f76dd 100644 (file)
@@ -536,7 +536,7 @@ int r5l_handle_flush_request(struct r5l_log *log, struct bio *bio)
                bio_endio(bio);
                return 0;
        }
-       bio->bi_rw &= ~REQ_PREFLUSH;
+       bio->bi_opf &= ~REQ_PREFLUSH;
        return -EAGAIN;
 }
 
index d189e89..8912407 100644 (file)
@@ -806,7 +806,7 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
        dd_idx = 0;
        while (dd_idx == sh->pd_idx || dd_idx == sh->qd_idx)
                dd_idx++;
-       if (head->dev[dd_idx].towrite->bi_rw != sh->dev[dd_idx].towrite->bi_rw ||
+       if (head->dev[dd_idx].towrite->bi_opf != sh->dev[dd_idx].towrite->bi_opf ||
            bio_op(head->dev[dd_idx].towrite) != bio_op(sh->dev[dd_idx].towrite))
                goto unlock_out;
 
@@ -1003,7 +1003,7 @@ again:
 
                        pr_debug("%s: for %llu schedule op %d on disc %d\n",
                                __func__, (unsigned long long)sh->sector,
-                               bi->bi_rw, i);
+                               bi->bi_opf, i);
                        atomic_inc(&sh->count);
                        if (sh != head_sh)
                                atomic_inc(&head_sh->count);
@@ -1014,7 +1014,7 @@ again:
                                bi->bi_iter.bi_sector = (sh->sector
                                                 + rdev->data_offset);
                        if (test_bit(R5_ReadNoMerge, &head_sh->dev[i].flags))
-                               bi->bi_rw |= REQ_NOMERGE;
+                               bi->bi_opf |= REQ_NOMERGE;
 
                        if (test_bit(R5_SkipCopy, &sh->dev[i].flags))
                                WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));
@@ -1055,7 +1055,7 @@ again:
                        pr_debug("%s: for %llu schedule op %d on "
                                 "replacement disc %d\n",
                                __func__, (unsigned long long)sh->sector,
-                               rbi->bi_rw, i);
+                               rbi->bi_opf, i);
                        atomic_inc(&sh->count);
                        if (sh != head_sh)
                                atomic_inc(&head_sh->count);
@@ -1088,7 +1088,7 @@ again:
                        if (op_is_write(op))
                                set_bit(STRIPE_DEGRADED, &sh->state);
                        pr_debug("skip op %d on disc %d for sector %llu\n",
-                               bi->bi_rw, i, (unsigned long long)sh->sector);
+                               bi->bi_opf, i, (unsigned long long)sh->sector);
                        clear_bit(R5_LOCKED, &sh->dev[i].flags);
                        set_bit(STRIPE_HANDLE, &sh->state);
                }
@@ -1619,9 +1619,9 @@ again:
 
                        while (wbi && wbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
-                               if (wbi->bi_rw & REQ_FUA)
+                               if (wbi->bi_opf & REQ_FUA)
                                        set_bit(R5_WantFUA, &dev->flags);
-                               if (wbi->bi_rw & REQ_SYNC)
+                               if (wbi->bi_opf & REQ_SYNC)
                                        set_bit(R5_SyncIO, &dev->flags);
                                if (bio_op(wbi) == REQ_OP_DISCARD)
                                        set_bit(R5_Discard, &dev->flags);
@@ -5154,7 +5154,7 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
        DEFINE_WAIT(w);
        bool do_prepare;
 
-       if (unlikely(bi->bi_rw & REQ_PREFLUSH)) {
+       if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
                int ret = r5l_handle_flush_request(conf->log, bi);
 
                if (ret == 0)
@@ -5237,7 +5237,7 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
                        (unsigned long long)logical_sector);
 
                sh = raid5_get_active_stripe(conf, new_sector, previous,
-                                      (bi->bi_rw & REQ_RAHEAD), 0);
+                                      (bi->bi_opf & REQ_RAHEAD), 0);
                if (sh) {
                        if (unlikely(previous)) {
                                /* expansion might have moved on while waiting for a
@@ -5305,7 +5305,7 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
                        set_bit(STRIPE_HANDLE, &sh->state);
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        if ((!sh->batch_head || sh == sh->batch_head) &&
-                           (bi->bi_rw & REQ_SYNC) &&
+                           (bi->bi_opf & REQ_SYNC) &&
                            !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                atomic_inc(&conf->preread_active_stripes);
                        release_stripe_plug(mddev, sh);
index 09c3934..ffe88bc 100644 (file)
@@ -3378,20 +3378,28 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe,
                                ret = cxd2841er_get_carrier_offset_i(
                                                priv, p->bandwidth_hz,
                                                &carrier_offset);
+                               if (ret)
+                                       return ret;
                                break;
                        case SYS_DVBT:
                                ret = cxd2841er_get_carrier_offset_t(
                                        priv, p->bandwidth_hz,
                                        &carrier_offset);
+                               if (ret)
+                                       return ret;
                                break;
                        case SYS_DVBT2:
                                ret = cxd2841er_get_carrier_offset_t2(
                                        priv, p->bandwidth_hz,
                                        &carrier_offset);
+                               if (ret)
+                                       return ret;
                                break;
                        case SYS_DVBC_ANNEX_A:
                                ret = cxd2841er_get_carrier_offset_c(
                                        priv, &carrier_offset);
+                               if (ret)
+                                       return ret;
                                break;
                        default:
                                dev_dbg(&priv->i2c->dev,
@@ -3399,8 +3407,6 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe,
                                        __func__, priv->system);
                                return -EINVAL;
                        }
-                       if (ret)
-                               return ret;
                        dev_dbg(&priv->i2c->dev, "%s(): carrier offset %d\n",
                                __func__, carrier_offset);
                        p->frequency += carrier_offset;
index b77b0a4..95cbc85 100644 (file)
 #define ADV7180_REG_IDENT 0x0011
 #define ADV7180_ID_7180 0x18
 
-#define ADV7180_REG_ICONF1             0x0040
+#define ADV7180_REG_ICONF1             0x2040
 #define ADV7180_ICONF1_ACTIVE_LOW      0x01
 #define ADV7180_ICONF1_PSYNC_ONLY      0x10
 #define ADV7180_ICONF1_ACTIVE_TO_CLR   0xC0
 
 #define ADV7180_IRQ1_LOCK      0x01
 #define ADV7180_IRQ1_UNLOCK    0x02
-#define ADV7180_REG_ISR1       0x0042
-#define ADV7180_REG_ICR1       0x0043
-#define ADV7180_REG_IMR1       0x0044
-#define ADV7180_REG_IMR2       0x0048
+#define ADV7180_REG_ISR1       0x2042
+#define ADV7180_REG_ICR1       0x2043
+#define ADV7180_REG_IMR1       0x2044
+#define ADV7180_REG_IMR2       0x2048
 #define ADV7180_IRQ3_AD_CHANGE 0x08
-#define ADV7180_REG_ISR3       0x004A
-#define ADV7180_REG_ICR3       0x004B
-#define ADV7180_REG_IMR3       0x004C
-#define ADV7180_REG_IMR4       0x50
+#define ADV7180_REG_ISR3       0x204A
+#define ADV7180_REG_ICR3       0x204B
+#define ADV7180_REG_IMR3       0x204C
+#define ADV7180_REG_IMR4       0x2050
 
 #define ADV7180_REG_NTSC_V_BIT_END     0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND    0x4F
index 6d7cad5..53030d6 100644 (file)
@@ -1041,6 +1041,8 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd,
                               struct v4l2_dv_timings *timings)
 {
        struct adv7511_state *state = get_adv7511_state(sd);
+       struct v4l2_bt_timings *bt = &timings->bt;
+       u32 fps;
 
        v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
@@ -1052,15 +1054,29 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd,
           if the format is one of the CEA or DMT timings. */
        v4l2_find_dv_timings_cap(timings, &adv7511_timings_cap, 0, NULL, NULL);
 
-       timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS;
-
        /* save timings */
        state->dv_timings = *timings;
 
        /* set h/vsync polarities */
        adv7511_wr_and_or(sd, 0x17, 0x9f,
-               ((timings->bt.polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) |
-               ((timings->bt.polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20));
+               ((bt->polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) |
+               ((bt->polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20));
+
+       fps = (u32)bt->pixelclock / (V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt));
+       switch (fps) {
+       case 24:
+               adv7511_wr_and_or(sd, 0xfb, 0xf9, 1 << 1);
+               break;
+       case 25:
+               adv7511_wr_and_or(sd, 0xfb, 0xf9, 2 << 1);
+               break;
+       case 30:
+               adv7511_wr_and_or(sd, 0xfb, 0xf9, 3 << 1);
+               break;
+       default:
+               adv7511_wr_and_or(sd, 0xfb, 0xf9, 0);
+               break;
+       }
 
        /* update quantization range based on new dv_timings */
        adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
index e277b7c..c7806ec 100644 (file)
@@ -246,7 +246,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
        struct video_device *vfd_enc;
        struct resource *res;
        int i, j, ret;
-       DEFINE_DMA_ATTRS(attrs);
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -378,9 +377,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
                goto err_enc_reg;
        }
 
-       /* Avoid the iommu eat big hunks */
-       dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs);
-
        mtk_v4l2_debug(0, "encoder registered as /dev/video%d",
                        vfd_enc->num);
 
index 3df66d1..b7892f3 100644 (file)
@@ -430,14 +430,11 @@ int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
  */
 void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
 {
-       if (ctx && ctx->node[0]) {
-               DEFINE_DMA_ATTRS(attrs);
-
-               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+       if (ctx && ctx->node[0])
                dma_free_attrs(ctx->bdisp_dev->dev,
                               sizeof(struct bdisp_node) * MAX_NB_NODE,
-                              ctx->node[0], ctx->node_paddr[0], &attrs);
-       }
+                              ctx->node[0], ctx->node_paddr[0],
+                              DMA_ATTR_WRITE_COMBINE);
 }
 
 /**
@@ -455,12 +452,10 @@ int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
        unsigned int i, node_size = sizeof(struct bdisp_node);
        void *base;
        dma_addr_t paddr;
-       DEFINE_DMA_ATTRS(attrs);
 
        /* Allocate all the nodes within a single memory page */
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
        base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
-                              GFP_KERNEL | GFP_DMA, &attrs);
+                              GFP_KERNEL | GFP_DMA, DMA_ATTR_WRITE_COMBINE);
        if (!base) {
                dev_err(dev, "%s no mem\n", __func__);
                return -ENOMEM;
@@ -493,13 +488,9 @@ void bdisp_hw_free_filters(struct device *dev)
 {
        int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
 
-       if (bdisp_h_filter[0].virt) {
-               DEFINE_DMA_ATTRS(attrs);
-
-               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+       if (bdisp_h_filter[0].virt)
                dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
-                              bdisp_h_filter[0].paddr, &attrs);
-       }
+                              bdisp_h_filter[0].paddr, DMA_ATTR_WRITE_COMBINE);
 }
 
 /**
@@ -516,12 +507,11 @@ int bdisp_hw_alloc_filters(struct device *dev)
        unsigned int i, size;
        void *base;
        dma_addr_t paddr;
-       DEFINE_DMA_ATTRS(attrs);
 
        /* Allocate all the filters within a single memory page */
        size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs);
+       base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA,
+                              DMA_ATTR_WRITE_COMBINE);
        if (!base)
                return -ENOMEM;
 
index 6b17015..cd0ff4a 100644 (file)
@@ -171,6 +171,9 @@ struct vim2m_ctx {
        int                     mode;
 
        enum v4l2_colorspace    colorspace;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_xfer_func     xfer_func;
+       enum v4l2_quantization  quant;
 
        /* Source and destination queue data */
        struct vim2m_q_data   q_data[2];
@@ -493,6 +496,9 @@ static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
        f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
        f->fmt.pix.sizeimage    = q_data->sizeimage;
        f->fmt.pix.colorspace   = ctx->colorspace;
+       f->fmt.pix.xfer_func    = ctx->xfer_func;
+       f->fmt.pix.ycbcr_enc    = ctx->ycbcr_enc;
+       f->fmt.pix.quantization = ctx->quant;
 
        return 0;
 }
@@ -549,6 +555,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
        }
        f->fmt.pix.colorspace = ctx->colorspace;
+       f->fmt.pix.xfer_func = ctx->xfer_func;
+       f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc;
+       f->fmt.pix.quantization = ctx->quant;
 
        return vidioc_try_fmt(f, fmt);
 }
@@ -630,8 +639,12 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
                return ret;
 
        ret = vidioc_s_fmt(file2ctx(file), f);
-       if (!ret)
+       if (!ret) {
                ctx->colorspace = f->fmt.pix.colorspace;
+               ctx->xfer_func = f->fmt.pix.xfer_func;
+               ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
+               ctx->quant = f->fmt.pix.quantization;
+       }
        return ret;
 }
 
index 66aa729..f9f878b 100644 (file)
@@ -169,7 +169,6 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
        struct vivid_dev *dev = adap->priv;
        struct cec_msg reply;
        u8 dest = cec_msg_destination(msg);
-       u16 pa;
        u8 disp_ctl;
        char osd[14];
 
@@ -178,15 +177,6 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
        cec_msg_init(&reply, dest, cec_msg_initiator(msg));
 
        switch (cec_msg_opcode(msg)) {
-       case CEC_MSG_SET_STREAM_PATH:
-               if (cec_is_sink(adap))
-                       return -ENOMSG;
-               cec_ops_set_stream_path(msg, &pa);
-               if (pa != adap->phys_addr)
-                       return -ENOMSG;
-               cec_msg_active_source(&reply, adap->phys_addr);
-               cec_transmit_msg(adap, &reply, false);
-               break;
        case CEC_MSG_SET_OSD_STRING:
                if (!cec_is_sink(adap))
                        return -ENOMSG;
index 863f658..59fa204 100644 (file)
@@ -27,7 +27,7 @@ struct vb2_dc_buf {
        unsigned long                   size;
        void                            *cookie;
        dma_addr_t                      dma_addr;
-       struct dma_attrs                attrs;
+       unsigned long                   attrs;
        enum dma_data_direction         dma_dir;
        struct sg_table                 *dma_sgt;
        struct frame_vector             *vec;
@@ -130,12 +130,12 @@ static void vb2_dc_put(void *buf_priv)
                kfree(buf->sgt_base);
        }
        dma_free_attrs(buf->dev, buf->size, buf->cookie, buf->dma_addr,
-                       &buf->attrs);
+                      buf->attrs);
        put_device(buf->dev);
        kfree(buf);
 }
 
-static void *vb2_dc_alloc(struct device *dev, const struct dma_attrs *attrs,
+static void *vb2_dc_alloc(struct device *dev, unsigned long attrs,
                          unsigned long size, enum dma_data_direction dma_dir,
                          gfp_t gfp_flags)
 {
@@ -146,16 +146,16 @@ static void *vb2_dc_alloc(struct device *dev, const struct dma_attrs *attrs,
                return ERR_PTR(-ENOMEM);
 
        if (attrs)
-               buf->attrs = *attrs;
+               buf->attrs = attrs;
        buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,
-                                       GFP_KERNEL | gfp_flags, &buf->attrs);
+                                       GFP_KERNEL | gfp_flags, buf->attrs);
        if (!buf->cookie) {
                dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
                kfree(buf);
                return ERR_PTR(-ENOMEM);
        }
 
-       if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->attrs))
+       if ((buf->attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0)
                buf->vaddr = buf->cookie;
 
        /* Prevent the device from being released while the buffer is used */
@@ -189,7 +189,7 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
        vma->vm_pgoff = 0;
 
        ret = dma_mmap_attrs(buf->dev, vma, buf->cookie,
-               buf->dma_addr, buf->size, &buf->attrs);
+               buf->dma_addr, buf->size, buf->attrs);
 
        if (ret) {
                pr_err("Remapping memory failed, error: %d\n", ret);
@@ -372,7 +372,7 @@ static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf)
        }
 
        ret = dma_get_sgtable_attrs(buf->dev, sgt, buf->cookie, buf->dma_addr,
-               buf->size, &buf->attrs);
+               buf->size, buf->attrs);
        if (ret < 0) {
                dev_err(buf->dev, "failed to get scatterlist from DMA API\n");
                kfree(sgt);
@@ -421,15 +421,12 @@ static void vb2_dc_put_userptr(void *buf_priv)
        struct page **pages;
 
        if (sgt) {
-               DEFINE_DMA_ATTRS(attrs);
-
-               dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
                /*
                 * No need to sync to CPU, it's already synced to the CPU
                 * since the finish() memop will have been called before this.
                 */
                dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                                  buf->dma_dir, &attrs);
+                                  buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
                pages = frame_vector_pages(buf->vec);
                /* sgt should exist only if vector contains pages... */
                BUG_ON(IS_ERR(pages));
@@ -484,9 +481,6 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
        struct sg_table *sgt;
        unsigned long contig_size;
        unsigned long dma_align = dma_get_cache_alignment();
-       DEFINE_DMA_ATTRS(attrs);
-
-       dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
 
        /* Only cache aligned DMA transfers are reliable */
        if (!IS_ALIGNED(vaddr | size, dma_align)) {
@@ -548,7 +542,7 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
         * prepare() memop is called.
         */
        sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                                     buf->dma_dir, &attrs);
+                                     buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
        if (sgt->nents <= 0) {
                pr_err("failed to map scatterlist\n");
                ret = -EIO;
@@ -572,7 +566,7 @@ out:
 
 fail_map_sg:
        dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                          buf->dma_dir, &attrs);
+                          buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
 
 fail_sgt_init:
        sg_free_table(sgt);
@@ -749,7 +743,7 @@ EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
 int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size)
 {
        if (!dev->dma_parms) {
-               dev->dma_parms = kzalloc(sizeof(dev->dma_parms), GFP_KERNEL);
+               dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
                if (!dev->dma_parms)
                        return -ENOMEM;
        }
index a39db8a..bd82d70 100644 (file)
@@ -95,7 +95,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
        return 0;
 }
 
-static void *vb2_dma_sg_alloc(struct device *dev, const struct dma_attrs *dma_attrs,
+static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
                              unsigned long size, enum dma_data_direction dma_dir,
                              gfp_t gfp_flags)
 {
@@ -103,9 +103,6 @@ static void *vb2_dma_sg_alloc(struct device *dev, const struct dma_attrs *dma_at
        struct sg_table *sgt;
        int ret;
        int num_pages;
-       DEFINE_DMA_ATTRS(attrs);
-
-       dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
 
        if (WARN_ON(dev == NULL))
                return NULL;
@@ -144,7 +141,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, const struct dma_attrs *dma_at
         * prepare() memop is called.
         */
        sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                                     buf->dma_dir, &attrs);
+                                     buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
        if (!sgt->nents)
                goto fail_map;
 
@@ -179,13 +176,10 @@ static void vb2_dma_sg_put(void *buf_priv)
        int i = buf->num_pages;
 
        if (atomic_dec_and_test(&buf->refcount)) {
-               DEFINE_DMA_ATTRS(attrs);
-
-               dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
                dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
                        buf->num_pages);
                dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                                  buf->dma_dir, &attrs);
+                                  buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
                if (buf->vaddr)
                        vm_unmap_ram(buf->vaddr, buf->num_pages);
                sg_free_table(buf->dma_sgt);
@@ -228,10 +222,8 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
 {
        struct vb2_dma_sg_buf *buf;
        struct sg_table *sgt;
-       DEFINE_DMA_ATTRS(attrs);
        struct frame_vector *vec;
 
-       dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
        buf = kzalloc(sizeof *buf, GFP_KERNEL);
        if (!buf)
                return NULL;
@@ -262,7 +254,7 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
         * prepare() memop is called.
         */
        sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
-                                     buf->dma_dir, &attrs);
+                                     buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
        if (!sgt->nents)
                goto userptr_fail_map;
 
@@ -286,14 +278,11 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
        struct vb2_dma_sg_buf *buf = buf_priv;
        struct sg_table *sgt = &buf->sg_table;
        int i = buf->num_pages;
-       DEFINE_DMA_ATTRS(attrs);
-
-       dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
 
        dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
               __func__, buf->num_pages);
        dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir,
-                          &attrs);
+                          DMA_ATTR_SKIP_CPU_SYNC);
        if (buf->vaddr)
                vm_unmap_ram(buf->vaddr, buf->num_pages);
        sg_free_table(buf->dma_sgt);
index 7e8a07e..c2820a6 100644 (file)
@@ -33,7 +33,7 @@ struct vb2_vmalloc_buf {
 
 static void vb2_vmalloc_put(void *buf_priv);
 
-static void *vb2_vmalloc_alloc(struct device *dev, const struct dma_attrs *attrs,
+static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs,
                               unsigned long size, enum dma_data_direction dma_dir,
                               gfp_t gfp_flags)
 {
index 1337123..4b4c0c3 100644 (file)
@@ -115,7 +115,7 @@ config FSL_CORENET_CF
 
 config FSL_IFC
        bool
-       depends on FSL_SOC
+       depends on FSL_SOC || ARCH_LAYERSCAPE
 
 config JZ4780_NEMC
        bool "Ingenic JZ4780 SoC NEMC driver"
index 904b4af..1b182b1 100644 (file)
@@ -31,7 +31,9 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_ifc.h>
-#include <asm/prom.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
 EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
index 40bb8ae..aacf584 100644 (file)
@@ -2338,23 +2338,11 @@ static struct memstick_driver msb_driver = {
        .resume   = msb_resume
 };
 
-static int major;
-
 static int __init msb_init(void)
 {
-       int rc = register_blkdev(0, DRIVER_NAME);
-
-       if (rc < 0) {
-               pr_err("failed to register major (error %d)\n", rc);
-               return rc;
-       }
-
-       major = rc;
-       rc = memstick_register_driver(&msb_driver);
-       if (rc) {
-               unregister_blkdev(major, DRIVER_NAME);
+       int rc = memstick_register_driver(&msb_driver);
+       if (rc)
                pr_err("failed to register memstick driver (error %d)\n", rc);
-       }
 
        return rc;
 }
@@ -2362,7 +2350,6 @@ static int __init msb_init(void)
 static void __exit msb_exit(void)
 {
        memstick_unregister_driver(&msb_driver);
-       unregister_blkdev(major, DRIVER_NAME);
        idr_destroy(&msb_disk_idr);
 }
 
index 4387ccb..7410c6d 100644 (file)
@@ -69,5 +69,6 @@ OBJCOPYFLAGS :=
 OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
                        --set-section-flags .text=alloc,readonly \
                        --rename-section .text=.rodata
-$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o
+targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o
+$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE
        $(call if_changed,objcopy)
index 4cf8f82..a70b853 100644 (file)
@@ -182,7 +182,7 @@ static void genwqe_dev_free(struct genwqe_dev *cd)
  */
 static int genwqe_bus_reset(struct genwqe_dev *cd)
 {
-       int bars, rc = 0;
+       int rc = 0;
        struct pci_dev *pci_dev = cd->pci_dev;
        void __iomem *mmio;
 
@@ -193,8 +193,7 @@ static int genwqe_bus_reset(struct genwqe_dev *cd)
        cd->mmio = NULL;
        pci_iounmap(pci_dev, mmio);
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
 
        /*
         * Firmware/BIOS might change memory mapping during bus reset.
@@ -218,7 +217,7 @@ static int genwqe_bus_reset(struct genwqe_dev *cd)
                            GENWQE_INJECT_GFIR_FATAL |
                            GENWQE_INJECT_GFIR_INFO);
 
-       rc = pci_request_selected_regions(pci_dev, bars, genwqe_driver_name);
+       rc = pci_request_mem_regions(pci_dev, genwqe_driver_name);
        if (rc) {
                dev_err(&pci_dev->dev,
                        "[%s] err: request bars failed (%d)\n", __func__, rc);
@@ -1068,10 +1067,9 @@ static int genwqe_health_check_stop(struct genwqe_dev *cd)
  */
 static int genwqe_pci_setup(struct genwqe_dev *cd)
 {
-       int err, bars;
+       int err;
        struct pci_dev *pci_dev = cd->pci_dev;
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
        err = pci_enable_device_mem(pci_dev);
        if (err) {
                dev_err(&pci_dev->dev,
@@ -1080,7 +1078,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
        }
 
        /* Reserve PCI I/O and memory resources */
-       err = pci_request_selected_regions(pci_dev, bars, genwqe_driver_name);
+       err = pci_request_mem_regions(pci_dev, genwqe_driver_name);
        if (err) {
                dev_err(&pci_dev->dev,
                        "[%s] err: request bars failed (%d)\n", __func__, err);
@@ -1142,7 +1140,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
  out_iounmap:
        pci_iounmap(pci_dev, cd->mmio);
  out_release_resources:
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
  err_disable_device:
        pci_disable_device(pci_dev);
  err_out:
@@ -1154,14 +1152,12 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
  */
 static void genwqe_pci_remove(struct genwqe_dev *cd)
 {
-       int bars;
        struct pci_dev *pci_dev = cd->pci_dev;
 
        if (cd->mmio)
                pci_iounmap(pci_dev, cd->mmio);
 
-       bars = pci_select_bars(pci_dev, IORESOURCE_MEM);
-       pci_release_selected_regions(pci_dev, bars);
+       pci_release_mem_regions(pci_dev);
        pci_disable_device(pci_dev);
 }
 
index 5a3fd76..5525a20 100644 (file)
@@ -49,7 +49,7 @@ static noinline void do_usercopy_stack(bool to_user, bool bad_frame)
 
        /* This is a pointer to outside our current stack frame. */
        if (bad_frame) {
-               bad_stack = do_usercopy_stack_callee((uintptr_t)bad_stack);
+               bad_stack = do_usercopy_stack_callee((uintptr_t)&bad_stack);
        } else {
                /* Put start address just inside stack. */
                bad_stack = task_stack_page(current) + THREAD_SIZE;
index 89e5917..6fd9d36 100644 (file)
@@ -146,3 +146,7 @@ config VOP
          More information about the Intel MIC family as well as the Linux
          OS and tools for MIC to use with this driver are available from
          <http://software.intel.com/en-us/mic-developer>.
+
+if VOP
+source "drivers/vhost/Kconfig.vringh"
+endif
index e047efd..9599d73 100644 (file)
@@ -38,7 +38,7 @@ static inline struct mic_device *vpdev_to_mdev(struct device *dev)
 static dma_addr_t
 _mic_dma_map_page(struct device *dev, struct page *page,
                  unsigned long offset, size_t size,
-                 enum dma_data_direction dir, struct dma_attrs *attrs)
+                 enum dma_data_direction dir, unsigned long attrs)
 {
        void *va = phys_to_virt(page_to_phys(page)) + offset;
        struct mic_device *mdev = vpdev_to_mdev(dev);
@@ -48,7 +48,7 @@ _mic_dma_map_page(struct device *dev, struct page *page,
 
 static void _mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
                                size_t size, enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        struct mic_device *mdev = vpdev_to_mdev(dev);
 
@@ -144,7 +144,7 @@ static inline struct mic_device *scdev_to_mdev(struct scif_hw_dev *scdev)
 
 static void *__mic_dma_alloc(struct device *dev, size_t size,
                             dma_addr_t *dma_handle, gfp_t gfp,
-                            struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
        struct mic_device *mdev = scdev_to_mdev(scdev);
@@ -164,7 +164,7 @@ static void *__mic_dma_alloc(struct device *dev, size_t size,
 }
 
 static void __mic_dma_free(struct device *dev, size_t size, void *vaddr,
-                          dma_addr_t dma_handle, struct dma_attrs *attrs)
+                          dma_addr_t dma_handle, unsigned long attrs)
 {
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
        struct mic_device *mdev = scdev_to_mdev(scdev);
@@ -176,7 +176,7 @@ static void __mic_dma_free(struct device *dev, size_t size, void *vaddr,
 static dma_addr_t
 __mic_dma_map_page(struct device *dev, struct page *page, unsigned long offset,
                   size_t size, enum dma_data_direction dir,
-                  struct dma_attrs *attrs)
+                  unsigned long attrs)
 {
        void *va = phys_to_virt(page_to_phys(page)) + offset;
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
@@ -188,7 +188,7 @@ __mic_dma_map_page(struct device *dev, struct page *page, unsigned long offset,
 static void
 __mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
                     size_t size, enum dma_data_direction dir,
-                    struct dma_attrs *attrs)
+                    unsigned long attrs)
 {
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
        struct mic_device *mdev = scdev_to_mdev(scdev);
@@ -198,7 +198,7 @@ __mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
 
 static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg,
                            int nents, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
        struct mic_device *mdev = scdev_to_mdev(scdev);
@@ -229,7 +229,7 @@ err:
 static void __mic_dma_unmap_sg(struct device *dev,
                               struct scatterlist *sg, int nents,
                               enum dma_data_direction dir,
-                              struct dma_attrs *attrs)
+                              unsigned long attrs)
 {
        struct scif_hw_dev *scdev = dev_get_drvdata(dev);
        struct mic_device *mdev = scdev_to_mdev(scdev);
@@ -327,7 +327,7 @@ static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev)
 static dma_addr_t
 mic_dma_map_page(struct device *dev, struct page *page,
                 unsigned long offset, size_t size, enum dma_data_direction dir,
-                struct dma_attrs *attrs)
+                unsigned long attrs)
 {
        void *va = phys_to_virt(page_to_phys(page)) + offset;
        struct mic_device *mdev = dev_get_drvdata(dev->parent);
@@ -338,7 +338,7 @@ mic_dma_map_page(struct device *dev, struct page *page,
 static void
 mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
                   size_t size, enum dma_data_direction dir,
-                  struct dma_attrs *attrs)
+                  unsigned long attrs)
 {
        struct mic_device *mdev = dev_get_drvdata(dev->parent);
        mic_unmap_single(mdev, dma_addr, size);
index 845dd27..3779475 100644 (file)
@@ -122,7 +122,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        for (offset = 0; offset <= master->size - blocksize;
             offset += blocksize) {
                /* Nothing more in higher memory on BCM47XX (MIPS) */
-               if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
+               if (IS_ENABLED(CONFIG_BCM47XX) && offset >= 0x2000000)
                        break;
 
                if (curr_part >= BCM47XXPART_MAX_PARTS) {
index 9a1a6ff..94d3eb4 100644 (file)
@@ -416,7 +416,7 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t
        return ret;
 }
 
-static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
+static int do_write_buffer(struct map_info *map, struct flchip *chip,
                                  unsigned long adr, const u_char *buf, int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
index 64a2485..58329d2 100644 (file)
@@ -113,12 +113,12 @@ config MTD_SST25L
          if you want to specify device partitioning.
 
 config MTD_BCM47XXSFLASH
-       tristate "R/O support for serial flash on BCMA bus"
+       tristate "Support for serial flash on BCMA bus"
        depends on BCMA_SFLASH && (MIPS || ARM)
        help
          BCMA bus can have various flash memories attached, they are
          registered by bcma as platform devices. This enables driver for
-         serial flash memories (only read-only mode is implemented).
+         serial flash memories.
 
 config MTD_SLRAM
        tristate "Uncached system RAM"
@@ -171,18 +171,6 @@ config MTDRAM_ERASE_SIZE
          as a module, it is also possible to specify this as a parameter when
          loading the module.
 
-#If not a module (I don't want to test it as a module)
-config MTDRAM_ABS_POS
-       hex "SRAM Hexadecimal Absolute position or 0"
-       depends on MTD_MTDRAM=y
-       default "0"
-       help
-         If you have system RAM accessible by the CPU but not used by Linux
-         in normal operation, you can give the physical address at which the
-         available RAM starts, and the MTDRAM driver will use it instead of
-         allocating space from Linux's available memory. Otherwise, leave
-         this set to zero. Most people will want to leave this as zero.
-
 config MTD_BLOCK2MTD
        tristate "MTD using block device"
        depends on BLOCK
index 9d68544..9cf7fcd 100644 (file)
@@ -73,14 +73,15 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return spi_write(spi, flash->command, len + 1);
 }
 
-static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
-                       size_t *retlen, const u_char *buf)
+static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+                           const u_char *buf)
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
        struct spi_transfer t[2] = {};
        struct spi_message m;
        int cmd_sz = m25p_cmdsz(nor);
+       ssize_t ret;
 
        spi_message_init(&m);
 
@@ -98,9 +99,14 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
        t[1].len = len;
        spi_message_add_tail(&t[1], &m);
 
-       spi_sync(spi, &m);
+       ret = spi_sync(spi, &m);
+       if (ret)
+               return ret;
 
-       *retlen += m.actual_length - cmd_sz;
+       ret = m.actual_length - cmd_sz;
+       if (ret < 0)
+               return -EIO;
+       return ret;
 }
 
 static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
@@ -119,21 +125,21 @@ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
  * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
  */
-static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf)
+static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+                          u_char *buf)
 {
        struct m25p *flash = nor->priv;
        struct spi_device *spi = flash->spi;
        struct spi_transfer t[2];
        struct spi_message m;
        unsigned int dummy = nor->read_dummy;
+       ssize_t ret;
 
        /* convert the dummy cycles to the number of bytes */
        dummy /= 8;
 
        if (spi_flash_read_supported(spi)) {
                struct spi_flash_read_message msg;
-               int ret;
 
                memset(&msg, 0, sizeof(msg));
 
@@ -149,8 +155,9 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
                msg.data_nbits = m25p80_rx_nbits(nor);
 
                ret = spi_flash_read(spi, &msg);
-               *retlen = msg.retlen;
-               return ret;
+               if (ret < 0)
+                       return ret;
+               return msg.retlen;
        }
 
        spi_message_init(&m);
@@ -165,13 +172,17 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
 
        t[1].rx_buf = buf;
        t[1].rx_nbits = m25p80_rx_nbits(nor);
-       t[1].len = len;
+       t[1].len = min(len, spi_max_transfer_size(spi));
        spi_message_add_tail(&t[1], &m);
 
-       spi_sync(spi, &m);
+       ret = spi_sync(spi, &m);
+       if (ret)
+               return ret;
 
-       *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
-       return 0;
+       ret = m.actual_length - m25p_cmdsz(nor) - dummy;
+       if (ret < 0)
+               return -EIO;
+       return ret;
 }
 
 /*
index 22f3858..3fad359 100644 (file)
@@ -186,7 +186,7 @@ static int of_flash_probe(struct platform_device *dev)
         * consists internally of 2 non-identical NOR chips on one die.
         */
        p = of_get_property(dp, "reg", &count);
-       if (count % reg_tuple_size != 0) {
+       if (!p || count % reg_tuple_size != 0) {
                dev_err(&dev->dev, "Malformed reg property on %s\n",
                                dev->dev.of_node->full_name);
                err = -EINVAL;
index 744ca5c..f9fa3fa 100644 (file)
@@ -75,15 +75,15 @@ static int __init init_msp_flash(void)
 
        printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
 
-       msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+       msp_flash = kcalloc(fcnt, sizeof(*msp_flash), GFP_KERNEL);
        if (!msp_flash)
                return -ENOMEM;
 
-       msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+       msp_parts = kcalloc(fcnt, sizeof(*msp_parts), GFP_KERNEL);
        if (!msp_parts)
                goto free_msp_flash;
 
-       msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+       msp_maps = kcalloc(fcnt, sizeof(*msp_maps), GFP_KERNEL);
        if (!msp_maps)
                goto free_msp_parts;
 
index 142fc3d..784c6e1 100644 (file)
@@ -230,8 +230,10 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
 
                info->mtd = mtd_concat_create(cdev, info->num_subdev,
                                              plat->name);
-               if (info->mtd == NULL)
+               if (info->mtd == NULL) {
                        ret = -ENXIO;
+                       goto err;
+               }
        }
        info->mtd->dev.parent = &pdev->dev;
 
index f05e0e9..21ff580 100644 (file)
@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
 
 config MTD_NAND_FSL_IFC
        tristate "NAND support for Freescale IFC controller"
-       depends on MTD_NAND && FSL_SOC
+       depends on MTD_NAND && (FSL_SOC || ARCH_LAYERSCAPE)
        select FSL_IFC
        select MEMORY
        help
@@ -539,7 +539,6 @@ config MTD_NAND_FSMC
 config MTD_NAND_XWAY
        tristate "Support for NAND on Lantiq XWAY SoC"
        depends on LANTIQ && SOC_TYPE_XWAY
-       select MTD_NAND_PLATFORM
        help
          Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
          to the External Bus Unit (EBU).
@@ -563,4 +562,11 @@ config MTD_NAND_QCOM
          Enables support for NAND flash chips on SoCs containing the EBI2 NAND
          controller. This controller is found on IPQ806x SoC.
 
+config MTD_NAND_MTK
+       tristate "Support for NAND controller on MTK SoCs"
+       depends on HAS_DMA
+       help
+         Enables support for NAND controller on MTK SoCs.
+         This controller is found on mt27xx, mt81xx, mt65xx SoCs.
+
 endif # MTD_NAND
index f553353..cafde6f 100644 (file)
@@ -57,5 +57,6 @@ obj-$(CONFIG_MTD_NAND_SUNXI)          += sunxi_nand.o
 obj-$(CONFIG_MTD_NAND_HISI504)         += hisi504_nand.o
 obj-$(CONFIG_MTD_NAND_BRCMNAND)                += brcmnand/
 obj-$(CONFIG_MTD_NAND_QCOM)            += qcom_nandc.o
+obj-$(CONFIG_MTD_NAND_MTK)             += mtk_nand.o mtk_ecc.o
 
 nand-objs := nand_base.o nand_bbt.o nand_timings.o
index b76ad7c..8eb2c64 100644 (file)
@@ -340,6 +340,36 @@ static const u16 brcmnand_regs_v71[] = {
        [BRCMNAND_FC_BASE]              = 0x400,
 };
 
+/* BRCMNAND v7.2 */
+static const u16 brcmnand_regs_v72[] = {
+       [BRCMNAND_CMD_START]            =  0x04,
+       [BRCMNAND_CMD_EXT_ADDRESS]      =  0x08,
+       [BRCMNAND_CMD_ADDRESS]          =  0x0c,
+       [BRCMNAND_INTFC_STATUS]         =  0x14,
+       [BRCMNAND_CS_SELECT]            =  0x18,
+       [BRCMNAND_CS_XOR]               =  0x1c,
+       [BRCMNAND_LL_OP]                =  0x20,
+       [BRCMNAND_CS0_BASE]             =  0x50,
+       [BRCMNAND_CS1_BASE]             =     0,
+       [BRCMNAND_CORR_THRESHOLD]       =  0xdc,
+       [BRCMNAND_CORR_THRESHOLD_EXT]   =  0xe0,
+       [BRCMNAND_UNCORR_COUNT]         =  0xfc,
+       [BRCMNAND_CORR_COUNT]           = 0x100,
+       [BRCMNAND_CORR_EXT_ADDR]        = 0x10c,
+       [BRCMNAND_CORR_ADDR]            = 0x110,
+       [BRCMNAND_UNCORR_EXT_ADDR]      = 0x114,
+       [BRCMNAND_UNCORR_ADDR]          = 0x118,
+       [BRCMNAND_SEMAPHORE]            = 0x150,
+       [BRCMNAND_ID]                   = 0x194,
+       [BRCMNAND_ID_EXT]               = 0x198,
+       [BRCMNAND_LL_RDATA]             = 0x19c,
+       [BRCMNAND_OOB_READ_BASE]        = 0x200,
+       [BRCMNAND_OOB_READ_10_BASE]     =     0,
+       [BRCMNAND_OOB_WRITE_BASE]       = 0x400,
+       [BRCMNAND_OOB_WRITE_10_BASE]    =     0,
+       [BRCMNAND_FC_BASE]              = 0x600,
+};
+
 enum brcmnand_cs_reg {
        BRCMNAND_CS_CFG_EXT = 0,
        BRCMNAND_CS_CFG,
@@ -435,7 +465,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        }
 
        /* Register offsets */
-       if (ctrl->nand_version >= 0x0701)
+       if (ctrl->nand_version >= 0x0702)
+               ctrl->reg_offsets = brcmnand_regs_v72;
+       else if (ctrl->nand_version >= 0x0701)
                ctrl->reg_offsets = brcmnand_regs_v71;
        else if (ctrl->nand_version >= 0x0600)
                ctrl->reg_offsets = brcmnand_regs_v60;
@@ -480,7 +512,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        }
 
        /* Maximum spare area sector size (per 512B) */
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0702)
+               ctrl->max_oob = 128;
+       else if (ctrl->nand_version >= 0x0600)
                ctrl->max_oob = 64;
        else if (ctrl->nand_version >= 0x0500)
                ctrl->max_oob = 32;
@@ -583,14 +617,20 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
        enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
        int cs = host->cs;
 
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0702)
+               bits = 7;
+       else if (ctrl->nand_version >= 0x0600)
                bits = 6;
        else if (ctrl->nand_version >= 0x0500)
                bits = 5;
        else
                bits = 4;
 
-       if (ctrl->nand_version >= 0x0600) {
+       if (ctrl->nand_version >= 0x0702) {
+               if (cs >= 4)
+                       reg = BRCMNAND_CORR_THRESHOLD_EXT;
+               shift = (cs % 4) * bits;
+       } else if (ctrl->nand_version >= 0x0600) {
                if (cs >= 5)
                        reg = BRCMNAND_CORR_THRESHOLD_EXT;
                shift = (cs % 5) * bits;
@@ -631,19 +671,28 @@ enum {
 
 static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
 {
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0702)
+               return GENMASK(7, 0);
+       else if (ctrl->nand_version >= 0x0600)
                return GENMASK(6, 0);
        else
                return GENMASK(5, 0);
 }
 
 #define NAND_ACC_CONTROL_ECC_SHIFT     16
+#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13
 
 static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
 {
        u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
 
-       return mask << NAND_ACC_CONTROL_ECC_SHIFT;
+       mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
+
+       /* v7.2 includes additional ECC levels */
+       if (ctrl->nand_version >= 0x0702)
+               mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
+
+       return mask;
 }
 
 static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
@@ -667,7 +716,9 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
 
 static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
 {
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0702)
+               return 9;
+       else if (ctrl->nand_version >= 0x0600)
                return 7;
        else if (ctrl->nand_version >= 0x0500)
                return 6;
@@ -773,10 +824,16 @@ enum brcmnand_llop_type {
  * Internal support functions
  ***********************************************************************/
 
-static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
+static inline bool is_hamming_ecc(struct brcmnand_controller *ctrl,
+                                 struct brcmnand_cfg *cfg)
 {
-       return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
-               cfg->ecc_level == 15;
+       if (ctrl->nand_version <= 0x0701)
+               return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
+                       cfg->ecc_level == 15;
+       else
+               return cfg->sector_size_1k == 0 && ((cfg->spare_area_size == 16 &&
+                       cfg->ecc_level == 15) ||
+                       (cfg->spare_area_size == 28 && cfg->ecc_level == 16));
 }
 
 /*
@@ -931,7 +988,7 @@ static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
        if (p->sector_size_1k)
                ecc_level <<= 1;
 
-       if (is_hamming_ecc(p)) {
+       if (is_hamming_ecc(host->ctrl, p)) {
                ecc->bytes = 3 * sectors;
                mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
                return 0;
@@ -1108,7 +1165,7 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
        ctrl->cmd_pending = cmd;
 
        intfc = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
-       BUG_ON(!(intfc & INTFC_CTLR_READY));
+       WARN_ON(!(intfc & INTFC_CTLR_READY));
 
        mb(); /* flush previous writes */
        brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
@@ -1545,6 +1602,56 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
        return ret;
 }
 
+/*
+ * Check a page to see if it is erased (w/ bitflips) after an uncorrectable ECC
+ * error
+ *
+ * Because the HW ECC signals an ECC error if an erase paged has even a single
+ * bitflip, we must check each ECC error to see if it is actually an erased
+ * page with bitflips, not a truly corrupted page.
+ *
+ * On a real error, return a negative error code (-EBADMSG for ECC error), and
+ * buf will contain raw data.
+ * Otherwise, buf gets filled with 0xffs and return the maximum number of
+ * bitflips-per-ECC-sector to the caller.
+ *
+ */
+static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
+                 struct nand_chip *chip, void *buf, u64 addr)
+{
+       int i, sas;
+       void *oob = chip->oob_poi;
+       int bitflips = 0;
+       int page = addr >> chip->page_shift;
+       int ret;
+
+       if (!buf) {
+               buf = chip->buffers->databuf;
+               /* Invalidate page cache */
+               chip->pagebuf = -1;
+       }
+
+       sas = mtd->oobsize / chip->ecc.steps;
+
+       /* read without ecc for verification */
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+       ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
+               ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size,
+                                                 oob, sas, NULL, 0,
+                                                 chip->ecc.strength);
+               if (ret < 0)
+                       return ret;
+
+               bitflips = max(bitflips, ret);
+       }
+
+       return bitflips;
+}
+
 static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
                         u64 addr, unsigned int trans, u32 *buf, u8 *oob)
 {
@@ -1552,9 +1659,11 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
        struct brcmnand_controller *ctrl = host->ctrl;
        u64 err_addr = 0;
        int err;
+       bool retry = true;
 
        dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
 
+try_dmaread:
        brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
 
        if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
@@ -1575,6 +1684,34 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
        }
 
        if (mtd_is_eccerr(err)) {
+               /*
+                * On controller version and 7.0, 7.1 , DMA read after a
+                * prior PIO read that reported uncorrectable error,
+                * the DMA engine captures this error following DMA read
+                * cleared only on subsequent DMA read, so just retry once
+                * to clear a possible false error reported for current DMA
+                * read
+                */
+               if ((ctrl->nand_version == 0x0700) ||
+                   (ctrl->nand_version == 0x0701)) {
+                       if (retry) {
+                               retry = false;
+                               goto try_dmaread;
+                       }
+               }
+
+               /*
+                * Controller version 7.2 has hw encoder to detect erased page
+                * bitflips, apply sw verification for older controllers only
+                */
+               if (ctrl->nand_version < 0x0702) {
+                       err = brcmstb_nand_verify_erased_page(mtd, chip, buf,
+                                                             addr);
+                       /* erased page bitflips corrected */
+                       if (err > 0)
+                               return err;
+               }
+
                dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
                        (unsigned long long)err_addr);
                mtd->ecc_stats.failed++;
@@ -1857,7 +1994,8 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
        return 0;
 }
 
-static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
+static void brcmnand_print_cfg(struct brcmnand_host *host,
+                              char *buf, struct brcmnand_cfg *cfg)
 {
        buf += sprintf(buf,
                "%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
@@ -1868,7 +2006,7 @@ static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
                cfg->spare_area_size, cfg->device_width);
 
        /* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
-       if (is_hamming_ecc(cfg))
+       if (is_hamming_ecc(host->ctrl, cfg))
                sprintf(buf, ", Hamming ECC");
        else if (cfg->sector_size_1k)
                sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
@@ -1987,7 +2125,7 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
 
        brcmnand_set_ecc_enabled(host, 1);
 
-       brcmnand_print_cfg(msg, cfg);
+       brcmnand_print_cfg(host, msg, cfg);
        dev_info(ctrl->dev, "detected %s\n", msg);
 
        /* Configure ACC_CONTROL */
@@ -1995,6 +2133,10 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
        tmp = nand_readreg(ctrl, offs);
        tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
        tmp &= ~ACC_CONTROL_RD_ERASED;
+
+       /* We need to turn on Read from erased paged protected by ECC */
+       if (ctrl->nand_version >= 0x0702)
+               tmp |= ACC_CONTROL_RD_ERASED;
        tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
        if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
                /*
@@ -2195,6 +2337,7 @@ static const struct of_device_id brcmnand_of_match[] = {
        { .compatible = "brcm,brcmnand-v6.2" },
        { .compatible = "brcm,brcmnand-v7.0" },
        { .compatible = "brcm,brcmnand-v7.1" },
+       { .compatible = "brcm,brcmnand-v7.2" },
        {},
 };
 MODULE_DEVICE_TABLE(of, brcmnand_of_match);
index d74f4ba..731c605 100644 (file)
@@ -375,6 +375,6 @@ static struct platform_driver jz4780_bch_driver = {
 module_platform_driver(jz4780_bch_driver);
 
 MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harvey.hunt@imgtec.com>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
 MODULE_DESCRIPTION("Ingenic JZ4780 BCH error correction driver");
 MODULE_LICENSE("GPL v2");
index daf3c42..175f67d 100644 (file)
@@ -412,6 +412,6 @@ static struct platform_driver jz4780_nand_driver = {
 module_platform_driver(jz4780_nand_driver);
 
 MODULE_AUTHOR("Alex Smith <alex@alex-smith.me.uk>");
-MODULE_AUTHOR("Harvey Hunt <harvey.hunt@imgtec.com>");
+MODULE_AUTHOR("Harvey Hunt <harveyhuntnexus@gmail.com>");
 MODULE_DESCRIPTION("Ingenic JZ4780 NAND driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c
new file mode 100644 (file)
index 0000000..25a4fbd
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * MTK ECC controller driver.
+ * Copyright (C) 2016  MediaTek Inc.
+ * Authors:    Xiaolei Li              <xiaolei.li@mediatek.com>
+ *             Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/mutex.h>
+
+#include "mtk_ecc.h"
+
+#define ECC_IDLE_MASK          BIT(0)
+#define ECC_IRQ_EN             BIT(0)
+#define ECC_OP_ENABLE          (1)
+#define ECC_OP_DISABLE         (0)
+
+#define ECC_ENCCON             (0x00)
+#define ECC_ENCCNFG            (0x04)
+#define                ECC_CNFG_4BIT           (0)
+#define                ECC_CNFG_6BIT           (1)
+#define                ECC_CNFG_8BIT           (2)
+#define                ECC_CNFG_10BIT          (3)
+#define                ECC_CNFG_12BIT          (4)
+#define                ECC_CNFG_14BIT          (5)
+#define                ECC_CNFG_16BIT          (6)
+#define                ECC_CNFG_18BIT          (7)
+#define                ECC_CNFG_20BIT          (8)
+#define                ECC_CNFG_22BIT          (9)
+#define                ECC_CNFG_24BIT          (0xa)
+#define                ECC_CNFG_28BIT          (0xb)
+#define                ECC_CNFG_32BIT          (0xc)
+#define                ECC_CNFG_36BIT          (0xd)
+#define                ECC_CNFG_40BIT          (0xe)
+#define                ECC_CNFG_44BIT          (0xf)
+#define                ECC_CNFG_48BIT          (0x10)
+#define                ECC_CNFG_52BIT          (0x11)
+#define                ECC_CNFG_56BIT          (0x12)
+#define                ECC_CNFG_60BIT          (0x13)
+#define                ECC_MODE_SHIFT          (5)
+#define                ECC_MS_SHIFT            (16)
+#define ECC_ENCDIADDR          (0x08)
+#define ECC_ENCIDLE            (0x0C)
+#define ECC_ENCPAR(x)          (0x10 + (x) * sizeof(u32))
+#define ECC_ENCIRQ_EN          (0x80)
+#define ECC_ENCIRQ_STA         (0x84)
+#define ECC_DECCON             (0x100)
+#define ECC_DECCNFG            (0x104)
+#define                DEC_EMPTY_EN            BIT(31)
+#define                DEC_CNFG_CORRECT        (0x3 << 12)
+#define ECC_DECIDLE            (0x10C)
+#define ECC_DECENUM0           (0x114)
+#define                ERR_MASK                (0x3f)
+#define ECC_DECDONE            (0x124)
+#define ECC_DECIRQ_EN          (0x200)
+#define ECC_DECIRQ_STA         (0x204)
+
+#define ECC_TIMEOUT            (500000)
+
+#define ECC_IDLE_REG(op)       ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
+#define ECC_CTL_REG(op)                ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+#define ECC_IRQ_REG(op)                ((op) == ECC_ENCODE ? \
+                                       ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
+
+struct mtk_ecc {
+       struct device *dev;
+       void __iomem *regs;
+       struct clk *clk;
+
+       struct completion done;
+       struct mutex lock;
+       u32 sectors;
+};
+
+static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+                                    enum mtk_ecc_operation op)
+{
+       struct device *dev = ecc->dev;
+       u32 val;
+       int ret;
+
+       ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(op), val,
+                                       val & ECC_IDLE_MASK,
+                                       10, ECC_TIMEOUT);
+       if (ret)
+               dev_warn(dev, "%s NOT idle\n",
+                        op == ECC_ENCODE ? "encoder" : "decoder");
+}
+
+static irqreturn_t mtk_ecc_irq(int irq, void *id)
+{
+       struct mtk_ecc *ecc = id;
+       enum mtk_ecc_operation op;
+       u32 dec, enc;
+
+       dec = readw(ecc->regs + ECC_DECIRQ_STA) & ECC_IRQ_EN;
+       if (dec) {
+               op = ECC_DECODE;
+               dec = readw(ecc->regs + ECC_DECDONE);
+               if (dec & ecc->sectors) {
+                       ecc->sectors = 0;
+                       complete(&ecc->done);
+               } else {
+                       return IRQ_HANDLED;
+               }
+       } else {
+               enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ECC_IRQ_EN;
+               if (enc) {
+                       op = ECC_ENCODE;
+                       complete(&ecc->done);
+               } else {
+                       return IRQ_NONE;
+               }
+       }
+
+       writel(0, ecc->regs + ECC_IRQ_REG(op));
+
+       return IRQ_HANDLED;
+}
+
+static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+       u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
+       u32 reg;
+
+       switch (config->strength) {
+       case 4:
+               ecc_bit = ECC_CNFG_4BIT;
+               break;
+       case 6:
+               ecc_bit = ECC_CNFG_6BIT;
+               break;
+       case 8:
+               ecc_bit = ECC_CNFG_8BIT;
+               break;
+       case 10:
+               ecc_bit = ECC_CNFG_10BIT;
+               break;
+       case 12:
+               ecc_bit = ECC_CNFG_12BIT;
+               break;
+       case 14:
+               ecc_bit = ECC_CNFG_14BIT;
+               break;
+       case 16:
+               ecc_bit = ECC_CNFG_16BIT;
+               break;
+       case 18:
+               ecc_bit = ECC_CNFG_18BIT;
+               break;
+       case 20:
+               ecc_bit = ECC_CNFG_20BIT;
+               break;
+       case 22:
+               ecc_bit = ECC_CNFG_22BIT;
+               break;
+       case 24:
+               ecc_bit = ECC_CNFG_24BIT;
+               break;
+       case 28:
+               ecc_bit = ECC_CNFG_28BIT;
+               break;
+       case 32:
+               ecc_bit = ECC_CNFG_32BIT;
+               break;
+       case 36:
+               ecc_bit = ECC_CNFG_36BIT;
+               break;
+       case 40:
+               ecc_bit = ECC_CNFG_40BIT;
+               break;
+       case 44:
+               ecc_bit = ECC_CNFG_44BIT;
+               break;
+       case 48:
+               ecc_bit = ECC_CNFG_48BIT;
+               break;
+       case 52:
+               ecc_bit = ECC_CNFG_52BIT;
+               break;
+       case 56:
+               ecc_bit = ECC_CNFG_56BIT;
+               break;
+       case 60:
+               ecc_bit = ECC_CNFG_60BIT;
+               break;
+       default:
+               dev_err(ecc->dev, "invalid strength %d, default to 4 bits\n",
+                       config->strength);
+       }
+
+       if (config->op == ECC_ENCODE) {
+               /* configure ECC encoder (in bits) */
+               enc_sz = config->len << 3;
+
+               reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+               reg |= (enc_sz << ECC_MS_SHIFT);
+               writel(reg, ecc->regs + ECC_ENCCNFG);
+
+               if (config->mode != ECC_NFI_MODE)
+                       writel(lower_32_bits(config->addr),
+                              ecc->regs + ECC_ENCDIADDR);
+
+       } else {
+               /* configure ECC decoder (in bits) */
+               dec_sz = (config->len << 3) +
+                                       config->strength * ECC_PARITY_BITS;
+
+               reg = ecc_bit | (config->mode << ECC_MODE_SHIFT);
+               reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
+               reg |= DEC_EMPTY_EN;
+               writel(reg, ecc->regs + ECC_DECCNFG);
+
+               if (config->sectors)
+                       ecc->sectors = 1 << (config->sectors - 1);
+       }
+}
+
+void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
+                      int sectors)
+{
+       u32 offset, i, err;
+       u32 bitflips = 0;
+
+       stats->corrected = 0;
+       stats->failed = 0;
+
+       for (i = 0; i < sectors; i++) {
+               offset = (i >> 2) << 2;
+               err = readl(ecc->regs + ECC_DECENUM0 + offset);
+               err = err >> ((i % 4) * 8);
+               err &= ERR_MASK;
+               if (err == ERR_MASK) {
+                       /* uncorrectable errors */
+                       stats->failed++;
+                       continue;
+               }
+
+               stats->corrected += err;
+               bitflips = max_t(u32, bitflips, err);
+       }
+
+       stats->bitflips = bitflips;
+}
+EXPORT_SYMBOL(mtk_ecc_get_stats);
+
+void mtk_ecc_release(struct mtk_ecc *ecc)
+{
+       clk_disable_unprepare(ecc->clk);
+       put_device(ecc->dev);
+}
+EXPORT_SYMBOL(mtk_ecc_release);
+
+static void mtk_ecc_hw_init(struct mtk_ecc *ecc)
+{
+       mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+       writew(ECC_OP_DISABLE, ecc->regs + ECC_ENCCON);
+
+       mtk_ecc_wait_idle(ecc, ECC_DECODE);
+       writel(ECC_OP_DISABLE, ecc->regs + ECC_DECCON);
+}
+
+static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
+{
+       struct platform_device *pdev;
+       struct mtk_ecc *ecc;
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev || !platform_get_drvdata(pdev))
+               return ERR_PTR(-EPROBE_DEFER);
+
+       get_device(&pdev->dev);
+       ecc = platform_get_drvdata(pdev);
+       clk_prepare_enable(ecc->clk);
+       mtk_ecc_hw_init(ecc);
+
+       return ecc;
+}
+
+struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
+{
+       struct mtk_ecc *ecc = NULL;
+       struct device_node *np;
+
+       np = of_parse_phandle(of_node, "ecc-engine", 0);
+       if (np) {
+               ecc = mtk_ecc_get(np);
+               of_node_put(np);
+       }
+
+       return ecc;
+}
+EXPORT_SYMBOL(of_mtk_ecc_get);
+
+int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+{
+       enum mtk_ecc_operation op = config->op;
+       int ret;
+
+       ret = mutex_lock_interruptible(&ecc->lock);
+       if (ret) {
+               dev_err(ecc->dev, "interrupted when attempting to lock\n");
+               return ret;
+       }
+
+       mtk_ecc_wait_idle(ecc, op);
+       mtk_ecc_config(ecc, config);
+       writew(ECC_OP_ENABLE, ecc->regs + ECC_CTL_REG(op));
+
+       init_completion(&ecc->done);
+       writew(ECC_IRQ_EN, ecc->regs + ECC_IRQ_REG(op));
+
+       return 0;
+}
+EXPORT_SYMBOL(mtk_ecc_enable);
+
+void mtk_ecc_disable(struct mtk_ecc *ecc)
+{
+       enum mtk_ecc_operation op = ECC_ENCODE;
+
+       /* find out the running operation */
+       if (readw(ecc->regs + ECC_CTL_REG(op)) != ECC_OP_ENABLE)
+               op = ECC_DECODE;
+
+       /* disable it */
+       mtk_ecc_wait_idle(ecc, op);
+       writew(0, ecc->regs + ECC_IRQ_REG(op));
+       writew(ECC_OP_DISABLE, ecc->regs + ECC_CTL_REG(op));
+
+       mutex_unlock(&ecc->lock);
+}
+EXPORT_SYMBOL(mtk_ecc_disable);
+
+int mtk_ecc_wait_done(struct mtk_ecc *ecc, enum mtk_ecc_operation op)
+{
+       int ret;
+
+       ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
+       if (!ret) {
+               dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
+                       (op == ECC_ENCODE) ? "encoder" : "decoder");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mtk_ecc_wait_done);
+
+int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+                  u8 *data, u32 bytes)
+{
+       dma_addr_t addr;
+       u32 *p, len, i;
+       int ret = 0;
+
+       addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
+       ret = dma_mapping_error(ecc->dev, addr);
+       if (ret) {
+               dev_err(ecc->dev, "dma mapping error\n");
+               return -EINVAL;
+       }
+
+       config->op = ECC_ENCODE;
+       config->addr = addr;
+       ret = mtk_ecc_enable(ecc, config);
+       if (ret) {
+               dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
+               return ret;
+       }
+
+       ret = mtk_ecc_wait_done(ecc, ECC_ENCODE);
+       if (ret)
+               goto timeout;
+
+       mtk_ecc_wait_idle(ecc, ECC_ENCODE);
+
+       /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+       len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
+       p = (u32 *)(data + bytes);
+
+       /* write the parity bytes generated by the ECC back to the OOB region */
+       for (i = 0; i < len; i++)
+               p[i] = readl(ecc->regs + ECC_ENCPAR(i));
+timeout:
+
+       dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
+       mtk_ecc_disable(ecc);
+
+       return ret;
+}
+EXPORT_SYMBOL(mtk_ecc_encode);
+
+void mtk_ecc_adjust_strength(u32 *p)
+{
+       u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
+                       40, 44, 48, 52, 56, 60};
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ecc); i++) {
+               if (*p <= ecc[i]) {
+                       if (!i)
+                               *p = ecc[i];
+                       else if (*p != ecc[i])
+                               *p = ecc[i - 1];
+                       return;
+               }
+       }
+
+       *p = ecc[ARRAY_SIZE(ecc) - 1];
+}
+EXPORT_SYMBOL(mtk_ecc_adjust_strength);
+
+static int mtk_ecc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_ecc *ecc;
+       struct resource *res;
+       int irq, ret;
+
+       ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
+       if (!ecc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ecc->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ecc->regs)) {
+               dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
+               return PTR_ERR(ecc->regs);
+       }
+
+       ecc->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(ecc->clk)) {
+               dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
+               return PTR_ERR(ecc->clk);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "failed to get irq\n");
+               return -EINVAL;
+       }
+
+       ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(dev, "failed to set DMA mask\n");
+               return ret;
+       }
+
+       ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
+       if (ret) {
+               dev_err(dev, "failed to request irq\n");
+               return -EINVAL;
+       }
+
+       ecc->dev = dev;
+       mutex_init(&ecc->lock);
+       platform_set_drvdata(pdev, ecc);
+       dev_info(dev, "probed\n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_ecc_suspend(struct device *dev)
+{
+       struct mtk_ecc *ecc = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(ecc->clk);
+
+       return 0;
+}
+
+static int mtk_ecc_resume(struct device *dev)
+{
+       struct mtk_ecc *ecc = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(ecc->clk);
+       if (ret) {
+               dev_err(dev, "failed to enable clk\n");
+               return ret;
+       }
+
+       mtk_ecc_hw_init(ecc);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
+#endif
+
+static const struct of_device_id mtk_ecc_dt_match[] = {
+       { .compatible = "mediatek,mt2701-ecc" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
+
+static struct platform_driver mtk_ecc_driver = {
+       .probe  = mtk_ecc_probe,
+       .driver = {
+               .name  = "mtk-ecc",
+               .of_match_table = of_match_ptr(mtk_ecc_dt_match),
+#ifdef CONFIG_PM_SLEEP
+               .pm = &mtk_ecc_pm_ops,
+#endif
+       },
+};
+
+module_platform_driver(mtk_ecc_driver);
+
+MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+MODULE_DESCRIPTION("MTK Nand ECC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/mtk_ecc.h b/drivers/mtd/nand/mtk_ecc.h
new file mode 100644 (file)
index 0000000..cbeba5c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * MTK SDG1 ECC controller
+ *
+ * Copyright (c) 2016 Mediatek
+ * Authors:    Xiaolei Li              <xiaolei.li@mediatek.com>
+ *             Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
+#define __DRIVERS_MTD_NAND_MTK_ECC_H__
+
+#include <linux/types.h>
+
+#define ECC_PARITY_BITS                (14)
+
+enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+
+struct device_node;
+struct mtk_ecc;
+
+struct mtk_ecc_stats {
+       u32 corrected;
+       u32 bitflips;
+       u32 failed;
+};
+
+struct mtk_ecc_config {
+       enum mtk_ecc_operation op;
+       enum mtk_ecc_mode mode;
+       dma_addr_t addr;
+       u32 strength;
+       u32 sectors;
+       u32 len;
+};
+
+int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
+void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
+int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+void mtk_ecc_disable(struct mtk_ecc *);
+void mtk_ecc_adjust_strength(u32 *);
+
+struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+void mtk_ecc_release(struct mtk_ecc *);
+
+#endif
diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c
new file mode 100644 (file)
index 0000000..ddaa2ac
--- /dev/null
@@ -0,0 +1,1526 @@
+/*
+ * MTK NAND Flash controller driver.
+ * Copyright (C) 2016 MediaTek Inc.
+ * Authors:    Xiaolei Li              <xiaolei.li@mediatek.com>
+ *             Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/mtd.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include "mtk_ecc.h"
+
+/* NAND controller register definition */
+#define NFI_CNFG               (0x00)
+#define                CNFG_AHB                BIT(0)
+#define                CNFG_READ_EN            BIT(1)
+#define                CNFG_DMA_BURST_EN       BIT(2)
+#define                CNFG_BYTE_RW            BIT(6)
+#define                CNFG_HW_ECC_EN          BIT(8)
+#define                CNFG_AUTO_FMT_EN        BIT(9)
+#define                CNFG_OP_CUST            (6 << 12)
+#define NFI_PAGEFMT            (0x04)
+#define                PAGEFMT_FDM_ECC_SHIFT   (12)
+#define                PAGEFMT_FDM_SHIFT       (8)
+#define                PAGEFMT_SPARE_16        (0)
+#define                PAGEFMT_SPARE_26        (1)
+#define                PAGEFMT_SPARE_27        (2)
+#define                PAGEFMT_SPARE_28        (3)
+#define                PAGEFMT_SPARE_32        (4)
+#define                PAGEFMT_SPARE_36        (5)
+#define                PAGEFMT_SPARE_40        (6)
+#define                PAGEFMT_SPARE_44        (7)
+#define                PAGEFMT_SPARE_48        (8)
+#define                PAGEFMT_SPARE_49        (9)
+#define                PAGEFMT_SPARE_50        (0xa)
+#define                PAGEFMT_SPARE_51        (0xb)
+#define                PAGEFMT_SPARE_52        (0xc)
+#define                PAGEFMT_SPARE_62        (0xd)
+#define                PAGEFMT_SPARE_63        (0xe)
+#define                PAGEFMT_SPARE_64        (0xf)
+#define                PAGEFMT_SPARE_SHIFT     (4)
+#define                PAGEFMT_SEC_SEL_512     BIT(2)
+#define                PAGEFMT_512_2K          (0)
+#define                PAGEFMT_2K_4K           (1)
+#define                PAGEFMT_4K_8K           (2)
+#define                PAGEFMT_8K_16K          (3)
+/* NFI control */
+#define NFI_CON                        (0x08)
+#define                CON_FIFO_FLUSH          BIT(0)
+#define                CON_NFI_RST             BIT(1)
+#define                CON_BRD                 BIT(8)  /* burst  read */
+#define                CON_BWR                 BIT(9)  /* burst  write */
+#define                CON_SEC_SHIFT           (12)
+/* Timming control register */
+#define NFI_ACCCON             (0x0C)
+#define NFI_INTR_EN            (0x10)
+#define                INTR_AHB_DONE_EN        BIT(6)
+#define NFI_INTR_STA           (0x14)
+#define NFI_CMD                        (0x20)
+#define NFI_ADDRNOB            (0x30)
+#define NFI_COLADDR            (0x34)
+#define NFI_ROWADDR            (0x38)
+#define NFI_STRDATA            (0x40)
+#define                STAR_EN                 (1)
+#define                STAR_DE                 (0)
+#define NFI_CNRNB              (0x44)
+#define NFI_DATAW              (0x50)
+#define NFI_DATAR              (0x54)
+#define NFI_PIO_DIRDY          (0x58)
+#define                PIO_DI_RDY              (0x01)
+#define NFI_STA                        (0x60)
+#define                STA_CMD                 BIT(0)
+#define                STA_ADDR                BIT(1)
+#define                STA_BUSY                BIT(8)
+#define                STA_EMP_PAGE            BIT(12)
+#define                NFI_FSM_CUSTDATA        (0xe << 16)
+#define                NFI_FSM_MASK            (0xf << 16)
+#define NFI_ADDRCNTR           (0x70)
+#define                CNTR_MASK               GENMASK(16, 12)
+#define NFI_STRADDR            (0x80)
+#define NFI_BYTELEN            (0x84)
+#define NFI_CSEL               (0x90)
+#define NFI_FDML(x)            (0xA0 + (x) * sizeof(u32) * 2)
+#define NFI_FDMM(x)            (0xA4 + (x) * sizeof(u32) * 2)
+#define NFI_FDM_MAX_SIZE       (8)
+#define NFI_FDM_MIN_SIZE       (1)
+#define NFI_MASTER_STA         (0x224)
+#define                MASTER_STA_MASK         (0x0FFF)
+#define NFI_EMPTY_THRESH       (0x23C)
+
+#define MTK_NAME               "mtk-nand"
+#define KB(x)                  ((x) * 1024UL)
+#define MB(x)                  (KB(x) * 1024UL)
+
+#define MTK_TIMEOUT            (500000)
+#define MTK_RESET_TIMEOUT      (1000000)
+#define MTK_MAX_SECTOR         (16)
+#define MTK_NAND_MAX_NSELS     (2)
+
+struct mtk_nfc_bad_mark_ctl {
+       void (*bm_swap)(struct mtd_info *, u8 *buf, int raw);
+       u32 sec;
+       u32 pos;
+};
+
+/*
+ * FDM: region used to store free OOB data
+ */
+struct mtk_nfc_fdm {
+       u32 reg_size;
+       u32 ecc_size;
+};
+
+struct mtk_nfc_nand_chip {
+       struct list_head node;
+       struct nand_chip nand;
+
+       struct mtk_nfc_bad_mark_ctl bad_mark;
+       struct mtk_nfc_fdm fdm;
+       u32 spare_per_sector;
+
+       int nsels;
+       u8 sels[0];
+       /* nothing after this field */
+};
+
+struct mtk_nfc_clk {
+       struct clk *nfi_clk;
+       struct clk *pad_clk;
+};
+
+struct mtk_nfc {
+       struct nand_hw_control controller;
+       struct mtk_ecc_config ecc_cfg;
+       struct mtk_nfc_clk clk;
+       struct mtk_ecc *ecc;
+
+       struct device *dev;
+       void __iomem *regs;
+
+       struct completion done;
+       struct list_head chips;
+
+       u8 *buffer;
+};
+
+static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
+{
+       return container_of(nand, struct mtk_nfc_nand_chip, nand);
+}
+
+static inline u8 *data_ptr(struct nand_chip *chip, const u8 *p, int i)
+{
+       return (u8 *)p + i * chip->ecc.size;
+}
+
+static inline u8 *oob_ptr(struct nand_chip *chip, int i)
+{
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       u8 *poi;
+
+       /* map the sector's FDM data to free oob:
+        * the beginning of the oob area stores the FDM data of bad mark sectors
+        */
+
+       if (i < mtk_nand->bad_mark.sec)
+               poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
+       else if (i == mtk_nand->bad_mark.sec)
+               poi = chip->oob_poi;
+       else
+               poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
+
+       return poi;
+}
+
+static inline int mtk_data_len(struct nand_chip *chip)
+{
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+
+       return chip->ecc.size + mtk_nand->spare_per_sector;
+}
+
+static inline u8 *mtk_data_ptr(struct nand_chip *chip,  int i)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+       return nfc->buffer + i * mtk_data_len(chip);
+}
+
+static inline u8 *mtk_oob_ptr(struct nand_chip *chip, int i)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+       return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
+}
+
+static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
+{
+       writel(val, nfc->regs + reg);
+}
+
+static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
+{
+       writew(val, nfc->regs + reg);
+}
+
+static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
+{
+       writeb(val, nfc->regs + reg);
+}
+
+static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
+{
+       return readl_relaxed(nfc->regs + reg);
+}
+
+static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
+{
+       return readw_relaxed(nfc->regs + reg);
+}
+
+static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
+{
+       return readb_relaxed(nfc->regs + reg);
+}
+
+static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
+{
+       struct device *dev = nfc->dev;
+       u32 val;
+       int ret;
+
+       /* reset all registers and force the NFI master to terminate */
+       nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+
+       /* wait for the master to finish the last transaction */
+       ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
+                                !(val & MASTER_STA_MASK), 50,
+                                MTK_RESET_TIMEOUT);
+       if (ret)
+               dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
+                        NFI_MASTER_STA, val);
+
+       /* ensure any status register affected by the NFI master is reset */
+       nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
+       nfi_writew(nfc, STAR_DE, NFI_STRDATA);
+}
+
+static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
+{
+       struct device *dev = nfc->dev;
+       u32 val;
+       int ret;
+
+       nfi_writel(nfc, command, NFI_CMD);
+
+       ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+                                       !(val & STA_CMD), 10,  MTK_TIMEOUT);
+       if (ret) {
+               dev_warn(dev, "nfi core timed out entering command mode\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
+{
+       struct device *dev = nfc->dev;
+       u32 val;
+       int ret;
+
+       nfi_writel(nfc, addr, NFI_COLADDR);
+       nfi_writel(nfc, 0, NFI_ROWADDR);
+       nfi_writew(nfc, 1, NFI_ADDRNOB);
+
+       ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
+                                       !(val & STA_ADDR), 10, MTK_TIMEOUT);
+       if (ret) {
+               dev_warn(dev, "nfi core timed out entering address mode\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       u32 fmt, spare;
+
+       if (!mtd->writesize)
+               return 0;
+
+       spare = mtk_nand->spare_per_sector;
+
+       switch (mtd->writesize) {
+       case 512:
+               fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
+               break;
+       case KB(2):
+               if (chip->ecc.size == 512)
+                       fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
+               else
+                       fmt = PAGEFMT_512_2K;
+               break;
+       case KB(4):
+               if (chip->ecc.size == 512)
+                       fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
+               else
+                       fmt = PAGEFMT_2K_4K;
+               break;
+       case KB(8):
+               if (chip->ecc.size == 512)
+                       fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
+               else
+                       fmt = PAGEFMT_4K_8K;
+               break;
+       case KB(16):
+               fmt = PAGEFMT_8K_16K;
+               break;
+       default:
+               dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
+               return -EINVAL;
+       }
+
+       /*
+        * the hardware will double the value for this eccsize, so we need to
+        * halve it
+        */
+       if (chip->ecc.size == 1024)
+               spare >>= 1;
+
+       switch (spare) {
+       case 16:
+               fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 26:
+               fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 27:
+               fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 28:
+               fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 32:
+               fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 36:
+               fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 40:
+               fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 44:
+               fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 48:
+               fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 49:
+               fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 50:
+               fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 51:
+               fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 52:
+               fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 62:
+               fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 63:
+               fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
+               break;
+       case 64:
+               fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
+               break;
+       default:
+               dev_err(nfc->dev, "invalid spare per sector %d\n", spare);
+               return -EINVAL;
+       }
+
+       fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
+       fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
+       nfi_writew(nfc, fmt, NFI_PAGEFMT);
+
+       nfc->ecc_cfg.strength = chip->ecc.strength;
+       nfc->ecc_cfg.len = chip->ecc.size + mtk_nand->fdm.ecc_size;
+
+       return 0;
+}
+
+static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct mtk_nfc *nfc = nand_get_controller_data(nand);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
+
+       if (chip < 0)
+               return;
+
+       mtk_nfc_hw_runtime_config(mtd);
+
+       nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
+}
+
+static int mtk_nfc_dev_ready(struct mtd_info *mtd)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+
+       if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
+               return 0;
+
+       return 1;
+}
+
+static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+
+       if (ctrl & NAND_ALE) {
+               mtk_nfc_send_address(nfc, dat);
+       } else if (ctrl & NAND_CLE) {
+               mtk_nfc_hw_reset(nfc);
+
+               nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
+               mtk_nfc_send_command(nfc, dat);
+       }
+}
+
+static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
+{
+       int rc;
+       u8 val;
+
+       rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
+                                      val & PIO_DI_RDY, 10, MTK_TIMEOUT);
+       if (rc < 0)
+               dev_err(nfc->dev, "data not ready\n");
+}
+
+static inline u8 mtk_nfc_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       u32 reg;
+
+       /* after each byte read, the NFI_STA reg is reset by the hardware */
+       reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+       if (reg != NFI_FSM_CUSTDATA) {
+               reg = nfi_readw(nfc, NFI_CNFG);
+               reg |= CNFG_BYTE_RW | CNFG_READ_EN;
+               nfi_writew(nfc, reg, NFI_CNFG);
+
+               /*
+                * set to max sector to allow the HW to continue reading over
+                * unaligned accesses
+                */
+               reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
+               nfi_writel(nfc, reg, NFI_CON);
+
+               /* trigger to fetch data */
+               nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+       }
+
+       mtk_nfc_wait_ioready(nfc);
+
+       return nfi_readb(nfc, NFI_DATAR);
+}
+
+static void mtk_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               buf[i] = mtk_nfc_read_byte(mtd);
+}
+
+static void mtk_nfc_write_byte(struct mtd_info *mtd, u8 byte)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+       u32 reg;
+
+       reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
+
+       if (reg != NFI_FSM_CUSTDATA) {
+               reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
+               nfi_writew(nfc, reg, NFI_CNFG);
+
+               reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
+               nfi_writel(nfc, reg, NFI_CON);
+
+               nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+       }
+
+       mtk_nfc_wait_ioready(nfc);
+       nfi_writeb(nfc, byte, NFI_DATAW);
+}
+
+static void mtk_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               mtk_nfc_write_byte(mtd, buf[i]);
+}
+
+static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       int size = chip->ecc.size + mtk_nand->fdm.reg_size;
+
+       nfc->ecc_cfg.mode = ECC_DMA_MODE;
+       nfc->ecc_cfg.op = ECC_ENCODE;
+
+       return mtk_ecc_encode(nfc->ecc, &nfc->ecc_cfg, data, size);
+}
+
+static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, u8 *b, int c)
+{
+       /* nop */
+}
+
+static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, u8 *buf, int raw)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+       u32 bad_pos = nand->bad_mark.pos;
+
+       if (raw)
+               bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+       else
+               bad_pos += nand->bad_mark.sec * chip->ecc.size;
+
+       swap(chip->oob_poi[0], buf[bad_pos]);
+}
+
+static int mtk_nfc_format_subpage(struct mtd_info *mtd, u32 offset,
+                                 u32 len, const u8 *buf)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       u32 start, end;
+       int i, ret;
+
+       start = offset / chip->ecc.size;
+       end = DIV_ROUND_UP(offset + len, chip->ecc.size);
+
+       memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+       for (i = 0; i < chip->ecc.steps; i++) {
+               memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+                      chip->ecc.size);
+
+               if (start > i || i >= end)
+                       continue;
+
+               if (i == mtk_nand->bad_mark.sec)
+                       mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+               memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+
+               /* program the CRC back to the OOB */
+               ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void mtk_nfc_format_page(struct mtd_info *mtd, const u8 *buf)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       u32 i;
+
+       memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+       for (i = 0; i < chip->ecc.steps; i++) {
+               if (buf)
+                       memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
+                              chip->ecc.size);
+
+               if (i == mtk_nand->bad_mark.sec)
+                       mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+               memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
+       }
+}
+
+static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
+                                   u32 sectors)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       u32 vall, valm;
+       u8 *oobptr;
+       int i, j;
+
+       for (i = 0; i < sectors; i++) {
+               oobptr = oob_ptr(chip, start + i);
+               vall = nfi_readl(nfc, NFI_FDML(i));
+               valm = nfi_readl(nfc, NFI_FDMM(i));
+
+               for (j = 0; j < fdm->reg_size; j++)
+                       oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+       }
+}
+
+static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       u32 vall, valm;
+       u8 *oobptr;
+       int i, j;
+
+       for (i = 0; i < chip->ecc.steps; i++) {
+               oobptr = oob_ptr(chip, i);
+               vall = 0;
+               valm = 0;
+               for (j = 0; j < 8; j++) {
+                       if (j < 4)
+                               vall |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                                               << (j * 8);
+                       else
+                               valm |= (j < fdm->reg_size ? oobptr[j] : 0xff)
+                                               << ((j - 4) * 8);
+               }
+               nfi_writel(nfc, vall, NFI_FDML(i));
+               nfi_writel(nfc, valm, NFI_FDMM(i));
+       }
+}
+
+static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                                const u8 *buf, int page, int len)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct device *dev = nfc->dev;
+       dma_addr_t addr;
+       u32 reg;
+       int ret;
+
+       addr = dma_map_single(dev, (void *)buf, len, DMA_TO_DEVICE);
+       ret = dma_mapping_error(nfc->dev, addr);
+       if (ret) {
+               dev_err(nfc->dev, "dma mapping error\n");
+               return -EINVAL;
+       }
+
+       reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
+       nfi_writew(nfc, reg, NFI_CNFG);
+
+       nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
+       nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+       nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+
+       init_completion(&nfc->done);
+
+       reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
+       nfi_writel(nfc, reg, NFI_CON);
+       nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+       ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+       if (!ret) {
+               dev_err(dev, "program ahb done timeout\n");
+               nfi_writew(nfc, 0, NFI_INTR_EN);
+               ret = -ETIMEDOUT;
+               goto timeout;
+       }
+
+       ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
+                                       (reg & CNTR_MASK) >= chip->ecc.steps,
+                                       10, MTK_TIMEOUT);
+       if (ret)
+               dev_err(dev, "hwecc write timeout\n");
+
+timeout:
+
+       dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
+       nfi_writel(nfc, 0, NFI_CON);
+
+       return ret;
+}
+
+static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                             const u8 *buf, int page, int raw)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       size_t len;
+       const u8 *bufpoi;
+       u32 reg;
+       int ret;
+
+       if (!raw) {
+               /* OOB => FDM: from register,  ECC: from HW */
+               reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
+               nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
+
+               nfc->ecc_cfg.op = ECC_ENCODE;
+               nfc->ecc_cfg.mode = ECC_NFI_MODE;
+               ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+               if (ret) {
+                       /* clear NFI config */
+                       reg = nfi_readw(nfc, NFI_CNFG);
+                       reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+                       nfi_writew(nfc, reg, NFI_CNFG);
+
+                       return ret;
+               }
+
+               memcpy(nfc->buffer, buf, mtd->writesize);
+               mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
+               bufpoi = nfc->buffer;
+
+               /* write OOB into the FDM registers (OOB area in MTK NAND) */
+               mtk_nfc_write_fdm(chip);
+       } else {
+               bufpoi = buf;
+       }
+
+       len = mtd->writesize + (raw ? mtd->oobsize : 0);
+       ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
+
+       if (!raw)
+               mtk_ecc_disable(nfc->ecc);
+
+       return ret;
+}
+
+static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd,
+                                   struct nand_chip *chip, const u8 *buf,
+                                   int oob_on, int page)
+{
+       return mtk_nfc_write_page(mtd, chip, buf, page, 0);
+}
+
+static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                                 const u8 *buf, int oob_on, int pg)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+
+       mtk_nfc_format_page(mtd, buf);
+       return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
+}
+
+static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd,
+                                      struct nand_chip *chip, u32 offset,
+                                      u32 data_len, const u8 *buf,
+                                      int oob_on, int page)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       int ret;
+
+       ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
+       if (ret < 0)
+               return ret;
+
+       /* use the data in the private buffer (now with FDM and CRC) */
+       return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
+}
+
+static int mtk_nfc_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+                                int page)
+{
+       int ret;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+       ret = mtk_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+       if (ret < 0)
+               return -EIO;
+
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       ret = chip->waitfunc(mtd, chip);
+
+       return ret & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+static int mtk_nfc_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_ecc_stats stats;
+       int rc, i;
+
+       rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
+       if (rc) {
+               memset(buf, 0xff, sectors * chip->ecc.size);
+               for (i = 0; i < sectors; i++)
+                       memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
+               return 0;
+       }
+
+       mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
+       mtd->ecc_stats.corrected += stats.corrected;
+       mtd->ecc_stats.failed += stats.failed;
+
+       return stats.bitflips;
+}
+
+static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+                               u32 data_offs, u32 readlen,
+                               u8 *bufpoi, int page, int raw)
+{
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       u32 spare = mtk_nand->spare_per_sector;
+       u32 column, sectors, start, end, reg;
+       dma_addr_t addr;
+       int bitflips;
+       size_t len;
+       u8 *buf;
+       int rc;
+
+       start = data_offs / chip->ecc.size;
+       end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+
+       sectors = end - start;
+       column = start * (chip->ecc.size + spare);
+
+       len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
+       buf = bufpoi + start * chip->ecc.size;
+
+       if (column != 0)
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
+
+       addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
+       rc = dma_mapping_error(nfc->dev, addr);
+       if (rc) {
+               dev_err(nfc->dev, "dma mapping error\n");
+
+               return -EINVAL;
+       }
+
+       reg = nfi_readw(nfc, NFI_CNFG);
+       reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
+       if (!raw) {
+               reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
+               nfi_writew(nfc, reg, NFI_CNFG);
+
+               nfc->ecc_cfg.mode = ECC_NFI_MODE;
+               nfc->ecc_cfg.sectors = sectors;
+               nfc->ecc_cfg.op = ECC_DECODE;
+               rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
+               if (rc) {
+                       dev_err(nfc->dev, "ecc enable\n");
+                       /* clear NFI_CNFG */
+                       reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
+                               CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
+                       nfi_writew(nfc, reg, NFI_CNFG);
+                       dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+
+                       return rc;
+               }
+       } else {
+               nfi_writew(nfc, reg, NFI_CNFG);
+       }
+
+       nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
+       nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
+       nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
+
+       init_completion(&nfc->done);
+       reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
+       nfi_writel(nfc, reg, NFI_CON);
+       nfi_writew(nfc, STAR_EN, NFI_STRDATA);
+
+       rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
+       if (!rc)
+               dev_warn(nfc->dev, "read ahb/dma done timeout\n");
+
+       rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
+                                      (reg & CNTR_MASK) >= sectors, 10,
+                                      MTK_TIMEOUT);
+       if (rc < 0) {
+               dev_err(nfc->dev, "subpage done timeout\n");
+               bitflips = -EIO;
+       } else {
+               bitflips = 0;
+               if (!raw) {
+                       rc = mtk_ecc_wait_done(nfc->ecc, ECC_DECODE);
+                       bitflips = rc < 0 ? -ETIMEDOUT :
+                               mtk_nfc_update_ecc_stats(mtd, buf, sectors);
+                       mtk_nfc_read_fdm(chip, start, sectors);
+               }
+       }
+
+       dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
+
+       if (raw)
+               goto done;
+
+       mtk_ecc_disable(nfc->ecc);
+
+       if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
+               mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
+done:
+       nfi_writel(nfc, 0, NFI_CON);
+
+       return bitflips;
+}
+
+static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
+                                     struct nand_chip *chip, u32 off,
+                                     u32 len, u8 *p, int pg)
+{
+       return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
+}
+
+static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
+                                  struct nand_chip *chip, u8 *p,
+                                  int oob_on, int pg)
+{
+       return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
+}
+
+static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+                                u8 *buf, int oob_on, int page)
+{
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc *nfc = nand_get_controller_data(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       int i, ret;
+
+       memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
+       ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
+                                  page, 1);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < chip->ecc.steps; i++) {
+               memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
+
+               if (i == mtk_nand->bad_mark.sec)
+                       mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
+
+               if (buf)
+                       memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
+                              chip->ecc.size);
+       }
+
+       return ret;
+}
+
+static int mtk_nfc_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+                               int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       return mtk_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
+{
+       /*
+        * ACCON: access timing control register
+        * -------------------------------------
+        * 31:28: minimum required time for CS post pulling down after accessing
+        *      the device
+        * 27:22: minimum required time for CS pre pulling down before accessing
+        *      the device
+        * 21:16: minimum required time from NCEB low to NREB low
+        * 15:12: minimum required time from NWEB high to NREB low.
+        * 11:08: write enable hold time
+        * 07:04: write wait states
+        * 03:00: read wait states
+        */
+       nfi_writel(nfc, 0x10804211, NFI_ACCCON);
+
+       /*
+        * CNRNB: nand ready/busy register
+        * -------------------------------
+        * 7:4: timeout register for polling the NAND busy/ready signal
+        * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
+        */
+       nfi_writew(nfc, 0xf1, NFI_CNRNB);
+       nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+       mtk_nfc_hw_reset(nfc);
+
+       nfi_readl(nfc, NFI_INTR_STA);
+       nfi_writel(nfc, 0, NFI_INTR_EN);
+}
+
+static irqreturn_t mtk_nfc_irq(int irq, void *id)
+{
+       struct mtk_nfc *nfc = id;
+       u16 sta, ien;
+
+       sta = nfi_readw(nfc, NFI_INTR_STA);
+       ien = nfi_readw(nfc, NFI_INTR_EN);
+
+       if (!(sta & ien))
+               return IRQ_NONE;
+
+       nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
+       complete(&nfc->done);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
+{
+       int ret;
+
+       ret = clk_prepare_enable(clk->nfi_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable nfi clk\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(clk->pad_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable pad clk\n");
+               clk_disable_unprepare(clk->nfi_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
+{
+       clk_disable_unprepare(clk->nfi_clk);
+       clk_disable_unprepare(clk->pad_clk);
+}
+
+static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
+                                 struct mtd_oob_region *oob_region)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
+       u32 eccsteps;
+
+       eccsteps = mtd->writesize / chip->ecc.size;
+
+       if (section >= eccsteps)
+               return -ERANGE;
+
+       oob_region->length = fdm->reg_size - fdm->ecc_size;
+       oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
+
+       return 0;
+}
+
+static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                struct mtd_oob_region *oob_region)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
+       u32 eccsteps;
+
+       if (section)
+               return -ERANGE;
+
+       eccsteps = mtd->writesize / chip->ecc.size;
+       oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
+       oob_region->length = mtd->oobsize - oob_region->offset;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
+       .free = mtk_nfc_ooblayout_free,
+       .ecc = mtk_nfc_ooblayout_ecc,
+};
+
+static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
+       u32 ecc_bytes;
+
+       ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
+
+       fdm->reg_size = chip->spare_per_sector - ecc_bytes;
+       if (fdm->reg_size > NFI_FDM_MAX_SIZE)
+               fdm->reg_size = NFI_FDM_MAX_SIZE;
+
+       /* bad block mark storage */
+       fdm->ecc_size = 1;
+}
+
+static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
+                                    struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+
+       if (mtd->writesize == 512) {
+               bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
+       } else {
+               bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
+               bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
+               bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
+       }
+}
+
+static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
+                       48, 49, 50, 51, 52, 62, 63, 64};
+       u32 eccsteps, i;
+
+       eccsteps = mtd->writesize / nand->ecc.size;
+       *sps = mtd->oobsize / eccsteps;
+
+       if (nand->ecc.size == 1024)
+               *sps >>= 1;
+
+       for (i = 0; i < ARRAY_SIZE(spare); i++) {
+               if (*sps <= spare[i]) {
+                       if (!i)
+                               *sps = spare[i];
+                       else if (*sps != spare[i])
+                               *sps = spare[i - 1];
+                       break;
+               }
+       }
+
+       if (i >= ARRAY_SIZE(spare))
+               *sps = spare[ARRAY_SIZE(spare) - 1];
+
+       if (nand->ecc.size == 1024)
+               *sps <<= 1;
+}
+
+static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       u32 spare;
+       int free;
+
+       /* support only ecc hw mode */
+       if (nand->ecc.mode != NAND_ECC_HW) {
+               dev_err(dev, "ecc.mode not supported\n");
+               return -EINVAL;
+       }
+
+       /* if optional dt settings not present */
+       if (!nand->ecc.size || !nand->ecc.strength) {
+               /* use datasheet requirements */
+               nand->ecc.strength = nand->ecc_strength_ds;
+               nand->ecc.size = nand->ecc_step_ds;
+
+               /*
+                * align eccstrength and eccsize
+                * this controller only supports 512 and 1024 sizes
+                */
+               if (nand->ecc.size < 1024) {
+                       if (mtd->writesize > 512) {
+                               nand->ecc.size = 1024;
+                               nand->ecc.strength <<= 1;
+                       } else {
+                               nand->ecc.size = 512;
+                       }
+               } else {
+                       nand->ecc.size = 1024;
+               }
+
+               mtk_nfc_set_spare_per_sector(&spare, mtd);
+
+               /* calculate oob bytes except ecc parity data */
+               free = ((nand->ecc.strength * ECC_PARITY_BITS) + 7) >> 3;
+               free = spare - free;
+
+               /*
+                * enhance ecc strength if oob left is bigger than max FDM size
+                * or reduce ecc strength if oob size is not enough for ecc
+                * parity data.
+                */
+               if (free > NFI_FDM_MAX_SIZE) {
+                       spare -= NFI_FDM_MAX_SIZE;
+                       nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
+               } else if (free < 0) {
+                       spare -= NFI_FDM_MIN_SIZE;
+                       nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
+               }
+       }
+
+       mtk_ecc_adjust_strength(&nand->ecc.strength);
+
+       dev_info(dev, "eccsize %d eccstrength %d\n",
+                nand->ecc.size, nand->ecc.strength);
+
+       return 0;
+}
+
+static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
+                                 struct device_node *np)
+{
+       struct mtk_nfc_nand_chip *chip;
+       struct nand_chip *nand;
+       struct mtd_info *mtd;
+       int nsels, len;
+       u32 tmp;
+       int ret;
+       int i;
+
+       if (!of_get_property(np, "reg", &nsels))
+               return -ENODEV;
+
+       nsels /= sizeof(u32);
+       if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
+               dev_err(dev, "invalid reg property size %d\n", nsels);
+               return -EINVAL;
+       }
+
+       chip = devm_kzalloc(dev, sizeof(*chip) + nsels * sizeof(u8),
+                           GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->nsels = nsels;
+       for (i = 0; i < nsels; i++) {
+               ret = of_property_read_u32_index(np, "reg", i, &tmp);
+               if (ret) {
+                       dev_err(dev, "reg property failure : %d\n", ret);
+                       return ret;
+               }
+               chip->sels[i] = tmp;
+       }
+
+       nand = &chip->nand;
+       nand->controller = &nfc->controller;
+
+       nand_set_flash_node(nand, np);
+       nand_set_controller_data(nand, nfc);
+
+       nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
+       nand->dev_ready = mtk_nfc_dev_ready;
+       nand->select_chip = mtk_nfc_select_chip;
+       nand->write_byte = mtk_nfc_write_byte;
+       nand->write_buf = mtk_nfc_write_buf;
+       nand->read_byte = mtk_nfc_read_byte;
+       nand->read_buf = mtk_nfc_read_buf;
+       nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
+
+       /* set default mode in case dt entry is missing */
+       nand->ecc.mode = NAND_ECC_HW;
+
+       nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
+       nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
+       nand->ecc.write_page = mtk_nfc_write_page_hwecc;
+       nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
+       nand->ecc.write_oob = mtk_nfc_write_oob_std;
+
+       nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
+       nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
+       nand->ecc.read_page = mtk_nfc_read_page_hwecc;
+       nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
+       nand->ecc.read_oob = mtk_nfc_read_oob_std;
+
+       mtd = nand_to_mtd(nand);
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = dev;
+       mtd->name = MTK_NAME;
+       mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
+
+       mtk_nfc_hw_init(nfc);
+
+       ret = nand_scan_ident(mtd, nsels, NULL);
+       if (ret)
+               return -ENODEV;
+
+       /* store bbt magic in page, cause OOB is not protected */
+       if (nand->bbt_options & NAND_BBT_USE_FLASH)
+               nand->bbt_options |= NAND_BBT_NO_OOB;
+
+       ret = mtk_nfc_ecc_init(dev, mtd);
+       if (ret)
+               return -EINVAL;
+
+       if (nand->options & NAND_BUSWIDTH_16) {
+               dev_err(dev, "16bits buswidth not supported");
+               return -EINVAL;
+       }
+
+       mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
+       mtk_nfc_set_fdm(&chip->fdm, mtd);
+       mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
+
+       len = mtd->writesize + mtd->oobsize;
+       nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
+       if (!nfc->buffer)
+               return  -ENOMEM;
+
+       ret = nand_scan_tail(mtd);
+       if (ret)
+               return -ENODEV;
+
+       ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+       if (ret) {
+               dev_err(dev, "mtd parse partition error\n");
+               nand_release(mtd);
+               return ret;
+       }
+
+       list_add_tail(&chip->node, &nfc->chips);
+
+       return 0;
+}
+
+static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
+{
+       struct device_node *np = dev->of_node;
+       struct device_node *nand_np;
+       int ret;
+
+       for_each_child_of_node(np, nand_np) {
+               ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
+               if (ret) {
+                       of_node_put(nand_np);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mtk_nfc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct mtk_nfc *nfc;
+       struct resource *res;
+       int ret, irq;
+
+       nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
+       if (!nfc)
+               return -ENOMEM;
+
+       spin_lock_init(&nfc->controller.lock);
+       init_waitqueue_head(&nfc->controller.wq);
+       INIT_LIST_HEAD(&nfc->chips);
+
+       /* probe defer if not ready */
+       nfc->ecc = of_mtk_ecc_get(np);
+       if (IS_ERR(nfc->ecc))
+               return PTR_ERR(nfc->ecc);
+       else if (!nfc->ecc)
+               return -ENODEV;
+
+       nfc->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(nfc->regs)) {
+               ret = PTR_ERR(nfc->regs);
+               dev_err(dev, "no nfi base\n");
+               goto release_ecc;
+       }
+
+       nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
+       if (IS_ERR(nfc->clk.nfi_clk)) {
+               dev_err(dev, "no clk\n");
+               ret = PTR_ERR(nfc->clk.nfi_clk);
+               goto release_ecc;
+       }
+
+       nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
+       if (IS_ERR(nfc->clk.pad_clk)) {
+               dev_err(dev, "no pad clk\n");
+               ret = PTR_ERR(nfc->clk.pad_clk);
+               goto release_ecc;
+       }
+
+       ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+       if (ret)
+               goto release_ecc;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "no nfi irq resource\n");
+               ret = -EINVAL;
+               goto clk_disable;
+       }
+
+       ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
+       if (ret) {
+               dev_err(dev, "failed to request nfi irq\n");
+               goto clk_disable;
+       }
+
+       ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(dev, "failed to set dma mask\n");
+               goto clk_disable;
+       }
+
+       platform_set_drvdata(pdev, nfc);
+
+       ret = mtk_nfc_nand_chips_init(dev, nfc);
+       if (ret) {
+               dev_err(dev, "failed to init nand chips\n");
+               goto clk_disable;
+       }
+
+       return 0;
+
+clk_disable:
+       mtk_nfc_disable_clk(&nfc->clk);
+
+release_ecc:
+       mtk_ecc_release(nfc->ecc);
+
+       return ret;
+}
+
+static int mtk_nfc_remove(struct platform_device *pdev)
+{
+       struct mtk_nfc *nfc = platform_get_drvdata(pdev);
+       struct mtk_nfc_nand_chip *chip;
+
+       while (!list_empty(&nfc->chips)) {
+               chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
+                                       node);
+               nand_release(nand_to_mtd(&chip->nand));
+               list_del(&chip->node);
+       }
+
+       mtk_ecc_release(nfc->ecc);
+       mtk_nfc_disable_clk(&nfc->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_nfc_suspend(struct device *dev)
+{
+       struct mtk_nfc *nfc = dev_get_drvdata(dev);
+
+       mtk_nfc_disable_clk(&nfc->clk);
+
+       return 0;
+}
+
+static int mtk_nfc_resume(struct device *dev)
+{
+       struct mtk_nfc *nfc = dev_get_drvdata(dev);
+       struct mtk_nfc_nand_chip *chip;
+       struct nand_chip *nand;
+       struct mtd_info *mtd;
+       int ret;
+       u32 i;
+
+       udelay(200);
+
+       ret = mtk_nfc_enable_clk(dev, &nfc->clk);
+       if (ret)
+               return ret;
+
+       mtk_nfc_hw_init(nfc);
+
+       /* reset NAND chip if VCC was powered off */
+       list_for_each_entry(chip, &nfc->chips, node) {
+               nand = &chip->nand;
+               mtd = nand_to_mtd(nand);
+               for (i = 0; i < chip->nsels; i++) {
+                       nand->select_chip(mtd, i);
+                       nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+               }
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
+#endif
+
+static const struct of_device_id mtk_nfc_id_table[] = {
+       { .compatible = "mediatek,mt2701-nfc" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mtk_nfc_id_table);
+
+static struct platform_driver mtk_nfc_driver = {
+       .probe  = mtk_nfc_probe,
+       .remove = mtk_nfc_remove,
+       .driver = {
+               .name  = MTK_NAME,
+               .of_match_table = mtk_nfc_id_table,
+#ifdef CONFIG_PM_SLEEP
+               .pm = &mtk_nfc_pm_ops,
+#endif
+       },
+};
+
+module_platform_driver(mtk_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
index 0b0dc29..77533f7 100644 (file)
@@ -2610,7 +2610,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                int cached = writelen > bytes && page != blockmask;
                uint8_t *wbuf = buf;
                int use_bufpoi;
-               int part_pagewr = (column || writelen < (mtd->writesize - 1));
+               int part_pagewr = (column || writelen < mtd->writesize);
 
                if (part_pagewr)
                        use_bufpoi = 1;
index ccc05f5..2af9869 100644 (file)
@@ -168,6 +168,7 @@ struct nand_flash_dev nand_flash_ids[] = {
 /* Manufacturer IDs */
 struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_TOSHIBA, "Toshiba"},
+       {NAND_MFR_ESMT, "ESMT"},
        {NAND_MFR_SAMSUNG, "Samsung"},
        {NAND_MFR_FUJITSU, "Fujitsu"},
        {NAND_MFR_NATIONAL, "National"},
index a136da8..a59361c 100644 (file)
 #define        PREFETCH_STATUS_FIFO_CNT(val)   ((val >> 24) & 0x7F)
 #define        STATUS_BUFF_EMPTY               0x00000001
 
-#define OMAP24XX_DMA_GPMC              4
-
 #define SECTOR_BYTES           512
 /* 4 bit padding to make byte aligned, 56 = 52 + 4 */
 #define BCH4_BIT_PAD           4
@@ -1811,7 +1809,6 @@ static int omap_nand_probe(struct platform_device *pdev)
        struct nand_chip                *nand_chip;
        int                             err;
        dma_cap_mask_t                  mask;
-       unsigned                        sig;
        struct resource                 *res;
        struct device                   *dev = &pdev->dev;
        int                             min_oobbytes = BADBLOCK_MARKER_LENGTH;
@@ -1924,11 +1921,11 @@ static int omap_nand_probe(struct platform_device *pdev)
        case NAND_OMAP_PREFETCH_DMA:
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
-               sig = OMAP24XX_DMA_GPMC;
-               info->dma = dma_request_channel(mask, omap_dma_filter_fn, &sig);
-               if (!info->dma) {
+               info->dma = dma_request_chan(pdev->dev.parent, "rxtx");
+
+               if (IS_ERR(info->dma)) {
                        dev_err(&pdev->dev, "DMA engine request failed\n");
-                       err = -ENXIO;
+                       err = PTR_ERR(info->dma);
                        goto return_error;
                } else {
                        struct dma_slave_config cfg;
index a83a690..e414b31 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/iopoll.h>
+#include <linux/reset.h>
 
 #define NFC_REG_CTL            0x0000
 #define NFC_REG_ST             0x0004
 
 /* define bit use in NFC_ECC_ST */
 #define NFC_ECC_ERR(x)         BIT(x)
+#define NFC_ECC_ERR_MSK                GENMASK(15, 0)
 #define NFC_ECC_PAT_FOUND(x)   BIT(x + 16)
 #define NFC_ECC_ERR_CNT(b, x)  (((x) >> (((b) % 4) * 8)) & 0xff)
 
@@ -269,10 +271,12 @@ struct sunxi_nfc {
        void __iomem *regs;
        struct clk *ahb_clk;
        struct clk *mod_clk;
+       struct reset_control *reset;
        unsigned long assigned_cs;
        unsigned long clk_rate;
        struct list_head chips;
        struct completion complete;
+       struct dma_chan *dmac;
 };
 
 static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
@@ -365,6 +369,67 @@ static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
        return ret;
 }
 
+static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
+                                   int chunksize, int nchunks,
+                                   enum dma_data_direction ddir,
+                                   struct scatterlist *sg)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct dma_async_tx_descriptor *dmad;
+       enum dma_transfer_direction tdir;
+       dma_cookie_t dmat;
+       int ret;
+
+       if (ddir == DMA_FROM_DEVICE)
+               tdir = DMA_DEV_TO_MEM;
+       else
+               tdir = DMA_MEM_TO_DEV;
+
+       sg_init_one(sg, buf, nchunks * chunksize);
+       ret = dma_map_sg(nfc->dev, sg, 1, ddir);
+       if (!ret)
+               return -ENOMEM;
+
+       dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
+       if (!dmad) {
+               ret = -EINVAL;
+               goto err_unmap_buf;
+       }
+
+       writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+              nfc->regs + NFC_REG_CTL);
+       writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
+       writel(chunksize, nfc->regs + NFC_REG_CNT);
+       dmat = dmaengine_submit(dmad);
+
+       ret = dma_submit_error(dmat);
+       if (ret)
+               goto err_clr_dma_flag;
+
+       return 0;
+
+err_clr_dma_flag:
+       writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+              nfc->regs + NFC_REG_CTL);
+
+err_unmap_buf:
+       dma_unmap_sg(nfc->dev, sg, 1, ddir);
+       return ret;
+}
+
+static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
+                                    enum dma_data_direction ddir,
+                                    struct scatterlist *sg)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+       dma_unmap_sg(nfc->dev, sg, 1, ddir);
+       writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+              nfc->regs + NFC_REG_CTL);
+}
+
 static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
@@ -822,17 +887,15 @@ static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
 }
 
 static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
-                                   int step, bool *erased)
+                                   int step, u32 status, bool *erased)
 {
        struct nand_chip *nand = mtd_to_nand(mtd);
        struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
        struct nand_ecc_ctrl *ecc = &nand->ecc;
-       u32 status, tmp;
+       u32 tmp;
 
        *erased = false;
 
-       status = readl(nfc->regs + NFC_REG_ECC_ST);
-
        if (status & NFC_ECC_ERR(step))
                return -EBADMSG;
 
@@ -898,6 +961,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
        *cur_off = oob_off + ecc->bytes + 4;
 
        ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
+                                      readl(nfc->regs + NFC_REG_ECC_ST),
                                       &erased);
        if (erased)
                return 1;
@@ -967,6 +1031,130 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
                *cur_off = mtd->oobsize + mtd->writesize;
 }
 
+static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
+                                           int oob_required, int page,
+                                           int nchunks)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       bool randomized = nand->options & NAND_NEED_SCRAMBLING;
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+       unsigned int max_bitflips = 0;
+       int ret, i, raw_mode = 0;
+       struct scatterlist sg;
+       u32 status;
+
+       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+       if (ret)
+               return ret;
+
+       ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
+                                      DMA_FROM_DEVICE, &sg);
+       if (ret)
+               return ret;
+
+       sunxi_nfc_hw_ecc_enable(mtd);
+       sunxi_nfc_randomizer_config(mtd, page, false);
+       sunxi_nfc_randomizer_enable(mtd);
+
+       writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
+              NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
+
+       dma_async_issue_pending(nfc->dmac);
+
+       writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
+              nfc->regs + NFC_REG_CMD);
+
+       ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
+       if (ret)
+               dmaengine_terminate_all(nfc->dmac);
+
+       sunxi_nfc_randomizer_disable(mtd);
+       sunxi_nfc_hw_ecc_disable(mtd);
+
+       sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sg);
+
+       if (ret)
+               return ret;
+
+       status = readl(nfc->regs + NFC_REG_ECC_ST);
+
+       for (i = 0; i < nchunks; i++) {
+               int data_off = i * ecc->size;
+               int oob_off = i * (ecc->bytes + 4);
+               u8 *data = buf + data_off;
+               u8 *oob = nand->oob_poi + oob_off;
+               bool erased;
+
+               ret = sunxi_nfc_hw_ecc_correct(mtd, randomized ? data : NULL,
+                                              oob_required ? oob : NULL,
+                                              i, status, &erased);
+
+               /* ECC errors are handled in the second loop. */
+               if (ret < 0)
+                       continue;
+
+               if (oob_required && !erased) {
+                       /* TODO: use DMA to retrieve OOB */
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                                     mtd->writesize + oob_off, -1);
+                       nand->read_buf(mtd, oob, ecc->bytes + 4);
+
+                       sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, i,
+                                                           !i, page);
+               }
+
+               if (erased)
+                       raw_mode = 1;
+
+               sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+       }
+
+       if (status & NFC_ECC_ERR_MSK) {
+               for (i = 0; i < nchunks; i++) {
+                       int data_off = i * ecc->size;
+                       int oob_off = i * (ecc->bytes + 4);
+                       u8 *data = buf + data_off;
+                       u8 *oob = nand->oob_poi + oob_off;
+
+                       if (!(status & NFC_ECC_ERR(i)))
+                               continue;
+
+                       /*
+                        * Re-read the data with the randomizer disabled to
+                        * identify bitflips in erased pages.
+                        */
+                       if (randomized) {
+                               /* TODO: use DMA to read page in raw mode */
+                               nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                                             data_off, -1);
+                               nand->read_buf(mtd, data, ecc->size);
+                       }
+
+                       /* TODO: use DMA to retrieve OOB */
+                       nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                                     mtd->writesize + oob_off, -1);
+                       nand->read_buf(mtd, oob, ecc->bytes + 4);
+
+                       ret = nand_check_erased_ecc_chunk(data, ecc->size,
+                                                         oob, ecc->bytes + 4,
+                                                         NULL, 0,
+                                                         ecc->strength);
+                       if (ret >= 0)
+                               raw_mode = 1;
+
+                       sunxi_nfc_hw_ecc_update_stats(mtd, &max_bitflips, ret);
+               }
+       }
+
+       if (oob_required)
+               sunxi_nfc_hw_ecc_read_extra_oob(mtd, nand->oob_poi,
+                                               NULL, !raw_mode,
+                                               page);
+
+       return max_bitflips;
+}
+
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
                                        const u8 *data, int data_off,
                                        const u8 *oob, int oob_off,
@@ -1065,6 +1253,23 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
        return max_bitflips;
 }
 
+static int sunxi_nfc_hw_ecc_read_page_dma(struct mtd_info *mtd,
+                                         struct nand_chip *chip, u8 *buf,
+                                         int oob_required, int page)
+{
+       int ret;
+
+       ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, oob_required, page,
+                                              chip->ecc.steps);
+       if (ret >= 0)
+               return ret;
+
+       /* Fallback to PIO mode */
+       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+
+       return sunxi_nfc_hw_ecc_read_page(mtd, chip, buf, oob_required, page);
+}
+
 static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
                                         struct nand_chip *chip,
                                         u32 data_offs, u32 readlen,
@@ -1098,6 +1303,25 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd,
        return max_bitflips;
 }
 
+static int sunxi_nfc_hw_ecc_read_subpage_dma(struct mtd_info *mtd,
+                                            struct nand_chip *chip,
+                                            u32 data_offs, u32 readlen,
+                                            u8 *buf, int page)
+{
+       int nchunks = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
+       int ret;
+
+       ret = sunxi_nfc_hw_ecc_read_chunks_dma(mtd, buf, false, page, nchunks);
+       if (ret >= 0)
+               return ret;
+
+       /* Fallback to PIO mode */
+       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+
+       return sunxi_nfc_hw_ecc_read_subpage(mtd, chip, data_offs, readlen,
+                                            buf, page);
+}
+
 static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
                                       struct nand_chip *chip,
                                       const uint8_t *buf, int oob_required,
@@ -1130,6 +1354,99 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
        return 0;
 }
 
+static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd,
+                                         struct nand_chip *chip,
+                                         u32 data_offs, u32 data_len,
+                                         const u8 *buf, int oob_required,
+                                         int page)
+{
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       int ret, i, cur_off = 0;
+
+       sunxi_nfc_hw_ecc_enable(mtd);
+
+       for (i = data_offs / ecc->size;
+            i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) {
+               int data_off = i * ecc->size;
+               int oob_off = i * (ecc->bytes + 4);
+               const u8 *data = buf + data_off;
+               const u8 *oob = chip->oob_poi + oob_off;
+
+               ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
+                                                  oob_off + mtd->writesize,
+                                                  &cur_off, !i, page);
+               if (ret)
+                       return ret;
+       }
+
+       sunxi_nfc_hw_ecc_disable(mtd);
+
+       return 0;
+}
+
+static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd,
+                                          struct nand_chip *chip,
+                                          const u8 *buf,
+                                          int oob_required,
+                                          int page)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+       struct scatterlist sg;
+       int ret, i;
+
+       ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+       if (ret)
+               return ret;
+
+       ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, ecc->steps,
+                                      DMA_TO_DEVICE, &sg);
+       if (ret)
+               goto pio_fallback;
+
+       for (i = 0; i < ecc->steps; i++) {
+               const u8 *oob = nand->oob_poi + (i * (ecc->bytes + 4));
+
+               sunxi_nfc_hw_ecc_set_prot_oob_bytes(mtd, oob, i, !i, page);
+       }
+
+       sunxi_nfc_hw_ecc_enable(mtd);
+       sunxi_nfc_randomizer_config(mtd, page, false);
+       sunxi_nfc_randomizer_enable(mtd);
+
+       writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
+              nfc->regs + NFC_REG_RCMD_SET);
+
+       dma_async_issue_pending(nfc->dmac);
+
+       writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
+              NFC_DATA_TRANS | NFC_ACCESS_DIR,
+              nfc->regs + NFC_REG_CMD);
+
+       ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
+       if (ret)
+               dmaengine_terminate_all(nfc->dmac);
+
+       sunxi_nfc_randomizer_disable(mtd);
+       sunxi_nfc_hw_ecc_disable(mtd);
+
+       sunxi_nfc_dma_op_cleanup(mtd, DMA_TO_DEVICE, &sg);
+
+       if (ret)
+               return ret;
+
+       if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
+               /* TODO: use DMA to transfer extra OOB bytes ? */
+               sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
+                                                NULL, page);
+
+       return 0;
+
+pio_fallback:
+       return sunxi_nfc_hw_ecc_write_page(mtd, chip, buf, oob_required, page);
+}
+
 static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
                                               struct nand_chip *chip,
                                               uint8_t *buf, int oob_required,
@@ -1497,10 +1814,19 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
        int ret;
        int i;
 
+       if (ecc->size != 512 && ecc->size != 1024)
+               return -EINVAL;
+
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
+       /* Prefer 1k ECC chunk over 512 ones */
+       if (ecc->size == 512 && mtd->writesize > 512) {
+               ecc->size = 1024;
+               ecc->strength *= 2;
+       }
+
        /* Add ECC info retrieval from DT */
        for (i = 0; i < ARRAY_SIZE(strengths); i++) {
                if (ecc->strength <= strengths[i])
@@ -1550,14 +1876,28 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
                                       struct nand_ecc_ctrl *ecc,
                                       struct device_node *np)
 {
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+       struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        int ret;
 
        ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
        if (ret)
                return ret;
 
-       ecc->read_page = sunxi_nfc_hw_ecc_read_page;
-       ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+       if (nfc->dmac) {
+               ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
+               ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
+               ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
+               nand->options |= NAND_USE_BOUNCE_BUFFER;
+       } else {
+               ecc->read_page = sunxi_nfc_hw_ecc_read_page;
+               ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
+               ecc->write_page = sunxi_nfc_hw_ecc_write_page;
+       }
+
+       /* TODO: support DMA for raw accesses and subpage write */
+       ecc->write_subpage = sunxi_nfc_hw_ecc_write_subpage;
        ecc->read_oob_raw = nand_read_oob_std;
        ecc->write_oob_raw = nand_write_oob_std;
        ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
@@ -1871,26 +2211,59 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
        if (ret)
                goto out_ahb_clk_unprepare;
 
+       nfc->reset = devm_reset_control_get_optional(dev, "ahb");
+       if (!IS_ERR(nfc->reset)) {
+               ret = reset_control_deassert(nfc->reset);
+               if (ret) {
+                       dev_err(dev, "reset err %d\n", ret);
+                       goto out_mod_clk_unprepare;
+               }
+       } else if (PTR_ERR(nfc->reset) != -ENOENT) {
+               ret = PTR_ERR(nfc->reset);
+               goto out_mod_clk_unprepare;
+       }
+
        ret = sunxi_nfc_rst(nfc);
        if (ret)
-               goto out_mod_clk_unprepare;
+               goto out_ahb_reset_reassert;
 
        writel(0, nfc->regs + NFC_REG_INT);
        ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt,
                               0, "sunxi-nand", nfc);
        if (ret)
-               goto out_mod_clk_unprepare;
+               goto out_ahb_reset_reassert;
+
+       nfc->dmac = dma_request_slave_channel(dev, "rxtx");
+       if (nfc->dmac) {
+               struct dma_slave_config dmac_cfg = { };
+
+               dmac_cfg.src_addr = r->start + NFC_REG_IO_DATA;
+               dmac_cfg.dst_addr = dmac_cfg.src_addr;
+               dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
+               dmac_cfg.src_maxburst = 4;
+               dmac_cfg.dst_maxburst = 4;
+               dmaengine_slave_config(nfc->dmac, &dmac_cfg);
+       } else {
+               dev_warn(dev, "failed to request rxtx DMA channel\n");
+       }
 
        platform_set_drvdata(pdev, nfc);
 
        ret = sunxi_nand_chips_init(dev, nfc);
        if (ret) {
                dev_err(dev, "failed to init nand chips\n");
-               goto out_mod_clk_unprepare;
+               goto out_release_dmac;
        }
 
        return 0;
 
+out_release_dmac:
+       if (nfc->dmac)
+               dma_release_channel(nfc->dmac);
+out_ahb_reset_reassert:
+       if (!IS_ERR(nfc->reset))
+               reset_control_assert(nfc->reset);
 out_mod_clk_unprepare:
        clk_disable_unprepare(nfc->mod_clk);
 out_ahb_clk_unprepare:
@@ -1904,6 +2277,12 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
        struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
 
        sunxi_nand_chips_cleanup(nfc);
+
+       if (!IS_ERR(nfc->reset))
+               reset_control_assert(nfc->reset);
+
+       if (nfc->dmac)
+               dma_release_channel(nfc->dmac);
        clk_disable_unprepare(nfc->mod_clk);
        clk_disable_unprepare(nfc->ahb_clk);
 
index 0cf0ac0..1f2948c 100644 (file)
@@ -4,6 +4,7 @@
  *  by the Free Software Foundation.
  *
  *  Copyright © 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de>
  */
 
 #include <linux/mtd/nand.h>
 #define EBU_ADDSEL1            0x24
 #define EBU_NAND_CON           0xB0
 #define EBU_NAND_WAIT          0xB4
+#define  NAND_WAIT_RD          BIT(0) /* NAND flash status output */
+#define  NAND_WAIT_WR_C                BIT(3) /* NAND Write/Read complete */
 #define EBU_NAND_ECC0          0xB8
 #define EBU_NAND_ECC_AC                0xBC
 
-/* nand commands */
-#define NAND_CMD_ALE           (1 << 2)
-#define NAND_CMD_CLE           (1 << 3)
-#define NAND_CMD_CS            (1 << 4)
-#define NAND_WRITE_CMD_RESET   0xff
+/*
+ * nand commands
+ * The pins of the NAND chip are selected based on the address bits of the
+ * "register" read and write. There are no special registers, but an
+ * address range and the lower address bits are used to activate the
+ * correct line. For example when the bit (1 << 2) is set in the address
+ * the ALE pin will be activated.
+ */
+#define NAND_CMD_ALE           BIT(2) /* address latch enable */
+#define NAND_CMD_CLE           BIT(3) /* command latch enable */
+#define NAND_CMD_CS            BIT(4) /* chip select */
+#define NAND_CMD_SE            BIT(5) /* spare area access latch */
+#define NAND_CMD_WP            BIT(6) /* write protect */
 #define NAND_WRITE_CMD         (NAND_CMD_CS | NAND_CMD_CLE)
 #define NAND_WRITE_ADDR                (NAND_CMD_CS | NAND_CMD_ALE)
 #define NAND_WRITE_DATA                (NAND_CMD_CS)
 #define NAND_READ_DATA         (NAND_CMD_CS)
-#define NAND_WAIT_WR_C         (1 << 3)
-#define NAND_WAIT_RD           (0x1)
 
 /* we need to tel the ebu which addr we mapped the nand to */
 #define ADDSEL1_MASK(x)                (x << 4)
 #define NAND_CON_CSMUX         (1 << 1)
 #define NAND_CON_NANDM         1
 
-static void xway_reset_chip(struct nand_chip *chip)
+struct xway_nand_data {
+       struct nand_chip        chip;
+       unsigned long           csflags;
+       void __iomem            *nandaddr;
+};
+
+static u8 xway_readb(struct mtd_info *mtd, int op)
 {
-       unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
-       unsigned long flags;
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct xway_nand_data *data = nand_get_controller_data(chip);
 
-       nandaddr &= ~NAND_WRITE_ADDR;
-       nandaddr |= NAND_WRITE_CMD;
+       return readb(data->nandaddr + op);
+}
 
-       /* finish with a reset */
-       spin_lock_irqsave(&ebu_lock, flags);
-       writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr);
-       while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
-               ;
-       spin_unlock_irqrestore(&ebu_lock, flags);
+static void xway_writeb(struct mtd_info *mtd, int op, u8 value)
+{
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct xway_nand_data *data = nand_get_controller_data(chip);
+
+       writeb(value, data->nandaddr + op);
 }
 
-static void xway_select_chip(struct mtd_info *mtd, int chip)
+static void xway_select_chip(struct mtd_info *mtd, int select)
 {
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct xway_nand_data *data = nand_get_controller_data(chip);
 
-       switch (chip) {
+       switch (select) {
        case -1:
                ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
                ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+               spin_unlock_irqrestore(&ebu_lock, data->csflags);
                break;
        case 0:
+               spin_lock_irqsave(&ebu_lock, data->csflags);
                ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
                ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
                break;
@@ -89,26 +108,16 @@ static void xway_select_chip(struct mtd_info *mtd, int chip)
 
 static void xway_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
-       unsigned long flags;
-
-       if (ctrl & NAND_CTRL_CHANGE) {
-               nandaddr &= ~(NAND_WRITE_CMD | NAND_WRITE_ADDR);
-               if (ctrl & NAND_CLE)
-                       nandaddr |= NAND_WRITE_CMD;
-               else
-                       nandaddr |= NAND_WRITE_ADDR;
-               this->IO_ADDR_W = (void __iomem *) nandaddr;
-       }
+       if (cmd == NAND_CMD_NONE)
+               return;
 
-       if (cmd != NAND_CMD_NONE) {
-               spin_lock_irqsave(&ebu_lock, flags);
-               writeb(cmd, this->IO_ADDR_W);
-               while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
-                       ;
-               spin_unlock_irqrestore(&ebu_lock, flags);
-       }
+       if (ctrl & NAND_CLE)
+               xway_writeb(mtd, NAND_WRITE_CMD, cmd);
+       else if (ctrl & NAND_ALE)
+               xway_writeb(mtd, NAND_WRITE_ADDR, cmd);
+
+       while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+               ;
 }
 
 static int xway_dev_ready(struct mtd_info *mtd)
@@ -118,80 +127,122 @@ static int xway_dev_ready(struct mtd_info *mtd)
 
 static unsigned char xway_read_byte(struct mtd_info *mtd)
 {
-       struct nand_chip *this = mtd_to_nand(mtd);
-       unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
-       unsigned long flags;
-       int ret;
+       return xway_readb(mtd, NAND_READ_DATA);
+}
+
+static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       int i;
 
-       spin_lock_irqsave(&ebu_lock, flags);
-       ret = ltq_r8((void __iomem *)(nandaddr + NAND_READ_DATA));
-       spin_unlock_irqrestore(&ebu_lock, flags);
+       for (i = 0; i < len; i++)
+               buf[i] = xway_readb(mtd, NAND_WRITE_DATA);
+}
 
-       return ret;
+static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               xway_writeb(mtd, NAND_WRITE_DATA, buf[i]);
 }
 
+/*
+ * Probe for the NAND device.
+ */
 static int xway_nand_probe(struct platform_device *pdev)
 {
-       struct nand_chip *this = platform_get_drvdata(pdev);
-       unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
-       const __be32 *cs = of_get_property(pdev->dev.of_node,
-                                       "lantiq,cs", NULL);
+       struct xway_nand_data *data;
+       struct mtd_info *mtd;
+       struct resource *res;
+       int err;
+       u32 cs;
        u32 cs_flag = 0;
 
+       /* Allocate memory for the device structure (and zero it) */
+       data = devm_kzalloc(&pdev->dev, sizeof(struct xway_nand_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->nandaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->nandaddr))
+               return PTR_ERR(data->nandaddr);
+
+       nand_set_flash_node(&data->chip, pdev->dev.of_node);
+       mtd = nand_to_mtd(&data->chip);
+       mtd->dev.parent = &pdev->dev;
+
+       data->chip.cmd_ctrl = xway_cmd_ctrl;
+       data->chip.dev_ready = xway_dev_ready;
+       data->chip.select_chip = xway_select_chip;
+       data->chip.write_buf = xway_write_buf;
+       data->chip.read_buf = xway_read_buf;
+       data->chip.read_byte = xway_read_byte;
+       data->chip.chip_delay = 30;
+
+       data->chip.ecc.mode = NAND_ECC_SOFT;
+       data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+       platform_set_drvdata(pdev, data);
+       nand_set_controller_data(&data->chip, data);
+
        /* load our CS from the DT. Either we find a valid 1 or default to 0 */
-       if (cs && (*cs == 1))
+       err = of_property_read_u32(pdev->dev.of_node, "lantiq,cs", &cs);
+       if (!err && cs == 1)
                cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
 
        /* setup the EBU to run in NAND mode on our base addr */
-       ltq_ebu_w32(CPHYSADDR(nandaddr)
-               | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
+       ltq_ebu_w32(CPHYSADDR(data->nandaddr)
+                   | ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);
 
        ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
-               | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
-               | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
+                   | BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
+                   | BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
 
        ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
-               | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
-               | cs_flag, EBU_NAND_CON);
+                   | NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
+                   | cs_flag, EBU_NAND_CON);
 
-       /* finish with a reset */
-       xway_reset_chip(this);
+       /* Scan to find existence of the device */
+       err = nand_scan(mtd, 1);
+       if (err)
+               return err;
 
-       return 0;
-}
+       err = mtd_device_register(mtd, NULL, 0);
+       if (err)
+               nand_release(mtd);
 
-static struct platform_nand_data xway_nand_data = {
-       .chip = {
-               .nr_chips               = 1,
-               .chip_delay             = 30,
-       },
-       .ctrl = {
-               .probe          = xway_nand_probe,
-               .cmd_ctrl       = xway_cmd_ctrl,
-               .dev_ready      = xway_dev_ready,
-               .select_chip    = xway_select_chip,
-               .read_byte      = xway_read_byte,
-       }
-};
+       return err;
+}
 
 /*
- * Try to find the node inside the DT. If it is available attach out
- * platform_nand_data
+ * Remove a NAND device.
  */
-static int __init xway_register_nand(void)
+static int xway_nand_remove(struct platform_device *pdev)
 {
-       struct device_node *node;
-       struct platform_device *pdev;
-
-       node = of_find_compatible_node(NULL, NULL, "lantiq,nand-xway");
-       if (!node)
-               return -ENOENT;
-       pdev = of_find_device_by_node(node);
-       if (!pdev)
-               return -EINVAL;
-       pdev->dev.platform_data = &xway_nand_data;
-       of_node_put(node);
+       struct xway_nand_data *data = platform_get_drvdata(pdev);
+
+       nand_release(nand_to_mtd(&data->chip));
+
        return 0;
 }
 
-subsys_initcall(xway_register_nand);
+static const struct of_device_id xway_nand_match[] = {
+       { .compatible = "lantiq,nand-xway" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xway_nand_match);
+
+static struct platform_driver xway_nand_driver = {
+       .probe  = xway_nand_probe,
+       .remove = xway_nand_remove,
+       .driver = {
+               .name           = "lantiq,nand-xway",
+               .of_match_table = xway_nand_match,
+       },
+};
+
+module_platform_driver(xway_nand_driver);
+
+MODULE_LICENSE("GPL");
index a4b029a..1a6d0e3 100644 (file)
@@ -3188,13 +3188,13 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
                        size_t tmp_retlen;
 
                        ret = action(mtd, from, len, &tmp_retlen, buf);
+                       if (ret)
+                               break;
 
                        buf += tmp_retlen;
                        len -= tmp_retlen;
                        *retlen += tmp_retlen;
 
-                       if (ret)
-                               break;
                }
                otp_pages--;
        }
index d42c98e..4a682ee 100644 (file)
@@ -29,6 +29,26 @@ config MTD_SPI_NOR_USE_4K_SECTORS
          Please note that some tools/drivers/filesystems may not work with
          4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
 
+config SPI_ATMEL_QUADSPI
+       tristate "Atmel Quad SPI Controller"
+       depends on ARCH_AT91 || (ARM && COMPILE_TEST)
+       depends on OF && HAS_IOMEM
+       help
+         This enables support for the Quad SPI controller in master mode.
+         This driver does not support generic SPI. The implementation only
+         supports SPI NOR.
+
+config SPI_CADENCE_QUADSPI
+       tristate "Cadence Quad SPI controller"
+       depends on OF && ARM
+       help
+         Enable support for the Cadence Quad SPI Flash controller.
+
+         Cadence QSPI is a specialized controller for connecting an SPI
+         Flash over 1/2/4-bit wide bus. Enable this option if you have a
+         device with a Cadence QSPI controller and want to access the
+         Flash as an MTD device.
+
 config SPI_FSL_QUADSPI
        tristate "Freescale Quad SPI controller"
        depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
@@ -38,6 +58,13 @@ config SPI_FSL_QUADSPI
          This controller does not support generic SPI. It only supports
          SPI NOR.
 
+config SPI_HISI_SFC
+       tristate "Hisilicon SPI-NOR Flash Controller(SFC)"
+       depends on ARCH_HISI || COMPILE_TEST
+       depends on HAS_IOMEM && HAS_DMA
+       help
+         This enables support for hisilicon SPI-NOR flash controller.
+
 config SPI_NXP_SPIFI
        tristate "NXP SPI Flash Interface (SPIFI)"
        depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
index 0bf3a7f..121695e 100644 (file)
@@ -1,4 +1,7 @@
 obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor.o
+obj-$(CONFIG_SPI_ATMEL_QUADSPI)        += atmel-quadspi.o
+obj-$(CONFIG_SPI_CADENCE_QUADSPI)      += cadence-quadspi.o
 obj-$(CONFIG_SPI_FSL_QUADSPI)  += fsl-quadspi.o
+obj-$(CONFIG_SPI_HISI_SFC)     += hisi-sfc.o
 obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
 obj-$(CONFIG_SPI_NXP_SPIFI)    += nxp-spifi.o
diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c
new file mode 100644 (file)
index 0000000..47937d9
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * Driver for Atmel QSPI Controller
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/platform_data/atmel.h>
+#include <linux/of.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+/* QSPI register offsets */
+#define QSPI_CR      0x0000  /* Control Register */
+#define QSPI_MR      0x0004  /* Mode Register */
+#define QSPI_RD      0x0008  /* Receive Data Register */
+#define QSPI_TD      0x000c  /* Transmit Data Register */
+#define QSPI_SR      0x0010  /* Status Register */
+#define QSPI_IER     0x0014  /* Interrupt Enable Register */
+#define QSPI_IDR     0x0018  /* Interrupt Disable Register */
+#define QSPI_IMR     0x001c  /* Interrupt Mask Register */
+#define QSPI_SCR     0x0020  /* Serial Clock Register */
+
+#define QSPI_IAR     0x0030  /* Instruction Address Register */
+#define QSPI_ICR     0x0034  /* Instruction Code Register */
+#define QSPI_IFR     0x0038  /* Instruction Frame Register */
+
+#define QSPI_SMR     0x0040  /* Scrambling Mode Register */
+#define QSPI_SKR     0x0044  /* Scrambling Key Register */
+
+#define QSPI_WPMR    0x00E4  /* Write Protection Mode Register */
+#define QSPI_WPSR    0x00E8  /* Write Protection Status Register */
+
+#define QSPI_VERSION 0x00FC  /* Version Register */
+
+
+/* Bitfields in QSPI_CR (Control Register) */
+#define QSPI_CR_QSPIEN                  BIT(0)
+#define QSPI_CR_QSPIDIS                 BIT(1)
+#define QSPI_CR_SWRST                   BIT(7)
+#define QSPI_CR_LASTXFER                BIT(24)
+
+/* Bitfields in QSPI_MR (Mode Register) */
+#define QSPI_MR_SSM                     BIT(0)
+#define QSPI_MR_LLB                     BIT(1)
+#define QSPI_MR_WDRBT                   BIT(2)
+#define QSPI_MR_SMRM                    BIT(3)
+#define QSPI_MR_CSMODE_MASK             GENMASK(5, 4)
+#define QSPI_MR_CSMODE_NOT_RELOADED     (0 << 4)
+#define QSPI_MR_CSMODE_LASTXFER         (1 << 4)
+#define QSPI_MR_CSMODE_SYSTEMATICALLY   (2 << 4)
+#define QSPI_MR_NBBITS_MASK             GENMASK(11, 8)
+#define QSPI_MR_NBBITS(n)               ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
+#define QSPI_MR_DLYBCT_MASK             GENMASK(23, 16)
+#define QSPI_MR_DLYBCT(n)               (((n) << 16) & QSPI_MR_DLYBCT_MASK)
+#define QSPI_MR_DLYCS_MASK              GENMASK(31, 24)
+#define QSPI_MR_DLYCS(n)                (((n) << 24) & QSPI_MR_DLYCS_MASK)
+
+/* Bitfields in QSPI_SR/QSPI_IER/QSPI_IDR/QSPI_IMR  */
+#define QSPI_SR_RDRF                    BIT(0)
+#define QSPI_SR_TDRE                    BIT(1)
+#define QSPI_SR_TXEMPTY                 BIT(2)
+#define QSPI_SR_OVRES                   BIT(3)
+#define QSPI_SR_CSR                     BIT(8)
+#define QSPI_SR_CSS                     BIT(9)
+#define QSPI_SR_INSTRE                  BIT(10)
+#define QSPI_SR_QSPIENS                 BIT(24)
+
+#define QSPI_SR_CMD_COMPLETED  (QSPI_SR_INSTRE | QSPI_SR_CSR)
+
+/* Bitfields in QSPI_SCR (Serial Clock Register) */
+#define QSPI_SCR_CPOL                   BIT(0)
+#define QSPI_SCR_CPHA                   BIT(1)
+#define QSPI_SCR_SCBR_MASK              GENMASK(15, 8)
+#define QSPI_SCR_SCBR(n)                (((n) << 8) & QSPI_SCR_SCBR_MASK)
+#define QSPI_SCR_DLYBS_MASK             GENMASK(23, 16)
+#define QSPI_SCR_DLYBS(n)               (((n) << 16) & QSPI_SCR_DLYBS_MASK)
+
+/* Bitfields in QSPI_ICR (Instruction Code Register) */
+#define QSPI_ICR_INST_MASK              GENMASK(7, 0)
+#define QSPI_ICR_INST(inst)             (((inst) << 0) & QSPI_ICR_INST_MASK)
+#define QSPI_ICR_OPT_MASK               GENMASK(23, 16)
+#define QSPI_ICR_OPT(opt)               (((opt) << 16) & QSPI_ICR_OPT_MASK)
+
+/* Bitfields in QSPI_IFR (Instruction Frame Register) */
+#define QSPI_IFR_WIDTH_MASK             GENMASK(2, 0)
+#define QSPI_IFR_WIDTH_SINGLE_BIT_SPI   (0 << 0)
+#define QSPI_IFR_WIDTH_DUAL_OUTPUT      (1 << 0)
+#define QSPI_IFR_WIDTH_QUAD_OUTPUT      (2 << 0)
+#define QSPI_IFR_WIDTH_DUAL_IO          (3 << 0)
+#define QSPI_IFR_WIDTH_QUAD_IO          (4 << 0)
+#define QSPI_IFR_WIDTH_DUAL_CMD         (5 << 0)
+#define QSPI_IFR_WIDTH_QUAD_CMD         (6 << 0)
+#define QSPI_IFR_INSTEN                 BIT(4)
+#define QSPI_IFR_ADDREN                 BIT(5)
+#define QSPI_IFR_OPTEN                  BIT(6)
+#define QSPI_IFR_DATAEN                 BIT(7)
+#define QSPI_IFR_OPTL_MASK              GENMASK(9, 8)
+#define QSPI_IFR_OPTL_1BIT              (0 << 8)
+#define QSPI_IFR_OPTL_2BIT              (1 << 8)
+#define QSPI_IFR_OPTL_4BIT              (2 << 8)
+#define QSPI_IFR_OPTL_8BIT              (3 << 8)
+#define QSPI_IFR_ADDRL                  BIT(10)
+#define QSPI_IFR_TFRTYP_MASK            GENMASK(13, 12)
+#define QSPI_IFR_TFRTYP_TRSFR_READ      (0 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_READ_MEM  (1 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_WRITE     (2 << 12)
+#define QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM (3 << 13)
+#define QSPI_IFR_CRM                    BIT(14)
+#define QSPI_IFR_NBDUM_MASK             GENMASK(20, 16)
+#define QSPI_IFR_NBDUM(n)               (((n) << 16) & QSPI_IFR_NBDUM_MASK)
+
+/* Bitfields in QSPI_SMR (Scrambling Mode Register) */
+#define QSPI_SMR_SCREN                  BIT(0)
+#define QSPI_SMR_RVDIS                  BIT(1)
+
+/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
+#define QSPI_WPMR_WPEN                  BIT(0)
+#define QSPI_WPMR_WPKEY_MASK            GENMASK(31, 8)
+#define QSPI_WPMR_WPKEY(wpkey)          (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
+
+/* Bitfields in QSPI_WPSR (Write Protection Status Register) */
+#define QSPI_WPSR_WPVS                  BIT(0)
+#define QSPI_WPSR_WPVSRC_MASK           GENMASK(15, 8)
+#define QSPI_WPSR_WPVSRC(src)           (((src) << 8) & QSPI_WPSR_WPVSRC)
+
+
+struct atmel_qspi {
+       void __iomem            *regs;
+       void __iomem            *mem;
+       struct clk              *clk;
+       struct platform_device  *pdev;
+       u32                     pending;
+
+       struct spi_nor          nor;
+       u32                     clk_rate;
+       struct completion       cmd_completion;
+};
+
+struct atmel_qspi_command {
+       union {
+               struct {
+                       u32     instruction:1;
+                       u32     address:3;
+                       u32     mode:1;
+                       u32     dummy:1;
+                       u32     data:1;
+                       u32     reserved:25;
+               }               bits;
+               u32     word;
+       }       enable;
+       u8      instruction;
+       u8      mode;
+       u8      num_mode_cycles;
+       u8      num_dummy_cycles;
+       u32     address;
+
+       size_t          buf_len;
+       const void      *tx_buf;
+       void            *rx_buf;
+};
+
+/* Register access functions */
+static inline u32 qspi_readl(struct atmel_qspi *aq, u32 reg)
+{
+       return readl_relaxed(aq->regs + reg);
+}
+
+static inline void qspi_writel(struct atmel_qspi *aq, u32 reg, u32 value)
+{
+       writel_relaxed(value, aq->regs + reg);
+}
+
+static int atmel_qspi_run_transfer(struct atmel_qspi *aq,
+                                  const struct atmel_qspi_command *cmd)
+{
+       void __iomem *ahb_mem;
+
+       /* Then fallback to a PIO transfer (memcpy() DOES NOT work!) */
+       ahb_mem = aq->mem;
+       if (cmd->enable.bits.address)
+               ahb_mem += cmd->address;
+       if (cmd->tx_buf)
+               _memcpy_toio(ahb_mem, cmd->tx_buf, cmd->buf_len);
+       else
+               _memcpy_fromio(cmd->rx_buf, ahb_mem, cmd->buf_len);
+
+       return 0;
+}
+
+#ifdef DEBUG
+static void atmel_qspi_debug_command(struct atmel_qspi *aq,
+                                    const struct atmel_qspi_command *cmd,
+                                    u32 ifr)
+{
+       u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+       size_t len = 0;
+       int i;
+
+       if (cmd->enable.bits.instruction)
+               cmd_buf[len++] = cmd->instruction;
+
+       for (i = cmd->enable.bits.address-1; i >= 0; --i)
+               cmd_buf[len++] = (cmd->address >> (i << 3)) & 0xff;
+
+       if (cmd->enable.bits.mode)
+               cmd_buf[len++] = cmd->mode;
+
+       if (cmd->enable.bits.dummy) {
+               int num = cmd->num_dummy_cycles;
+
+               switch (ifr & QSPI_IFR_WIDTH_MASK) {
+               case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
+               case QSPI_IFR_WIDTH_DUAL_OUTPUT:
+               case QSPI_IFR_WIDTH_QUAD_OUTPUT:
+                       num >>= 3;
+                       break;
+               case QSPI_IFR_WIDTH_DUAL_IO:
+               case QSPI_IFR_WIDTH_DUAL_CMD:
+                       num >>= 2;
+                       break;
+               case QSPI_IFR_WIDTH_QUAD_IO:
+               case QSPI_IFR_WIDTH_QUAD_CMD:
+                       num >>= 1;
+                       break;
+               default:
+                       return;
+               }
+
+               for (i = 0; i < num; ++i)
+                       cmd_buf[len++] = 0;
+       }
+
+       /* Dump the SPI command */
+       print_hex_dump(KERN_DEBUG, "qspi cmd: ", DUMP_PREFIX_NONE,
+                      32, 1, cmd_buf, len, false);
+
+#ifdef VERBOSE_DEBUG
+       /* If verbose debug is enabled, also dump the TX data */
+       if (cmd->enable.bits.data && cmd->tx_buf)
+               print_hex_dump(KERN_DEBUG, "qspi tx : ", DUMP_PREFIX_NONE,
+                              32, 1, cmd->tx_buf, cmd->buf_len, false);
+#endif
+}
+#else
+#define atmel_qspi_debug_command(aq, cmd, ifr)
+#endif
+
+static int atmel_qspi_run_command(struct atmel_qspi *aq,
+                                 const struct atmel_qspi_command *cmd,
+                                 u32 ifr_tfrtyp, u32 ifr_width)
+{
+       u32 iar, icr, ifr, sr;
+       int err = 0;
+
+       iar = 0;
+       icr = 0;
+       ifr = ifr_tfrtyp | ifr_width;
+
+       /* Compute instruction parameters */
+       if (cmd->enable.bits.instruction) {
+               icr |= QSPI_ICR_INST(cmd->instruction);
+               ifr |= QSPI_IFR_INSTEN;
+       }
+
+       /* Compute address parameters */
+       switch (cmd->enable.bits.address) {
+       case 4:
+               ifr |= QSPI_IFR_ADDRL;
+               /* fall through to the 24bit (3 byte) address case. */
+       case 3:
+               iar = (cmd->enable.bits.data) ? 0 : cmd->address;
+               ifr |= QSPI_IFR_ADDREN;
+               break;
+       case 0:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Compute option parameters */
+       if (cmd->enable.bits.mode && cmd->num_mode_cycles) {
+               u32 mode_cycle_bits, mode_bits;
+
+               icr |= QSPI_ICR_OPT(cmd->mode);
+               ifr |= QSPI_IFR_OPTEN;
+
+               switch (ifr & QSPI_IFR_WIDTH_MASK) {
+               case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
+               case QSPI_IFR_WIDTH_DUAL_OUTPUT:
+               case QSPI_IFR_WIDTH_QUAD_OUTPUT:
+                       mode_cycle_bits = 1;
+                       break;
+               case QSPI_IFR_WIDTH_DUAL_IO:
+               case QSPI_IFR_WIDTH_DUAL_CMD:
+                       mode_cycle_bits = 2;
+                       break;
+               case QSPI_IFR_WIDTH_QUAD_IO:
+               case QSPI_IFR_WIDTH_QUAD_CMD:
+                       mode_cycle_bits = 4;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
+               switch (mode_bits) {
+               case 1:
+                       ifr |= QSPI_IFR_OPTL_1BIT;
+                       break;
+
+               case 2:
+                       ifr |= QSPI_IFR_OPTL_2BIT;
+                       break;
+
+               case 4:
+                       ifr |= QSPI_IFR_OPTL_4BIT;
+                       break;
+
+               case 8:
+                       ifr |= QSPI_IFR_OPTL_8BIT;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* Set number of dummy cycles */
+       if (cmd->enable.bits.dummy)
+               ifr |= QSPI_IFR_NBDUM(cmd->num_dummy_cycles);
+
+       /* Set data enable */
+       if (cmd->enable.bits.data) {
+               ifr |= QSPI_IFR_DATAEN;
+
+               /* Special case for Continuous Read Mode */
+               if (!cmd->tx_buf && !cmd->rx_buf)
+                       ifr |= QSPI_IFR_CRM;
+       }
+
+       /* Clear pending interrupts */
+       (void)qspi_readl(aq, QSPI_SR);
+
+       /* Set QSPI Instruction Frame registers */
+       atmel_qspi_debug_command(aq, cmd, ifr);
+       qspi_writel(aq, QSPI_IAR, iar);
+       qspi_writel(aq, QSPI_ICR, icr);
+       qspi_writel(aq, QSPI_IFR, ifr);
+
+       /* Skip to the final steps if there is no data */
+       if (!cmd->enable.bits.data)
+               goto no_data;
+
+       /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
+       (void)qspi_readl(aq, QSPI_IFR);
+
+       /* Stop here for continuous read */
+       if (!cmd->tx_buf && !cmd->rx_buf)
+               return 0;
+       /* Send/Receive data */
+       err = atmel_qspi_run_transfer(aq, cmd);
+
+       /* Release the chip-select */
+       qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
+
+       if (err)
+               return err;
+
+#if defined(DEBUG) && defined(VERBOSE_DEBUG)
+       /*
+        * If verbose debug is enabled, also dump the RX data in addition to
+        * the SPI command previously dumped by atmel_qspi_debug_command()
+        */
+       if (cmd->rx_buf)
+               print_hex_dump(KERN_DEBUG, "qspi rx : ", DUMP_PREFIX_NONE,
+                              32, 1, cmd->rx_buf, cmd->buf_len, false);
+#endif
+no_data:
+       /* Poll INSTRuction End status */
+       sr = qspi_readl(aq, QSPI_SR);
+       if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
+               return err;
+
+       /* Wait for INSTRuction End interrupt */
+       reinit_completion(&aq->cmd_completion);
+       aq->pending = sr & QSPI_SR_CMD_COMPLETED;
+       qspi_writel(aq, QSPI_IER, QSPI_SR_CMD_COMPLETED);
+       if (!wait_for_completion_timeout(&aq->cmd_completion,
+                                        msecs_to_jiffies(1000)))
+               err = -ETIMEDOUT;
+       qspi_writel(aq, QSPI_IDR, QSPI_SR_CMD_COMPLETED);
+
+       return err;
+}
+
+static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
+                              u8 *buf, int len)
+{
+       struct atmel_qspi *aq = nor->priv;
+       struct atmel_qspi_command cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.enable.bits.instruction = 1;
+       cmd.enable.bits.data = 1;
+       cmd.instruction = opcode;
+       cmd.rx_buf = buf;
+       cmd.buf_len = len;
+       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
+                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+}
+
+static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
+                               u8 *buf, int len)
+{
+       struct atmel_qspi *aq = nor->priv;
+       struct atmel_qspi_command cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.enable.bits.instruction = 1;
+       cmd.enable.bits.data = (buf != NULL && len > 0);
+       cmd.instruction = opcode;
+       cmd.tx_buf = buf;
+       cmd.buf_len = len;
+       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
+                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+}
+
+static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
+                               const u_char *write_buf)
+{
+       struct atmel_qspi *aq = nor->priv;
+       struct atmel_qspi_command cmd;
+       ssize_t ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.enable.bits.instruction = 1;
+       cmd.enable.bits.address = nor->addr_width;
+       cmd.enable.bits.data = 1;
+       cmd.instruction = nor->program_opcode;
+       cmd.address = (u32)to;
+       cmd.tx_buf = write_buf;
+       cmd.buf_len = len;
+       ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
+                                    QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+       return (ret < 0) ? ret : len;
+}
+
+static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
+{
+       struct atmel_qspi *aq = nor->priv;
+       struct atmel_qspi_command cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.enable.bits.instruction = 1;
+       cmd.enable.bits.address = nor->addr_width;
+       cmd.instruction = nor->erase_opcode;
+       cmd.address = (u32)offs;
+       return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
+                                     QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
+}
+
+static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
+                              u_char *read_buf)
+{
+       struct atmel_qspi *aq = nor->priv;
+       struct atmel_qspi_command cmd;
+       u8 num_mode_cycles, num_dummy_cycles;
+       u32 ifr_width;
+       ssize_t ret;
+
+       switch (nor->flash_read) {
+       case SPI_NOR_NORMAL:
+       case SPI_NOR_FAST:
+               ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
+               break;
+
+       case SPI_NOR_DUAL:
+               ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
+               break;
+
+       case SPI_NOR_QUAD:
+               ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (nor->read_dummy >= 2) {
+               num_mode_cycles = 2;
+               num_dummy_cycles = nor->read_dummy - 2;
+       } else {
+               num_mode_cycles = nor->read_dummy;
+               num_dummy_cycles = 0;
+       }
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.enable.bits.instruction = 1;
+       cmd.enable.bits.address = nor->addr_width;
+       cmd.enable.bits.mode = (num_mode_cycles > 0);
+       cmd.enable.bits.dummy = (num_dummy_cycles > 0);
+       cmd.enable.bits.data = 1;
+       cmd.instruction = nor->read_opcode;
+       cmd.address = (u32)from;
+       cmd.mode = 0xff; /* This value prevents from entering the 0-4-4 mode */
+       cmd.num_mode_cycles = num_mode_cycles;
+       cmd.num_dummy_cycles = num_dummy_cycles;
+       cmd.rx_buf = read_buf;
+       cmd.buf_len = len;
+       ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
+                                    ifr_width);
+       return (ret < 0) ? ret : len;
+}
+
+static int atmel_qspi_init(struct atmel_qspi *aq)
+{
+       unsigned long src_rate;
+       u32 mr, scr, scbr;
+
+       /* Reset the QSPI controller */
+       qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
+
+       /* Set the QSPI controller in Serial Memory Mode */
+       mr = QSPI_MR_NBBITS(8) | QSPI_MR_SSM;
+       qspi_writel(aq, QSPI_MR, mr);
+
+       src_rate = clk_get_rate(aq->clk);
+       if (!src_rate)
+               return -EINVAL;
+
+       /* Compute the QSPI baudrate */
+       scbr = DIV_ROUND_UP(src_rate, aq->clk_rate);
+       if (scbr > 0)
+               scbr--;
+       scr = QSPI_SCR_SCBR(scbr);
+       qspi_writel(aq, QSPI_SCR, scr);
+
+       /* Enable the QSPI controller */
+       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
+
+       return 0;
+}
+
+static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
+{
+       struct atmel_qspi *aq = (struct atmel_qspi *)dev_id;
+       u32 status, mask, pending;
+
+       status = qspi_readl(aq, QSPI_SR);
+       mask = qspi_readl(aq, QSPI_IMR);
+       pending = status & mask;
+
+       if (!pending)
+               return IRQ_NONE;
+
+       aq->pending |= pending;
+       if ((aq->pending & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
+               complete(&aq->cmd_completion);
+
+       return IRQ_HANDLED;
+}
+
+static int atmel_qspi_probe(struct platform_device *pdev)
+{
+       struct device_node *child, *np = pdev->dev.of_node;
+       struct atmel_qspi *aq;
+       struct resource *res;
+       struct spi_nor *nor;
+       struct mtd_info *mtd;
+       int irq, err = 0;
+
+       if (of_get_child_count(np) != 1)
+               return -ENODEV;
+       child = of_get_next_child(np, NULL);
+
+       aq = devm_kzalloc(&pdev->dev, sizeof(*aq), GFP_KERNEL);
+       if (!aq) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       platform_set_drvdata(pdev, aq);
+       init_completion(&aq->cmd_completion);
+       aq->pdev = pdev;
+
+       /* Map the registers */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
+       aq->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(aq->regs)) {
+               dev_err(&pdev->dev, "missing registers\n");
+               err = PTR_ERR(aq->regs);
+               goto exit;
+       }
+
+       /* Map the AHB memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap");
+       aq->mem = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(aq->mem)) {
+               dev_err(&pdev->dev, "missing AHB memory\n");
+               err = PTR_ERR(aq->mem);
+               goto exit;
+       }
+
+       /* Get the peripheral clock */
+       aq->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(aq->clk)) {
+               dev_err(&pdev->dev, "missing peripheral clock\n");
+               err = PTR_ERR(aq->clk);
+               goto exit;
+       }
+
+       /* Enable the peripheral clock */
+       err = clk_prepare_enable(aq->clk);
+       if (err) {
+               dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
+               goto exit;
+       }
+
+       /* Request the IRQ */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "missing IRQ\n");
+               err = irq;
+               goto disable_clk;
+       }
+       err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
+                              0, dev_name(&pdev->dev), aq);
+       if (err)
+               goto disable_clk;
+
+       /* Setup the spi-nor */
+       nor = &aq->nor;
+       mtd = &nor->mtd;
+
+       nor->dev = &pdev->dev;
+       spi_nor_set_flash_node(nor, child);
+       nor->priv = aq;
+       mtd->priv = nor;
+
+       nor->read_reg = atmel_qspi_read_reg;
+       nor->write_reg = atmel_qspi_write_reg;
+       nor->read = atmel_qspi_read;
+       nor->write = atmel_qspi_write;
+       nor->erase = atmel_qspi_erase;
+
+       err = of_property_read_u32(child, "spi-max-frequency", &aq->clk_rate);
+       if (err < 0)
+               goto disable_clk;
+
+       err = atmel_qspi_init(aq);
+       if (err)
+               goto disable_clk;
+
+       err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+       if (err)
+               goto disable_clk;
+
+       err = mtd_device_register(mtd, NULL, 0);
+       if (err)
+               goto disable_clk;
+
+       of_node_put(child);
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(aq->clk);
+exit:
+       of_node_put(child);
+
+       return err;
+}
+
+static int atmel_qspi_remove(struct platform_device *pdev)
+{
+       struct atmel_qspi *aq = platform_get_drvdata(pdev);
+
+       mtd_device_unregister(&aq->nor.mtd);
+       qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIDIS);
+       clk_disable_unprepare(aq->clk);
+       return 0;
+}
+
+
+static const struct of_device_id atmel_qspi_dt_ids[] = {
+       { .compatible = "atmel,sama5d2-qspi" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_qspi_dt_ids);
+
+static struct platform_driver atmel_qspi_driver = {
+       .driver = {
+               .name   = "atmel_qspi",
+               .of_match_table = atmel_qspi_dt_ids,
+       },
+       .probe          = atmel_qspi_probe,
+       .remove         = atmel_qspi_remove,
+};
+module_platform_driver(atmel_qspi_driver);
+
+MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
+MODULE_DESCRIPTION("Atmel QSPI Controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
new file mode 100644 (file)
index 0000000..d403ba7
--- /dev/null
@@ -0,0 +1,1299 @@
+/*
+ * Driver for Cadence QSPI Controller
+ *
+ * Copyright Altera Corporation (C) 2012-2014. All rights reserved.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spi/spi.h>
+#include <linux/timer.h>
+
+#define CQSPI_NAME                     "cadence-qspi"
+#define CQSPI_MAX_CHIPSELECT           16
+
+struct cqspi_st;
+
+struct cqspi_flash_pdata {
+       struct spi_nor  nor;
+       struct cqspi_st *cqspi;
+       u32             clk_rate;
+       u32             read_delay;
+       u32             tshsl_ns;
+       u32             tsd2d_ns;
+       u32             tchsh_ns;
+       u32             tslch_ns;
+       u8              inst_width;
+       u8              addr_width;
+       u8              data_width;
+       u8              cs;
+       bool            registered;
+};
+
+struct cqspi_st {
+       struct platform_device  *pdev;
+
+       struct clk              *clk;
+       unsigned int            sclk;
+
+       void __iomem            *iobase;
+       void __iomem            *ahb_base;
+       struct completion       transfer_complete;
+       struct mutex            bus_mutex;
+
+       int                     current_cs;
+       int                     current_page_size;
+       int                     current_erase_size;
+       int                     current_addr_width;
+       unsigned long           master_ref_clk_hz;
+       bool                    is_decoded_cs;
+       u32                     fifo_depth;
+       u32                     fifo_width;
+       u32                     trigger_address;
+       struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
+};
+
+/* Operation timeout value */
+#define CQSPI_TIMEOUT_MS                       500
+#define CQSPI_READ_TIMEOUT_MS                  10
+
+/* Instruction type */
+#define CQSPI_INST_TYPE_SINGLE                 0
+#define CQSPI_INST_TYPE_DUAL                   1
+#define CQSPI_INST_TYPE_QUAD                   2
+
+#define CQSPI_DUMMY_CLKS_PER_BYTE              8
+#define CQSPI_DUMMY_BYTES_MAX                  4
+#define CQSPI_DUMMY_CLKS_MAX                   31
+
+#define CQSPI_STIG_DATA_LEN_MAX                        8
+
+/* Register map */
+#define CQSPI_REG_CONFIG                       0x00
+#define CQSPI_REG_CONFIG_ENABLE_MASK           BIT(0)
+#define CQSPI_REG_CONFIG_DECODE_MASK           BIT(9)
+#define CQSPI_REG_CONFIG_CHIPSELECT_LSB                10
+#define CQSPI_REG_CONFIG_DMA_MASK              BIT(15)
+#define CQSPI_REG_CONFIG_BAUD_LSB              19
+#define CQSPI_REG_CONFIG_IDLE_LSB              31
+#define CQSPI_REG_CONFIG_CHIPSELECT_MASK       0xF
+#define CQSPI_REG_CONFIG_BAUD_MASK             0xF
+
+#define CQSPI_REG_RD_INSTR                     0x04
+#define CQSPI_REG_RD_INSTR_OPCODE_LSB          0
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB      8
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB       12
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB       16
+#define CQSPI_REG_RD_INSTR_MODE_EN_LSB         20
+#define CQSPI_REG_RD_INSTR_DUMMY_LSB           24
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK     0x3
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK      0x3
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK      0x3
+#define CQSPI_REG_RD_INSTR_DUMMY_MASK          0x1F
+
+#define CQSPI_REG_WR_INSTR                     0x08
+#define CQSPI_REG_WR_INSTR_OPCODE_LSB          0
+#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB       12
+#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB       16
+
+#define CQSPI_REG_DELAY                                0x0C
+#define CQSPI_REG_DELAY_TSLCH_LSB              0
+#define CQSPI_REG_DELAY_TCHSH_LSB              8
+#define CQSPI_REG_DELAY_TSD2D_LSB              16
+#define CQSPI_REG_DELAY_TSHSL_LSB              24
+#define CQSPI_REG_DELAY_TSLCH_MASK             0xFF
+#define CQSPI_REG_DELAY_TCHSH_MASK             0xFF
+#define CQSPI_REG_DELAY_TSD2D_MASK             0xFF
+#define CQSPI_REG_DELAY_TSHSL_MASK             0xFF
+
+#define CQSPI_REG_READCAPTURE                  0x10
+#define CQSPI_REG_READCAPTURE_BYPASS_LSB       0
+#define CQSPI_REG_READCAPTURE_DELAY_LSB                1
+#define CQSPI_REG_READCAPTURE_DELAY_MASK       0xF
+
+#define CQSPI_REG_SIZE                         0x14
+#define CQSPI_REG_SIZE_ADDRESS_LSB             0
+#define CQSPI_REG_SIZE_PAGE_LSB                        4
+#define CQSPI_REG_SIZE_BLOCK_LSB               16
+#define CQSPI_REG_SIZE_ADDRESS_MASK            0xF
+#define CQSPI_REG_SIZE_PAGE_MASK               0xFFF
+#define CQSPI_REG_SIZE_BLOCK_MASK              0x3F
+
+#define CQSPI_REG_SRAMPARTITION                        0x18
+#define CQSPI_REG_INDIRECTTRIGGER              0x1C
+
+#define CQSPI_REG_DMA                          0x20
+#define CQSPI_REG_DMA_SINGLE_LSB               0
+#define CQSPI_REG_DMA_BURST_LSB                        8
+#define CQSPI_REG_DMA_SINGLE_MASK              0xFF
+#define CQSPI_REG_DMA_BURST_MASK               0xFF
+
+#define CQSPI_REG_REMAP                                0x24
+#define CQSPI_REG_MODE_BIT                     0x28
+
+#define CQSPI_REG_SDRAMLEVEL                   0x2C
+#define CQSPI_REG_SDRAMLEVEL_RD_LSB            0
+#define CQSPI_REG_SDRAMLEVEL_WR_LSB            16
+#define CQSPI_REG_SDRAMLEVEL_RD_MASK           0xFFFF
+#define CQSPI_REG_SDRAMLEVEL_WR_MASK           0xFFFF
+
+#define CQSPI_REG_IRQSTATUS                    0x40
+#define CQSPI_REG_IRQMASK                      0x44
+
+#define CQSPI_REG_INDIRECTRD                   0x60
+#define CQSPI_REG_INDIRECTRD_START_MASK                BIT(0)
+#define CQSPI_REG_INDIRECTRD_CANCEL_MASK       BIT(1)
+#define CQSPI_REG_INDIRECTRD_DONE_MASK         BIT(5)
+
+#define CQSPI_REG_INDIRECTRDWATERMARK          0x64
+#define CQSPI_REG_INDIRECTRDSTARTADDR          0x68
+#define CQSPI_REG_INDIRECTRDBYTES              0x6C
+
+#define CQSPI_REG_CMDCTRL                      0x90
+#define CQSPI_REG_CMDCTRL_EXECUTE_MASK         BIT(0)
+#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK      BIT(1)
+#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB         12
+#define CQSPI_REG_CMDCTRL_WR_EN_LSB            15
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB                16
+#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB          19
+#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB         20
+#define CQSPI_REG_CMDCTRL_RD_EN_LSB            23
+#define CQSPI_REG_CMDCTRL_OPCODE_LSB           24
+#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK                0x7
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK       0x3
+#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK                0x7
+
+#define CQSPI_REG_INDIRECTWR                   0x70
+#define CQSPI_REG_INDIRECTWR_START_MASK                BIT(0)
+#define CQSPI_REG_INDIRECTWR_CANCEL_MASK       BIT(1)
+#define CQSPI_REG_INDIRECTWR_DONE_MASK         BIT(5)
+
+#define CQSPI_REG_INDIRECTWRWATERMARK          0x74
+#define CQSPI_REG_INDIRECTWRSTARTADDR          0x78
+#define CQSPI_REG_INDIRECTWRBYTES              0x7C
+
+#define CQSPI_REG_CMDADDRESS                   0x94
+#define CQSPI_REG_CMDREADDATALOWER             0xA0
+#define CQSPI_REG_CMDREADDATAUPPER             0xA4
+#define CQSPI_REG_CMDWRITEDATALOWER            0xA8
+#define CQSPI_REG_CMDWRITEDATAUPPER            0xAC
+
+/* Interrupt status bits */
+#define CQSPI_REG_IRQ_MODE_ERR                 BIT(0)
+#define CQSPI_REG_IRQ_UNDERFLOW                        BIT(1)
+#define CQSPI_REG_IRQ_IND_COMP                 BIT(2)
+#define CQSPI_REG_IRQ_IND_RD_REJECT            BIT(3)
+#define CQSPI_REG_IRQ_WR_PROTECTED_ERR         BIT(4)
+#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR          BIT(5)
+#define CQSPI_REG_IRQ_WATERMARK                        BIT(6)
+#define CQSPI_REG_IRQ_IND_SRAM_FULL            BIT(12)
+
+#define CQSPI_IRQ_MASK_RD              (CQSPI_REG_IRQ_WATERMARK        | \
+                                        CQSPI_REG_IRQ_IND_SRAM_FULL    | \
+                                        CQSPI_REG_IRQ_IND_COMP)
+
+#define CQSPI_IRQ_MASK_WR              (CQSPI_REG_IRQ_IND_COMP         | \
+                                        CQSPI_REG_IRQ_WATERMARK        | \
+                                        CQSPI_REG_IRQ_UNDERFLOW)
+
+#define CQSPI_IRQ_STATUS_MASK          0x1FFFF
+
+static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clear)
+{
+       unsigned long end = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
+       u32 val;
+
+       while (1) {
+               val = readl(reg);
+               if (clear)
+                       val = ~val;
+               val &= mask;
+
+               if (val == mask)
+                       return 0;
+
+               if (time_after(jiffies, end))
+                       return -ETIMEDOUT;
+       }
+}
+
+static bool cqspi_is_idle(struct cqspi_st *cqspi)
+{
+       u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
+
+       return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB);
+}
+
+static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
+{
+       u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL);
+
+       reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
+       return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
+}
+
+static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
+{
+       struct cqspi_st *cqspi = dev;
+       unsigned int irq_status;
+
+       /* Read interrupt status */
+       irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
+
+       /* Clear interrupt */
+       writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);
+
+       irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
+
+       if (irq_status)
+               complete(&cqspi->transfer_complete);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int cqspi_calc_rdreg(struct spi_nor *nor, const u8 opcode)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       u32 rdreg = 0;
+
+       rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
+       rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
+       rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+
+       return rdreg;
+}
+
+static int cqspi_wait_idle(struct cqspi_st *cqspi)
+{
+       const unsigned int poll_idle_retry = 3;
+       unsigned int count = 0;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS);
+       while (1) {
+               /*
+                * Read few times in succession to ensure the controller
+                * is indeed idle, that is, the bit does not transition
+                * low again.
+                */
+               if (cqspi_is_idle(cqspi))
+                       count++;
+               else
+                       count = 0;
+
+               if (count >= poll_idle_retry)
+                       return 0;
+
+               if (time_after(jiffies, timeout)) {
+                       /* Timeout, in busy mode. */
+                       dev_err(&cqspi->pdev->dev,
+                               "QSPI is still busy after %dms timeout.\n",
+                               CQSPI_TIMEOUT_MS);
+                       return -ETIMEDOUT;
+               }
+
+               cpu_relax();
+       }
+}
+
+static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
+{
+       void __iomem *reg_base = cqspi->iobase;
+       int ret;
+
+       /* Write the CMDCTRL without start execution. */
+       writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+       /* Start execute */
+       reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK;
+       writel(reg, reg_base + CQSPI_REG_CMDCTRL);
+
+       /* Polling for completion. */
+       ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL,
+                                CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1);
+       if (ret) {
+               dev_err(&cqspi->pdev->dev,
+                       "Flash command execution timed out.\n");
+               return ret;
+       }
+
+       /* Polling QSPI idle status. */
+       return cqspi_wait_idle(cqspi);
+}
+
+static int cqspi_command_read(struct spi_nor *nor,
+                             const u8 *txbuf, const unsigned n_tx,
+                             u8 *rxbuf, const unsigned n_rx)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int rdreg;
+       unsigned int reg;
+       unsigned int read_len;
+       int status;
+
+       if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
+               dev_err(nor->dev, "Invalid input argument, len %d rxbuf 0x%p\n",
+                       n_rx, rxbuf);
+               return -EINVAL;
+       }
+
+       reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+
+       rdreg = cqspi_calc_rdreg(nor, txbuf[0]);
+       writel(rdreg, reg_base + CQSPI_REG_RD_INSTR);
+
+       reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
+
+       /* 0 means 1 byte. */
+       reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
+               << CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
+       status = cqspi_exec_flash_cmd(cqspi, reg);
+       if (status)
+               return status;
+
+       reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER);
+
+       /* Put the read value into rx_buf */
+       read_len = (n_rx > 4) ? 4 : n_rx;
+       memcpy(rxbuf, &reg, read_len);
+       rxbuf += read_len;
+
+       if (n_rx > 4) {
+               reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER);
+
+               read_len = n_rx - read_len;
+               memcpy(rxbuf, &reg, read_len);
+       }
+
+       return 0;
+}
+
+static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
+                              const u8 *txbuf, const unsigned n_tx)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int reg;
+       unsigned int data;
+       int ret;
+
+       if (n_tx > 4 || (n_tx && !txbuf)) {
+               dev_err(nor->dev,
+                       "Invalid input argument, cmdlen %d txbuf 0x%p\n",
+                       n_tx, txbuf);
+               return -EINVAL;
+       }
+
+       reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+       if (n_tx) {
+               reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
+               reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
+                       << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
+               data = 0;
+               memcpy(&data, txbuf, n_tx);
+               writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
+       }
+
+       ret = cqspi_exec_flash_cmd(cqspi, reg);
+       return ret;
+}
+
+static int cqspi_command_write_addr(struct spi_nor *nor,
+                                   const u8 opcode, const unsigned int addr)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int reg;
+
+       reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+       reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+       reg |= ((nor->addr_width - 1) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
+               << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
+
+       writel(addr, reg_base + CQSPI_REG_CMDADDRESS);
+
+       return cqspi_exec_flash_cmd(cqspi, reg);
+}
+
+static int cqspi_indirect_read_setup(struct spi_nor *nor,
+                                    const unsigned int from_addr)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int dummy_clk = 0;
+       unsigned int reg;
+
+       writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
+
+       reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+       reg |= cqspi_calc_rdreg(nor, nor->read_opcode);
+
+       /* Setup dummy clock cycles */
+       dummy_clk = nor->read_dummy;
+       if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+               dummy_clk = CQSPI_DUMMY_CLKS_MAX;
+
+       if (dummy_clk / 8) {
+               reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
+               /* Set mode bits high to ensure chip doesn't enter XIP */
+               writel(0xFF, reg_base + CQSPI_REG_MODE_BIT);
+
+               /* Need to subtract the mode byte (8 clocks). */
+               if (f_pdata->inst_width != CQSPI_INST_TYPE_QUAD)
+                       dummy_clk -= 8;
+
+               if (dummy_clk)
+                       reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
+                              << CQSPI_REG_RD_INSTR_DUMMY_LSB;
+       }
+
+       writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+
+       /* Set address width */
+       reg = readl(reg_base + CQSPI_REG_SIZE);
+       reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+       reg |= (nor->addr_width - 1);
+       writel(reg, reg_base + CQSPI_REG_SIZE);
+       return 0;
+}
+
+static int cqspi_indirect_read_execute(struct spi_nor *nor,
+                                      u8 *rxbuf, const unsigned n_rx)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       void __iomem *ahb_base = cqspi->ahb_base;
+       unsigned int remaining = n_rx;
+       unsigned int bytes_to_read = 0;
+       int ret = 0;
+
+       writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
+
+       /* Clear all interrupts. */
+       writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
+
+       writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
+
+       reinit_completion(&cqspi->transfer_complete);
+       writel(CQSPI_REG_INDIRECTRD_START_MASK,
+              reg_base + CQSPI_REG_INDIRECTRD);
+
+       while (remaining > 0) {
+               ret = wait_for_completion_timeout(&cqspi->transfer_complete,
+                                                 msecs_to_jiffies
+                                                 (CQSPI_READ_TIMEOUT_MS));
+
+               bytes_to_read = cqspi_get_rd_sram_level(cqspi);
+
+               if (!ret && bytes_to_read == 0) {
+                       dev_err(nor->dev, "Indirect read timeout, no bytes\n");
+                       ret = -ETIMEDOUT;
+                       goto failrd;
+               }
+
+               while (bytes_to_read != 0) {
+                       bytes_to_read *= cqspi->fifo_width;
+                       bytes_to_read = bytes_to_read > remaining ?
+                                       remaining : bytes_to_read;
+                       readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4));
+                       rxbuf += bytes_to_read;
+                       remaining -= bytes_to_read;
+                       bytes_to_read = cqspi_get_rd_sram_level(cqspi);
+               }
+
+               if (remaining > 0)
+                       reinit_completion(&cqspi->transfer_complete);
+       }
+
+       /* Check indirect done status */
+       ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD,
+                                CQSPI_REG_INDIRECTRD_DONE_MASK, 0);
+       if (ret) {
+               dev_err(nor->dev,
+                       "Indirect read completion error (%i)\n", ret);
+               goto failrd;
+       }
+
+       /* Disable interrupt */
+       writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+       /* Clear indirect completion status */
+       writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);
+
+       return 0;
+
+failrd:
+       /* Disable interrupt */
+       writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+       /* Cancel the indirect read */
+       writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
+              reg_base + CQSPI_REG_INDIRECTRD);
+       return ret;
+}
+
+static int cqspi_indirect_write_setup(struct spi_nor *nor,
+                                     const unsigned int to_addr)
+{
+       unsigned int reg;
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+
+       /* Set opcode. */
+       reg = nor->program_opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+       writel(reg, reg_base + CQSPI_REG_WR_INSTR);
+       reg = cqspi_calc_rdreg(nor, nor->program_opcode);
+       writel(reg, reg_base + CQSPI_REG_RD_INSTR);
+
+       writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
+
+       reg = readl(reg_base + CQSPI_REG_SIZE);
+       reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+       reg |= (nor->addr_width - 1);
+       writel(reg, reg_base + CQSPI_REG_SIZE);
+       return 0;
+}
+
+static int cqspi_indirect_write_execute(struct spi_nor *nor,
+                                       const u8 *txbuf, const unsigned n_tx)
+{
+       const unsigned int page_size = nor->page_size;
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int remaining = n_tx;
+       unsigned int write_bytes;
+       int ret;
+
+       writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
+
+       /* Clear all interrupts. */
+       writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
+
+       writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK);
+
+       reinit_completion(&cqspi->transfer_complete);
+       writel(CQSPI_REG_INDIRECTWR_START_MASK,
+              reg_base + CQSPI_REG_INDIRECTWR);
+
+       while (remaining > 0) {
+               write_bytes = remaining > page_size ? page_size : remaining;
+               writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4));
+
+               ret = wait_for_completion_timeout(&cqspi->transfer_complete,
+                                                 msecs_to_jiffies
+                                                 (CQSPI_TIMEOUT_MS));
+               if (!ret) {
+                       dev_err(nor->dev, "Indirect write timeout\n");
+                       ret = -ETIMEDOUT;
+                       goto failwr;
+               }
+
+               txbuf += write_bytes;
+               remaining -= write_bytes;
+
+               if (remaining > 0)
+                       reinit_completion(&cqspi->transfer_complete);
+       }
+
+       /* Check indirect done status */
+       ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR,
+                                CQSPI_REG_INDIRECTWR_DONE_MASK, 0);
+       if (ret) {
+               dev_err(nor->dev,
+                       "Indirect write completion error (%i)\n", ret);
+               goto failwr;
+       }
+
+       /* Disable interrupt. */
+       writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+       /* Clear indirect completion status */
+       writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR);
+
+       cqspi_wait_idle(cqspi);
+
+       return 0;
+
+failwr:
+       /* Disable interrupt. */
+       writel(0, reg_base + CQSPI_REG_IRQMASK);
+
+       /* Cancel the indirect write */
+       writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
+              reg_base + CQSPI_REG_INDIRECTWR);
+       return ret;
+}
+
+static void cqspi_chipselect(struct spi_nor *nor)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int chip_select = f_pdata->cs;
+       unsigned int reg;
+
+       reg = readl(reg_base + CQSPI_REG_CONFIG);
+       if (cqspi->is_decoded_cs) {
+               reg |= CQSPI_REG_CONFIG_DECODE_MASK;
+       } else {
+               reg &= ~CQSPI_REG_CONFIG_DECODE_MASK;
+
+               /* Convert CS if without decoder.
+                * CS0 to 4b'1110
+                * CS1 to 4b'1101
+                * CS2 to 4b'1011
+                * CS3 to 4b'0111
+                */
+               chip_select = 0xF & ~(1 << chip_select);
+       }
+
+       reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
+                << CQSPI_REG_CONFIG_CHIPSELECT_LSB);
+       reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK)
+           << CQSPI_REG_CONFIG_CHIPSELECT_LSB;
+       writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_configure_cs_and_sizes(struct spi_nor *nor)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *iobase = cqspi->iobase;
+       unsigned int reg;
+
+       /* configure page size and block size. */
+       reg = readl(iobase + CQSPI_REG_SIZE);
+       reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
+       reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
+       reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
+       reg |= (nor->page_size << CQSPI_REG_SIZE_PAGE_LSB);
+       reg |= (ilog2(nor->mtd.erasesize) << CQSPI_REG_SIZE_BLOCK_LSB);
+       reg |= (nor->addr_width - 1);
+       writel(reg, iobase + CQSPI_REG_SIZE);
+
+       /* configure the chip select */
+       cqspi_chipselect(nor);
+
+       /* Store the new configuration of the controller */
+       cqspi->current_page_size = nor->page_size;
+       cqspi->current_erase_size = nor->mtd.erasesize;
+       cqspi->current_addr_width = nor->addr_width;
+}
+
+static unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz,
+                                          const unsigned int ns_val)
+{
+       unsigned int ticks;
+
+       ticks = ref_clk_hz / 1000;      /* kHz */
+       ticks = DIV_ROUND_UP(ticks * ns_val, 1000000);
+
+       return ticks;
+}
+
+static void cqspi_delay(struct spi_nor *nor)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       void __iomem *iobase = cqspi->iobase;
+       const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
+       unsigned int tshsl, tchsh, tslch, tsd2d;
+       unsigned int reg;
+       unsigned int tsclk;
+
+       /* calculate the number of ref ticks for one sclk tick */
+       tsclk = DIV_ROUND_UP(ref_clk_hz, cqspi->sclk);
+
+       tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns);
+       /* this particular value must be at least one sclk */
+       if (tshsl < tsclk)
+               tshsl = tsclk;
+
+       tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns);
+       tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns);
+       tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns);
+
+       reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK)
+              << CQSPI_REG_DELAY_TSHSL_LSB;
+       reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK)
+               << CQSPI_REG_DELAY_TCHSH_LSB;
+       reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK)
+               << CQSPI_REG_DELAY_TSLCH_LSB;
+       reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK)
+               << CQSPI_REG_DELAY_TSD2D_LSB;
+       writel(reg, iobase + CQSPI_REG_DELAY);
+}
+
+static void cqspi_config_baudrate_div(struct cqspi_st *cqspi)
+{
+       const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz;
+       void __iomem *reg_base = cqspi->iobase;
+       u32 reg, div;
+
+       /* Recalculate the baudrate divisor based on QSPI specification. */
+       div = DIV_ROUND_UP(ref_clk_hz, 2 * cqspi->sclk) - 1;
+
+       reg = readl(reg_base + CQSPI_REG_CONFIG);
+       reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
+       reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
+       writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_readdata_capture(struct cqspi_st *cqspi,
+                                  const unsigned int bypass,
+                                  const unsigned int delay)
+{
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int reg;
+
+       reg = readl(reg_base + CQSPI_REG_READCAPTURE);
+
+       if (bypass)
+               reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+       else
+               reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+
+       reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
+                << CQSPI_REG_READCAPTURE_DELAY_LSB);
+
+       reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK)
+               << CQSPI_REG_READCAPTURE_DELAY_LSB;
+
+       writel(reg, reg_base + CQSPI_REG_READCAPTURE);
+}
+
+static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable)
+{
+       void __iomem *reg_base = cqspi->iobase;
+       unsigned int reg;
+
+       reg = readl(reg_base + CQSPI_REG_CONFIG);
+
+       if (enable)
+               reg |= CQSPI_REG_CONFIG_ENABLE_MASK;
+       else
+               reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK;
+
+       writel(reg, reg_base + CQSPI_REG_CONFIG);
+}
+
+static void cqspi_configure(struct spi_nor *nor)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+       const unsigned int sclk = f_pdata->clk_rate;
+       int switch_cs = (cqspi->current_cs != f_pdata->cs);
+       int switch_ck = (cqspi->sclk != sclk);
+
+       if ((cqspi->current_page_size != nor->page_size) ||
+           (cqspi->current_erase_size != nor->mtd.erasesize) ||
+           (cqspi->current_addr_width != nor->addr_width))
+               switch_cs = 1;
+
+       if (switch_cs || switch_ck)
+               cqspi_controller_enable(cqspi, 0);
+
+       /* Switch chip select. */
+       if (switch_cs) {
+               cqspi->current_cs = f_pdata->cs;
+               cqspi_configure_cs_and_sizes(nor);
+       }
+
+       /* Setup baudrate divisor and delays */
+       if (switch_ck) {
+               cqspi->sclk = sclk;
+               cqspi_config_baudrate_div(cqspi);
+               cqspi_delay(nor);
+               cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay);
+       }
+
+       if (switch_cs || switch_ck)
+               cqspi_controller_enable(cqspi, 1);
+}
+
+static int cqspi_set_protocol(struct spi_nor *nor, const int read)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+
+       f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE;
+       f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE;
+       f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+
+       if (read) {
+               switch (nor->flash_read) {
+               case SPI_NOR_NORMAL:
+               case SPI_NOR_FAST:
+                       f_pdata->data_width = CQSPI_INST_TYPE_SINGLE;
+                       break;
+               case SPI_NOR_DUAL:
+                       f_pdata->data_width = CQSPI_INST_TYPE_DUAL;
+                       break;
+               case SPI_NOR_QUAD:
+                       f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       cqspi_configure(nor);
+
+       return 0;
+}
+
+static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
+                          size_t len, const u_char *buf)
+{
+       int ret;
+
+       ret = cqspi_set_protocol(nor, 0);
+       if (ret)
+               return ret;
+
+       ret = cqspi_indirect_write_setup(nor, to);
+       if (ret)
+               return ret;
+
+       ret = cqspi_indirect_write_execute(nor, buf, len);
+       if (ret)
+               return ret;
+
+       return (ret < 0) ? ret : len;
+}
+
+static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
+                         size_t len, u_char *buf)
+{
+       int ret;
+
+       ret = cqspi_set_protocol(nor, 1);
+       if (ret)
+               return ret;
+
+       ret = cqspi_indirect_read_setup(nor, from);
+       if (ret)
+               return ret;
+
+       ret = cqspi_indirect_read_execute(nor, buf, len);
+       if (ret)
+               return ret;
+
+       return (ret < 0) ? ret : len;
+}
+
+static int cqspi_erase(struct spi_nor *nor, loff_t offs)
+{
+       int ret;
+
+       ret = cqspi_set_protocol(nor, 0);
+       if (ret)
+               return ret;
+
+       /* Send write enable, then erase commands. */
+       ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
+       if (ret)
+               return ret;
+
+       /* Set up command buffer. */
+       ret = cqspi_command_write_addr(nor, nor->erase_opcode, offs);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int cqspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+
+       mutex_lock(&cqspi->bus_mutex);
+
+       return 0;
+}
+
+static void cqspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct cqspi_flash_pdata *f_pdata = nor->priv;
+       struct cqspi_st *cqspi = f_pdata->cqspi;
+
+       mutex_unlock(&cqspi->bus_mutex);
+}
+
+static int cqspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+       int ret;
+
+       ret = cqspi_set_protocol(nor, 0);
+       if (!ret)
+               ret = cqspi_command_read(nor, &opcode, 1, buf, len);
+
+       return ret;
+}
+
+static int cqspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+       int ret;
+
+       ret = cqspi_set_protocol(nor, 0);
+       if (!ret)
+               ret = cqspi_command_write(nor, opcode, buf, len);
+
+       return ret;
+}
+
+static int cqspi_of_get_flash_pdata(struct platform_device *pdev,
+                                   struct cqspi_flash_pdata *f_pdata,
+                                   struct device_node *np)
+{
+       if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) {
+               dev_err(&pdev->dev, "couldn't determine read-delay\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) {
+               dev_err(&pdev->dev, "couldn't determine tshsl-ns\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) {
+               dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) {
+               dev_err(&pdev->dev, "couldn't determine tchsh-ns\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) {
+               dev_err(&pdev->dev, "couldn't determine tslch-ns\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) {
+               dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int cqspi_of_get_pdata(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct cqspi_st *cqspi = platform_get_drvdata(pdev);
+
+       cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
+
+       if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
+               dev_err(&pdev->dev, "couldn't determine fifo-depth\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
+               dev_err(&pdev->dev, "couldn't determine fifo-width\n");
+               return -ENXIO;
+       }
+
+       if (of_property_read_u32(np, "cdns,trigger-address",
+                                &cqspi->trigger_address)) {
+               dev_err(&pdev->dev, "couldn't determine trigger-address\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static void cqspi_controller_init(struct cqspi_st *cqspi)
+{
+       cqspi_controller_enable(cqspi, 0);
+
+       /* Configure the remap address register, no remap */
+       writel(0, cqspi->iobase + CQSPI_REG_REMAP);
+
+       /* Disable all interrupts. */
+       writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
+
+       /* Configure the SRAM split to 1:1 . */
+       writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
+
+       /* Load indirect trigger address. */
+       writel(cqspi->trigger_address,
+              cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
+
+       /* Program read watermark -- 1/2 of the FIFO. */
+       writel(cqspi->fifo_depth * cqspi->fifo_width / 2,
+              cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK);
+       /* Program write watermark -- 1/8 of the FIFO. */
+       writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
+              cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
+
+       cqspi_controller_enable(cqspi, 1);
+}
+
+static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
+{
+       struct platform_device *pdev = cqspi->pdev;
+       struct device *dev = &pdev->dev;
+       struct cqspi_flash_pdata *f_pdata;
+       struct spi_nor *nor;
+       struct mtd_info *mtd;
+       unsigned int cs;
+       int i, ret;
+
+       /* Get flash device data */
+       for_each_available_child_of_node(dev->of_node, np) {
+               if (of_property_read_u32(np, "reg", &cs)) {
+                       dev_err(dev, "Couldn't determine chip select.\n");
+                       goto err;
+               }
+
+               if (cs > CQSPI_MAX_CHIPSELECT) {
+                       dev_err(dev, "Chip select %d out of range.\n", cs);
+                       goto err;
+               }
+
+               f_pdata = &cqspi->f_pdata[cs];
+               f_pdata->cqspi = cqspi;
+               f_pdata->cs = cs;
+
+               ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np);
+               if (ret)
+                       goto err;
+
+               nor = &f_pdata->nor;
+               mtd = &nor->mtd;
+
+               mtd->priv = nor;
+
+               nor->dev = dev;
+               spi_nor_set_flash_node(nor, np);
+               nor->priv = f_pdata;
+
+               nor->read_reg = cqspi_read_reg;
+               nor->write_reg = cqspi_write_reg;
+               nor->read = cqspi_read;
+               nor->write = cqspi_write;
+               nor->erase = cqspi_erase;
+               nor->prepare = cqspi_prep;
+               nor->unprepare = cqspi_unprep;
+
+               mtd->name = devm_kasprintf(dev, GFP_KERNEL, "%s.%d",
+                                          dev_name(dev), cs);
+               if (!mtd->name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+               if (ret)
+                       goto err;
+
+               ret = mtd_device_register(mtd, NULL, 0);
+               if (ret)
+                       goto err;
+
+               f_pdata->registered = true;
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
+               if (cqspi->f_pdata[i].registered)
+                       mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
+       return ret;
+}
+
+static int cqspi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct cqspi_st *cqspi;
+       struct resource *res;
+       struct resource *res_ahb;
+       int ret;
+       int irq;
+
+       cqspi = devm_kzalloc(dev, sizeof(*cqspi), GFP_KERNEL);
+       if (!cqspi)
+               return -ENOMEM;
+
+       mutex_init(&cqspi->bus_mutex);
+       cqspi->pdev = pdev;
+       platform_set_drvdata(pdev, cqspi);
+
+       /* Obtain configuration from OF. */
+       ret = cqspi_of_get_pdata(pdev);
+       if (ret) {
+               dev_err(dev, "Cannot get mandatory OF data.\n");
+               return -ENODEV;
+       }
+
+       /* Obtain QSPI clock. */
+       cqspi->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(cqspi->clk)) {
+               dev_err(dev, "Cannot claim QSPI clock.\n");
+               return PTR_ERR(cqspi->clk);
+       }
+
+       /* Obtain and remap controller address. */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       cqspi->iobase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(cqspi->iobase)) {
+               dev_err(dev, "Cannot remap controller address.\n");
+               return PTR_ERR(cqspi->iobase);
+       }
+
+       /* Obtain and remap AHB address. */
+       res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb);
+       if (IS_ERR(cqspi->ahb_base)) {
+               dev_err(dev, "Cannot remap AHB address.\n");
+               return PTR_ERR(cqspi->ahb_base);
+       }
+
+       init_completion(&cqspi->transfer_complete);
+
+       /* Obtain IRQ line. */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "Cannot obtain IRQ.\n");
+               return -ENXIO;
+       }
+
+       ret = clk_prepare_enable(cqspi->clk);
+       if (ret) {
+               dev_err(dev, "Cannot enable QSPI clock.\n");
+               return ret;
+       }
+
+       cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
+
+       ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
+                              pdev->name, cqspi);
+       if (ret) {
+               dev_err(dev, "Cannot request IRQ.\n");
+               goto probe_irq_failed;
+       }
+
+       cqspi_wait_idle(cqspi);
+       cqspi_controller_init(cqspi);
+       cqspi->current_cs = -1;
+       cqspi->sclk = 0;
+
+       ret = cqspi_setup_flash(cqspi, np);
+       if (ret) {
+               dev_err(dev, "Cadence QSPI NOR probe failed %d\n", ret);
+               goto probe_setup_failed;
+       }
+
+       return ret;
+probe_irq_failed:
+       cqspi_controller_enable(cqspi, 0);
+probe_setup_failed:
+       clk_disable_unprepare(cqspi->clk);
+       return ret;
+}
+
+static int cqspi_remove(struct platform_device *pdev)
+{
+       struct cqspi_st *cqspi = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < CQSPI_MAX_CHIPSELECT; i++)
+               if (cqspi->f_pdata[i].registered)
+                       mtd_device_unregister(&cqspi->f_pdata[i].nor.mtd);
+
+       cqspi_controller_enable(cqspi, 0);
+
+       clk_disable_unprepare(cqspi->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cqspi_suspend(struct device *dev)
+{
+       struct cqspi_st *cqspi = dev_get_drvdata(dev);
+
+       cqspi_controller_enable(cqspi, 0);
+       return 0;
+}
+
+static int cqspi_resume(struct device *dev)
+{
+       struct cqspi_st *cqspi = dev_get_drvdata(dev);
+
+       cqspi_controller_enable(cqspi, 1);
+       return 0;
+}
+
+static const struct dev_pm_ops cqspi__dev_pm_ops = {
+       .suspend = cqspi_suspend,
+       .resume = cqspi_resume,
+};
+
+#define CQSPI_DEV_PM_OPS       (&cqspi__dev_pm_ops)
+#else
+#define CQSPI_DEV_PM_OPS       NULL
+#endif
+
+static struct of_device_id const cqspi_dt_ids[] = {
+       {.compatible = "cdns,qspi-nor",},
+       { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, cqspi_dt_ids);
+
+static struct platform_driver cqspi_platform_driver = {
+       .probe = cqspi_probe,
+       .remove = cqspi_remove,
+       .driver = {
+               .name = CQSPI_NAME,
+               .pm = CQSPI_DEV_PM_OPS,
+               .of_match_table = cqspi_dt_ids,
+       },
+};
+
+module_platform_driver(cqspi_platform_driver);
+
+MODULE_DESCRIPTION("Cadence QSPI Controller Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" CQSPI_NAME);
+MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
+MODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>");
index 9ab2b51..5c82e4e 100644 (file)
@@ -618,9 +618,9 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
        qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
 }
 
-static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
+static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
                                u8 opcode, unsigned int to, u32 *txbuf,
-                               unsigned count, size_t *retlen)
+                               unsigned count)
 {
        int ret, i, j;
        u32 tmp;
@@ -647,8 +647,8 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
        /* Trigger it */
        ret = fsl_qspi_runcmd(q, opcode, to, count);
 
-       if (ret == 0 && retlen)
-               *retlen += count;
+       if (ret == 0)
+               return count;
 
        return ret;
 }
@@ -859,7 +859,9 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 
        } else if (len > 0) {
                ret = fsl_qspi_nor_write(q, nor, opcode, 0,
-                                       (u32 *)buf, len, NULL);
+                                       (u32 *)buf, len);
+               if (ret > 0)
+                       return 0;
        } else {
                dev_err(q->dev, "invalid cmd %d\n", opcode);
                ret = -EINVAL;
@@ -868,20 +870,20 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return ret;
 }
 
-static void fsl_qspi_write(struct spi_nor *nor, loff_t to,
-               size_t len, size_t *retlen, const u_char *buf)
+static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
+                             size_t len, const u_char *buf)
 {
        struct fsl_qspi *q = nor->priv;
-
-       fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
-                               (u32 *)buf, len, retlen);
+       ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+                                        (u32 *)buf, len);
 
        /* invalid the data in the AHB buffer. */
        fsl_qspi_invalid(q);
+       return ret;
 }
 
-static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
-               size_t len, size_t *retlen, u_char *buf)
+static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
+                            size_t len, u_char *buf)
 {
        struct fsl_qspi *q = nor->priv;
        u8 cmd = nor->read_opcode;
@@ -923,8 +925,7 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
        memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
                len);
 
-       *retlen += len;
-       return 0;
+       return len;
 }
 
 static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c
new file mode 100644 (file)
index 0000000..20378b0
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * HiSilicon SPI Nor Flash Controller Driver
+ *
+ * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Hardware register offsets and field definitions */
+#define FMC_CFG                                0x00
+#define FMC_CFG_OP_MODE_MASK           BIT_MASK(0)
+#define FMC_CFG_OP_MODE_BOOT           0
+#define FMC_CFG_OP_MODE_NORMAL         1
+#define FMC_CFG_FLASH_SEL(type)                (((type) & 0x3) << 1)
+#define FMC_CFG_FLASH_SEL_MASK         0x6
+#define FMC_ECC_TYPE(type)             (((type) & 0x7) << 5)
+#define FMC_ECC_TYPE_MASK              GENMASK(7, 5)
+#define SPI_NOR_ADDR_MODE_MASK         BIT_MASK(10)
+#define SPI_NOR_ADDR_MODE_3BYTES       (0x0 << 10)
+#define SPI_NOR_ADDR_MODE_4BYTES       (0x1 << 10)
+#define FMC_GLOBAL_CFG                 0x04
+#define FMC_GLOBAL_CFG_WP_ENABLE       BIT(6)
+#define FMC_SPI_TIMING_CFG             0x08
+#define TIMING_CFG_TCSH(nr)            (((nr) & 0xf) << 8)
+#define TIMING_CFG_TCSS(nr)            (((nr) & 0xf) << 4)
+#define TIMING_CFG_TSHSL(nr)           ((nr) & 0xf)
+#define CS_HOLD_TIME                   0x6
+#define CS_SETUP_TIME                  0x6
+#define CS_DESELECT_TIME               0xf
+#define FMC_INT                                0x18
+#define FMC_INT_OP_DONE                        BIT(0)
+#define FMC_INT_CLR                    0x20
+#define FMC_CMD                                0x24
+#define FMC_CMD_CMD1(cmd)              ((cmd) & 0xff)
+#define FMC_ADDRL                      0x2c
+#define FMC_OP_CFG                     0x30
+#define OP_CFG_FM_CS(cs)               ((cs) << 11)
+#define OP_CFG_MEM_IF_TYPE(type)       (((type) & 0x7) << 7)
+#define OP_CFG_ADDR_NUM(addr)          (((addr) & 0x7) << 4)
+#define OP_CFG_DUMMY_NUM(dummy)                ((dummy) & 0xf)
+#define FMC_DATA_NUM                   0x38
+#define FMC_DATA_NUM_CNT(cnt)          ((cnt) & GENMASK(13, 0))
+#define FMC_OP                         0x3c
+#define FMC_OP_DUMMY_EN                        BIT(8)
+#define FMC_OP_CMD1_EN                 BIT(7)
+#define FMC_OP_ADDR_EN                 BIT(6)
+#define FMC_OP_WRITE_DATA_EN           BIT(5)
+#define FMC_OP_READ_DATA_EN            BIT(2)
+#define FMC_OP_READ_STATUS_EN          BIT(1)
+#define FMC_OP_REG_OP_START            BIT(0)
+#define FMC_DMA_LEN                    0x40
+#define FMC_DMA_LEN_SET(len)           ((len) & GENMASK(27, 0))
+#define FMC_DMA_SADDR_D0               0x4c
+#define HIFMC_DMA_MAX_LEN              (4096)
+#define HIFMC_DMA_MASK                 (HIFMC_DMA_MAX_LEN - 1)
+#define FMC_OP_DMA                     0x68
+#define OP_CTRL_RD_OPCODE(code)                (((code) & 0xff) << 16)
+#define OP_CTRL_WR_OPCODE(code)                (((code) & 0xff) << 8)
+#define OP_CTRL_RW_OP(op)              ((op) << 1)
+#define OP_CTRL_DMA_OP_READY           BIT(0)
+#define FMC_OP_READ                    0x0
+#define FMC_OP_WRITE                   0x1
+#define FMC_WAIT_TIMEOUT               1000000
+
+enum hifmc_iftype {
+       IF_TYPE_STD,
+       IF_TYPE_DUAL,
+       IF_TYPE_DIO,
+       IF_TYPE_QUAD,
+       IF_TYPE_QIO,
+};
+
+struct hifmc_priv {
+       u32 chipselect;
+       u32 clkrate;
+       struct hifmc_host *host;
+};
+
+#define HIFMC_MAX_CHIP_NUM             2
+struct hifmc_host {
+       struct device *dev;
+       struct mutex lock;
+
+       void __iomem *regbase;
+       void __iomem *iobase;
+       struct clk *clk;
+       void *buffer;
+       dma_addr_t dma_buffer;
+
+       struct spi_nor  *nor[HIFMC_MAX_CHIP_NUM];
+       u32 num_chip;
+};
+
+static inline int wait_op_finish(struct hifmc_host *host)
+{
+       u32 reg;
+
+       return readl_poll_timeout(host->regbase + FMC_INT, reg,
+               (reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
+}
+
+static int get_if_type(enum read_mode flash_read)
+{
+       enum hifmc_iftype if_type;
+
+       switch (flash_read) {
+       case SPI_NOR_DUAL:
+               if_type = IF_TYPE_DUAL;
+               break;
+       case SPI_NOR_QUAD:
+               if_type = IF_TYPE_QUAD;
+               break;
+       case SPI_NOR_NORMAL:
+       case SPI_NOR_FAST:
+       default:
+               if_type = IF_TYPE_STD;
+               break;
+       }
+
+       return if_type;
+}
+
+static void hisi_spi_nor_init(struct hifmc_host *host)
+{
+       u32 reg;
+
+       reg = TIMING_CFG_TCSH(CS_HOLD_TIME)
+               | TIMING_CFG_TCSS(CS_SETUP_TIME)
+               | TIMING_CFG_TSHSL(CS_DESELECT_TIME);
+       writel(reg, host->regbase + FMC_SPI_TIMING_CFG);
+}
+
+static int hisi_spi_nor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       int ret;
+
+       mutex_lock(&host->lock);
+
+       ret = clk_set_rate(host->clk, priv->clkrate);
+       if (ret)
+               goto out;
+
+       ret = clk_prepare_enable(host->clk);
+       if (ret)
+               goto out;
+
+       return 0;
+
+out:
+       mutex_unlock(&host->lock);
+       return ret;
+}
+
+static void hisi_spi_nor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+
+       clk_disable_unprepare(host->clk);
+       mutex_unlock(&host->lock);
+}
+
+static int hisi_spi_nor_op_reg(struct spi_nor *nor,
+                               u8 opcode, int len, u8 optype)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       u32 reg;
+
+       reg = FMC_CMD_CMD1(opcode);
+       writel(reg, host->regbase + FMC_CMD);
+
+       reg = FMC_DATA_NUM_CNT(len);
+       writel(reg, host->regbase + FMC_DATA_NUM);
+
+       reg = OP_CFG_FM_CS(priv->chipselect);
+       writel(reg, host->regbase + FMC_OP_CFG);
+
+       writel(0xff, host->regbase + FMC_INT_CLR);
+       reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START | optype;
+       writel(reg, host->regbase + FMC_OP);
+
+       return wait_op_finish(host);
+}
+
+static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+               int len)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       int ret;
+
+       ret = hisi_spi_nor_op_reg(nor, opcode, len, FMC_OP_READ_DATA_EN);
+       if (ret)
+               return ret;
+
+       memcpy_fromio(buf, host->iobase, len);
+       return 0;
+}
+
+static int hisi_spi_nor_write_reg(struct spi_nor *nor, u8 opcode,
+                               u8 *buf, int len)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+
+       if (len)
+               memcpy_toio(host->iobase, buf, len);
+
+       return hisi_spi_nor_op_reg(nor, opcode, len, FMC_OP_WRITE_DATA_EN);
+}
+
+static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
+               dma_addr_t dma_buf, size_t len, u8 op_type)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       u8 if_type = 0;
+       u32 reg;
+
+       reg = readl(host->regbase + FMC_CFG);
+       reg &= ~(FMC_CFG_OP_MODE_MASK | SPI_NOR_ADDR_MODE_MASK);
+       reg |= FMC_CFG_OP_MODE_NORMAL;
+       reg |= (nor->addr_width == 4) ? SPI_NOR_ADDR_MODE_4BYTES
+               : SPI_NOR_ADDR_MODE_3BYTES;
+       writel(reg, host->regbase + FMC_CFG);
+
+       writel(start_off, host->regbase + FMC_ADDRL);
+       writel(dma_buf, host->regbase + FMC_DMA_SADDR_D0);
+       writel(FMC_DMA_LEN_SET(len), host->regbase + FMC_DMA_LEN);
+
+       reg = OP_CFG_FM_CS(priv->chipselect);
+       if_type = get_if_type(nor->flash_read);
+       reg |= OP_CFG_MEM_IF_TYPE(if_type);
+       if (op_type == FMC_OP_READ)
+               reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
+       writel(reg, host->regbase + FMC_OP_CFG);
+
+       writel(0xff, host->regbase + FMC_INT_CLR);
+       reg = OP_CTRL_RW_OP(op_type) | OP_CTRL_DMA_OP_READY;
+       reg |= (op_type == FMC_OP_READ)
+               ? OP_CTRL_RD_OPCODE(nor->read_opcode)
+               : OP_CTRL_WR_OPCODE(nor->program_opcode);
+       writel(reg, host->regbase + FMC_OP_DMA);
+
+       return wait_op_finish(host);
+}
+
+static ssize_t hisi_spi_nor_read(struct spi_nor *nor, loff_t from, size_t len,
+               u_char *read_buf)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       size_t offset;
+       int ret;
+
+       for (offset = 0; offset < len; offset += HIFMC_DMA_MAX_LEN) {
+               size_t trans = min_t(size_t, HIFMC_DMA_MAX_LEN, len - offset);
+
+               ret = hisi_spi_nor_dma_transfer(nor,
+                       from + offset, host->dma_buffer, trans, FMC_OP_READ);
+               if (ret) {
+                       dev_warn(nor->dev, "DMA read timeout\n");
+                       return ret;
+               }
+               memcpy(read_buf + offset, host->buffer, trans);
+       }
+
+       return len;
+}
+
+static ssize_t hisi_spi_nor_write(struct spi_nor *nor, loff_t to,
+                       size_t len, const u_char *write_buf)
+{
+       struct hifmc_priv *priv = nor->priv;
+       struct hifmc_host *host = priv->host;
+       size_t offset;
+       int ret;
+
+       for (offset = 0; offset < len; offset += HIFMC_DMA_MAX_LEN) {
+               size_t trans = min_t(size_t, HIFMC_DMA_MAX_LEN, len - offset);
+
+               memcpy(host->buffer, write_buf + offset, trans);
+               ret = hisi_spi_nor_dma_transfer(nor,
+                       to + offset, host->dma_buffer, trans, FMC_OP_WRITE);
+               if (ret) {
+                       dev_warn(nor->dev, "DMA write timeout\n");
+                       return ret;
+               }
+       }
+
+       return len;
+}
+
+/**
+ * Get spi flash device information and register it as a mtd device.
+ */
+static int hisi_spi_nor_register(struct device_node *np,
+                               struct hifmc_host *host)
+{
+       struct device *dev = host->dev;
+       struct spi_nor *nor;
+       struct hifmc_priv *priv;
+       struct mtd_info *mtd;
+       int ret;
+
+       nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
+       if (!nor)
+               return -ENOMEM;
+
+       nor->dev = dev;
+       spi_nor_set_flash_node(nor, np);
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = of_property_read_u32(np, "reg", &priv->chipselect);
+       if (ret) {
+               dev_err(dev, "There's no reg property for %s\n",
+                       np->full_name);
+               return ret;
+       }
+
+       ret = of_property_read_u32(np, "spi-max-frequency",
+                       &priv->clkrate);
+       if (ret) {
+               dev_err(dev, "There's no spi-max-frequency property for %s\n",
+                       np->full_name);
+               return ret;
+       }
+       priv->host = host;
+       nor->priv = priv;
+
+       nor->prepare = hisi_spi_nor_prep;
+       nor->unprepare = hisi_spi_nor_unprep;
+       nor->read_reg = hisi_spi_nor_read_reg;
+       nor->write_reg = hisi_spi_nor_write_reg;
+       nor->read = hisi_spi_nor_read;
+       nor->write = hisi_spi_nor_write;
+       nor->erase = NULL;
+       ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+       if (ret)
+               return ret;
+
+       mtd = &nor->mtd;
+       mtd->name = np->name;
+       ret = mtd_device_register(mtd, NULL, 0);
+       if (ret)
+               return ret;
+
+       host->nor[host->num_chip] = nor;
+       host->num_chip++;
+       return 0;
+}
+
+static void hisi_spi_nor_unregister_all(struct hifmc_host *host)
+{
+       int i;
+
+       for (i = 0; i < host->num_chip; i++)
+               mtd_device_unregister(&host->nor[i]->mtd);
+}
+
+static int hisi_spi_nor_register_all(struct hifmc_host *host)
+{
+       struct device *dev = host->dev;
+       struct device_node *np;
+       int ret;
+
+       for_each_available_child_of_node(dev->of_node, np) {
+               ret = hisi_spi_nor_register(np, host);
+               if (ret)
+                       goto fail;
+
+               if (host->num_chip == HIFMC_MAX_CHIP_NUM) {
+                       dev_warn(dev, "Flash device number exceeds the maximum chipselect number\n");
+                       break;
+               }
+       }
+
+       return 0;
+
+fail:
+       hisi_spi_nor_unregister_all(host);
+       return ret;
+}
+
+static int hisi_spi_nor_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct hifmc_host *host;
+       int ret;
+
+       host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+       if (!host)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, host);
+       host->dev = dev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
+       host->regbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(host->regbase))
+               return PTR_ERR(host->regbase);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
+       host->iobase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(host->iobase))
+               return PTR_ERR(host->iobase);
+
+       host->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(host->clk))
+               return PTR_ERR(host->clk);
+
+       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_warn(dev, "Unable to set dma mask\n");
+               return ret;
+       }
+
+       host->buffer = dmam_alloc_coherent(dev, HIFMC_DMA_MAX_LEN,
+                       &host->dma_buffer, GFP_KERNEL);
+       if (!host->buffer)
+               return -ENOMEM;
+
+       mutex_init(&host->lock);
+       clk_prepare_enable(host->clk);
+       hisi_spi_nor_init(host);
+       ret = hisi_spi_nor_register_all(host);
+       if (ret)
+               mutex_destroy(&host->lock);
+
+       clk_disable_unprepare(host->clk);
+       return ret;
+}
+
+static int hisi_spi_nor_remove(struct platform_device *pdev)
+{
+       struct hifmc_host *host = platform_get_drvdata(pdev);
+
+       hisi_spi_nor_unregister_all(host);
+       mutex_destroy(&host->lock);
+       clk_disable_unprepare(host->clk);
+       return 0;
+}
+
+static const struct of_device_id hisi_spi_nor_dt_ids[] = {
+       { .compatible = "hisilicon,fmc-spi-nor"},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hisi_spi_nor_dt_ids);
+
+static struct platform_driver hisi_spi_nor_driver = {
+       .driver = {
+               .name   = "hisi-sfc",
+               .of_match_table = hisi_spi_nor_dt_ids,
+       },
+       .probe  = hisi_spi_nor_probe,
+       .remove = hisi_spi_nor_remove,
+};
+module_platform_driver(hisi_spi_nor_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HiSilicon SPI Nor Flash Controller Driver");
index 8bed1a4..e661877 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/ioport.h>
 #include <linux/math64.h>
 #include <linux/module.h>
-#include <linux/mtd/mtd.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -243,8 +242,8 @@ static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr)
        writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR3_REG);
 }
 
-static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
-                          size_t *retlen, u_char *buffer)
+static ssize_t mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
+                              u_char *buffer)
 {
        int i, ret;
        int addr = (int)from;
@@ -255,13 +254,13 @@ static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
        mt8173_nor_set_read_mode(mt8173_nor);
        mt8173_nor_set_addr(mt8173_nor, addr);
 
-       for (i = 0; i < length; i++, (*retlen)++) {
+       for (i = 0; i < length; i++) {
                ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_READ_CMD);
                if (ret < 0)
                        return ret;
                buf[i] = readb(mt8173_nor->base + MTK_NOR_RDATA_REG);
        }
-       return 0;
+       return length;
 }
 
 static int mt8173_nor_write_single_byte(struct mt8173_nor *mt8173_nor,
@@ -297,36 +296,44 @@ static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr,
        return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WR_CMD);
 }
 
-static void mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len,
-                            size_t *retlen, const u_char *buf)
+static ssize_t mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len,
+                               const u_char *buf)
 {
        int ret;
        struct mt8173_nor *mt8173_nor = nor->priv;
+       size_t i;
 
        ret = mt8173_nor_write_buffer_enable(mt8173_nor);
-       if (ret < 0)
+       if (ret < 0) {
                dev_warn(mt8173_nor->dev, "write buffer enable failed!\n");
+               return ret;
+       }
 
-       while (len >= SFLASH_WRBUF_SIZE) {
+       for (i = 0; i + SFLASH_WRBUF_SIZE <= len; i += SFLASH_WRBUF_SIZE) {
                ret = mt8173_nor_write_buffer(mt8173_nor, to, buf);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(mt8173_nor->dev, "write buffer failed!\n");
-               len -= SFLASH_WRBUF_SIZE;
+                       return ret;
+               }
                to += SFLASH_WRBUF_SIZE;
                buf += SFLASH_WRBUF_SIZE;
-               (*retlen) += SFLASH_WRBUF_SIZE;
        }
        ret = mt8173_nor_write_buffer_disable(mt8173_nor);
-       if (ret < 0)
+       if (ret < 0) {
                dev_warn(mt8173_nor->dev, "write buffer disable failed!\n");
+               return ret;
+       }
 
-       if (len) {
-               ret = mt8173_nor_write_single_byte(mt8173_nor, to, (int)len,
-                                                  (u8 *)buf);
-               if (ret < 0)
+       if (i < len) {
+               ret = mt8173_nor_write_single_byte(mt8173_nor, to,
+                                                  (int)(len - i), (u8 *)buf);
+               if (ret < 0) {
                        dev_err(mt8173_nor->dev, "write single byte failed!\n");
-               (*retlen) += len;
+                       return ret;
+               }
        }
+
+       return len;
 }
 
 static int mt8173_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
index ae428cb..73a14f4 100644 (file)
@@ -172,8 +172,8 @@ static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
        return nxp_spifi_wait_for_cmd(spifi);
 }
 
-static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
-                         size_t *retlen, u_char *buf)
+static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
+                             u_char *buf)
 {
        struct nxp_spifi *spifi = nor->priv;
        int ret;
@@ -183,24 +183,23 @@ static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len,
                return ret;
 
        memcpy_fromio(buf, spifi->flash_base + from, len);
-       *retlen += len;
 
-       return 0;
+       return len;
 }
 
-static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
-                           size_t *retlen, const u_char *buf)
+static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
+                              const u_char *buf)
 {
        struct nxp_spifi *spifi = nor->priv;
        u32 cmd;
        int ret;
+       size_t i;
 
        ret = nxp_spifi_set_memory_mode_off(spifi);
        if (ret)
-               return;
+               return ret;
 
        writel(to, spifi->io_base + SPIFI_ADDR);
-       *retlen += len;
 
        cmd = SPIFI_CMD_DOUT |
              SPIFI_CMD_DATALEN(len) |
@@ -209,10 +208,14 @@ static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len,
              SPIFI_CMD_FRAMEFORM(spifi->nor.addr_width + 1);
        writel(cmd, spifi->io_base + SPIFI_CMD);
 
-       while (len--)
-               writeb(*buf++, spifi->io_base + SPIFI_DATA);
+       for (i = 0; i < len; i++)
+               writeb(buf[i], spifi->io_base + SPIFI_DATA);
+
+       ret = nxp_spifi_wait_for_cmd(spifi);
+       if (ret)
+               return ret;
 
-       nxp_spifi_wait_for_cmd(spifi);
+       return len;
 }
 
 static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs)
index c52e455..d0fc165 100644 (file)
@@ -661,7 +661,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
        status_new = (status_old & ~mask & ~SR_TB) | val;
 
        /* Don't protect status register if we're fully unlocked */
-       if (lock_len == mtd->size)
+       if (lock_len == 0)
                status_new &= ~SR_SRWD;
 
        if (!use_top)
@@ -830,10 +830,26 @@ static const struct flash_info spi_nor_ids[] = {
        { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
 
        /* GigaDevice */
-       { "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
-       { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
-       { "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-       { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
+       {
+               "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
+       {
+               "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
+       {
+               "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
+       {
+               "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
+                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+       },
 
        /* Intel/Numonyx -- xxxs33b */
        { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
@@ -871,6 +887,7 @@ static const struct flash_info spi_nor_ids[] = {
        { "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
        { "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
        { "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+       { "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 
        /* PMC */
        { "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
@@ -1031,8 +1048,25 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
        if (ret)
                return ret;
 
-       ret = nor->read(nor, from, len, retlen, buf);
+       while (len) {
+               ret = nor->read(nor, from, len, buf);
+               if (ret == 0) {
+                       /* We shouldn't see 0-length reads */
+                       ret = -EIO;
+                       goto read_err;
+               }
+               if (ret < 0)
+                       goto read_err;
+
+               WARN_ON(ret > len);
+               *retlen += ret;
+               buf += ret;
+               from += ret;
+               len -= ret;
+       }
+       ret = 0;
 
+read_err:
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
        return ret;
 }
@@ -1060,10 +1094,14 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
                nor->program_opcode = SPINOR_OP_BP;
 
                /* write one byte. */
-               nor->write(nor, to, 1, retlen, buf);
+               ret = nor->write(nor, to, 1, buf);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+                    (int)ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto time_out;
+                       goto sst_write_err;
        }
        to += actual;
 
@@ -1072,10 +1110,14 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
                nor->program_opcode = SPINOR_OP_AAI_WP;
 
                /* write two bytes. */
-               nor->write(nor, to, 2, retlen, buf + actual);
+               ret = nor->write(nor, to, 2, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 2, "While writing 2 bytes written %i bytes\n",
+                    (int)ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto time_out;
+                       goto sst_write_err;
                to += 2;
                nor->sst_write_second = true;
        }
@@ -1084,21 +1126,26 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
        write_disable(nor);
        ret = spi_nor_wait_till_ready(nor);
        if (ret)
-               goto time_out;
+               goto sst_write_err;
 
        /* Write out trailing byte if it exists. */
        if (actual != len) {
                write_enable(nor);
 
                nor->program_opcode = SPINOR_OP_BP;
-               nor->write(nor, to, 1, retlen, buf + actual);
-
+               ret = nor->write(nor, to, 1, buf + actual);
+               if (ret < 0)
+                       goto sst_write_err;
+               WARN(ret != 1, "While writing 1 byte written %i bytes\n",
+                    (int)ret);
                ret = spi_nor_wait_till_ready(nor);
                if (ret)
-                       goto time_out;
+                       goto sst_write_err;
                write_disable(nor);
+               actual += 1;
        }
-time_out:
+sst_write_err:
+       *retlen += actual;
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
        return ret;
 }
@@ -1112,8 +1159,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
        size_t *retlen, const u_char *buf)
 {
        struct spi_nor *nor = mtd_to_spi_nor(mtd);
-       u32 page_offset, page_size, i;
-       int ret;
+       size_t page_offset, page_remain, i;
+       ssize_t ret;
 
        dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
 
@@ -1121,35 +1168,37 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
        if (ret)
                return ret;
 
-       write_enable(nor);
-
-       page_offset = to & (nor->page_size - 1);
+       for (i = 0; i < len; ) {
+               ssize_t written;
 
-       /* do all the bytes fit onto one page? */
-       if (page_offset + len <= nor->page_size) {
-               nor->write(nor, to, len, retlen, buf);
-       } else {
+               page_offset = (to + i) & (nor->page_size - 1);
+               WARN_ONCE(page_offset,
+                         "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
+                         page_offset);
                /* the size of data remaining on the first page */
-               page_size = nor->page_size - page_offset;
-               nor->write(nor, to, page_size, retlen, buf);
-
-               /* write everything in nor->page_size chunks */
-               for (i = page_size; i < len; i += page_size) {
-                       page_size = len - i;
-                       if (page_size > nor->page_size)
-                               page_size = nor->page_size;
+               page_remain = min_t(size_t,
+                                   nor->page_size - page_offset, len - i);
 
-                       ret = spi_nor_wait_till_ready(nor);
-                       if (ret)
-                               goto write_err;
-
-                       write_enable(nor);
+               write_enable(nor);
+               ret = nor->write(nor, to + i, page_remain, buf + i);
+               if (ret < 0)
+                       goto write_err;
+               written = ret;
 
-                       nor->write(nor, to + i, page_size, retlen, buf + i);
+               ret = spi_nor_wait_till_ready(nor);
+               if (ret)
+                       goto write_err;
+               *retlen += written;
+               i += written;
+               if (written != page_remain) {
+                       dev_err(nor->dev,
+                               "While writing %zu bytes written %zd bytes\n",
+                               page_remain, written);
+                       ret = -EIO;
+                       goto write_err;
                }
        }
 
-       ret = spi_nor_wait_till_ready(nor);
 write_err:
        spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
        return ret;
index daf82ba..41b13d1 100644 (file)
@@ -380,8 +380,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
                " block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
                block_address);
 
-       if (block_address >= ssfdc->map_len)
-               BUG();
+       BUG_ON(block_address >= ssfdc->map_len);
 
        block_address = ssfdc->logic_block_map[block_address];
 
index 09a4cca..f26dec8 100644 (file)
@@ -290,7 +290,7 @@ static int overwrite_test(void)
 
        while (opno < max_overwrite) {
 
-               err = rewrite_page(0);
+               err = write_page(0);
                if (err)
                        break;
 
index c1aaf03..903becd 100644 (file)
@@ -174,6 +174,40 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
        return 0;
 }
 
+/**
+ * add_fastmap - add a Fastmap related physical eraseblock.
+ * @ai: attaching information
+ * @pnum: physical eraseblock number the VID header came from
+ * @vid_hdr: the volume identifier header
+ * @ec: erase counter of the physical eraseblock
+ *
+ * This function allocates a 'struct ubi_ainf_peb' object for a Fastamp
+ * physical eraseblock @pnum and adds it to the 'fastmap' list.
+ * Such blocks can be Fastmap super and data blocks from both the most
+ * recent Fastmap we're attaching from or from old Fastmaps which will
+ * be erased.
+ */
+static int add_fastmap(struct ubi_attach_info *ai, int pnum,
+                      struct ubi_vid_hdr *vid_hdr, int ec)
+{
+       struct ubi_ainf_peb *aeb;
+
+       aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+       if (!aeb)
+               return -ENOMEM;
+
+       aeb->pnum = pnum;
+       aeb->vol_id = be32_to_cpu(vidh->vol_id);
+       aeb->sqnum = be64_to_cpu(vidh->sqnum);
+       aeb->ec = ec;
+       list_add(&aeb->u.list, &ai->fastmap);
+
+       dbg_bld("add to fastmap list: PEB %d, vol_id %d, sqnum: %llu", pnum,
+               aeb->vol_id, aeb->sqnum);
+
+       return 0;
+}
+
 /**
  * validate_vid_hdr - check volume identifier header.
  * @ubi: UBI device description object
@@ -803,13 +837,26 @@ out_unlock:
        return err;
 }
 
+static bool vol_ignored(int vol_id)
+{
+       switch (vol_id) {
+               case UBI_LAYOUT_VOLUME_ID:
+               return true;
+       }
+
+#ifdef CONFIG_MTD_UBI_FASTMAP
+       return ubi_is_fm_vol(vol_id);
+#else
+       return false;
+#endif
+}
+
 /**
  * scan_peb - scan and process UBI headers of a PEB.
  * @ubi: UBI device description object
  * @ai: attaching information
  * @pnum: the physical eraseblock number
- * @vid: The volume ID of the found volume will be stored in this pointer
- * @sqnum: The sqnum of the found volume will be stored in this pointer
+ * @fast: true if we're scanning for a Fastmap
  *
  * This function reads UBI headers of PEB @pnum, checks them, and adds
  * information about this PEB to the corresponding list or RB-tree in the
@@ -817,9 +864,9 @@ out_unlock:
  * successfully handled and a negative error code in case of failure.
  */
 static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
-                   int pnum, int *vid, unsigned long long *sqnum)
+                   int pnum, bool fast)
 {
-       long long uninitialized_var(ec);
+       long long ec;
        int err, bitflips = 0, vol_id = -1, ec_err = 0;
 
        dbg_bld("scan PEB %d", pnum);
@@ -935,6 +982,20 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
                         */
                        ai->maybe_bad_peb_count += 1;
        case UBI_IO_BAD_HDR:
+                       /*
+                        * If we're facing a bad VID header we have to drop *all*
+                        * Fastmap data structures we find. The most recent Fastmap
+                        * could be bad and therefore there is a chance that we attach
+                        * from an old one. On a fine MTD stack a PEB must not render
+                        * bad all of a sudden, but the reality is different.
+                        * So, let's be paranoid and help finding the root cause by
+                        * falling back to scanning mode instead of attaching with a
+                        * bad EBA table and cause data corruption which is hard to
+                        * analyze.
+                        */
+                       if (fast)
+                               ai->force_full_scan = 1;
+
                if (ec_err)
                        /*
                         * Both headers are corrupted. There is a possibility
@@ -991,21 +1052,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
        }
 
        vol_id = be32_to_cpu(vidh->vol_id);
-       if (vid)
-               *vid = vol_id;
-       if (sqnum)
-               *sqnum = be64_to_cpu(vidh->sqnum);
-       if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
+       if (vol_id > UBI_MAX_VOLUMES && !vol_ignored(vol_id)) {
                int lnum = be32_to_cpu(vidh->lnum);
 
                /* Unsupported internal volume */
                switch (vidh->compat) {
                case UBI_COMPAT_DELETE:
-                       if (vol_id != UBI_FM_SB_VOLUME_ID
-                           && vol_id != UBI_FM_DATA_VOLUME_ID) {
-                               ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
-                                       vol_id, lnum);
-                       }
+                       ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
+                               vol_id, lnum);
+
                        err = add_to_list(ai, pnum, vol_id, lnum,
                                          ec, 1, &ai->erase);
                        if (err)
@@ -1037,7 +1092,12 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
        if (ec_err)
                ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
                         pnum);
-       err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
+       if (ubi_is_fm_vol(vol_id))
+               err = add_fastmap(ai, pnum, vidh, ec);
+       else
+               err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
        if (err)
                return err;
 
@@ -1186,6 +1246,10 @@ static void destroy_ai(struct ubi_attach_info *ai)
                list_del(&aeb->u.list);
                kmem_cache_free(ai->aeb_slab_cache, aeb);
        }
+       list_for_each_entry_safe(aeb, aeb_tmp, &ai->fastmap, u.list) {
+               list_del(&aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, aeb);
+       }
 
        /* Destroy the volume RB-tree */
        rb = ai->volumes.rb_node;
@@ -1245,7 +1309,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
                cond_resched();
 
                dbg_gen("process PEB %d", pnum);
-               err = scan_peb(ubi, ai, pnum, NULL, NULL);
+               err = scan_peb(ubi, ai, pnum, false);
                if (err < 0)
                        goto out_vidh;
        }
@@ -1311,6 +1375,7 @@ static struct ubi_attach_info *alloc_ai(void)
        INIT_LIST_HEAD(&ai->free);
        INIT_LIST_HEAD(&ai->erase);
        INIT_LIST_HEAD(&ai->alien);
+       INIT_LIST_HEAD(&ai->fastmap);
        ai->volumes = RB_ROOT;
        ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
                                               sizeof(struct ubi_ainf_peb),
@@ -1326,7 +1391,7 @@ static struct ubi_attach_info *alloc_ai(void)
 #ifdef CONFIG_MTD_UBI_FASTMAP
 
 /**
- * scan_fastmap - try to find a fastmap and attach from it.
+ * scan_fast - try to find a fastmap and attach from it.
  * @ubi: UBI device description object
  * @ai: attach info object
  *
@@ -1337,52 +1402,58 @@ static struct ubi_attach_info *alloc_ai(void)
  */
 static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
 {
-       int err, pnum, fm_anchor = -1;
-       unsigned long long max_sqnum = 0;
+       int err, pnum;
+       struct ubi_attach_info *scan_ai;
 
        err = -ENOMEM;
 
+       scan_ai = alloc_ai();
+       if (!scan_ai)
+               goto out;
+
        ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
        if (!ech)
-               goto out;
+               goto out_ai;
 
        vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
        if (!vidh)
                goto out_ech;
 
        for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
-               int vol_id = -1;
-               unsigned long long sqnum = -1;
                cond_resched();
 
                dbg_gen("process PEB %d", pnum);
-               err = scan_peb(ubi, *ai, pnum, &vol_id, &sqnum);
+               err = scan_peb(ubi, scan_ai, pnum, true);
                if (err < 0)
                        goto out_vidh;
-
-               if (vol_id == UBI_FM_SB_VOLUME_ID && sqnum > max_sqnum) {
-                       max_sqnum = sqnum;
-                       fm_anchor = pnum;
-               }
        }
 
        ubi_free_vid_hdr(ubi, vidh);
        kfree(ech);
 
-       if (fm_anchor < 0)
-               return UBI_NO_FASTMAP;
+       if (scan_ai->force_full_scan)
+               err = UBI_NO_FASTMAP;
+       else
+               err = ubi_scan_fastmap(ubi, *ai, scan_ai);
 
-       destroy_ai(*ai);
-       *ai = alloc_ai();
-       if (!*ai)
-               return -ENOMEM;
+       if (err) {
+               /*
+                * Didn't attach via fastmap, do a full scan but reuse what
+                * we've aready scanned.
+                */
+               destroy_ai(*ai);
+               *ai = scan_ai;
+       } else
+               destroy_ai(scan_ai);
 
-       return ubi_scan_fastmap(ubi, *ai, fm_anchor);
+       return err;
 
 out_vidh:
        ubi_free_vid_hdr(ubi, vidh);
 out_ech:
        kfree(ech);
+out_ai:
+       destroy_ai(scan_ai);
 out:
        return err;
 }
index ef36182..0680516 100644 (file)
@@ -874,7 +874,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        for (i = 0; i < UBI_MAX_DEVICES; i++) {
                ubi = ubi_devices[i];
                if (ubi && mtd->index == ubi->mtd->index) {
-                       ubi_err(ubi, "mtd%d is already attached to ubi%d",
+                       pr_err("ubi: mtd%d is already attached to ubi%d",
                                mtd->index, i);
                        return -EEXIST;
                }
@@ -889,7 +889,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
         * no sense to attach emulated MTD devices, so we prohibit this.
         */
        if (mtd->type == MTD_UBIVOLUME) {
-               ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI",
+               pr_err("ubi: refuse attaching mtd%d - it is already emulated on top of UBI",
                        mtd->index);
                return -EINVAL;
        }
@@ -900,7 +900,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
                        if (!ubi_devices[ubi_num])
                                break;
                if (ubi_num == UBI_MAX_DEVICES) {
-                       ubi_err(ubi, "only %d UBI devices may be created",
+                       pr_err("ubi: only %d UBI devices may be created",
                                UBI_MAX_DEVICES);
                        return -ENFILE;
                }
@@ -910,7 +910,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
 
                /* Make sure ubi_num is not busy */
                if (ubi_devices[ubi_num]) {
-                       ubi_err(ubi, "already exists");
+                       pr_err("ubi: ubi%i already exists", ubi_num);
                        return -EEXIST;
                }
        }
@@ -992,6 +992,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
                        goto out_detach;
        }
 
+       /* Make device "available" before it becomes accessible via sysfs */
+       ubi_devices[ubi_num] = ubi;
+
        err = uif_init(ubi, &ref);
        if (err)
                goto out_detach;
@@ -1036,7 +1039,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        wake_up_process(ubi->bgt_thread);
        spin_unlock(&ubi->wl_lock);
 
-       ubi_devices[ubi_num] = ubi;
        ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
        return ubi_num;
 
@@ -1047,6 +1049,7 @@ out_uif:
        ubi_assert(ref);
        uif_close(ubi);
 out_detach:
+       ubi_devices[ubi_num] = NULL;
        ubi_wl_close(ubi);
        ubi_free_internal_volumes(ubi);
        vfree(ubi->vtbl);
index 990898b..48eb55f 100644 (file)
  */
 
 #include <linux/crc32.h>
+#include <linux/bitmap.h>
 #include "ubi.h"
 
 /**
  * init_seen - allocate memory for used for debugging.
  * @ubi: UBI device description object
  */
-static inline int *init_seen(struct ubi_device *ubi)
+static inline unsigned long *init_seen(struct ubi_device *ubi)
 {
-       int *ret;
+       unsigned long *ret;
 
        if (!ubi_dbg_chk_fastmap(ubi))
                return NULL;
 
-       ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL);
+       ret = kcalloc(BITS_TO_LONGS(ubi->peb_count), sizeof(unsigned long),
+                     GFP_KERNEL);
        if (!ret)
                return ERR_PTR(-ENOMEM);
 
@@ -39,7 +41,7 @@ static inline int *init_seen(struct ubi_device *ubi)
  * free_seen - free the seen logic integer array.
  * @seen: integer array of @ubi->peb_count size
  */
-static inline void free_seen(int *seen)
+static inline void free_seen(unsigned long *seen)
 {
        kfree(seen);
 }
@@ -50,12 +52,12 @@ static inline void free_seen(int *seen)
  * @pnum: The PEB to be makred as seen
  * @seen: integer array of @ubi->peb_count size
  */
-static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen)
+static inline void set_seen(struct ubi_device *ubi, int pnum, unsigned long *seen)
 {
        if (!ubi_dbg_chk_fastmap(ubi) || !seen)
                return;
 
-       seen[pnum] = 1;
+       set_bit(pnum, seen);
 }
 
 /**
@@ -63,7 +65,7 @@ static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen)
  * @ubi: UBI device description object
  * @seen: integer array of @ubi->peb_count size
  */
-static int self_check_seen(struct ubi_device *ubi, int *seen)
+static int self_check_seen(struct ubi_device *ubi, unsigned long *seen)
 {
        int pnum, ret = 0;
 
@@ -71,7 +73,7 @@ static int self_check_seen(struct ubi_device *ubi, int *seen)
                return 0;
 
        for (pnum = 0; pnum < ubi->peb_count; pnum++) {
-               if (!seen[pnum] && ubi->lookuptbl[pnum]) {
+               if (test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {
                        ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
                        ret = -EINVAL;
                }
@@ -578,7 +580,7 @@ static int count_fastmap_pebs(struct ubi_attach_info *ai)
        list_for_each_entry(aeb, &ai->free, u.list)
                n++;
 
-        ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
+       ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
                ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
                        n++;
 
@@ -849,28 +851,58 @@ fail:
        return ret;
 }
 
+/**
+ * find_fm_anchor - find the most recent Fastmap superblock (anchor)
+ * @ai: UBI attach info to be filled
+ */
+static int find_fm_anchor(struct ubi_attach_info *ai)
+{
+       int ret = -1;
+       struct ubi_ainf_peb *aeb;
+       unsigned long long max_sqnum = 0;
+
+       list_for_each_entry(aeb, &ai->fastmap, u.list) {
+               if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) {
+                       max_sqnum = aeb->sqnum;
+                       ret = aeb->pnum;
+               }
+       }
+
+       return ret;
+}
+
 /**
  * ubi_scan_fastmap - scan the fastmap.
  * @ubi: UBI device object
  * @ai: UBI attach info to be filled
- * @fm_anchor: The fastmap starts at this PEB
+ * @scan_ai: UBI attach info from the first 64 PEBs,
+ *           used to find the most recent Fastmap data structure
  *
  * Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found,
  * UBI_BAD_FASTMAP if one was found but is not usable.
  * < 0 indicates an internal error.
  */
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-                    int fm_anchor)
+                    struct ubi_attach_info *scan_ai)
 {
        struct ubi_fm_sb *fmsb, *fmsb2;
        struct ubi_vid_hdr *vh;
        struct ubi_ec_hdr *ech;
        struct ubi_fastmap_layout *fm;
-       int i, used_blocks, pnum, ret = 0;
+       struct ubi_ainf_peb *tmp_aeb, *aeb;
+       int i, used_blocks, pnum, fm_anchor, ret = 0;
        size_t fm_size;
        __be32 crc, tmp_crc;
        unsigned long long sqnum = 0;
 
+       fm_anchor = find_fm_anchor(scan_ai);
+       if (fm_anchor < 0)
+               return UBI_NO_FASTMAP;
+
+       /* Move all (possible) fastmap blocks into our new attach structure. */
+       list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
+               list_move_tail(&aeb->u.list, &ai->fastmap);
+
        down_write(&ubi->fm_protect);
        memset(ubi->fm_buf, 0, ubi->fm_size);
 
@@ -945,6 +977,13 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
                        goto free_hdr;
                }
 
+               if (i == 0 && pnum != fm_anchor) {
+                       ubi_err(ubi, "Fastmap anchor PEB mismatch: PEB: %i vs. %i",
+                               pnum, fm_anchor);
+                       ret = UBI_BAD_FASTMAP;
+                       goto free_hdr;
+               }
+
                ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
                if (ret && ret != UBI_IO_BITFLIPS) {
                        ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)",
@@ -1102,7 +1141,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
        struct rb_node *tmp_rb;
        int ret, i, j, free_peb_count, used_peb_count, vol_count;
        int scrub_peb_count, erase_peb_count;
-       int *seen_pebs = NULL;
+       unsigned long *seen_pebs = NULL;
 
        fm_raw = ubi->fm_buf;
        memset(ubi->fm_buf, 0, ubi->fm_size);
index cb7c075..1cb287e 100644 (file)
@@ -99,9 +99,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
        struct gluebi_device *gluebi;
        int ubi_mode = UBI_READONLY;
 
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
        if (mtd->flags & MTD_WRITEABLE)
                ubi_mode = UBI_READWRITE;
 
@@ -129,7 +126,6 @@ static int gluebi_get_device(struct mtd_info *mtd)
                                       ubi_mode);
        if (IS_ERR(gluebi->desc)) {
                mutex_unlock(&devices_mutex);
-               module_put(THIS_MODULE);
                return PTR_ERR(gluebi->desc);
        }
        gluebi->refcnt += 1;
@@ -153,7 +149,6 @@ static void gluebi_put_device(struct mtd_info *mtd)
        gluebi->refcnt -= 1;
        if (gluebi->refcnt == 0)
                ubi_close_volume(gluebi->desc);
-       module_put(THIS_MODULE);
        mutex_unlock(&devices_mutex);
 }
 
index 10cf3b5..ff8cafe 100644 (file)
@@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
 
        p = (char *)vid_hdr - ubi->vid_hdr_shift;
        read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
-                         ubi->vid_hdr_alsize);
+                         ubi->vid_hdr_shift + UBI_VID_HDR_SIZE);
        if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
                return read_err;
 
index 61d4e99..b616a11 100644 (file)
@@ -703,6 +703,8 @@ struct ubi_ainf_volume {
  * @erase: list of physical eraseblocks which have to be erased
  * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
  *         those belonging to "preserve"-compatible internal volumes)
+ * @fastmap: list of physical eraseblocks which relate to fastmap (e.g.,
+ *           eraseblocks of the current and not yet erased old fastmap blocks)
  * @corr_peb_count: count of PEBs in the @corr list
  * @empty_peb_count: count of PEBs which are presumably empty (contain only
  *                   0xFF bytes)
@@ -713,6 +715,8 @@ struct ubi_ainf_volume {
  * @vols_found: number of volumes found
  * @highest_vol_id: highest volume ID
  * @is_empty: flag indicating whether the MTD device is empty or not
+ * @force_full_scan: flag indicating whether we need to do a full scan and drop
+                    all existing Fastmap data structures
  * @min_ec: lowest erase counter value
  * @max_ec: highest erase counter value
  * @max_sqnum: highest sequence number value
@@ -731,6 +735,7 @@ struct ubi_attach_info {
        struct list_head free;
        struct list_head erase;
        struct list_head alien;
+       struct list_head fastmap;
        int corr_peb_count;
        int empty_peb_count;
        int alien_peb_count;
@@ -739,6 +744,7 @@ struct ubi_attach_info {
        int vols_found;
        int highest_vol_id;
        int is_empty;
+       int force_full_scan;
        int min_ec;
        int max_ec;
        unsigned long long max_sqnum;
@@ -911,7 +917,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
 size_t ubi_calc_fm_size(struct ubi_device *ubi);
 int ubi_update_fastmap(struct ubi_device *ubi);
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
-                    int fm_anchor);
+                    struct ubi_attach_info *scan_ai);
 #else
 static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
 #endif
@@ -1105,4 +1111,42 @@ static inline int idx2vol_id(const struct ubi_device *ubi, int idx)
                return idx;
 }
 
+/**
+ * ubi_is_fm_vol - check whether a volume ID is a Fastmap volume.
+ * @vol_id: volume ID
+ */
+static inline bool ubi_is_fm_vol(int vol_id)
+{
+       switch (vol_id) {
+               case UBI_FM_SB_VOLUME_ID:
+               case UBI_FM_DATA_VOLUME_ID:
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * ubi_find_fm_block - check whether a PEB is part of the current Fastmap.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to look for
+ *
+ * This function returns a wear leveling object if @pnum relates to the current
+ * fastmap, @NULL otherwise.
+ */
+static inline struct ubi_wl_entry *ubi_find_fm_block(const struct ubi_device *ubi,
+                                                    int pnum)
+{
+       int i;
+
+       if (ubi->fm) {
+               for (i = 0; i < ubi->fm->used_blocks; i++) {
+                       if (ubi->fm->e[i]->pnum == pnum)
+                               return ubi->fm->e[i];
+               }
+       }
+
+       return NULL;
+}
+
 #endif /* !__UBI_UBI_H__ */
index 10059df..0138f52 100644 (file)
@@ -488,13 +488,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                spin_unlock(&ubi->volumes_lock);
        }
 
-       /* Change volume table record */
-       vtbl_rec = ubi->vtbl[vol_id];
-       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
-       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
-       if (err)
-               goto out_acc;
-
        if (pebs < 0) {
                for (i = 0; i < -pebs; i++) {
                        err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
@@ -512,6 +505,24 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                spin_unlock(&ubi->volumes_lock);
        }
 
+       /*
+        * When we shrink a volume we have to flush all pending (erase) work.
+        * Otherwise it can happen that upon next attach UBI finds a LEB with
+        * lnum > highest_lnum and refuses to attach.
+        */
+       if (pebs < 0) {
+               err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
+               if (err)
+                       goto out_acc;
+       }
+
+       /* Change volume table record */
+       vtbl_rec = ubi->vtbl[vol_id];
+       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
+       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+       if (err)
+               goto out_acc;
+
        vol->reserved_pebs = reserved_pebs;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = reserved_pebs;
index 959c7b1..f453326 100644 (file)
@@ -1598,19 +1598,44 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
                }
        }
 
-       dbg_wl("found %i PEBs", found_pebs);
+       list_for_each_entry(aeb, &ai->fastmap, u.list) {
+               cond_resched();
+
+               e = ubi_find_fm_block(ubi, aeb->pnum);
 
-       if (ubi->fm) {
-               ubi_assert(ubi->good_peb_count ==
-                          found_pebs + ubi->fm->used_blocks);
+               if (e) {
+                       ubi_assert(!ubi->lookuptbl[e->pnum]);
+                       ubi->lookuptbl[e->pnum] = e;
+               } else {
+                       /*
+                        * Usually old Fastmap PEBs are scheduled for erasure
+                        * and we don't have to care about them but if we face
+                        * an power cut before scheduling them we need to
+                        * take care of them here.
+                        */
+                       if (ubi->lookuptbl[aeb->pnum])
+                               continue;
+
+                       e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
+                       if (!e)
+                               goto out_free;
 
-               for (i = 0; i < ubi->fm->used_blocks; i++) {
-                       e = ubi->fm->e[i];
+                       e->pnum = aeb->pnum;
+                       e->ec = aeb->ec;
+                       ubi_assert(!ubi->lookuptbl[e->pnum]);
                        ubi->lookuptbl[e->pnum] = e;
+                       if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
+                               wl_entry_destroy(ubi, e);
+                               goto out_free;
+                       }
                }
+
+               found_pebs++;
        }
-       else
-               ubi_assert(ubi->good_peb_count == found_pebs);
+
+       dbg_wl("found %i PEBs", found_pebs);
+
+       ubi_assert(ubi->good_peb_count == found_pebs);
 
        reserved_pebs = WL_RESERVED_PEBS;
        ubi_fastmap_init(ubi, &reserved_pebs);
index 5470980..f81df91 100644 (file)
@@ -52,5 +52,5 @@ config CAIF_VIRTIO
        The caif driver for CAIF over Virtio.
 
 if CAIF_VIRTIO
-source "drivers/vhost/Kconfig"
+source "drivers/vhost/Kconfig.vringh"
 endif
index 4721948..3a529fb 100644 (file)
@@ -185,8 +185,8 @@ static ssize_t print_frame(char *buf, size_t size, char *frm,
                        /* Fast forward. */
                        i = count - cut;
                        len += snprintf((buf + len), (size - len),
-                                       "--- %u bytes skipped ---\n",
-                                       (int)(count - (cut * 2)));
+                                       "--- %zu bytes skipped ---\n",
+                                       count - (cut * 2));
                }
 
                if ((!(i % 10)) && i) {
index 21f1068..77ffc43 100644 (file)
@@ -233,8 +233,7 @@ static int b53_mmap_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
-       if (pdata)
-               dev->pdata = pdata;
+       dev->pdata = pdata;
 
        platform_set_drvdata(pdev, dev);
 
index cd1d630..b2b8387 100644 (file)
@@ -1622,7 +1622,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
                          "switch_0", priv);
        if (ret < 0) {
                pr_err("failed to request switch_0 IRQ\n");
-               goto out_unmap;
+               goto out_mdio;
        }
 
        ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
@@ -1679,6 +1679,8 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 
 out_free_irq0:
        free_irq(priv->irq0, priv);
+out_mdio:
+       bcm_sf2_mdio_unregister(priv);
 out_unmap:
        base = &priv->core;
        for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
@@ -1686,7 +1688,6 @@ out_unmap:
                        iounmap(*base);
                base++;
        }
-       bcm_sf2_mdio_unregister(priv);
        return ret;
 }
 
index 5698f53..39ca935 100644 (file)
@@ -910,7 +910,8 @@ static int ax_probe(struct platform_device *pdev)
        iounmap(ax->map2);
 
  exit_mem2:
-       release_mem_region(mem2->start, mem2_size);
+       if (mem2)
+               release_mem_region(mem2->start, mem2_size);
 
  exit_mem1:
        iounmap(ei_local->mem);
index 49025e9..bda31f3 100644 (file)
@@ -815,6 +815,7 @@ static int init_phy(struct net_device *dev)
                phydev = of_phy_connect(dev, phynode,
                        &altera_tse_adjust_link, 0, priv->phy_iface);
        }
+       of_node_put(phynode);
 
        if (!phydev) {
                netdev_err(dev, "Could not find the PHY\n");
index ebf9224..a9b2709 100644 (file)
@@ -154,7 +154,7 @@ static int xgbe_alloc_channels(struct xgbe_prv_data *pdata)
                goto err_rx_ring;
 
        for (i = 0, channel = channel_mem; i < count; i++, channel++) {
-               snprintf(channel->name, sizeof(channel->name), "channel-%d", i);
+               snprintf(channel->name, sizeof(channel->name), "channel-%u", i);
                channel->pdata = pdata;
                channel->queue_index = i;
                channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE +
index 7714b7d..37a0f46 100644 (file)
@@ -772,6 +772,7 @@ int xgene_enet_phy_connect(struct net_device *ndev)
 
                phy_dev = of_phy_connect(ndev, np, &xgene_enet_adjust_link,
                                         0, pdata->phy_mode);
+               of_node_put(np);
                if (!phy_dev) {
                        netdev_err(ndev, "Could not connect to PHY\n");
                        return -ENODEV;
index 586beda..4bff0f3 100644 (file)
@@ -749,14 +749,16 @@ int arc_emac_probe(struct net_device *ndev, int interface)
        err = of_address_to_resource(dev->of_node, 0, &res_regs);
        if (err) {
                dev_err(dev, "failed to retrieve registers base from device tree\n");
-               return -ENODEV;
+               err = -ENODEV;
+               goto out_put_node;
        }
 
        /* Get IRQ from device tree */
        irq = irq_of_parse_and_map(dev->of_node, 0);
        if (!irq) {
                dev_err(dev, "failed to retrieve <irq> value from device tree\n");
-               return -ENODEV;
+               err = -ENODEV;
+               goto out_put_node;
        }
 
        ndev->netdev_ops = &arc_emac_netdev_ops;
@@ -778,7 +780,7 @@ int arc_emac_probe(struct net_device *ndev, int interface)
                err = clk_prepare_enable(priv->clk);
                if (err) {
                        dev_err(dev, "failed to enable clock\n");
-                       return err;
+                       goto out_put_node;
                }
 
                clock_frequency = clk_get_rate(priv->clk);
@@ -787,7 +789,8 @@ int arc_emac_probe(struct net_device *ndev, int interface)
                if (of_property_read_u32(dev->of_node, "clock-frequency",
                                         &clock_frequency)) {
                        dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out_put_node;
                }
        }
 
@@ -867,6 +870,7 @@ int arc_emac_probe(struct net_device *ndev, int interface)
                goto out_netif_api;
        }
 
+       of_node_put(phy_node);
        return 0;
 
 out_netif_api:
@@ -877,6 +881,9 @@ out_mdio:
 out_clken:
        if (priv->clk)
                clk_disable_unprepare(priv->clk);
+out_put_node:
+       of_node_put(phy_node);
+
        return err;
 }
 EXPORT_SYMBOL_GPL(arc_emac_probe);
index e708e36..6453148 100644 (file)
@@ -1251,7 +1251,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct alx_priv *alx;
        struct alx_hw *hw;
        bool phy_configured;
-       int bars, err;
+       int err;
 
        err = pci_enable_device_mem(pdev);
        if (err)
@@ -1271,11 +1271,10 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       err = pci_request_selected_regions(pdev, bars, alx_drv_name);
+       err = pci_request_mem_regions(pdev, alx_drv_name);
        if (err) {
                dev_err(&pdev->dev,
-                       "pci_request_selected_regions failed(bars:%d)\n", bars);
+                       "pci_request_mem_regions failed\n");
                goto out_pci_disable;
        }
 
@@ -1401,7 +1400,7 @@ out_unmap:
 out_free_netdev:
        free_netdev(netdev);
 out_pci_release:
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
 out_pci_disable:
        pci_disable_device(pdev);
        return err;
@@ -1420,8 +1419,7 @@ static void alx_remove(struct pci_dev *pdev)
 
        unregister_netdev(alx->dev);
        iounmap(hw->hw_addr);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
index 0d4ea92..b047fd6 100644 (file)
@@ -1504,6 +1504,7 @@ static int nb8800_probe(struct platform_device *pdev)
 err_free_dma:
        nb8800_dma_free(dev);
 err_free_bus:
+       of_node_put(priv->phy_node);
        mdiobus_unregister(bus);
 err_disable_clk:
        clk_disable_unprepare(priv->clk);
@@ -1519,6 +1520,7 @@ static int nb8800_remove(struct platform_device *pdev)
        struct nb8800_priv *priv = netdev_priv(ndev);
 
        unregister_netdev(ndev);
+       of_node_put(priv->phy_node);
 
        mdiobus_unregister(priv->mii_bus);
 
index 87c6b5b..6c8bc5f 100644 (file)
@@ -1859,7 +1859,7 @@ static int bcm_enet_probe(struct platform_device *pdev)
        } else {
 
                /* run platform code to initialize PHY device */
-               if (pd->mii_config &&
+               if (pd && pd->mii_config &&
                    pd->mii_config(dev, 1, bcm_enet_mdio_read_mii,
                                   bcm_enet_mdio_write_mii)) {
                        dev_err(&pdev->dev, "unable to configure mdio bus\n");
index 8fc246e..05c1c1d 100644 (file)
@@ -312,7 +312,8 @@ bnad_debugfs_write_regrd(struct file *file, const char __user *buf,
        struct bnad_debug_info *regrd_debug = file->private_data;
        struct bnad *bnad = (struct bnad *)regrd_debug->i_private;
        struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
-       int addr, len, rc, i;
+       int rc, i;
+       u32 addr, len;
        u32 *regbuf;
        void __iomem *rb, *reg_addr;
        unsigned long flags;
@@ -372,7 +373,8 @@ bnad_debugfs_write_regwr(struct file *file, const char __user *buf,
        struct bnad_debug_info *debug = file->private_data;
        struct bnad *bnad = (struct bnad *)debug->i_private;
        struct bfa_ioc *ioc = &bnad->bna.ioceth.ioc;
-       int addr, val, rc;
+       int rc;
+       u32 addr, val;
        void __iomem *reg_addr;
        unsigned long flags;
        void *kern_buf;
index e8bc15b..4ab404f 100644 (file)
@@ -1513,6 +1513,7 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
        return 0;
 
 err:
+       of_node_put(p->phy_np);
        free_netdev(netdev);
        return result;
 }
@@ -1520,8 +1521,10 @@ err:
 static int octeon_mgmt_remove(struct platform_device *pdev)
 {
        struct net_device *netdev = platform_get_drvdata(pdev);
+       struct octeon_mgmt *p = netdev_priv(netdev);
 
        unregister_netdev(netdev);
+       of_node_put(p->phy_np);
        free_netdev(netdev);
        return 0;
 }
index bad253b..ad3552d 100644 (file)
@@ -1192,7 +1192,7 @@ out_free: dev_kfree_skb_any(skb);
 
        /* Discard the packet if the length is greater than mtu */
        max_pkt_len = ETH_HLEN + dev->mtu;
-       if (skb_vlan_tag_present(skb))
+       if (skb_vlan_tagged(skb))
                max_pkt_len += VLAN_HLEN;
        if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
                goto out_free;
index 4705e2d..e0ebe13 100644 (file)
@@ -104,6 +104,8 @@ enum {
 
 enum CPL_error {
        CPL_ERR_NONE               = 0,
+       CPL_ERR_TCAM_PARITY        = 1,
+       CPL_ERR_TCAM_MISS          = 2,
        CPL_ERR_TCAM_FULL          = 3,
        CPL_ERR_BAD_LENGTH         = 15,
        CPL_ERR_BAD_ROUTE          = 18,
index 1bb57d3..c8fd4f8 100644 (file)
@@ -1188,7 +1188,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Discard the packet if the length is greater than mtu */
        max_pkt_len = ETH_HLEN + dev->mtu;
-       if (skb_vlan_tag_present(skb))
+       if (skb_vlan_tagged(skb))
                max_pkt_len += VLAN_HLEN;
        if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len)))
                goto out_free;
index f15560a..48f82ab 100644 (file)
@@ -1566,7 +1566,7 @@ static int enic_request_intr(struct enic *enic)
                        intr = enic_msix_rq_intr(enic, i);
                        snprintf(enic->msix[intr].devname,
                                sizeof(enic->msix[intr].devname),
-                               "%.11s-rx-%d", netdev->name, i);
+                               "%.11s-rx-%u", netdev->name, i);
                        enic->msix[intr].isr = enic_isr_msix;
                        enic->msix[intr].devid = &enic->napi[i];
                }
@@ -1577,7 +1577,7 @@ static int enic_request_intr(struct enic *enic)
                        intr = enic_msix_wq_intr(enic, i);
                        snprintf(enic->msix[intr].devname,
                                sizeof(enic->msix[intr].devname),
-                               "%.11s-tx-%d", netdev->name, i);
+                               "%.11s-tx-%u", netdev->name, i);
                        enic->msix[intr].isr = enic_isr_msix;
                        enic->msix[intr].devid = &enic->napi[wq];
                }
index cbe8497..f0e9e2e 100644 (file)
@@ -1319,7 +1319,7 @@ de4x5_open(struct net_device *dev)
 
     if (request_irq(dev->irq, de4x5_interrupt, IRQF_SHARED,
                                                     lp->adapter_name, dev)) {
-       printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+       printk("de4x5_open(): Requested IRQ%d is busy - attempting FAST/SHARE...", dev->irq);
        if (request_irq(dev->irq, de4x5_interrupt, IRQF_SHARED,
                                                     lp->adapter_name, dev)) {
            printk("\n              Cannot get IRQ- reconfigure your hardware.\n");
index 3fb87e2..5c8afe1 100644 (file)
@@ -795,6 +795,7 @@ static int  hns_mac_get_info(struct hns_mac_cb *mac_cb)
                        dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n",
                                mac_cb->mac_id, np->name);
                }
+               of_node_put(np);
 
                return 0;
        }
@@ -812,10 +813,12 @@ static int  hns_mac_get_info(struct hns_mac_cb *mac_cb)
                        dev_dbg(mac_cb->dev, "mac%d phy_node: %s\n",
                                mac_cb->mac_id, np->name);
                }
+               of_node_put(np);
 
-               syscon = syscon_node_to_regmap(
-                               of_parse_phandle(to_of_node(mac_cb->fw_port),
-                                                "serdes-syscon", 0));
+               np = of_parse_phandle(to_of_node(mac_cb->fw_port),
+                                       "serdes-syscon", 0);
+               syscon = syscon_node_to_regmap(np);
+               of_node_put(np);
                if (IS_ERR_OR_NULL(syscon)) {
                        dev_err(mac_cb->dev, "serdes-syscon is needed!\n");
                        return -EINVAL;
index 2ef4277..afb5daa 100644 (file)
@@ -51,7 +51,7 @@ int hns_dsaf_get_cfg(struct dsaf_device *dsaf_dev)
        const char *mode_str;
        struct regmap *syscon;
        struct resource *res;
-       struct device_node *np = dsaf_dev->dev->of_node;
+       struct device_node *np = dsaf_dev->dev->of_node, *np_temp;
        struct platform_device *pdev = to_platform_device(dsaf_dev->dev);
 
        if (dev_of_node(dsaf_dev->dev)) {
@@ -102,8 +102,9 @@ int hns_dsaf_get_cfg(struct dsaf_device *dsaf_dev)
                dsaf_dev->dsaf_tc_mode = HRD_DSAF_4TC_MODE;
 
        if (dev_of_node(dsaf_dev->dev)) {
-               syscon = syscon_node_to_regmap(
-                               of_parse_phandle(np, "subctrl-syscon", 0));
+               np_temp = of_parse_phandle(np, "subctrl-syscon", 0);
+               syscon = syscon_node_to_regmap(np_temp);
+               of_node_put(np_temp);
                if (IS_ERR_OR_NULL(syscon)) {
                        res = platform_get_resource(pdev, IORESOURCE_MEM,
                                                    res_idx++);
index 41f32c0..02f4439 100644 (file)
@@ -7330,8 +7330,7 @@ err_flashmap:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -7398,8 +7397,7 @@ static void e1000_remove(struct pci_dev *pdev)
        if ((adapter->hw.flash_address) &&
            (adapter->hw.mac.type < e1000_pch_spt))
                iounmap(adapter->hw.flash_address);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        free_netdev(netdev);
 
index b8245c7..774a565 100644 (file)
@@ -1963,10 +1963,7 @@ static int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_dma;
        }
 
-       err = pci_request_selected_regions(pdev,
-                                          pci_select_bars(pdev,
-                                                          IORESOURCE_MEM),
-                                          fm10k_driver_name);
+       err = pci_request_mem_regions(pdev, fm10k_driver_name);
        if (err) {
                dev_err(&pdev->dev,
                        "pci_request_selected_regions failed: %d\n", err);
@@ -2070,8 +2067,7 @@ err_sw_init:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_netdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -2119,8 +2115,7 @@ static void fm10k_remove(struct pci_dev *pdev)
 
        free_netdev(netdev);
 
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
 
index 339d99b..81c99e1 100644 (file)
@@ -10710,8 +10710,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* set up pci connections */
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), i40e_driver_name);
+       err = pci_request_mem_regions(pdev, i40e_driver_name);
        if (err) {
                dev_info(&pdev->dev,
                         "pci_request_selected_regions failed %d\n", err);
@@ -11208,8 +11207,7 @@ err_ioremap:
        kfree(pf);
 err_pf_alloc:
        pci_disable_pcie_error_reporting(pdev);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -11320,8 +11318,7 @@ static void i40e_remove(struct pci_dev *pdev)
 
        iounmap(hw->hw_addr);
        kfree(pf);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
index 9bcba42..942a89f 100644 (file)
@@ -2324,9 +2324,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM),
-                                          igb_driver_name);
+       err = pci_request_mem_regions(pdev, igb_driver_name);
        if (err)
                goto err_pci_reg;
 
@@ -2750,8 +2748,7 @@ err_sw_init:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -2916,8 +2913,7 @@ static void igb_remove(struct pci_dev *pdev)
        pci_iounmap(pdev, adapter->io_addr);
        if (hw->flash_address)
                iounmap(hw->flash_address);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        kfree(adapter->shadow_vfta);
        free_netdev(netdev);
index 7871f53..5418c69 100644 (file)
@@ -9353,8 +9353,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_using_dac = 0;
        }
 
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), ixgbe_driver_name);
+       err = pci_request_mem_regions(pdev, ixgbe_driver_name);
        if (err) {
                dev_err(&pdev->dev,
                        "pci_request_selected_regions failed 0x%x\n", err);
@@ -9740,8 +9739,7 @@ err_ioremap:
        disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state);
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        if (!adapter || disable_dev)
@@ -9808,8 +9806,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
 
 #endif
        iounmap(adapter->io_addr);
-       pci_release_selected_regions(pdev, pci_select_bars(pdev,
-                                    IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        e_dev_info("complete\n");
 
index f92018b..d41c28d 100644 (file)
@@ -4118,6 +4118,7 @@ static int mvneta_probe(struct platform_device *pdev)
                        pp->bm_priv = NULL;
                }
        }
+       of_node_put(bm_node);
 
        err = mvneta_init(&pdev->dev, pp);
        if (err < 0)
index 0b04717..60227a3 100644 (file)
@@ -6234,6 +6234,7 @@ err_free_stats:
 err_free_irq:
        irq_dispose_mapping(port->irq);
 err_free_netdev:
+       of_node_put(phy_node);
        free_netdev(dev);
        return err;
 }
@@ -6244,6 +6245,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
        int i;
 
        unregister_netdev(port->dev);
+       of_node_put(port->phy_node);
        free_percpu(port->pcpu);
        free_percpu(port->stats);
        for (i = 0; i < txq_number; i++)
index aeeb2e7..5d5000c 100644 (file)
@@ -1506,6 +1506,7 @@ static int pxa168_eth_probe(struct platform_device *pdev)
                }
                of_property_read_u32(np, "reg", &pep->phy_addr);
                pep->phy_intf = of_get_phy_mode(pdev->dev.of_node);
+               of_node_put(np);
        }
 
        /* Hardware supports only 3 ports */
index f4497cf..d728704 100644 (file)
@@ -721,6 +721,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET         0x98
 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET                0xa0
 #define QUERY_DEV_CAP_ETH_BACKPL_OFFSET                0x9c
+#define QUERY_DEV_CAP_DIAG_RPRT_PER_PORT       0x9c
 #define QUERY_DEV_CAP_FW_REASSIGN_MAC          0x9d
 #define QUERY_DEV_CAP_VXLAN                    0x9e
 #define QUERY_DEV_CAP_MAD_DEMUX_OFFSET         0xb0
@@ -935,6 +936,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
        if (field32 & (1 << 7))
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT;
+       MLX4_GET(field32, outbox, QUERY_DEV_CAP_DIAG_RPRT_PER_PORT);
+       if (field32 & (1 << 17))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
        if (field & 1<<6)
                dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
@@ -2457,6 +2461,42 @@ int mlx4_NOP(struct mlx4_dev *dev)
                        MLX4_CMD_NATIVE);
 }
 
+int mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier,
+                            const u32 offset[],
+                            u32 value[], size_t array_len, u8 port)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       size_t i;
+       int ret;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       outbox = mailbox->buf;
+
+       ret = mlx4_cmd_box(dev, 0, mailbox->dma, port, op_modifier,
+                          MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A,
+                          MLX4_CMD_NATIVE);
+       if (ret)
+               goto out;
+
+       for (i = 0; i < array_len; i++) {
+               if (offset[i] > MLX4_MAILBOX_SIZE) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               MLX4_GET(value[i], outbox, offset[i]);
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return ret;
+}
+EXPORT_SYMBOL(mlx4_query_diag_counters);
+
 int mlx4_get_phys_port_id(struct mlx4_dev *dev)
 {
        u8 port;
index 04bc522..c07f4d0 100644 (file)
@@ -63,12 +63,12 @@ void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
                complete(&srq->free);
 }
 
-static int get_pas_size(void *srqc)
+static int get_pas_size(struct mlx5_srq_attr *in)
 {
-       u32 log_page_size = MLX5_GET(srqc, srqc, log_page_size) + 12;
-       u32 log_srq_size  = MLX5_GET(srqc, srqc, log_srq_size);
-       u32 log_rq_stride = MLX5_GET(srqc, srqc, log_rq_stride);
-       u32 page_offset   = MLX5_GET(srqc, srqc, page_offset);
+       u32 log_page_size = in->log_page_size + 12;
+       u32 log_srq_size  = in->log_size;
+       u32 log_rq_stride = in->wqe_shift;
+       u32 page_offset   = in->page_offset;
        u32 po_quanta     = 1 << (log_page_size - 6);
        u32 rq_sz         = 1 << (log_srq_size + 4 + log_rq_stride);
        u32 page_size     = 1 << log_page_size;
@@ -78,57 +78,58 @@ static int get_pas_size(void *srqc)
        return rq_num_pas * sizeof(u64);
 }
 
-static void rmpc_srqc_reformat(void *srqc, void *rmpc, bool srqc_to_rmpc)
+static void set_wq(void *wq, struct mlx5_srq_attr *in)
 {
-       void *wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
-
-       if (srqc_to_rmpc) {
-               switch (MLX5_GET(srqc, srqc, state)) {
-               case MLX5_SRQC_STATE_GOOD:
-                       MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
-                       break;
-               case MLX5_SRQC_STATE_ERROR:
-                       MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_ERR);
-                       break;
-               default:
-                       pr_warn("%s: %d: Unknown srq state = 0x%x\n", __func__,
-                               __LINE__, MLX5_GET(srqc, srqc, state));
-                       MLX5_SET(rmpc, rmpc, state, MLX5_GET(srqc, srqc, state));
-               }
-
-               MLX5_SET(wq,   wq, wq_signature,  MLX5_GET(srqc,  srqc, wq_signature));
-               MLX5_SET(wq,   wq, log_wq_pg_sz,  MLX5_GET(srqc,  srqc, log_page_size));
-               MLX5_SET(wq,   wq, log_wq_stride, MLX5_GET(srqc,  srqc, log_rq_stride) + 4);
-               MLX5_SET(wq,   wq, log_wq_sz,     MLX5_GET(srqc,  srqc, log_srq_size));
-               MLX5_SET(wq,   wq, page_offset,   MLX5_GET(srqc,  srqc, page_offset));
-               MLX5_SET(wq,   wq, lwm,           MLX5_GET(srqc,  srqc, lwm));
-               MLX5_SET(wq,   wq, pd,            MLX5_GET(srqc,  srqc, pd));
-               MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(srqc,     srqc, dbr_addr));
-       } else {
-               switch (MLX5_GET(rmpc, rmpc, state)) {
-               case MLX5_RMPC_STATE_RDY:
-                       MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_GOOD);
-                       break;
-               case MLX5_RMPC_STATE_ERR:
-                       MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_ERROR);
-                       break;
-               default:
-                       pr_warn("%s: %d: Unknown rmp state = 0x%x\n",
-                               __func__, __LINE__,
-                               MLX5_GET(rmpc, rmpc, state));
-                       MLX5_SET(srqc, srqc, state,
-                                MLX5_GET(rmpc, rmpc, state));
-               }
-
-               MLX5_SET(srqc,   srqc, wq_signature,   MLX5_GET(wq,   wq, wq_signature));
-               MLX5_SET(srqc,   srqc, log_page_size,  MLX5_GET(wq,   wq, log_wq_pg_sz));
-               MLX5_SET(srqc,   srqc, log_rq_stride,  MLX5_GET(wq,   wq, log_wq_stride) - 4);
-               MLX5_SET(srqc,   srqc, log_srq_size,   MLX5_GET(wq,   wq, log_wq_sz));
-               MLX5_SET(srqc,   srqc, page_offset,    MLX5_GET(wq,   wq, page_offset));
-               MLX5_SET(srqc,   srqc, lwm,            MLX5_GET(wq,   wq, lwm));
-               MLX5_SET(srqc,   srqc, pd,             MLX5_GET(wq,   wq, pd));
-               MLX5_SET64(srqc, srqc, dbr_addr,       MLX5_GET64(wq, wq, dbr_addr));
-       }
+       MLX5_SET(wq,   wq, wq_signature,  !!(in->flags
+                & MLX5_SRQ_FLAG_WQ_SIG));
+       MLX5_SET(wq,   wq, log_wq_pg_sz,  in->log_page_size);
+       MLX5_SET(wq,   wq, log_wq_stride, in->wqe_shift + 4);
+       MLX5_SET(wq,   wq, log_wq_sz,     in->log_size);
+       MLX5_SET(wq,   wq, page_offset,   in->page_offset);
+       MLX5_SET(wq,   wq, lwm,           in->lwm);
+       MLX5_SET(wq,   wq, pd,            in->pd);
+       MLX5_SET64(wq, wq, dbr_addr,      in->db_record);
+}
+
+static void set_srqc(void *srqc, struct mlx5_srq_attr *in)
+{
+       MLX5_SET(srqc,   srqc, wq_signature,  !!(in->flags
+                & MLX5_SRQ_FLAG_WQ_SIG));
+       MLX5_SET(srqc,   srqc, log_page_size, in->log_page_size);
+       MLX5_SET(srqc,   srqc, log_rq_stride, in->wqe_shift);
+       MLX5_SET(srqc,   srqc, log_srq_size,  in->log_size);
+       MLX5_SET(srqc,   srqc, page_offset,   in->page_offset);
+       MLX5_SET(srqc,   srqc, lwm,           in->lwm);
+       MLX5_SET(srqc,   srqc, pd,            in->pd);
+       MLX5_SET64(srqc, srqc, dbr_addr,      in->db_record);
+       MLX5_SET(srqc,   srqc, xrcd,          in->xrcd);
+       MLX5_SET(srqc,   srqc, cqn,           in->cqn);
+}
+
+static void get_wq(void *wq, struct mlx5_srq_attr *in)
+{
+       if (MLX5_GET(wq, wq, wq_signature))
+               in->flags &= MLX5_SRQ_FLAG_WQ_SIG;
+       in->log_page_size = MLX5_GET(wq,   wq, log_wq_pg_sz);
+       in->wqe_shift     = MLX5_GET(wq,   wq, log_wq_stride) - 4;
+       in->log_size      = MLX5_GET(wq,   wq, log_wq_sz);
+       in->page_offset   = MLX5_GET(wq,   wq, page_offset);
+       in->lwm           = MLX5_GET(wq,   wq, lwm);
+       in->pd            = MLX5_GET(wq,   wq, pd);
+       in->db_record     = MLX5_GET64(wq, wq, dbr_addr);
+}
+
+static void get_srqc(void *srqc, struct mlx5_srq_attr *in)
+{
+       if (MLX5_GET(srqc, srqc, wq_signature))
+               in->flags &= MLX5_SRQ_FLAG_WQ_SIG;
+       in->log_page_size = MLX5_GET(srqc,   srqc, log_page_size);
+       in->wqe_shift     = MLX5_GET(srqc,   srqc, log_rq_stride);
+       in->log_size      = MLX5_GET(srqc,   srqc, log_srq_size);
+       in->page_offset   = MLX5_GET(srqc,   srqc, page_offset);
+       in->lwm           = MLX5_GET(srqc,   srqc, lwm);
+       in->pd            = MLX5_GET(srqc,   srqc, pd);
+       in->db_record     = MLX5_GET64(srqc, srqc, dbr_addr);
 }
 
 struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
@@ -149,19 +150,36 @@ struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn)
 EXPORT_SYMBOL(mlx5_core_get_srq);
 
 static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
-                         struct mlx5_create_srq_mbox_in *in, int inlen)
+                         struct mlx5_srq_attr *in)
 {
-       struct mlx5_create_srq_mbox_out out;
+       u32 create_out[MLX5_ST_SZ_DW(create_srq_out)] = {0};
+       void *create_in;
+       void *srqc;
+       void *pas;
+       int pas_size;
+       int inlen;
        int err;
 
-       memset(&out, 0, sizeof(out));
+       pas_size  = get_pas_size(in);
+       inlen     = MLX5_ST_SZ_BYTES(create_srq_in) + pas_size;
+       create_in = mlx5_vzalloc(inlen);
+       if (!create_in)
+               return -ENOMEM;
+
+       srqc = MLX5_ADDR_OF(create_srq_in, create_in, srq_context_entry);
+       pas = MLX5_ADDR_OF(create_srq_in, create_in, pas);
 
-       in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ);
+       set_srqc(srqc, in);
+       memcpy(pas, in->pas, pas_size);
 
-       err = mlx5_cmd_exec_check_status(dev, (u32 *)in, inlen, (u32 *)(&out),
-                                        sizeof(out));
+       MLX5_SET(create_srq_in, create_in, opcode,
+                MLX5_CMD_OP_CREATE_SRQ);
 
-       srq->srqn = be32_to_cpu(out.srqn) & 0xffffff;
+       err = mlx5_cmd_exec_check_status(dev, create_in, inlen, create_out,
+                                        sizeof(create_out));
+       kvfree(create_in);
+       if (!err)
+               srq->srqn = MLX5_GET(create_srq_out, create_out, srqn);
 
        return err;
 }
@@ -169,67 +187,75 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
 static int destroy_srq_cmd(struct mlx5_core_dev *dev,
                           struct mlx5_core_srq *srq)
 {
-       struct mlx5_destroy_srq_mbox_in in;
-       struct mlx5_destroy_srq_mbox_out out;
+       u32 srq_in[MLX5_ST_SZ_DW(destroy_srq_in)] = {0};
+       u32 srq_out[MLX5_ST_SZ_DW(destroy_srq_out)] = {0};
 
-       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);
+       MLX5_SET(destroy_srq_in, srq_in, opcode,
+                MLX5_CMD_OP_DESTROY_SRQ);
+       MLX5_SET(destroy_srq_in, srq_in, srqn, srq->srqn);
 
-       return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in),
-                                         (u32 *)(&out), sizeof(out));
+       return mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in),
+                                         srq_out, sizeof(srq_out));
 }
 
 static int arm_srq_cmd(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;
-
-       memset(&in, 0, sizeof(in));
-       memset(&out, 0, sizeof(out));
+       /* arm_srq structs missing using identical xrc ones */
+       u32 srq_in[MLX5_ST_SZ_DW(arm_xrc_srq_in)] = {0};
+       u32 srq_out[MLX5_ST_SZ_DW(arm_xrc_srq_out)] = {0};
 
-       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);
+       MLX5_SET(arm_xrc_srq_in, srq_in, opcode,   MLX5_CMD_OP_ARM_XRC_SRQ);
+       MLX5_SET(arm_xrc_srq_in, srq_in, xrc_srqn, srq->srqn);
+       MLX5_SET(arm_xrc_srq_in, srq_in, lwm,      lwm);
 
-       return mlx5_cmd_exec_check_status(dev, (u32 *)(&in),
-                                         sizeof(in), (u32 *)(&out),
-                                         sizeof(out));
+       return  mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in),
+                                          srq_out, sizeof(srq_out));
 }
 
 static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
-                        struct mlx5_query_srq_mbox_out *out)
+                        struct mlx5_srq_attr *out)
 {
-       struct mlx5_query_srq_mbox_in in;
+       u32 srq_in[MLX5_ST_SZ_DW(query_srq_in)] = {0};
+       u32 *srq_out;
+       void *srqc;
+       int err;
 
-       memset(&in, 0, sizeof(in));
+       srq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_srq_out));
+       if (!srq_out)
+               return -ENOMEM;
 
-       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ);
-       in.srqn = cpu_to_be32(srq->srqn);
+       MLX5_SET(query_srq_in, srq_in, opcode,
+                MLX5_CMD_OP_QUERY_SRQ);
+       MLX5_SET(query_srq_in, srq_in, srqn, srq->srqn);
+       err =  mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in),
+                                         srq_out,
+                                         MLX5_ST_SZ_BYTES(query_srq_out));
+       if (err)
+               goto out;
 
-       return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in),
-                                         (u32 *)out, sizeof(*out));
+       srqc = MLX5_ADDR_OF(query_srq_out, srq_out, srq_context_entry);
+       get_srqc(srqc, out);
+       if (MLX5_GET(srqc, srqc, state) != MLX5_SRQC_STATE_GOOD)
+               out->flags |= MLX5_SRQ_FLAG_ERR;
+out:
+       kvfree(srq_out);
+       return err;
 }
 
 static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,
                              struct mlx5_core_srq *srq,
-                             struct mlx5_create_srq_mbox_in *in,
-                             int srq_inlen)
+                             struct mlx5_srq_attr *in)
 {
        u32 create_out[MLX5_ST_SZ_DW(create_xrc_srq_out)];
        void *create_in;
-       void *srqc;
        void *xrc_srqc;
        void *pas;
        int pas_size;
        int inlen;
        int err;
 
-       srqc      = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry);
-       pas_size  = get_pas_size(srqc);
+       pas_size  = get_pas_size(in);
        inlen     = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size;
        create_in = mlx5_vzalloc(inlen);
        if (!create_in)
@@ -239,7 +265,8 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev,
                                xrc_srq_context_entry);
        pas      = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas);
 
-       memcpy(xrc_srqc, srqc, MLX5_ST_SZ_BYTES(srqc));
+       set_srqc(xrc_srqc, in);
+       MLX5_SET(xrc_srqc, xrc_srqc, user_index, in->user_index);
        memcpy(pas, in->pas, pas_size);
        MLX5_SET(create_xrc_srq_in, create_in, opcode,
                 MLX5_CMD_OP_CREATE_XRC_SRQ);
@@ -293,11 +320,10 @@ static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev,
 
 static int query_xrc_srq_cmd(struct mlx5_core_dev *dev,
                             struct mlx5_core_srq *srq,
-                            struct mlx5_query_srq_mbox_out *out)
+                            struct mlx5_srq_attr *out)
 {
        u32 xrcsrq_in[MLX5_ST_SZ_DW(query_xrc_srq_in)];
        u32 *xrcsrq_out;
-       void *srqc;
        void *xrc_srqc;
        int err;
 
@@ -317,8 +343,9 @@ static int query_xrc_srq_cmd(struct mlx5_core_dev *dev,
 
        xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, xrcsrq_out,
                                xrc_srq_context_entry);
-       srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry);
-       memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc));
+       get_srqc(xrc_srqc, out);
+       if (MLX5_GET(xrc_srqc, xrc_srqc, state) != MLX5_XRC_SRQC_STATE_GOOD)
+               out->flags |= MLX5_SRQ_FLAG_ERR;
 
 out:
        kvfree(xrcsrq_out);
@@ -326,26 +353,27 @@ out:
 }
 
 static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
-                         struct mlx5_create_srq_mbox_in *in, int srq_inlen)
+                         struct mlx5_srq_attr *in)
 {
        void *create_in;
        void *rmpc;
-       void *srqc;
+       void *wq;
        int pas_size;
        int inlen;
        int err;
 
-       srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry);
-       pas_size = get_pas_size(srqc);
+       pas_size = get_pas_size(in);
        inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size;
        create_in = mlx5_vzalloc(inlen);
        if (!create_in)
                return -ENOMEM;
 
        rmpc = MLX5_ADDR_OF(create_rmp_in, create_in, ctx);
+       wq = MLX5_ADDR_OF(rmpc, rmpc, wq);
 
+       MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY);
+       set_wq(wq, in);
        memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size);
-       rmpc_srqc_reformat(srqc, rmpc, true);
 
        err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn);
 
@@ -390,11 +418,10 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev,
 }
 
 static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
-                        struct mlx5_query_srq_mbox_out *out)
+                        struct mlx5_srq_attr *out)
 {
        u32 *rmp_out;
        void *rmpc;
-       void *srqc;
        int err;
 
        rmp_out =  mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out));
@@ -405,9 +432,10 @@ static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
        if (err)
                goto out;
 
-       srqc = MLX5_ADDR_OF(query_srq_out, out,     srq_context_entry);
        rmpc = MLX5_ADDR_OF(query_rmp_out, rmp_out, rmp_context);
-       rmpc_srqc_reformat(srqc, rmpc, false);
+       get_wq(MLX5_ADDR_OF(rmpc, rmpc, wq), out);
+       if (MLX5_GET(rmpc, rmpc, state) != MLX5_RMPC_STATE_RDY)
+               out->flags |= MLX5_SRQ_FLAG_ERR;
 
 out:
        kvfree(rmp_out);
@@ -416,15 +444,14 @@ out:
 
 static int create_srq_split(struct mlx5_core_dev *dev,
                            struct mlx5_core_srq *srq,
-                           struct mlx5_create_srq_mbox_in *in,
-                           int inlen, int is_xrc)
+                           struct mlx5_srq_attr *in)
 {
        if (!dev->issi)
-               return create_srq_cmd(dev, srq, in, inlen);
+               return create_srq_cmd(dev, srq, in);
        else if (srq->common.res == MLX5_RES_XSRQ)
-               return create_xrc_srq_cmd(dev, srq, in, inlen);
+               return create_xrc_srq_cmd(dev, srq, in);
        else
-               return create_rmp_cmd(dev, srq, in, inlen);
+               return create_rmp_cmd(dev, srq, in);
 }
 
 static int destroy_srq_split(struct mlx5_core_dev *dev,
@@ -439,15 +466,17 @@ static int destroy_srq_split(struct mlx5_core_dev *dev,
 }
 
 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 is_xrc)
+                        struct mlx5_srq_attr *in)
 {
        int err;
        struct mlx5_srq_table *table = &dev->priv.srq_table;
 
-       srq->common.res = is_xrc ? MLX5_RES_XSRQ : MLX5_RES_SRQ;
+       if (in->type == IB_SRQT_XRC)
+               srq->common.res = MLX5_RES_XSRQ;
+       else
+               srq->common.res = MLX5_RES_SRQ;
 
-       err = create_srq_split(dev, srq, in, inlen, is_xrc);
+       err = create_srq_split(dev, srq, in);
        if (err)
                return err;
 
@@ -502,7 +531,7 @@ int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq)
 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_srq_attr *out)
 {
        if (!dev->issi)
                return query_srq_cmd(dev, srq, out);
index 03a5093..28274a6 100644 (file)
@@ -85,6 +85,7 @@ int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn)
 
        return err;
 }
+EXPORT_SYMBOL(mlx5_core_create_rq);
 
 int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in, int inlen)
 {
@@ -110,6 +111,7 @@ void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn)
 
        mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
 }
+EXPORT_SYMBOL(mlx5_core_destroy_rq);
 
 int mlx5_core_query_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *out)
 {
@@ -430,6 +432,7 @@ int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen,
 
        return err;
 }
+EXPORT_SYMBOL(mlx5_core_create_rqt);
 
 int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in,
                         int inlen)
@@ -455,3 +458,4 @@ void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn)
 
        mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
 }
+EXPORT_SYMBOL(mlx5_core_destroy_rqt);
index 2874dff..eaa37c0 100644 (file)
@@ -7412,7 +7412,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
 
        if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
            ((!ring_data->lro) ||
-            (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
+            (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG))) &&
            (dev->features & NETIF_F_RXCSUM)) {
                l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
                l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
index b26fe26..0e4f4a9 100644 (file)
@@ -509,6 +509,7 @@ int qed_resc_alloc(struct qed_dev *cdev)
                        DP_ERR(p_hwfn,
                               "Cannot allocate 0x%x EQ elements. The maximum of a u16 chain is 0x%x\n",
                               n_eqes, 0xFFFF);
+                       rc = -EINVAL;
                        goto alloc_err;
                }
 
@@ -888,7 +889,7 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
 
        if (hw_mode & (1 << MODE_MF_SI)) {
                u8 pf_id = 0;
-               u32 val;
+               u32 val = 0;
 
                if (!qed_hw_init_first_eth(p_hwfn, p_ptt, &pf_id)) {
                        if (p_hwfn->rel_pf_id == pf_id) {
@@ -2539,7 +2540,7 @@ int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate)
 
                rc = __qed_configure_vport_wfq(p_hwfn, p_ptt, vp_id, rate);
 
-               if (!rc) {
+               if (rc) {
                        qed_ptt_release(p_hwfn, p_ptt);
                        return rc;
                }
index a12c6ca..401e738 100644 (file)
@@ -590,7 +590,7 @@ qed_sp_eth_rx_queue_start(struct qed_hwfn *p_hwfn,
                          u16 cqe_pbl_size, void __iomem **pp_prod)
 {
        struct qed_hw_cid_data *p_rx_cid;
-       u64 init_prod_val = 0;
+       u32 init_prod_val = 0;
        u16 abs_l2_queue = 0;
        u8 abs_stats_id = 0;
        int rc;
@@ -618,7 +618,7 @@ qed_sp_eth_rx_queue_start(struct qed_hwfn *p_hwfn,
                                 MSTORM_ETH_PF_PRODS_OFFSET(abs_l2_queue);
 
        /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */
-       __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u64),
+       __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32),
                          (u32 *)(&init_prod_val));
 
        /* Allocate a CID for the queue */
@@ -1664,6 +1664,8 @@ static int qed_fill_eth_dev_info(struct qed_dev *cdev,
        info->num_tc = 1;
 
        if (IS_PF(cdev)) {
+               int max_vf_vlan_filters = 0;
+
                if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
                        for_each_hwfn(cdev, i)
                            info->num_queues +=
@@ -1676,7 +1678,12 @@ static int qed_fill_eth_dev_info(struct qed_dev *cdev,
                        info->num_queues = cdev->num_hwfns;
                }
 
-               info->num_vlan_filters = RESC_NUM(&cdev->hwfns[0], QED_VLAN);
+               if (IS_QED_SRIOV(cdev))
+                       max_vf_vlan_filters = cdev->p_iov_info->total_vfs *
+                                             QED_ETH_VF_NUM_VLAN_FILTERS;
+               info->num_vlan_filters = RESC_NUM(&cdev->hwfns[0], QED_VLAN) -
+                                        max_vf_vlan_filters;
+
                ether_addr_copy(info->port_mac,
                                cdev->hwfns[0].hw_info.hw_mac_addr);
        } else {
index 1f13abb..c7dc34b 100644 (file)
@@ -659,8 +659,13 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev,
        struct qed_sb_cnt_info sb_cnt_info;
        int rc;
        int i;
-       memset(&cdev->int_params, 0, sizeof(struct qed_int_params));
 
+       if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) {
+               DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n");
+               return -EINVAL;
+       }
+
+       memset(&cdev->int_params, 0, sizeof(struct qed_int_params));
        cdev->int_params.in.int_mode = int_mode;
        for_each_hwfn(cdev, i) {
                memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
index 4d161c7..15399da 100644 (file)
@@ -1404,7 +1404,7 @@ static int __qed_iov_spoofchk_set(struct qed_hwfn *p_hwfn,
        params.anti_spoofing_en = val;
 
        rc = qed_sp_vport_update(p_hwfn, &params, QED_SPQ_MODE_EBLOCK, NULL);
-       if (rc) {
+       if (!rc) {
                p_vf->spoof_chk = val;
                p_vf->req_spoofchk_val = p_vf->spoof_chk;
                DP_VERBOSE(p_hwfn, QED_MSG_IOV,
index 9819230..9b780b3 100644 (file)
@@ -388,7 +388,7 @@ int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn,
 
        /* Learn the address of the producer from the response */
        if (pp_prod) {
-               u64 init_prod_val = 0;
+               u32 init_prod_val = 0;
 
                *pp_prod = (u8 __iomem *)p_hwfn->regview + resp->offset;
                DP_VERBOSE(p_hwfn, QED_MSG_IOV,
@@ -396,7 +396,7 @@ int qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn,
                           rx_qid, *pp_prod, resp->offset);
 
                /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */
-               __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u64),
+               __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u32),
                                  (u32 *)&init_prod_val);
        }
 
index 91e7bb0..e4bd02e 100644 (file)
@@ -2064,10 +2064,13 @@ static int qede_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
        }
 
        /* Remove vlan */
-       rc = qede_set_ucast_rx_vlan(edev, QED_FILTER_XCAST_TYPE_DEL, vid);
-       if (rc) {
-               DP_ERR(edev, "Failed to remove VLAN %d\n", vid);
-               return -EINVAL;
+       if (vlan->configured) {
+               rc = qede_set_ucast_rx_vlan(edev, QED_FILTER_XCAST_TYPE_DEL,
+                                           vid);
+               if (rc) {
+                       DP_ERR(edev, "Failed to remove VLAN %d\n", vid);
+                       return -EINVAL;
+               }
        }
 
        qede_del_vlan_from_list(edev, vlan);
@@ -3268,6 +3271,7 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats)
        start.vport_id = 0;
        start.drop_ttl0 = true;
        start.remove_inner_vlan = vlan_removal_en;
+       start.clear_stats = clear_stats;
 
        rc = edev->ops->vport_start(cdev, &start);
 
index 9777e57..f4aa633 100644 (file)
@@ -45,7 +45,6 @@ struct qlcnic_dcb {
 static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb)
 {
        kfree(dcb);
-       dcb = NULL;
 }
 
 static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb)
index fd5d1c9..fd4a8e4 100644 (file)
@@ -1892,7 +1892,6 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                        skb->len += length;
                        skb->data_len += length;
                        skb->truesize += length;
-                       length -= length;
                        ql_update_mac_hdr_len(qdev, ib_mac_rsp,
                                              lbq_desc->p.pg_chunk.va,
                                              &hlen);
index ef668d3..da4c2d8 100644 (file)
@@ -1667,6 +1667,10 @@ static void rtl8139_tx_timeout_task (struct work_struct *work)
        int i;
        u8 tmp8;
 
+       napi_disable(&tp->napi);
+       netif_stop_queue(dev);
+       synchronize_sched();
+
        netdev_dbg(dev, "Transmit timeout, status %02x %04x %04x media %02x\n",
                   RTL_R8(ChipCmd), RTL_R16(IntrStatus),
                   RTL_R16(IntrMask), RTL_R8(MediaStatus));
@@ -1696,10 +1700,10 @@ static void rtl8139_tx_timeout_task (struct work_struct *work)
        spin_unlock_irq(&tp->lock);
 
        /* ...and finally, reset everything */
-       if (netif_running(dev)) {
-               rtl8139_hw_start (dev);
-               netif_wake_queue (dev);
-       }
+       napi_enable(&tp->napi);
+       rtl8139_hw_start(dev);
+       netif_wake_queue(dev);
+
        spin_unlock_bh(&tp->rx_lock);
 }
 
index 0e62d74..e55638c 100644 (file)
@@ -1749,13 +1749,21 @@ static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
 static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &tp->pci_dev->dev;
+
+       pm_runtime_get_noresume(d);
 
        rtl_lock_work(tp);
 
        wol->supported = WAKE_ANY;
-       wol->wolopts = __rtl8169_get_wol(tp);
+       if (pm_runtime_active(d))
+               wol->wolopts = __rtl8169_get_wol(tp);
+       else
+               wol->wolopts = tp->saved_wolopts;
 
        rtl_unlock_work(tp);
+
+       pm_runtime_put_noidle(d);
 }
 
 static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
@@ -1845,6 +1853,9 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
 static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &tp->pci_dev->dev;
+
+       pm_runtime_get_noresume(d);
 
        rtl_lock_work(tp);
 
@@ -1852,12 +1863,17 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
                tp->features |= RTL_FEATURE_WOL;
        else
                tp->features &= ~RTL_FEATURE_WOL;
-       __rtl8169_set_wol(tp, wol->wolopts);
+       if (pm_runtime_active(d))
+               __rtl8169_set_wol(tp, wol->wolopts);
+       else
+               tp->saved_wolopts = wol->wolopts;
 
        rtl_unlock_work(tp);
 
        device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
 
+       pm_runtime_put_noidle(d);
+
        return 0;
 }
 
@@ -2292,11 +2308,17 @@ static void rtl8169_get_ethtool_stats(struct net_device *dev,
                                      struct ethtool_stats *stats, u64 *data)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &tp->pci_dev->dev;
        struct rtl8169_counters *counters = tp->counters;
 
        ASSERT_RTNL();
 
-       rtl8169_update_counters(dev);
+       pm_runtime_get_noresume(d);
+
+       if (pm_runtime_active(d))
+               rtl8169_update_counters(dev);
+
+       pm_runtime_put_noidle(d);
 
        data[0] = le64_to_cpu(counters->tx_packets);
        data[1] = le64_to_cpu(counters->rx_packets);
@@ -4458,6 +4480,7 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
 static int rtl_set_mac_address(struct net_device *dev, void *p)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+       struct device *d = &tp->pci_dev->dev;
        struct sockaddr *addr = p;
 
        if (!is_valid_ether_addr(addr->sa_data))
@@ -4465,7 +4488,12 @@ static int rtl_set_mac_address(struct net_device *dev, void *p)
 
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
-       rtl_rar_set(tp, dev->dev_addr);
+       pm_runtime_get_noresume(d);
+
+       if (pm_runtime_active(d))
+               rtl_rar_set(tp, dev->dev_addr);
+
+       pm_runtime_put_noidle(d);
 
        return 0;
 }
@@ -7868,6 +7896,7 @@ static int rtl8169_runtime_resume(struct device *device)
        struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
+       rtl_rar_set(tp, dev->dev_addr);
 
        if (!tp->TxDescArray)
                return 0;
index 8377d02..1e1cc0f 100644 (file)
@@ -1005,6 +1005,7 @@ static int ravb_phy_init(struct net_device *ndev)
        }
        phydev = of_phy_connect(ndev, pn, ravb_adjust_link, 0,
                                priv->phy_interface);
+       of_node_put(pn);
        if (!phydev) {
                netdev_err(ndev, "failed to connect PHY\n");
                return -ENOENT;
index 7bd910c..799d58d 100644 (file)
@@ -1780,6 +1780,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
                                        sh_eth_adjust_link, 0,
                                        mdp->phy_interface);
 
+               of_node_put(pn);
                if (!phydev)
                        phydev = ERR_PTR(-ENOENT);
        } else {
index edd20c3..bec6963 100644 (file)
@@ -135,7 +135,9 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
 
        np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0);
        if (np_splitter) {
-               if (of_address_to_resource(np_splitter, 0, &res_splitter)) {
+               ret = of_address_to_resource(np_splitter, 0, &res_splitter);
+               of_node_put(np_splitter);
+               if (ret) {
                        dev_info(dev, "Missing emac splitter address\n");
                        return -EINVAL;
                }
@@ -159,14 +161,17 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
                                dev_err(dev,
                                        "%s: ERROR: missing emac splitter address\n",
                                        __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto err_node_put;
                        }
 
                        dwmac->splitter_base =
                            devm_ioremap_resource(dev, &res_splitter);
 
-                       if (IS_ERR(dwmac->splitter_base))
-                               return PTR_ERR(dwmac->splitter_base);
+                       if (IS_ERR(dwmac->splitter_base)) {
+                               ret = PTR_ERR(dwmac->splitter_base);
+                               goto err_node_put;
+                       }
                }
 
                index = of_property_match_string(np_sgmii_adapter, "reg-names",
@@ -178,14 +183,17 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
                                dev_err(dev,
                                        "%s: ERROR: failed mapping adapter\n",
                                        __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto err_node_put;
                        }
 
                        dwmac->pcs.sgmii_adapter_base =
                            devm_ioremap_resource(dev, &res_sgmii_adapter);
 
-                       if (IS_ERR(dwmac->pcs.sgmii_adapter_base))
-                               return PTR_ERR(dwmac->pcs.sgmii_adapter_base);
+                       if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) {
+                               ret = PTR_ERR(dwmac->pcs.sgmii_adapter_base);
+                               goto err_node_put;
+                       }
                }
 
                index = of_property_match_string(np_sgmii_adapter, "reg-names",
@@ -197,22 +205,30 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
                                dev_err(dev,
                                        "%s: ERROR: failed mapping tse control port\n",
                                        __func__);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto err_node_put;
                        }
 
                        dwmac->pcs.tse_pcs_base =
                            devm_ioremap_resource(dev, &res_tse_pcs);
 
-                       if (IS_ERR(dwmac->pcs.tse_pcs_base))
-                               return PTR_ERR(dwmac->pcs.tse_pcs_base);
+                       if (IS_ERR(dwmac->pcs.tse_pcs_base)) {
+                               ret = PTR_ERR(dwmac->pcs.tse_pcs_base);
+                               goto err_node_put;
+                       }
                }
        }
        dwmac->reg_offset = reg_offset;
        dwmac->reg_shift = reg_shift;
        dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
        dwmac->dev = dev;
+       of_node_put(np_sgmii_adapter);
 
        return 0;
+
+err_node_put:
+       of_node_put(np_sgmii_adapter);
+       return ret;
 }
 
 static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac)
index c23ccab..4c8c60a 100644 (file)
@@ -3397,6 +3397,7 @@ int stmmac_dvr_remove(struct device *dev)
        stmmac_set_mac(priv->ioaddr, false);
        netif_carrier_off(ndev);
        unregister_netdev(ndev);
+       of_node_put(priv->plat->phy_node);
        if (priv->stmmac_rst)
                reset_control_assert(priv->stmmac_rst);
        clk_disable_unprepare(priv->pclk);
index f7dfc0a..756bb54 100644 (file)
@@ -113,8 +113,10 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
                return NULL;
 
        axi = kzalloc(sizeof(*axi), GFP_KERNEL);
-       if (!axi)
+       if (!axi) {
+               of_node_put(np);
                return ERR_PTR(-ENOMEM);
+       }
 
        axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
        axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
@@ -127,6 +129,7 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
        of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt);
        of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt);
        of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
+       of_node_put(np);
 
        return axi;
 }
@@ -302,7 +305,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
                                       GFP_KERNEL);
                if (!dma_cfg) {
-                       of_node_put(np);
+                       of_node_put(plat->phy_node);
                        return ERR_PTR(-ENOMEM);
                }
                plat->dma_cfg = dma_cfg;
index 1a93a1f..c51f346 100644 (file)
@@ -2564,19 +2564,17 @@ clean_ndev_ret:
        return ret;
 }
 
-static int cpsw_remove_child_device(struct device *dev, void *c)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-
-       of_device_unregister(pdev);
-
-       return 0;
-}
-
 static int cpsw_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct cpsw_priv *priv = netdev_priv(ndev);
+       int ret;
+
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(&pdev->dev);
+               return ret;
+       }
 
        if (priv->data.dual_emac)
                unregister_netdev(cpsw_get_slave_ndev(priv, 1));
@@ -2584,8 +2582,9 @@ static int cpsw_remove(struct platform_device *pdev)
 
        cpsw_ale_destroy(priv->ale);
        cpdma_ctlr_destroy(priv->dma);
+       of_platform_depopulate(&pdev->dev);
+       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       device_for_each_child(&pdev->dev, NULL, cpsw_remove_child_device);
        if (priv->data.dual_emac)
                free_netdev(cpsw_get_slave_ndev(priv, 1));
        free_netdev(ndev);
index 73638f7..19e5f32 100644 (file)
@@ -357,13 +357,11 @@ EXPORT_SYMBOL_GPL(cpdma_ctlr_stop);
 
 int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
 {
-       unsigned long flags;
        int ret = 0, i;
 
        if (!ctlr)
                return -EINVAL;
 
-       spin_lock_irqsave(&ctlr->lock, flags);
        if (ctlr->state != CPDMA_STATE_IDLE)
                cpdma_ctlr_stop(ctlr);
 
@@ -371,7 +369,6 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
                cpdma_chan_destroy(ctlr->channels[i]);
 
        cpdma_desc_pool_destroy(ctlr->pool);
-       spin_unlock_irqrestore(&ctlr->lock, flags);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy);
index 6e305a8..727a79f 100644 (file)
@@ -1964,6 +1964,7 @@ static int davinci_emac_remove(struct platform_device *pdev)
        cpdma_ctlr_destroy(priv->dma);
 
        unregister_netdev(ndev);
+       of_node_put(priv->phy_node);
        pm_runtime_disable(&pdev->dev);
        free_netdev(ndev);
 
index 2d0beb1..d13e6e1 100644 (file)
@@ -344,7 +344,6 @@ static void free_rxsa(struct rcu_head *head)
 
        crypto_free_aead(sa->key.tfm);
        free_percpu(sa->stats);
-       macsec_rxsc_put(sa->sc);
        kfree(sa);
 }
 
@@ -863,6 +862,7 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err)
        struct net_device *dev = skb->dev;
        struct macsec_dev *macsec = macsec_priv(dev);
        struct macsec_rx_sa *rx_sa = macsec_skb_cb(skb)->rx_sa;
+       struct macsec_rx_sc *rx_sc = rx_sa->sc;
        int len, ret;
        u32 pn;
 
@@ -891,6 +891,7 @@ static void macsec_decrypt_done(struct crypto_async_request *base, int err)
 
 out:
        macsec_rxsa_put(rx_sa);
+       macsec_rxsc_put(rx_sc);
        dev_put(dev);
 }
 
@@ -1106,6 +1107,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
 
        list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
                struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci);
+               sc = sc ? macsec_rxsc_get(sc) : NULL;
 
                if (sc) {
                        secy = &macsec->secy;
@@ -1180,8 +1182,10 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
 
        if (IS_ERR(skb)) {
                /* the decrypt callback needs the reference */
-               if (PTR_ERR(skb) != -EINPROGRESS)
+               if (PTR_ERR(skb) != -EINPROGRESS) {
                        macsec_rxsa_put(rx_sa);
+                       macsec_rxsc_put(rx_sc);
+               }
                rcu_read_unlock();
                *pskb = NULL;
                return RX_HANDLER_CONSUMED;
@@ -1197,6 +1201,7 @@ deliver:
 
        if (rx_sa)
                macsec_rxsa_put(rx_sa);
+       macsec_rxsc_put(rx_sc);
 
        ret = gro_cells_receive(&macsec->gro_cells, skb);
        if (ret == NET_RX_SUCCESS)
@@ -1212,6 +1217,7 @@ deliver:
 drop:
        macsec_rxsa_put(rx_sa);
 drop_nosa:
+       macsec_rxsc_put(rx_sc);
        rcu_read_unlock();
 drop_direct:
        kfree_skb(skb);
@@ -1646,7 +1652,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
        rx_sc = get_rxsc_from_nl(genl_info_net(info), attrs, tb_rxsc, &dev, &secy);
-       if (IS_ERR(rx_sc) || !macsec_rxsc_get(rx_sc)) {
+       if (IS_ERR(rx_sc)) {
                rtnl_unlock();
                return PTR_ERR(rx_sc);
        }
@@ -3173,6 +3179,8 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
        if (err < 0)
                return err;
 
+       dev_hold(real_dev);
+
        /* need to be already registered so that ->init has run and
         * the MAC addr is set
         */
@@ -3201,8 +3209,6 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
 
        macsec_generation++;
 
-       dev_hold(real_dev);
-
        return 0;
 
 del_dev:
index d94a978..7756748 100644 (file)
@@ -345,10 +345,8 @@ static int xgene_mdio_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        csr_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(csr_base)) {
-               dev_err(dev, "Unable to retrieve mac CSR region\n");
+       if (IS_ERR(csr_base))
                return PTR_ERR(csr_base);
-       }
        pdata->mac_csr_addr = csr_base;
        pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET;
        pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET;
index 059f13b..1882d98 100644 (file)
@@ -869,7 +869,7 @@ static struct phy_driver ksphy_driver[] = {
 }, {
        .phy_id         = PHY_ID_KSZ8001,
        .name           = "Micrel KSZ8001 or KS8721",
-       .phy_id_mask    = 0x00ffffff,
+       .phy_id_mask    = 0x00fffffc,
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8041_type,
@@ -993,7 +993,7 @@ MODULE_LICENSE("GPL");
 static struct mdio_device_id __maybe_unused micrel_tbl[] = {
        { PHY_ID_KSZ9021, 0x000ffffe },
        { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK },
-       { PHY_ID_KSZ8001, 0x00ffffff },
+       { PHY_ID_KSZ8001, 0x00fffffc },
        { PHY_ID_KS8737, MICREL_PHY_ID_MASK },
        { PHY_ID_KSZ8021, 0x00ffffff },
        { PHY_ID_KSZ8031, 0x00ffffff },
index 2fc50ec..6f04445 100644 (file)
@@ -862,7 +862,7 @@ static int uhdlc_suspend(struct device *dev)
 static int uhdlc_resume(struct device *dev)
 {
        struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
-       struct ucc_tdm *utdm = priv->utdm;
+       struct ucc_tdm *utdm;
        struct ucc_tdm_info *ut_info;
        struct ucc_fast __iomem *uf_regs;
        struct ucc_fast_private *uccf;
@@ -877,6 +877,7 @@ static int uhdlc_resume(struct device *dev)
        if (!netif_running(priv->ndev))
                return 0;
 
+       utdm = priv->utdm;
        ut_info = priv->ut_info;
        uf_info = &ut_info->uf_info;
        uf_regs = priv->uf_regs;
index 355e1ae..8f0fd41 100644 (file)
@@ -139,11 +139,11 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar)
                    ar->id.subsystem_vendor, ar->id.subsystem_device);
 
        ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n",
-                   config_enabled(CONFIG_ATH10K_DEBUG),
-                   config_enabled(CONFIG_ATH10K_DEBUGFS),
-                   config_enabled(CONFIG_ATH10K_TRACING),
-                   config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
-                   config_enabled(CONFIG_NL80211_TESTMODE));
+                   IS_ENABLED(CONFIG_ATH10K_DEBUG),
+                   IS_ENABLED(CONFIG_ATH10K_DEBUGFS),
+                   IS_ENABLED(CONFIG_ATH10K_TRACING),
+                   IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED),
+                   IS_ENABLED(CONFIG_NL80211_TESTMODE));
 
        firmware = ar->normal_mode_fw.fw_file.firmware;
        if (firmware)
@@ -2424,7 +2424,7 @@ int ath10k_debug_register(struct ath10k *ar)
        debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
                            ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
 
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) {
                debugfs_create_file("dfs_simulate_radar", S_IWUSR,
                                    ar->debug.debugfs_phy, ar,
                                    &fops_simulate_radar);
index fb8e38d..0bbd0a0 100644 (file)
@@ -3039,7 +3039,7 @@ static void ath10k_regd_update(struct ath10k *ar)
 
        regpair = ar->ath_common.regulatory.regpair;
 
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
                nl_dfs_reg = ar->dfs_detector->region;
                wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg);
        } else {
@@ -3068,7 +3068,7 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
 
        ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
 
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
                ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
                           request->dfs_region);
                result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
@@ -7955,7 +7955,7 @@ int ath10k_mac_register(struct ath10k *ar)
        if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
                ar->hw->netdev_features = NETIF_F_HW_CSUM;
 
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) {
                /* Init ath dfs pattern detector */
                ar->ath_common.debug_mask = ATH_DBG_DFS;
                ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common,
@@ -8003,7 +8003,7 @@ err_unregister:
        ieee80211_unregister_hw(ar->hw);
 
 err_dfs_detector_exit:
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
                ar->dfs_detector->exit(ar->dfs_detector);
 
 err_free:
@@ -8018,7 +8018,7 @@ void ath10k_mac_unregister(struct ath10k *ar)
 {
        ieee80211_unregister_hw(ar->hw);
 
-       if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
+       if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector)
                ar->dfs_detector->exit(ar->dfs_detector);
 
        kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
index 169cd2e..d246288 100644 (file)
@@ -3704,7 +3704,7 @@ void ath10k_wmi_event_dfs(struct ath10k *ar,
                   phyerr->tsf_timestamp, tsf, buf_len);
 
        /* Skip event if DFS disabled */
-       if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED))
+       if (!IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED))
                return;
 
        ATH10K_DFS_STAT_INC(ar, pulses_total);
index 4ad6284..72e2ec6 100644 (file)
@@ -3881,7 +3881,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                                          BIT(NL80211_IFTYPE_P2P_CLIENT);
        }
 
-       if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) &&
+       if (IS_ENABLED(CONFIG_ATH6KL_REGDOMAIN) &&
            test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
                wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
                ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
index a876271..e2512d5 100644 (file)
@@ -731,7 +731,7 @@ void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
        struct ath_hw *ah = spec_priv->ah;
        u32 rxfilter;
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return;
 
        if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
@@ -806,7 +806,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
        char buf[32];
        ssize_t len;
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return -EOPNOTSUPP;
 
        len = min(count, sizeof(buf) - 1);
@@ -1072,7 +1072,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = {
 
 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
 {
-       if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
+       if (IS_ENABLED(CONFIG_ATH9K_DEBUGFS)) {
                relay_close(spec_priv->rfs_chan_spec_scan);
                spec_priv->rfs_chan_spec_scan = NULL;
        }
index edc74fc..cfa3fe8 100644 (file)
@@ -843,7 +843,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                               NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
                               NL80211_FEATURE_P2P_GO_CTWIN;
 
-       if (!config_enabled(CONFIG_ATH9K_TX99)) {
+       if (!IS_ENABLED(CONFIG_ATH9K_TX99)) {
                hw->wiphy->interface_modes =
                        BIT(NL80211_IFTYPE_P2P_GO) |
                        BIT(NL80211_IFTYPE_P2P_CLIENT) |
index 7594650..a394622 100644 (file)
@@ -1250,7 +1250,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&sc->mutex);
 
-       if (config_enabled(CONFIG_ATH9K_TX99)) {
+       if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
                if (sc->cur_chan->nvifs >= 1) {
                        mutex_unlock(&sc->mutex);
                        return -EOPNOTSUPP;
@@ -1300,7 +1300,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&sc->mutex);
 
-       if (config_enabled(CONFIG_ATH9K_TX99)) {
+       if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
                mutex_unlock(&sc->mutex);
                return -EOPNOTSUPP;
        }
@@ -1360,7 +1360,7 @@ static void ath9k_enable_ps(struct ath_softc *sc)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return;
 
        sc->ps_enabled = true;
@@ -1379,7 +1379,7 @@ static void ath9k_disable_ps(struct ath_softc *sc)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return;
 
        sc->ps_enabled = false;
@@ -1953,7 +1953,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        struct ieee80211_channel *chan;
        int pos;
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return -EOPNOTSUPP;
 
        spin_lock_bh(&common->cc_lock);
@@ -2003,7 +2003,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return;
 
        mutex_lock(&sc->mutex);
index 32160fc..6697342 100644 (file)
@@ -377,7 +377,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        u32 rfilt;
 
-       if (config_enabled(CONFIG_ATH9K_TX99))
+       if (IS_ENABLED(CONFIG_ATH9K_TX99))
                return 0;
 
        rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
index 2303ef9..2f8136d 100644 (file)
@@ -352,7 +352,7 @@ dfs_pattern_detector_init(struct ath_common *common,
 {
        struct dfs_pattern_detector *dpd;
 
-       if (!config_enabled(CONFIG_CFG80211_CERTIFICATION_ONUS))
+       if (!IS_ENABLED(CONFIG_CFG80211_CERTIFICATION_ONUS))
                return NULL;
 
        dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);
index 7e15ed9..f850603 100644 (file)
@@ -116,7 +116,7 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
 
 static bool dynamic_country_user_possible(struct ath_regulatory *reg)
 {
-       if (config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
+       if (IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
                return true;
 
        switch (reg->country_code) {
@@ -188,7 +188,7 @@ static bool dynamic_country_user_possible(struct ath_regulatory *reg)
 
 static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)
 {
-       if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
+       if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))
                return false;
        if (!dynamic_country_user_possible(reg))
                return false;
index 40d04ef..0d5c29a 100644 (file)
@@ -551,13 +551,15 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
                                 size_t count, loff_t *offp)
 {
        struct intel_ntb_dev *ndev;
+       struct pci_dev *pdev;
        void __iomem *mmio;
        char *buf;
        size_t buf_size;
        ssize_t ret, off;
-       union { u64 v64; u32 v32; u16 v16; } u;
+       union { u64 v64; u32 v32; u16 v16; u8 v8; } u;
 
        ndev = filp->private_data;
+       pdev = ndev_pdev(ndev);
        mmio = ndev->self_mmio;
 
        buf_size = min(count, 0x800ul);
@@ -631,6 +633,41 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
        off += scnprintf(buf + off, buf_size - off,
                         "Doorbell Bell -\t\t%#llx\n", u.v64);
 
+       off += scnprintf(buf + off, buf_size - off,
+                        "\nNTB Window Size:\n");
+
+       pci_read_config_byte(pdev, XEON_PBAR23SZ_OFFSET, &u.v8);
+       off += scnprintf(buf + off, buf_size - off,
+                        "PBAR23SZ %hhu\n", u.v8);
+       if (!ndev->bar4_split) {
+               pci_read_config_byte(pdev, XEON_PBAR45SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "PBAR45SZ %hhu\n", u.v8);
+       } else {
+               pci_read_config_byte(pdev, XEON_PBAR4SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "PBAR4SZ %hhu\n", u.v8);
+               pci_read_config_byte(pdev, XEON_PBAR5SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "PBAR5SZ %hhu\n", u.v8);
+       }
+
+       pci_read_config_byte(pdev, XEON_SBAR23SZ_OFFSET, &u.v8);
+       off += scnprintf(buf + off, buf_size - off,
+                        "SBAR23SZ %hhu\n", u.v8);
+       if (!ndev->bar4_split) {
+               pci_read_config_byte(pdev, XEON_SBAR45SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "SBAR45SZ %hhu\n", u.v8);
+       } else {
+               pci_read_config_byte(pdev, XEON_SBAR4SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "SBAR4SZ %hhu\n", u.v8);
+               pci_read_config_byte(pdev, XEON_SBAR5SZ_OFFSET, &u.v8);
+               off += scnprintf(buf + off, buf_size - off,
+                                "SBAR5SZ %hhu\n", u.v8);
+       }
+
        off += scnprintf(buf + off, buf_size - off,
                         "\nNTB Incoming XLAT:\n");
 
@@ -669,7 +706,7 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
                                 "LMT45 -\t\t\t%#018llx\n", u.v64);
        }
 
-       if (pdev_is_xeon(ndev->ntb.pdev)) {
+       if (pdev_is_xeon(pdev)) {
                if (ntb_topo_is_b2b(ndev->ntb.topo)) {
                        off += scnprintf(buf + off, buf_size - off,
                                         "\nNTB Outgoing B2B XLAT:\n");
@@ -750,22 +787,22 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf,
                off += scnprintf(buf + off, buf_size - off,
                                 "\nXEON NTB Hardware Errors:\n");
 
-               if (!pci_read_config_word(ndev->ntb.pdev,
+               if (!pci_read_config_word(pdev,
                                          XEON_DEVSTS_OFFSET, &u.v16))
                        off += scnprintf(buf + off, buf_size - off,
                                         "DEVSTS -\t\t%#06x\n", u.v16);
 
-               if (!pci_read_config_word(ndev->ntb.pdev,
+               if (!pci_read_config_word(pdev,
                                          XEON_LINK_STATUS_OFFSET, &u.v16))
                        off += scnprintf(buf + off, buf_size - off,
                                         "LNKSTS -\t\t%#06x\n", u.v16);
 
-               if (!pci_read_config_dword(ndev->ntb.pdev,
+               if (!pci_read_config_dword(pdev,
                                           XEON_UNCERRSTS_OFFSET, &u.v32))
                        off += scnprintf(buf + off, buf_size - off,
                                         "UNCERRSTS -\t\t%#06x\n", u.v32);
 
-               if (!pci_read_config_dword(ndev->ntb.pdev,
+               if (!pci_read_config_dword(pdev,
                                           XEON_CORERRSTS_OFFSET, &u.v32))
                        off += scnprintf(buf + off, buf_size - off,
                                         "CORERRSTS -\t\t%#06x\n", u.v32);
index 2ef9d91..d5c5894 100644 (file)
@@ -153,6 +153,7 @@ struct ntb_transport_qp {
        unsigned int rx_index;
        unsigned int rx_max_entry;
        unsigned int rx_max_frame;
+       unsigned int rx_alloc_entry;
        dma_cookie_t last_cookie;
        struct tasklet_struct rxc_db_work;
 
@@ -480,7 +481,9 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "rx_index - \t%u\n", qp->rx_index);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "rx_max_entry - \t%u\n\n", qp->rx_max_entry);
+                              "rx_max_entry - \t%u\n", qp->rx_max_entry);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry);
 
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "tx_bytes - \t%llu\n", qp->tx_bytes);
@@ -597,9 +600,12 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
 {
        struct ntb_transport_qp *qp = &nt->qp_vec[qp_num];
        struct ntb_transport_mw *mw;
+       struct ntb_dev *ndev = nt->ndev;
+       struct ntb_queue_entry *entry;
        unsigned int rx_size, num_qps_mw;
        unsigned int mw_num, mw_count, qp_count;
        unsigned int i;
+       int node;
 
        mw_count = nt->mw_count;
        qp_count = nt->qp_count;
@@ -626,6 +632,23 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
        qp->rx_max_entry = rx_size / qp->rx_max_frame;
        qp->rx_index = 0;
 
+       /*
+        * Checking to see if we have more entries than the default.
+        * We should add additional entries if that is the case so we
+        * can be in sync with the transport frames.
+        */
+       node = dev_to_node(&ndev->dev);
+       for (i = qp->rx_alloc_entry; i < qp->rx_max_entry; i++) {
+               entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
+               if (!entry)
+                       return -ENOMEM;
+
+               entry->qp = qp;
+               ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
+                            &qp->rx_free_q);
+               qp->rx_alloc_entry++;
+       }
+
        qp->remote_rx_info->entry = qp->rx_max_entry - 1;
 
        /* setup the hdr offsets with 0's */
@@ -1037,6 +1060,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
        int node;
        int rc, i;
 
+       mw_count = ntb_mw_count(ndev);
+       if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) {
+               dev_err(&ndev->dev, "Not enough scratch pad registers for %s",
+                       NTB_TRANSPORT_NAME);
+               return -EIO;
+       }
+
        if (ntb_db_is_unsafe(ndev))
                dev_dbg(&ndev->dev,
                        "doorbell is unsafe, proceed anyway...\n");
@@ -1052,8 +1082,6 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
 
        nt->ndev = ndev;
 
-       mw_count = ntb_mw_count(ndev);
-
        nt->mw_count = mw_count;
 
        nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec),
@@ -1722,8 +1750,9 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
                ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
                             &qp->rx_free_q);
        }
+       qp->rx_alloc_entry = NTB_QP_DEF_NUM_ENTRIES;
 
-       for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
+       for (i = 0; i < qp->tx_max_entry; i++) {
                entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
                if (!entry)
                        goto err2;
@@ -1744,6 +1773,7 @@ err2:
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
 err1:
+       qp->rx_alloc_entry = 0;
        while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
                kfree(entry);
        if (qp->tx_dma_chan)
index 8dfce9c..6a50f20 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/delay.h>
 #include <linux/sizes.h>
 #include <linux/ntb.h>
+#include <linux/mutex.h>
 
 #define DRIVER_NAME            "ntb_perf"
 #define DRIVER_DESCRIPTION     "PCIe NTB Performance Measurement Tool"
@@ -83,6 +84,10 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
 
 static struct dentry *perf_debugfs_dir;
 
+static unsigned long max_mw_size;
+module_param(max_mw_size, ulong, 0644);
+MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows");
+
 static unsigned int seg_order = 19; /* 512K */
 module_param(seg_order, uint, 0644);
 MODULE_PARM_DESC(seg_order, "size order [n^2] of buffer segment for testing");
@@ -117,6 +122,10 @@ struct pthr_ctx {
        int                     dma_prep_err;
        int                     src_idx;
        void                    *srcs[MAX_SRCS];
+       wait_queue_head_t       *wq;
+       int                     status;
+       u64                     copied;
+       u64                     diff_us;
 };
 
 struct perf_ctx {
@@ -124,23 +133,23 @@ struct perf_ctx {
        spinlock_t              db_lock;
        struct perf_mw          mw;
        bool                    link_is_up;
-       struct work_struct      link_cleanup;
        struct delayed_work     link_work;
+       wait_queue_head_t       link_wq;
        struct dentry           *debugfs_node_dir;
        struct dentry           *debugfs_run;
        struct dentry           *debugfs_threads;
        u8                      perf_threads;
-       bool                    run;
+       /* mutex ensures only one set of threads run at once */
+       struct mutex            run_mutex;
        struct pthr_ctx         pthr_ctx[MAX_THREADS];
        atomic_t                tsync;
+       atomic_t                tdone;
 };
 
 enum {
        VERSION = 0,
        MW_SZ_HIGH,
        MW_SZ_LOW,
-       SPAD_MSG,
-       SPAD_ACK,
        MAX_SPAD
 };
 
@@ -148,10 +157,16 @@ static void perf_link_event(void *ctx)
 {
        struct perf_ctx *perf = ctx;
 
-       if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1)
+       if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) {
                schedule_delayed_work(&perf->link_work, 2*HZ);
-       else
-               schedule_work(&perf->link_cleanup);
+       } else {
+               dev_dbg(&perf->ntb->pdev->dev, "link down\n");
+
+               if (!perf->link_is_up)
+                       cancel_delayed_work_sync(&perf->link_work);
+
+               perf->link_is_up = false;
+       }
 }
 
 static void perf_db_event(void *ctx, int vec)
@@ -271,6 +286,7 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
        char __iomem *tmp = dst;
        u64 perf, diff_us;
        ktime_t kstart, kstop, kdiff;
+       unsigned long last_sleep = jiffies;
 
        chunks = div64_u64(win_size, buf_size);
        total_chunks = div64_u64(total, buf_size);
@@ -286,30 +302,40 @@ static int perf_move_data(struct pthr_ctx *pctx, char __iomem *dst, char *src,
                } else
                        tmp += buf_size;
 
-               /* Probably should schedule every 4GB to prevent soft hang. */
-               if (((copied % SZ_4G) == 0) && !use_dma) {
+               /* Probably should schedule every 5s to prevent soft hang. */
+               if (unlikely((jiffies - last_sleep) > 5 * HZ)) {
+                       last_sleep = jiffies;
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(1);
                }
+
+               if (unlikely(kthread_should_stop()))
+                       break;
        }
 
        if (use_dma) {
-               pr_info("%s: All DMA descriptors submitted\n", current->comm);
-               while (atomic_read(&pctx->dma_sync) != 0)
+               pr_debug("%s: All DMA descriptors submitted\n", current->comm);
+               while (atomic_read(&pctx->dma_sync) != 0) {
+                       if (kthread_should_stop())
+                               break;
                        msleep(20);
+               }
        }
 
        kstop = ktime_get();
        kdiff = ktime_sub(kstop, kstart);
        diff_us = ktime_to_us(kdiff);
 
-       pr_info("%s: copied %llu bytes\n", current->comm, copied);
+       pr_debug("%s: copied %llu bytes\n", current->comm, copied);
 
-       pr_info("%s: lasted %llu usecs\n", current->comm, diff_us);
+       pr_debug("%s: lasted %llu usecs\n", current->comm, diff_us);
 
        perf = div64_u64(copied, diff_us);
 
-       pr_info("%s: MBytes/s: %llu\n", current->comm, perf);
+       pr_debug("%s: MBytes/s: %llu\n", current->comm, perf);
+
+       pctx->copied = copied;
+       pctx->diff_us = diff_us;
 
        return 0;
 }
@@ -331,7 +357,7 @@ static int ntb_perf_thread(void *data)
        int rc, node, i;
        struct dma_chan *dma_chan = NULL;
 
-       pr_info("kthread %s starting...\n", current->comm);
+       pr_debug("kthread %s starting...\n", current->comm);
 
        node = dev_to_node(&pdev->dev);
 
@@ -389,7 +415,10 @@ static int ntb_perf_thread(void *data)
                pctx->srcs[i] = NULL;
        }
 
-       return 0;
+       atomic_inc(&perf->tdone);
+       wake_up(pctx->wq);
+       rc = 0;
+       goto done;
 
 err:
        for (i = 0; i < MAX_SRCS; i++) {
@@ -402,6 +431,16 @@ err:
                pctx->dma_chan = NULL;
        }
 
+done:
+       /* Wait until we are told to stop */
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (kthread_should_stop())
+                       break;
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+
        return rc;
 }
 
@@ -472,6 +511,10 @@ static void perf_link_work(struct work_struct *work)
        dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__);
 
        size = perf->mw.phys_size;
+
+       if (max_mw_size && size > max_mw_size)
+               size = max_mw_size;
+
        ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size));
        ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size));
        ntb_peer_spad_write(ndev, VERSION, PERF_VERSION);
@@ -496,6 +539,7 @@ static void perf_link_work(struct work_struct *work)
                goto out1;
 
        perf->link_is_up = true;
+       wake_up(&perf->link_wq);
 
        return;
 
@@ -508,18 +552,6 @@ out:
                                      msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT));
 }
 
-static void perf_link_cleanup(struct work_struct *work)
-{
-       struct perf_ctx *perf = container_of(work,
-                                            struct perf_ctx,
-                                            link_cleanup);
-
-       dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__);
-
-       if (!perf->link_is_up)
-               cancel_delayed_work_sync(&perf->link_work);
-}
-
 static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
 {
        struct perf_mw *mw;
@@ -544,16 +576,44 @@ static ssize_t debugfs_run_read(struct file *filp, char __user *ubuf,
 {
        struct perf_ctx *perf = filp->private_data;
        char *buf;
-       ssize_t ret, out_offset;
+       ssize_t ret, out_off = 0;
+       struct pthr_ctx *pctx;
+       int i;
+       u64 rate;
 
        if (!perf)
                return 0;
 
-       buf = kmalloc(64, GFP_KERNEL);
+       buf = kmalloc(1024, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
-       out_offset = snprintf(buf, 64, "%d\n", perf->run);
-       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+
+       if (mutex_is_locked(&perf->run_mutex)) {
+               out_off = snprintf(buf, 64, "running\n");
+               goto read_from_buf;
+       }
+
+       for (i = 0; i < MAX_THREADS; i++) {
+               pctx = &perf->pthr_ctx[i];
+
+               if (pctx->status == -ENODATA)
+                       break;
+
+               if (pctx->status) {
+                       out_off += snprintf(buf + out_off, 1024 - out_off,
+                                           "%d: error %d\n", i,
+                                           pctx->status);
+                       continue;
+               }
+
+               rate = div64_u64(pctx->copied, pctx->diff_us);
+               out_off += snprintf(buf + out_off, 1024 - out_off,
+                       "%d: copied %llu bytes in %llu usecs, %llu MBytes/s\n",
+                       i, pctx->copied, pctx->diff_us, rate);
+       }
+
+read_from_buf:
+       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_off);
        kfree(buf);
 
        return ret;
@@ -564,80 +624,90 @@ static void threads_cleanup(struct perf_ctx *perf)
        struct pthr_ctx *pctx;
        int i;
 
-       perf->run = false;
        for (i = 0; i < MAX_THREADS; i++) {
                pctx = &perf->pthr_ctx[i];
                if (pctx->thread) {
-                       kthread_stop(pctx->thread);
+                       pctx->status = kthread_stop(pctx->thread);
                        pctx->thread = NULL;
                }
        }
 }
 
+static void perf_clear_thread_status(struct perf_ctx *perf)
+{
+       int i;
+
+       for (i = 0; i < MAX_THREADS; i++)
+               perf->pthr_ctx[i].status = -ENODATA;
+}
+
 static ssize_t debugfs_run_write(struct file *filp, const char __user *ubuf,
                                 size_t count, loff_t *offp)
 {
        struct perf_ctx *perf = filp->private_data;
        int node, i;
+       DECLARE_WAIT_QUEUE_HEAD(wq);
 
-       if (!perf->link_is_up)
-               return 0;
+       if (wait_event_interruptible(perf->link_wq, perf->link_is_up))
+               return -ENOLINK;
 
        if (perf->perf_threads == 0)
-               return 0;
+               return -EINVAL;
 
-       if (atomic_read(&perf->tsync) == 0)
-               perf->run = false;
+       if (!mutex_trylock(&perf->run_mutex))
+               return -EBUSY;
 
-       if (perf->run)
-               threads_cleanup(perf);
-       else {
-               perf->run = true;
+       perf_clear_thread_status(perf);
 
-               if (perf->perf_threads > MAX_THREADS) {
-                       perf->perf_threads = MAX_THREADS;
-                       pr_info("Reset total threads to: %u\n", MAX_THREADS);
-               }
+       if (perf->perf_threads > MAX_THREADS) {
+               perf->perf_threads = MAX_THREADS;
+               pr_info("Reset total threads to: %u\n", MAX_THREADS);
+       }
 
-               /* no greater than 1M */
-               if (seg_order > MAX_SEG_ORDER) {
-                       seg_order = MAX_SEG_ORDER;
-                       pr_info("Fix seg_order to %u\n", seg_order);
-               }
+       /* no greater than 1M */
+       if (seg_order > MAX_SEG_ORDER) {
+               seg_order = MAX_SEG_ORDER;
+               pr_info("Fix seg_order to %u\n", seg_order);
+       }
 
-               if (run_order < seg_order) {
-                       run_order = seg_order;
-                       pr_info("Fix run_order to %u\n", run_order);
-               }
+       if (run_order < seg_order) {
+               run_order = seg_order;
+               pr_info("Fix run_order to %u\n", run_order);
+       }
 
-               node = dev_to_node(&perf->ntb->pdev->dev);
-               /* launch kernel thread */
-               for (i = 0; i < perf->perf_threads; i++) {
-                       struct pthr_ctx *pctx;
-
-                       pctx = &perf->pthr_ctx[i];
-                       atomic_set(&pctx->dma_sync, 0);
-                       pctx->perf = perf;
-                       pctx->thread =
-                               kthread_create_on_node(ntb_perf_thread,
-                                                      (void *)pctx,
-                                                      node, "ntb_perf %d", i);
-                       if (IS_ERR(pctx->thread)) {
-                               pctx->thread = NULL;
-                               goto err;
-                       } else
-                               wake_up_process(pctx->thread);
-
-                       if (perf->run == false)
-                               return -ENXIO;
-               }
+       node = dev_to_node(&perf->ntb->pdev->dev);
+       atomic_set(&perf->tdone, 0);
 
+       /* launch kernel thread */
+       for (i = 0; i < perf->perf_threads; i++) {
+               struct pthr_ctx *pctx;
+
+               pctx = &perf->pthr_ctx[i];
+               atomic_set(&pctx->dma_sync, 0);
+               pctx->perf = perf;
+               pctx->wq = &wq;
+               pctx->thread =
+                       kthread_create_on_node(ntb_perf_thread,
+                                              (void *)pctx,
+                                              node, "ntb_perf %d", i);
+               if (IS_ERR(pctx->thread)) {
+                       pctx->thread = NULL;
+                       goto err;
+               } else {
+                       wake_up_process(pctx->thread);
+               }
        }
 
+       wait_event_interruptible(wq,
+               atomic_read(&perf->tdone) == perf->perf_threads);
+
+       threads_cleanup(perf);
+       mutex_unlock(&perf->run_mutex);
        return count;
 
 err:
        threads_cleanup(perf);
+       mutex_unlock(&perf->run_mutex);
        return -ENXIO;
 }
 
@@ -688,6 +758,12 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
        int node;
        int rc = 0;
 
+       if (ntb_spad_count(ntb) < MAX_SPAD) {
+               dev_err(&ntb->dev, "Not enough scratch pad registers for %s",
+                       DRIVER_NAME);
+               return -EIO;
+       }
+
        node = dev_to_node(&pdev->dev);
 
        perf = kzalloc_node(sizeof(*perf), GFP_KERNEL, node);
@@ -699,11 +775,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
        perf->ntb = ntb;
        perf->perf_threads = 1;
        atomic_set(&perf->tsync, 0);
-       perf->run = false;
+       mutex_init(&perf->run_mutex);
        spin_lock_init(&perf->db_lock);
        perf_setup_mw(ntb, perf);
+       init_waitqueue_head(&perf->link_wq);
        INIT_DELAYED_WORK(&perf->link_work, perf_link_work);
-       INIT_WORK(&perf->link_cleanup, perf_link_cleanup);
 
        rc = ntb_set_ctx(ntb, perf, &perf_ops);
        if (rc)
@@ -717,11 +793,12 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
        if (rc)
                goto err_ctx;
 
+       perf_clear_thread_status(perf);
+
        return 0;
 
 err_ctx:
        cancel_delayed_work_sync(&perf->link_work);
-       cancel_work_sync(&perf->link_cleanup);
        kfree(perf);
 err_perf:
        return rc;
@@ -734,8 +811,9 @@ static void perf_remove(struct ntb_client *client, struct ntb_dev *ntb)
 
        dev_dbg(&perf->ntb->dev, "%s called\n", __func__);
 
+       mutex_lock(&perf->run_mutex);
+
        cancel_delayed_work_sync(&perf->link_work);
-       cancel_work_sync(&perf->link_cleanup);
 
        ntb_clear_ctx(ntb);
        ntb_link_disable(ntb);
index fe16005..7d31179 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/debugfs.h>
 
 #include <linux/ntb.h>
 
@@ -96,8 +97,13 @@ struct pp_ctx {
        spinlock_t                      db_lock;
        struct timer_list               db_timer;
        unsigned long                   db_delay;
+       struct dentry                   *debugfs_node_dir;
+       struct dentry                   *debugfs_count;
+       atomic_t                        count;
 };
 
+static struct dentry *pp_debugfs_dir;
+
 static void pp_ping(unsigned long ctx)
 {
        struct pp_ctx *pp = (void *)ctx;
@@ -171,10 +177,32 @@ static void pp_db_event(void *ctx, int vec)
                dev_dbg(&pp->ntb->dev,
                        "Pong vec %d bits %#llx\n",
                        vec, db_bits);
+               atomic_inc(&pp->count);
        }
        spin_unlock_irqrestore(&pp->db_lock, irqflags);
 }
 
+static int pp_debugfs_setup(struct pp_ctx *pp)
+{
+       struct pci_dev *pdev = pp->ntb->pdev;
+
+       if (!pp_debugfs_dir)
+               return -ENODEV;
+
+       pp->debugfs_node_dir = debugfs_create_dir(pci_name(pdev),
+                                                 pp_debugfs_dir);
+       if (!pp->debugfs_node_dir)
+               return -ENODEV;
+
+       pp->debugfs_count = debugfs_create_atomic_t("count", S_IRUSR | S_IWUSR,
+                                                   pp->debugfs_node_dir,
+                                                   &pp->count);
+       if (!pp->debugfs_count)
+               return -ENODEV;
+
+       return 0;
+}
+
 static const struct ntb_ctx_ops pp_ops = {
        .link_event = pp_link_event,
        .db_event = pp_db_event,
@@ -210,6 +238,7 @@ static int pp_probe(struct ntb_client *client,
 
        pp->ntb = ntb;
        pp->db_bits = 0;
+       atomic_set(&pp->count, 0);
        spin_lock_init(&pp->db_lock);
        setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp);
        pp->db_delay = msecs_to_jiffies(delay_ms);
@@ -218,6 +247,10 @@ static int pp_probe(struct ntb_client *client,
        if (rc)
                goto err_ctx;
 
+       rc = pp_debugfs_setup(pp);
+       if (rc)
+               goto err_ctx;
+
        ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
        ntb_link_event(ntb);
 
@@ -234,6 +267,8 @@ static void pp_remove(struct ntb_client *client,
 {
        struct pp_ctx *pp = ntb->ctx;
 
+       debugfs_remove_recursive(pp->debugfs_node_dir);
+
        ntb_clear_ctx(ntb);
        del_timer_sync(&pp->db_timer);
        ntb_link_disable(ntb);
@@ -247,4 +282,29 @@ static struct ntb_client pp_client = {
                .remove = pp_remove,
        },
 };
-module_ntb_client(pp_client);
+
+static int __init pp_init(void)
+{
+       int rc;
+
+       if (debugfs_initialized())
+               pp_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+       rc = ntb_register_client(&pp_client);
+       if (rc)
+               goto err_client;
+
+       return 0;
+
+err_client:
+       debugfs_remove_recursive(pp_debugfs_dir);
+       return rc;
+}
+module_init(pp_init);
+
+static void __exit pp_exit(void)
+{
+       ntb_unregister_client(&pp_client);
+       debugfs_remove_recursive(pp_debugfs_dir);
+}
+module_exit(pp_exit);
index 6f5dc6c..61bf2ef 100644 (file)
  *
  * Eg: check if clearing the doorbell mask generates an interrupt.
  *
+ * # Check the link status
+ * root@self# cat $DBG_DIR/link
+ *
+ * # Block until the link is up
+ * root@self# echo Y > $DBG_DIR/link_event
+ *
  * # Set the doorbell mask
  * root@self# echo 's 1' > $DBG_DIR/mask
  *
  * root@self# cat $DBG_DIR/spad
  *
  * Observe that spad 0 and 1 have the values set by the peer.
+ *
+ * # Check the memory window translation info
+ * cat $DBG_DIR/peer_trans0
+ *
+ * # Setup a 16k memory window buffer
+ * echo 16384 > $DBG_DIR/peer_trans0
+ *
  */
 
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 
 #include <linux/ntb.h>
 
@@ -105,11 +119,27 @@ MODULE_VERSION(DRIVER_VERSION);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
 
+#define MAX_MWS 16
+
 static struct dentry *tool_dbgfs;
 
+struct tool_mw {
+       int idx;
+       struct tool_ctx *tc;
+       resource_size_t win_size;
+       resource_size_t size;
+       u8 __iomem *local;
+       u8 *peer;
+       dma_addr_t peer_dma;
+       struct dentry *peer_dbg_file;
+};
+
 struct tool_ctx {
        struct ntb_dev *ntb;
        struct dentry *dbgfs;
+       wait_queue_head_t link_wq;
+       int mw_count;
+       struct tool_mw mws[MAX_MWS];
 };
 
 #define SPAD_FNAME_SIZE 0x10
@@ -135,6 +165,8 @@ static void tool_link_event(void *ctx)
 
        dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
                up ? "up" : "down", speed, width);
+
+       wake_up(&tc->link_wq);
 }
 
 static void tool_db_event(void *ctx, int vec)
@@ -239,7 +271,14 @@ static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
        if (!spad_read_fn)
                return -EINVAL;
 
-       buf_size = min_t(size_t, size, 0x100);
+       spad_count = ntb_spad_count(tc->ntb);
+
+       /*
+        * We multiply the number of spads by 15 to get the buffer size
+        * this is from 3 for the %d, 10 for the largest hex value
+        * (0x00000000) and 2 for the tab and line feed.
+        */
+       buf_size = min_t(size_t, size, spad_count * 15);
 
        buf = kmalloc(buf_size, GFP_KERNEL);
        if (!buf)
@@ -247,7 +286,6 @@ static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
 
        pos = 0;
 
-       spad_count = ntb_spad_count(tc->ntb);
        for (i = 0; i < spad_count; ++i) {
                pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
                                 i, spad_read_fn(tc->ntb, i));
@@ -268,7 +306,7 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
 {
        int spad_idx;
        u32 spad_val;
-       char *buf;
+       char *buf, *buf_ptr;
        int pos, n;
        ssize_t rc;
 
@@ -288,14 +326,15 @@ static ssize_t tool_spadfn_write(struct tool_ctx *tc,
        }
 
        buf[size] = 0;
-
-       n = sscanf(buf, "%d %i%n", &spad_idx, &spad_val, &pos);
+       buf_ptr = buf;
+       n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
        while (n == 2) {
+               buf_ptr += pos;
                rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
                if (rc)
                        break;
 
-               n = sscanf(buf + pos, "%d %i%n", &spad_idx, &spad_val, &pos);
+               n = sscanf(buf_ptr, "%d %i%n", &spad_idx, &spad_val, &pos);
        }
 
        if (n < 0)
@@ -442,8 +481,384 @@ static TOOL_FOPS_RDWR(tool_peer_spad_fops,
                      tool_peer_spad_read,
                      tool_peer_spad_write);
 
+static ssize_t tool_link_read(struct file *filep, char __user *ubuf,
+                             size_t size, loff_t *offp)
+{
+       struct tool_ctx *tc = filep->private_data;
+       char buf[3];
+
+       buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+
+       return simple_read_from_buffer(ubuf, size, offp, buf, 2);
+}
+
+static ssize_t tool_link_write(struct file *filep, const char __user *ubuf,
+                              size_t size, loff_t *offp)
+{
+       struct tool_ctx *tc = filep->private_data;
+       char buf[32];
+       size_t buf_size;
+       bool val;
+       int rc;
+
+       buf_size = min(size, (sizeof(buf) - 1));
+       if (copy_from_user(buf, ubuf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       rc = strtobool(buf, &val);
+       if (rc)
+               return rc;
+
+       if (val)
+               rc = ntb_link_enable(tc->ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
+       else
+               rc = ntb_link_disable(tc->ntb);
+
+       if (rc)
+               return rc;
+
+       return size;
+}
+
+static TOOL_FOPS_RDWR(tool_link_fops,
+                     tool_link_read,
+                     tool_link_write);
+
+static ssize_t tool_link_event_write(struct file *filep,
+                                    const char __user *ubuf,
+                                    size_t size, loff_t *offp)
+{
+       struct tool_ctx *tc = filep->private_data;
+       char buf[32];
+       size_t buf_size;
+       bool val;
+       int rc;
+
+       buf_size = min(size, (sizeof(buf) - 1));
+       if (copy_from_user(buf, ubuf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       rc = strtobool(buf, &val);
+       if (rc)
+               return rc;
+
+       if (wait_event_interruptible(tc->link_wq,
+               ntb_link_is_up(tc->ntb, NULL, NULL) == val))
+               return -ERESTART;
+
+       return size;
+}
+
+static TOOL_FOPS_RDWR(tool_link_event_fops,
+                     NULL,
+                     tool_link_event_write);
+
+static ssize_t tool_mw_read(struct file *filep, char __user *ubuf,
+                           size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+       ssize_t rc;
+       loff_t pos = *offp;
+       void *buf;
+
+       if (mw->local == NULL)
+               return -EIO;
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= mw->win_size || !size)
+               return 0;
+       if (size > mw->win_size - pos)
+               size = mw->win_size - pos;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       memcpy_fromio(buf, mw->local + pos, size);
+       rc = copy_to_user(ubuf, buf, size);
+       if (rc == size) {
+               rc = -EFAULT;
+               goto err_free;
+       }
+
+       size -= rc;
+       *offp = pos + size;
+       rc = size;
+
+err_free:
+       kfree(buf);
+
+       return rc;
+}
+
+static ssize_t tool_mw_write(struct file *filep, const char __user *ubuf,
+                            size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+       ssize_t rc;
+       loff_t pos = *offp;
+       void *buf;
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= mw->win_size || !size)
+               return 0;
+       if (size > mw->win_size - pos)
+               size = mw->win_size - pos;
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       rc = copy_from_user(buf, ubuf, size);
+       if (rc == size) {
+               rc = -EFAULT;
+               goto err_free;
+       }
+
+       size -= rc;
+       *offp = pos + size;
+       rc = size;
+
+       memcpy_toio(mw->local + pos, buf, size);
+
+err_free:
+       kfree(buf);
+
+       return rc;
+}
+
+static TOOL_FOPS_RDWR(tool_mw_fops,
+                     tool_mw_read,
+                     tool_mw_write);
+
+static ssize_t tool_peer_mw_read(struct file *filep, char __user *ubuf,
+                                size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+
+       if (!mw->peer)
+               return -ENXIO;
+
+       return simple_read_from_buffer(ubuf, size, offp, mw->peer, mw->size);
+}
+
+static ssize_t tool_peer_mw_write(struct file *filep, const char __user *ubuf,
+                                 size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+
+       if (!mw->peer)
+               return -ENXIO;
+
+       return simple_write_to_buffer(mw->peer, mw->size, offp, ubuf, size);
+}
+
+static TOOL_FOPS_RDWR(tool_peer_mw_fops,
+                     tool_peer_mw_read,
+                     tool_peer_mw_write);
+
+static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
+{
+       int rc;
+       struct tool_mw *mw = &tc->mws[idx];
+       phys_addr_t base;
+       resource_size_t size, align, align_size;
+       char buf[16];
+
+       if (mw->peer)
+               return 0;
+
+       rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align,
+                             &align_size);
+       if (rc)
+               return rc;
+
+       mw->size = min_t(resource_size_t, req_size, size);
+       mw->size = round_up(mw->size, align);
+       mw->size = round_up(mw->size, align_size);
+       mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
+                                     &mw->peer_dma, GFP_KERNEL);
+
+       if (!mw->peer)
+               return -ENOMEM;
+
+       rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size);
+       if (rc)
+               goto err_free_dma;
+
+       snprintf(buf, sizeof(buf), "peer_mw%d", idx);
+       mw->peer_dbg_file = debugfs_create_file(buf, S_IRUSR | S_IWUSR,
+                                               mw->tc->dbgfs, mw,
+                                               &tool_peer_mw_fops);
+
+       return 0;
+
+err_free_dma:
+       dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
+                         mw->peer,
+                         mw->peer_dma);
+       mw->peer = NULL;
+       mw->peer_dma = 0;
+       mw->size = 0;
+
+       return rc;
+}
+
+static void tool_free_mw(struct tool_ctx *tc, int idx)
+{
+       struct tool_mw *mw = &tc->mws[idx];
+
+       if (mw->peer) {
+               ntb_mw_clear_trans(tc->ntb, idx);
+               dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
+                                 mw->peer,
+                                 mw->peer_dma);
+       }
+
+       mw->peer = NULL;
+       mw->peer_dma = 0;
+
+       debugfs_remove(mw->peer_dbg_file);
+
+       mw->peer_dbg_file = NULL;
+}
+
+static ssize_t tool_peer_mw_trans_read(struct file *filep,
+                                      char __user *ubuf,
+                                      size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+
+       char *buf;
+       size_t buf_size;
+       ssize_t ret, off = 0;
+
+       phys_addr_t base;
+       resource_size_t mw_size;
+       resource_size_t align;
+       resource_size_t align_size;
+
+       buf_size = min_t(size_t, size, 512);
+
+       buf = kmalloc(buf_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ntb_mw_get_range(mw->tc->ntb, mw->idx,
+                        &base, &mw_size, &align, &align_size);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Peer MW %d Information:\n", mw->idx);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Physical Address      \t%pa[p]\n",
+                        &base);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Window Size           \t%lld\n",
+                        (unsigned long long)mw_size);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Alignment             \t%lld\n",
+                        (unsigned long long)align);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Size Alignment        \t%lld\n",
+                        (unsigned long long)align_size);
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Ready                 \t%c\n",
+                        (mw->peer) ? 'Y' : 'N');
+
+       off += scnprintf(buf + off, buf_size - off,
+                        "Allocated Size       \t%zd\n",
+                        (mw->peer) ? (size_t)mw->size : 0);
+
+       ret = simple_read_from_buffer(ubuf, size, offp, buf, off);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t tool_peer_mw_trans_write(struct file *filep,
+                                       const char __user *ubuf,
+                                       size_t size, loff_t *offp)
+{
+       struct tool_mw *mw = filep->private_data;
+
+       char buf[32];
+       size_t buf_size;
+       unsigned long long val;
+       int rc;
+
+       buf_size = min(size, (sizeof(buf) - 1));
+       if (copy_from_user(buf, ubuf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       rc = kstrtoull(buf, 0, &val);
+       if (rc)
+               return rc;
+
+       tool_free_mw(mw->tc, mw->idx);
+       if (val)
+               rc = tool_setup_mw(mw->tc, mw->idx, val);
+
+       if (rc)
+               return rc;
+
+       return size;
+}
+
+static TOOL_FOPS_RDWR(tool_peer_mw_trans_fops,
+                     tool_peer_mw_trans_read,
+                     tool_peer_mw_trans_write);
+
+static int tool_init_mw(struct tool_ctx *tc, int idx)
+{
+       struct tool_mw *mw = &tc->mws[idx];
+       phys_addr_t base;
+       int rc;
+
+       rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size,
+                             NULL, NULL);
+       if (rc)
+               return rc;
+
+       mw->tc = tc;
+       mw->idx = idx;
+       mw->local = ioremap_wc(base, mw->win_size);
+       if (!mw->local)
+               return -EFAULT;
+
+       return 0;
+}
+
+static void tool_free_mws(struct tool_ctx *tc)
+{
+       int i;
+
+       for (i = 0; i < tc->mw_count; i++) {
+               tool_free_mw(tc, i);
+
+               if (tc->mws[i].local)
+                       iounmap(tc->mws[i].local);
+
+               tc->mws[i].local = NULL;
+       }
+}
+
 static void tool_setup_dbgfs(struct tool_ctx *tc)
 {
+       int i;
+
        /* This modules is useless without dbgfs... */
        if (!tool_dbgfs) {
                tc->dbgfs = NULL;
@@ -472,12 +887,31 @@ static void tool_setup_dbgfs(struct tool_ctx *tc)
 
        debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
                            tc, &tool_peer_spad_fops);
+
+       debugfs_create_file("link", S_IRUSR | S_IWUSR, tc->dbgfs,
+                           tc, &tool_link_fops);
+
+       debugfs_create_file("link_event", S_IWUSR, tc->dbgfs,
+                           tc, &tool_link_event_fops);
+
+       for (i = 0; i < tc->mw_count; i++) {
+               char buf[30];
+
+               snprintf(buf, sizeof(buf), "mw%d", i);
+               debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
+                                   &tc->mws[i], &tool_mw_fops);
+
+               snprintf(buf, sizeof(buf), "peer_trans%d", i);
+               debugfs_create_file(buf, S_IRUSR | S_IWUSR, tc->dbgfs,
+                                   &tc->mws[i], &tool_peer_mw_trans_fops);
+       }
 }
 
 static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
 {
        struct tool_ctx *tc;
        int rc;
+       int i;
 
        if (ntb_db_is_unsafe(ntb))
                dev_dbg(&ntb->dev, "doorbell is unsafe\n");
@@ -485,13 +919,21 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
        if (ntb_spad_is_unsafe(ntb))
                dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
 
-       tc = kmalloc(sizeof(*tc), GFP_KERNEL);
+       tc = kzalloc(sizeof(*tc), GFP_KERNEL);
        if (!tc) {
                rc = -ENOMEM;
                goto err_tc;
        }
 
        tc->ntb = ntb;
+       init_waitqueue_head(&tc->link_wq);
+
+       tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS);
+       for (i = 0; i < tc->mw_count; i++) {
+               rc = tool_init_mw(tc, i);
+               if (rc)
+                       goto err_ctx;
+       }
 
        tool_setup_dbgfs(tc);
 
@@ -505,6 +947,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
        return 0;
 
 err_ctx:
+       tool_free_mws(tc);
        debugfs_remove_recursive(tc->dbgfs);
        kfree(tc);
 err_tc:
@@ -515,6 +958,8 @@ static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
 {
        struct tool_ctx *tc = ntb->ctx;
 
+       tool_free_mws(tc);
+
        ntb_clear_ctx(ntb);
        ntb_link_disable(ntb);
 
index 9dce03f..88e9166 100644 (file)
@@ -1133,11 +1133,11 @@ static int btt_write_pg(struct btt *btt, struct bio_integrity_payload *bip,
 
 static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip,
                        struct page *page, unsigned int len, unsigned int off,
-                       int rw, sector_t sector)
+                       bool is_write, sector_t sector)
 {
        int ret;
 
-       if (rw == READ) {
+       if (!is_write) {
                ret = btt_read_pg(btt, bip, page, off, sector, len);
                flush_dcache_page(page);
        } else {
@@ -1155,7 +1155,7 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
        struct bvec_iter iter;
        unsigned long start;
        struct bio_vec bvec;
-       int err = 0, rw;
+       int err = 0;
        bool do_acct;
 
        /*
@@ -1170,7 +1170,6 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
        }
 
        do_acct = nd_iostat_start(bio, &start);
-       rw = bio_data_dir(bio);
        bio_for_each_segment(bvec, bio, iter) {
                unsigned int len = bvec.bv_len;
 
@@ -1181,11 +1180,12 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
                BUG_ON(len % btt->sector_size);
 
                err = btt_do_bvec(btt, bip, bvec.bv_page, len, bvec.bv_offset,
-                               rw, iter.bi_sector);
+                                 op_is_write(bio_op(bio)), iter.bi_sector);
                if (err) {
                        dev_info(&btt->nd_btt->dev,
                                        "io error in %s sector %lld, len %d,\n",
-                                       (rw == READ) ? "READ" : "WRITE",
+                                       (op_is_write(bio_op(bio))) ? "WRITE" :
+                                       "READ",
                                        (unsigned long long) iter.bi_sector, len);
                        bio->bi_error = err;
                        break;
@@ -1200,12 +1200,12 @@ out:
 }
 
 static int btt_rw_page(struct block_device *bdev, sector_t sector,
-               struct page *page, int rw)
+               struct page *page, bool is_write)
 {
        struct btt *btt = bdev->bd_disk->private_data;
 
-       btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, rw, sector);
-       page_endio(page, rw & WRITE, 0);
+       btt_do_bvec(btt, NULL, page, PAGE_SIZE, 0, is_write, sector);
+       page_endio(page, is_write, 0);
        return 0;
 }
 
index b511099..571a6c7 100644 (file)
@@ -67,7 +67,7 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
 }
 
 static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
-                       unsigned int len, unsigned int off, int rw,
+                       unsigned int len, unsigned int off, bool is_write,
                        sector_t sector)
 {
        int rc = 0;
@@ -79,7 +79,7 @@ static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
        if (unlikely(is_bad_pmem(&pmem->bb, sector, len)))
                bad_pmem = true;
 
-       if (rw == READ) {
+       if (!is_write) {
                if (unlikely(bad_pmem))
                        rc = -EIO;
                else {
@@ -128,13 +128,13 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        struct pmem_device *pmem = q->queuedata;
        struct nd_region *nd_region = to_region(pmem);
 
-       if (bio->bi_rw & REQ_FLUSH)
+       if (bio->bi_opf & REQ_FLUSH)
                nvdimm_flush(nd_region);
 
        do_acct = nd_iostat_start(bio, &start);
        bio_for_each_segment(bvec, bio, iter) {
                rc = pmem_do_bvec(pmem, bvec.bv_page, bvec.bv_len,
-                               bvec.bv_offset, bio_data_dir(bio),
+                               bvec.bv_offset, op_is_write(bio_op(bio)),
                                iter.bi_sector);
                if (rc) {
                        bio->bi_error = rc;
@@ -144,7 +144,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
        if (do_acct)
                nd_iostat_end(bio, start);
 
-       if (bio->bi_rw & REQ_FUA)
+       if (bio->bi_opf & REQ_FUA)
                nvdimm_flush(nd_region);
 
        bio_endio(bio);
@@ -152,12 +152,12 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
 }
 
 static int pmem_rw_page(struct block_device *bdev, sector_t sector,
-                      struct page *page, int rw)
+                      struct page *page, bool is_write)
 {
        struct pmem_device *pmem = bdev->bd_queue->queuedata;
        int rc;
 
-       rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, rw, sector);
+       rc = pmem_do_bvec(pmem, page, PAGE_SIZE, 0, is_write, sector);
 
        /*
         * The ->rw_page interface is subtle and tricky.  The core
@@ -166,7 +166,7 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
         * caused by double completion.
         */
        if (rc == 0)
-               page_endio(page, rw & WRITE, 0);
+               page_endio(page, is_write, 0);
 
        return rc;
 }
index 4cb9b15..d7c33f9 100644 (file)
@@ -1661,14 +1661,9 @@ static int nvme_pci_enable(struct nvme_dev *dev)
 
 static void nvme_dev_unmap(struct nvme_dev *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev->dev);
-       int bars;
-
        if (dev->bar)
                iounmap(dev->bar);
-
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(to_pci_dev(dev->dev));
 }
 
 static void nvme_pci_disable(struct nvme_dev *dev)
@@ -1897,13 +1892,9 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
 
 static int nvme_dev_map(struct nvme_dev *dev)
 {
-       int bars;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (!bars)
-               return -ENODEV;
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
+       if (pci_request_mem_regions(pdev, "nvme"))
                return -ENODEV;
 
        dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
@@ -1912,7 +1903,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        return 0;
   release:
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
        return -ENODEV;
 }
 
index 765390e..8aa1976 100644 (file)
@@ -499,8 +499,24 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);
 
 static int __init of_platform_default_populate_init(void)
 {
-       if (of_have_populated_dt())
-               of_platform_default_populate(NULL, NULL, NULL);
+       struct device_node *node;
+
+       if (!of_have_populated_dt())
+               return -ENODEV;
+
+       /*
+        * Handle ramoops explicitly, since it is inside /reserved-memory,
+        * which lacks a "compatible" property.
+        */
+       node = of_find_node_by_path("/reserved-memory");
+       if (node) {
+               node = of_find_compatible_node(node, NULL, "ramoops");
+               if (node)
+                       of_platform_device_create(node, NULL, NULL);
+       }
+
+       /* Populate everything else. */
+       of_platform_default_populate(NULL, NULL, NULL);
 
        return 0;
 }
index e24b059..3ed6238 100644 (file)
@@ -790,7 +790,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
 static dma_addr_t
 ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
                size_t size, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        return ccio_map_single(dev, page_address(page) + offset, size,
                        direction);
@@ -806,7 +806,7 @@ ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
  */
 static void 
 ccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
        unsigned long flags; 
@@ -844,7 +844,7 @@ ccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
  */
 static void * 
 ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
       void *ret;
 #if 0
@@ -878,9 +878,9 @@ ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
  */
 static void 
 ccio_free(struct device *dev, size_t size, void *cpu_addr,
-               dma_addr_t dma_handle, struct dma_attrs *attrs)
+               dma_addr_t dma_handle, unsigned long attrs)
 {
-       ccio_unmap_page(dev, dma_handle, size, 0, NULL);
+       ccio_unmap_page(dev, dma_handle, size, 0, 0);
        free_pages((unsigned long)cpu_addr, get_order(size));
 }
 
@@ -907,7 +907,7 @@ ccio_free(struct device *dev, size_t size, void *cpu_addr,
  */
 static int
 ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, 
-           enum dma_data_direction direction, struct dma_attrs *attrs)
+           enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
        int coalesced, filled = 0;
@@ -984,7 +984,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
  */
 static void 
 ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, 
-             enum dma_data_direction direction, struct dma_attrs *attrs)
+             enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
 
@@ -1004,7 +1004,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
                ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
 #endif
                ccio_unmap_page(dev, sg_dma_address(sglist),
-                                 sg_dma_len(sglist), direction, NULL);
+                                 sg_dma_len(sglist), direction, 0);
                ++sglist;
        }
 
index 42ec460..151b86b 100644 (file)
@@ -783,7 +783,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
 static dma_addr_t
 sba_map_page(struct device *dev, struct page *page, unsigned long offset,
                size_t size, enum dma_data_direction direction,
-               struct dma_attrs *attrs)
+               unsigned long attrs)
 {
        return sba_map_single(dev, page_address(page) + offset, size,
                        direction);
@@ -801,7 +801,7 @@ sba_map_page(struct device *dev, struct page *page, unsigned long offset,
  */
 static void
 sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
-               enum dma_data_direction direction, struct dma_attrs *attrs)
+               enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
 #if DELAYED_RESOURCE_CNT > 0
@@ -876,7 +876,7 @@ sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
  * See Documentation/DMA-API-HOWTO.txt
  */
 static void *sba_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle,
-               gfp_t gfp, struct dma_attrs *attrs)
+               gfp_t gfp, unsigned long attrs)
 {
        void *ret;
 
@@ -908,9 +908,9 @@ static void *sba_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle
  */
 static void
 sba_free(struct device *hwdev, size_t size, void *vaddr,
-                   dma_addr_t dma_handle, struct dma_attrs *attrs)
+                   dma_addr_t dma_handle, unsigned long attrs)
 {
-       sba_unmap_page(hwdev, dma_handle, size, 0, NULL);
+       sba_unmap_page(hwdev, dma_handle, size, 0, 0);
        free_pages((unsigned long) vaddr, get_order(size));
 }
 
@@ -943,7 +943,7 @@ int dump_run_sg = 0;
  */
 static int
 sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
-          enum dma_data_direction direction, struct dma_attrs *attrs)
+          enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
        int coalesced, filled = 0;
@@ -1026,7 +1026,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
  */
 static void 
 sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
-            enum dma_data_direction direction, struct dma_attrs *attrs)
+            enum dma_data_direction direction, unsigned long attrs)
 {
        struct ioc *ioc;
 #ifdef ASSERT_PDIR_SANITY
@@ -1051,7 +1051,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
        while (sg_dma_len(sglist) && nents--) {
 
                sba_unmap_page(dev, sg_dma_address(sglist), sg_dma_len(sglist),
-                               direction, NULL);
+                               direction, 0);
 #ifdef SBA_COLLECT_STATS
                ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
                ioc->usingle_calls--;   /* kluge since call is unmap_sg() */
index 56389be..67f9916 100644 (file)
@@ -25,7 +25,7 @@ config PCI_MSI
           If you don't know what to do here, say Y.
 
 config PCI_MSI_IRQ_DOMAIN
-       bool
+       def_bool ARM || ARM64 || X86
        depends on PCI_MSI
        select GENERIC_MSI_IRQ_DOMAIN
 
index dd7cdbe..c288e5a 100644 (file)
@@ -91,6 +91,35 @@ void pci_bus_remove_resources(struct pci_bus *bus)
        }
 }
 
+int devm_request_pci_bus_resources(struct device *dev,
+                                  struct list_head *resources)
+{
+       struct resource_entry *win;
+       struct resource *parent, *res;
+       int err;
+
+       resource_list_for_each_entry(win, resources) {
+               res = win->res;
+               switch (resource_type(res)) {
+               case IORESOURCE_IO:
+                       parent = &ioport_resource;
+                       break;
+               case IORESOURCE_MEM:
+                       parent = &iomem_resource;
+                       break;
+               default:
+                       continue;
+               }
+
+               err = devm_request_resource(dev, parent, res);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources);
+
 static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL};
 #ifdef CONFIG_PCI_BUS_ADDR_T_64BIT
 static struct pci_bus_region pci_64_bit = {0,
@@ -291,6 +320,7 @@ void pci_bus_add_device(struct pci_dev *dev)
        pci_fixup_device(pci_fixup_final, dev);
        pci_create_sysfs_dev_files(dev);
        pci_proc_attach_device(dev);
+       pci_bridge_d3_device_changed(dev);
 
        dev->match_driver = true;
        retval = device_attach(&dev->dev);
@@ -397,4 +427,3 @@ void pci_bus_put(struct pci_bus *bus)
                put_device(&bus->dev);
 }
 EXPORT_SYMBOL(pci_bus_put);
-
index f9832ad..43ed08d 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/slab.h>
 
-#include "ecam.h"
-
 /*
  * On 64-bit systems, we do a single ioremap for the whole config space
  * since we have enough virtual address range available.  On 32-bit, we
  * ioremap the config space for each bus individually.
  */
-static const bool per_bus_mapping = !config_enabled(CONFIG_64BIT);
+static const bool per_bus_mapping = !IS_ENABLED(CONFIG_64BIT);
 
 /*
  * Create a PCI config space window
@@ -52,6 +51,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
        if (!cfg)
                return ERR_PTR(-ENOMEM);
 
+       cfg->parent = dev;
        cfg->ops = ops;
        cfg->busr.start = busr->start;
        cfg->busr.end = busr->end;
@@ -95,7 +95,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
        }
 
        if (ops->init) {
-               err = ops->init(dev, cfg);
+               err = ops->init(cfg);
                if (err)
                        goto err_exit;
        }
diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h
deleted file mode 100644 (file)
index 9878beb..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 Broadcom
- *
- * 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 (the "GPL").
- *
- * 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 version 2 (GPLv2) for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 (GPLv2) along with this source code.
- */
-#ifndef DRIVERS_PCI_ECAM_H
-#define DRIVERS_PCI_ECAM_H
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-/*
- * struct to hold pci ops and bus shift of the config window
- * for a PCI controller.
- */
-struct pci_config_window;
-struct pci_ecam_ops {
-       unsigned int                    bus_shift;
-       struct pci_ops                  pci_ops;
-       int                             (*init)(struct device *,
-                                               struct pci_config_window *);
-};
-
-/*
- * struct to hold the mappings of a config space window. This
- * is expected to be used as sysdata for PCI controllers that
- * use ECAM.
- */
-struct pci_config_window {
-       struct resource                 res;
-       struct resource                 busr;
-       void                            *priv;
-       struct pci_ecam_ops             *ops;
-       union {
-               void __iomem            *win;   /* 64-bit single mapping */
-               void __iomem            **winp; /* 32-bit per-bus mapping */
-       };
-};
-
-/* create and free pci_config_window */
-struct pci_config_window *pci_ecam_create(struct device *dev,
-               struct resource *cfgres, struct resource *busr,
-               struct pci_ecam_ops *ops);
-void pci_ecam_free(struct pci_config_window *cfg);
-
-/* map_bus when ->sysdata is an instance of pci_config_window */
-void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
-                              int where);
-/* default ECAM ops */
-extern struct pci_ecam_ops pci_generic_ecam_ops;
-
-#ifdef CONFIG_PCI_HOST_GENERIC
-/* for DT-based PCI controllers that support ECAM */
-int pci_host_common_probe(struct platform_device *pdev,
-                         struct pci_ecam_ops *ops);
-#endif
-#endif
index 5d2374e..9b485d8 100644 (file)
@@ -3,8 +3,9 @@ menu "PCI host controller drivers"
 
 config PCI_DRA7XX
        bool "TI DRA7xx PCIe controller"
-       select PCIE_DW
        depends on OF && HAS_IOMEM && TI_PIPE3
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW
        help
         Enables support for the PCIe controller in the DRA7xx SoC.  There
         are two instances of PCIe controller in DRA7xx.  This controller can
@@ -16,11 +17,20 @@ config PCI_MVEBU
        depends on ARM
        depends on OF
 
+config PCI_AARDVARK
+       bool "Aardvark PCIe controller"
+       depends on ARCH_MVEBU && ARM64
+       depends on OF
+       depends on PCI_MSI_IRQ_DOMAIN
+       help
+        Add support for Aardvark 64bit PCIe Host Controller. This
+        controller is part of the South Bridge of the Marvel Armada
+        3700 SoC.
 
 config PCIE_XILINX_NWL
        bool "NWL PCIe Core"
        depends on ARCH_ZYNQMP
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
+       depends on PCI_MSI_IRQ_DOMAIN
        help
         Say 'Y' here if you want kernel support for Xilinx
         NWL PCIe controller. The controller can act as Root Port
@@ -29,6 +39,7 @@ config PCIE_XILINX_NWL
 
 config PCIE_DW_PLAT
        bool "Platform bus based DesignWare PCIe Controller"
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        ---help---
         This selects the DesignWare PCIe controller support. Select this if
@@ -40,16 +51,19 @@ config PCIE_DW_PLAT
 
 config PCIE_DW
        bool
+       depends on PCI_MSI_IRQ_DOMAIN
 
 config PCI_EXYNOS
        bool "Samsung Exynos PCIe controller"
        depends on SOC_EXYNOS5440
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
 
 config PCI_IMX6
        bool "Freescale i.MX6 PCIe controller"
        depends on SOC_IMX6Q
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
 
@@ -72,8 +86,7 @@ config PCI_RCAR_GEN2
 config PCIE_RCAR
        bool "Renesas R-Car PCIe controller"
        depends on ARCH_RENESAS || (ARM && COMPILE_TEST)
-       select PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI_MSI_IRQ_DOMAIN
        help
          Say Y here if you want PCIe controller support on R-Car SoCs.
 
@@ -85,6 +98,7 @@ config PCI_HOST_GENERIC
        bool "Generic PCI host controller"
        depends on (ARM || ARM64) && OF
        select PCI_HOST_COMMON
+       select IRQ_DOMAIN
        help
          Say Y here if you want to support a simple generic PCI host
          controller, such as the one emulated by kvmtool.
@@ -92,6 +106,7 @@ config PCI_HOST_GENERIC
 config PCIE_SPEAR13XX
        bool "STMicroelectronics SPEAr PCIe controller"
        depends on ARCH_SPEAR13XX
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
        help
@@ -100,6 +115,7 @@ config PCIE_SPEAR13XX
 config PCI_KEYSTONE
        bool "TI Keystone PCIe controller"
        depends on ARCH_KEYSTONE
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
@@ -120,7 +136,6 @@ config PCI_XGENE
        depends on ARCH_XGENE
        depends on OF
        select PCIEPORTBUS
-       select PCI_MSI_IRQ_DOMAIN if PCI_MSI
        help
          Say Y here if you want internal PCI support on APM X-Gene SoC.
          There are 5 internal PCIe ports available. Each port is GEN3 capable
@@ -128,7 +143,8 @@ config PCI_XGENE
 
 config PCI_XGENE_MSI
        bool "X-Gene v1 PCIe MSI feature"
-       depends on PCI_XGENE && PCI_MSI
+       depends on PCI_XGENE
+       depends on PCI_MSI_IRQ_DOMAIN
        default y
        help
          Say Y here if you want PCIe MSI support for the APM X-Gene v1 SoC.
@@ -137,6 +153,7 @@ config PCI_XGENE_MSI
 config PCI_LAYERSCAPE
        bool "Freescale Layerscape PCIe controller"
        depends on OF && (ARM || ARCH_LAYERSCAPE)
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select MFD_SYSCON
        help
@@ -177,8 +194,7 @@ config PCIE_IPROC_BCMA
 config PCIE_IPROC_MSI
        bool "Broadcom iProc PCIe MSI support"
        depends on PCIE_IPROC_PLATFORM || PCIE_IPROC_BCMA
-       depends on PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCI_MSI_IRQ_DOMAIN
        default ARCH_BCM_IPROC
        help
          Say Y here if you want to enable MSI support for Broadcom's iProc
@@ -195,8 +211,8 @@ config PCIE_ALTERA
 
 config PCIE_ALTERA_MSI
        bool "Altera PCIe MSI feature"
-       depends on PCIE_ALTERA && PCI_MSI
-       select PCI_MSI_IRQ_DOMAIN
+       depends on PCIE_ALTERA
+       depends on PCI_MSI_IRQ_DOMAIN
        help
          Say Y here if you want PCIe MSI support for the Altera FPGA.
          This MSI driver supports Altera MSI to GIC controller IP.
@@ -204,6 +220,7 @@ config PCIE_ALTERA_MSI
 config PCI_HISI
        depends on OF && ARM64
        bool "HiSilicon Hip05 and Hip06 SoCs PCIe controllers"
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIEPORTBUS
        select PCIE_DW
        help
@@ -213,6 +230,7 @@ config PCI_HISI
 config PCIE_QCOM
        bool "Qualcomm PCIe controller"
        depends on ARCH_QCOM && OF
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
@@ -237,6 +255,7 @@ config PCI_HOST_THUNDER_ECAM
 config PCIE_ARMADA_8K
        bool "Marvell Armada-8K PCIe controller"
        depends on ARCH_MVEBU
+       depends on PCI_MSI_IRQ_DOMAIN
        select PCIE_DW
        select PCIEPORTBUS
        help
@@ -245,4 +264,14 @@ config PCIE_ARMADA_8K
          Designware hardware and therefore the driver re-uses the
          Designware core functions to implement the driver.
 
+config PCIE_ARTPEC6
+       bool "Axis ARTPEC-6 PCIe controller"
+       depends on MACH_ARTPEC6
+       depends on PCI_MSI_IRQ_DOMAIN
+       select PCIE_DW
+       select PCIEPORTBUS
+       help
+         Say Y here to enable PCIe controller support on Axis ARTPEC-6
+         SoCs.  This PCIe controller uses the DesignWare core.
+
 endmenu
index 9c8698e..8843410 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCIE_RCAR) += pcie-rcar.o
@@ -29,3 +30,4 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
 obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
+obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c
new file mode 100644 (file)
index 0000000..ef9893f
--- /dev/null
@@ -0,0 +1,1001 @@
+/*
+ * Driver for the Aardvark PCIe controller, used on Marvell Armada
+ * 3700.
+ *
+ * Copyright (C) 2016 Marvell
+ *
+ * Author: Hezi Shahmoon <hezi.shahmoon@marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+
+/* PCIe core registers */
+#define PCIE_CORE_CMD_STATUS_REG                               0x4
+#define     PCIE_CORE_CMD_IO_ACCESS_EN                         BIT(0)
+#define     PCIE_CORE_CMD_MEM_ACCESS_EN                                BIT(1)
+#define     PCIE_CORE_CMD_MEM_IO_REQ_EN                                BIT(2)
+#define PCIE_CORE_DEV_CTRL_STATS_REG                           0xc8
+#define     PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE       (0 << 4)
+#define     PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT      5
+#define     PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE             (0 << 11)
+#define     PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT     12
+#define PCIE_CORE_LINK_CTRL_STAT_REG                           0xd0
+#define     PCIE_CORE_LINK_L0S_ENTRY                           BIT(0)
+#define     PCIE_CORE_LINK_TRAINING                            BIT(5)
+#define     PCIE_CORE_LINK_WIDTH_SHIFT                         20
+#define PCIE_CORE_ERR_CAPCTL_REG                               0x118
+#define     PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX                   BIT(5)
+#define     PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN                        BIT(6)
+#define     PCIE_CORE_ERR_CAPCTL_ECRC_CHCK                     BIT(7)
+#define     PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV                 BIT(8)
+
+/* PIO registers base address and register offsets */
+#define PIO_BASE_ADDR                          0x4000
+#define PIO_CTRL                               (PIO_BASE_ADDR + 0x0)
+#define   PIO_CTRL_TYPE_MASK                   GENMASK(3, 0)
+#define   PIO_CTRL_ADDR_WIN_DISABLE            BIT(24)
+#define PIO_STAT                               (PIO_BASE_ADDR + 0x4)
+#define   PIO_COMPLETION_STATUS_SHIFT          7
+#define   PIO_COMPLETION_STATUS_MASK           GENMASK(9, 7)
+#define   PIO_COMPLETION_STATUS_OK             0
+#define   PIO_COMPLETION_STATUS_UR             1
+#define   PIO_COMPLETION_STATUS_CRS            2
+#define   PIO_COMPLETION_STATUS_CA             4
+#define   PIO_NON_POSTED_REQ                   BIT(0)
+#define PIO_ADDR_LS                            (PIO_BASE_ADDR + 0x8)
+#define PIO_ADDR_MS                            (PIO_BASE_ADDR + 0xc)
+#define PIO_WR_DATA                            (PIO_BASE_ADDR + 0x10)
+#define PIO_WR_DATA_STRB                       (PIO_BASE_ADDR + 0x14)
+#define PIO_RD_DATA                            (PIO_BASE_ADDR + 0x18)
+#define PIO_START                              (PIO_BASE_ADDR + 0x1c)
+#define PIO_ISR                                        (PIO_BASE_ADDR + 0x20)
+#define PIO_ISRM                               (PIO_BASE_ADDR + 0x24)
+
+/* Aardvark Control registers */
+#define CONTROL_BASE_ADDR                      0x4800
+#define PCIE_CORE_CTRL0_REG                    (CONTROL_BASE_ADDR + 0x0)
+#define     PCIE_GEN_SEL_MSK                   0x3
+#define     PCIE_GEN_SEL_SHIFT                 0x0
+#define     SPEED_GEN_1                                0
+#define     SPEED_GEN_2                                1
+#define     SPEED_GEN_3                                2
+#define     IS_RC_MSK                          1
+#define     IS_RC_SHIFT                                2
+#define     LANE_CNT_MSK                       0x18
+#define     LANE_CNT_SHIFT                     0x3
+#define     LANE_COUNT_1                       (0 << LANE_CNT_SHIFT)
+#define     LANE_COUNT_2                       (1 << LANE_CNT_SHIFT)
+#define     LANE_COUNT_4                       (2 << LANE_CNT_SHIFT)
+#define     LANE_COUNT_8                       (3 << LANE_CNT_SHIFT)
+#define     LINK_TRAINING_EN                   BIT(6)
+#define     LEGACY_INTA                                BIT(28)
+#define     LEGACY_INTB                                BIT(29)
+#define     LEGACY_INTC                                BIT(30)
+#define     LEGACY_INTD                                BIT(31)
+#define PCIE_CORE_CTRL1_REG                    (CONTROL_BASE_ADDR + 0x4)
+#define     HOT_RESET_GEN                      BIT(0)
+#define PCIE_CORE_CTRL2_REG                    (CONTROL_BASE_ADDR + 0x8)
+#define     PCIE_CORE_CTRL2_RESERVED           0x7
+#define     PCIE_CORE_CTRL2_TD_ENABLE          BIT(4)
+#define     PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE        BIT(5)
+#define     PCIE_CORE_CTRL2_OB_WIN_ENABLE      BIT(6)
+#define     PCIE_CORE_CTRL2_MSI_ENABLE         BIT(10)
+#define PCIE_ISR0_REG                          (CONTROL_BASE_ADDR + 0x40)
+#define PCIE_ISR0_MASK_REG                     (CONTROL_BASE_ADDR + 0x44)
+#define     PCIE_ISR0_MSI_INT_PENDING          BIT(24)
+#define     PCIE_ISR0_INTX_ASSERT(val)         BIT(16 + (val))
+#define     PCIE_ISR0_INTX_DEASSERT(val)       BIT(20 + (val))
+#define            PCIE_ISR0_ALL_MASK                  GENMASK(26, 0)
+#define PCIE_ISR1_REG                          (CONTROL_BASE_ADDR + 0x48)
+#define PCIE_ISR1_MASK_REG                     (CONTROL_BASE_ADDR + 0x4C)
+#define     PCIE_ISR1_POWER_STATE_CHANGE       BIT(4)
+#define     PCIE_ISR1_FLUSH                    BIT(5)
+#define     PCIE_ISR1_ALL_MASK                 GENMASK(5, 4)
+#define PCIE_MSI_ADDR_LOW_REG                  (CONTROL_BASE_ADDR + 0x50)
+#define PCIE_MSI_ADDR_HIGH_REG                 (CONTROL_BASE_ADDR + 0x54)
+#define PCIE_MSI_STATUS_REG                    (CONTROL_BASE_ADDR + 0x58)
+#define PCIE_MSI_MASK_REG                      (CONTROL_BASE_ADDR + 0x5C)
+#define PCIE_MSI_PAYLOAD_REG                   (CONTROL_BASE_ADDR + 0x9C)
+
+/* PCIe window configuration */
+#define OB_WIN_BASE_ADDR                       0x4c00
+#define OB_WIN_BLOCK_SIZE                      0x20
+#define OB_WIN_REG_ADDR(win, offset)           (OB_WIN_BASE_ADDR + \
+                                                OB_WIN_BLOCK_SIZE * (win) + \
+                                                (offset))
+#define OB_WIN_MATCH_LS(win)                   OB_WIN_REG_ADDR(win, 0x00)
+#define OB_WIN_MATCH_MS(win)                   OB_WIN_REG_ADDR(win, 0x04)
+#define OB_WIN_REMAP_LS(win)                   OB_WIN_REG_ADDR(win, 0x08)
+#define OB_WIN_REMAP_MS(win)                   OB_WIN_REG_ADDR(win, 0x0c)
+#define OB_WIN_MASK_LS(win)                    OB_WIN_REG_ADDR(win, 0x10)
+#define OB_WIN_MASK_MS(win)                    OB_WIN_REG_ADDR(win, 0x14)
+#define OB_WIN_ACTIONS(win)                    OB_WIN_REG_ADDR(win, 0x18)
+
+/* PCIe window types */
+#define OB_PCIE_MEM                            0x0
+#define OB_PCIE_IO                             0x4
+
+/* LMI registers base address and register offsets */
+#define LMI_BASE_ADDR                          0x6000
+#define CFG_REG                                        (LMI_BASE_ADDR + 0x0)
+#define     LTSSM_SHIFT                                24
+#define     LTSSM_MASK                         0x3f
+#define     LTSSM_L0                           0x10
+#define     RC_BAR_CONFIG                      0x300
+
+/* PCIe core controller registers */
+#define CTRL_CORE_BASE_ADDR                    0x18000
+#define CTRL_CONFIG_REG                                (CTRL_CORE_BASE_ADDR + 0x0)
+#define     CTRL_MODE_SHIFT                    0x0
+#define     CTRL_MODE_MASK                     0x1
+#define     PCIE_CORE_MODE_DIRECT              0x0
+#define     PCIE_CORE_MODE_COMMAND             0x1
+
+/* PCIe Central Interrupts Registers */
+#define CENTRAL_INT_BASE_ADDR                  0x1b000
+#define HOST_CTRL_INT_STATUS_REG               (CENTRAL_INT_BASE_ADDR + 0x0)
+#define HOST_CTRL_INT_MASK_REG                 (CENTRAL_INT_BASE_ADDR + 0x4)
+#define     PCIE_IRQ_CMDQ_INT                  BIT(0)
+#define     PCIE_IRQ_MSI_STATUS_INT            BIT(1)
+#define     PCIE_IRQ_CMD_SENT_DONE             BIT(3)
+#define     PCIE_IRQ_DMA_INT                   BIT(4)
+#define     PCIE_IRQ_IB_DXFERDONE              BIT(5)
+#define     PCIE_IRQ_OB_DXFERDONE              BIT(6)
+#define     PCIE_IRQ_OB_RXFERDONE              BIT(7)
+#define     PCIE_IRQ_COMPQ_INT                 BIT(12)
+#define     PCIE_IRQ_DIR_RD_DDR_DET            BIT(13)
+#define     PCIE_IRQ_DIR_WR_DDR_DET            BIT(14)
+#define     PCIE_IRQ_CORE_INT                  BIT(16)
+#define     PCIE_IRQ_CORE_INT_PIO              BIT(17)
+#define     PCIE_IRQ_DPMU_INT                  BIT(18)
+#define     PCIE_IRQ_PCIE_MIS_INT              BIT(19)
+#define     PCIE_IRQ_MSI_INT1_DET              BIT(20)
+#define     PCIE_IRQ_MSI_INT2_DET              BIT(21)
+#define     PCIE_IRQ_RC_DBELL_DET              BIT(22)
+#define     PCIE_IRQ_EP_STATUS                 BIT(23)
+#define     PCIE_IRQ_ALL_MASK                  0xfff0fb
+#define     PCIE_IRQ_ENABLE_INTS_MASK          PCIE_IRQ_CORE_INT
+
+/* Transaction types */
+#define PCIE_CONFIG_RD_TYPE0                   0x8
+#define PCIE_CONFIG_RD_TYPE1                   0x9
+#define PCIE_CONFIG_WR_TYPE0                   0xa
+#define PCIE_CONFIG_WR_TYPE1                   0xb
+
+/* PCI_BDF shifts 8bit, so we need extra 4bit shift */
+#define PCIE_BDF(dev)                          (dev << 4)
+#define PCIE_CONF_BUS(bus)                     (((bus) & 0xff) << 20)
+#define PCIE_CONF_DEV(dev)                     (((dev) & 0x1f) << 15)
+#define PCIE_CONF_FUNC(fun)                    (((fun) & 0x7)  << 12)
+#define PCIE_CONF_REG(reg)                     ((reg) & 0xffc)
+#define PCIE_CONF_ADDR(bus, devfn, where)      \
+       (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))    | \
+        PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
+
+#define PIO_TIMEOUT_MS                 1
+
+#define LINK_WAIT_MAX_RETRIES          10
+#define LINK_WAIT_USLEEP_MIN           90000
+#define LINK_WAIT_USLEEP_MAX           100000
+
+#define LEGACY_IRQ_NUM                 4
+#define MSI_IRQ_NUM                    32
+
+struct advk_pcie {
+       struct platform_device *pdev;
+       void __iomem *base;
+       struct list_head resources;
+       struct irq_domain *irq_domain;
+       struct irq_chip irq_chip;
+       struct msi_controller msi;
+       struct irq_domain *msi_domain;
+       struct irq_chip msi_irq_chip;
+       DECLARE_BITMAP(msi_irq_in_use, MSI_IRQ_NUM);
+       struct mutex msi_used_lock;
+       u16 msi_msg;
+       int root_bus_nr;
+};
+
+static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
+{
+       writel(val, pcie->base + reg);
+}
+
+static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg)
+{
+       return readl(pcie->base + reg);
+}
+
+static int advk_pcie_link_up(struct advk_pcie *pcie)
+{
+       u32 val, ltssm_state;
+
+       val = advk_readl(pcie, CFG_REG);
+       ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
+       return ltssm_state >= LTSSM_L0;
+}
+
+static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
+{
+       int retries;
+
+       /* check if the link is up or not */
+       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+               if (advk_pcie_link_up(pcie)) {
+                       dev_info(&pcie->pdev->dev, "link up\n");
+                       return 0;
+               }
+
+               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+       }
+
+       dev_err(&pcie->pdev->dev, "link never came up\n");
+
+       return -ETIMEDOUT;
+}
+
+/*
+ * Set PCIe address window register which could be used for memory
+ * mapping.
+ */
+static void advk_pcie_set_ob_win(struct advk_pcie *pcie,
+                                u32 win_num, u32 match_ms,
+                                u32 match_ls, u32 mask_ms,
+                                u32 mask_ls, u32 remap_ms,
+                                u32 remap_ls, u32 action)
+{
+       advk_writel(pcie, match_ls, OB_WIN_MATCH_LS(win_num));
+       advk_writel(pcie, match_ms, OB_WIN_MATCH_MS(win_num));
+       advk_writel(pcie, mask_ms, OB_WIN_MASK_MS(win_num));
+       advk_writel(pcie, mask_ls, OB_WIN_MASK_LS(win_num));
+       advk_writel(pcie, remap_ms, OB_WIN_REMAP_MS(win_num));
+       advk_writel(pcie, remap_ls, OB_WIN_REMAP_LS(win_num));
+       advk_writel(pcie, action, OB_WIN_ACTIONS(win_num));
+       advk_writel(pcie, match_ls | BIT(0), OB_WIN_MATCH_LS(win_num));
+}
+
+static void advk_pcie_setup_hw(struct advk_pcie *pcie)
+{
+       u32 reg;
+       int i;
+
+       /* Point PCIe unit MBUS decode windows to DRAM space */
+       for (i = 0; i < 8; i++)
+               advk_pcie_set_ob_win(pcie, i, 0, 0, 0, 0, 0, 0, 0);
+
+       /* Set to Direct mode */
+       reg = advk_readl(pcie, CTRL_CONFIG_REG);
+       reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
+       reg |= ((PCIE_CORE_MODE_DIRECT & CTRL_MODE_MASK) << CTRL_MODE_SHIFT);
+       advk_writel(pcie, reg, CTRL_CONFIG_REG);
+
+       /* Set PCI global control register to RC mode */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+       reg |= (IS_RC_MSK << IS_RC_SHIFT);
+       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+       /* Set Advanced Error Capabilities and Control PF0 register */
+       reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
+               PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |
+               PCIE_CORE_ERR_CAPCTL_ECRC_CHCK |
+               PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV;
+       advk_writel(pcie, reg, PCIE_CORE_ERR_CAPCTL_REG);
+
+       /* Set PCIe Device Control and Status 1 PF0 register */
+       reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE |
+               (7 << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) |
+               PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE |
+               PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT;
+       advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG);
+
+       /* Program PCIe Control 2 to disable strict ordering */
+       reg = PCIE_CORE_CTRL2_RESERVED |
+               PCIE_CORE_CTRL2_TD_ENABLE;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+       /* Set GEN2 */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+       reg &= ~PCIE_GEN_SEL_MSK;
+       reg |= SPEED_GEN_2;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+       /* Set lane X1 */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+       reg &= ~LANE_CNT_MSK;
+       reg |= LANE_COUNT_1;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+       /* Enable link training */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
+       reg |= LINK_TRAINING_EN;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
+
+       /* Enable MSI */
+       reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
+       reg |= PCIE_CORE_CTRL2_MSI_ENABLE;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+       /* Clear all interrupts */
+       advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_REG);
+       advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
+       advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
+
+       /* Disable All ISR0/1 Sources */
+       reg = PCIE_ISR0_ALL_MASK;
+       reg &= ~PCIE_ISR0_MSI_INT_PENDING;
+       advk_writel(pcie, reg, PCIE_ISR0_MASK_REG);
+
+       advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
+
+       /* Unmask all MSI's */
+       advk_writel(pcie, 0, PCIE_MSI_MASK_REG);
+
+       /* Enable summary interrupt for GIC SPI source */
+       reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK);
+       advk_writel(pcie, reg, HOST_CTRL_INT_MASK_REG);
+
+       reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
+       reg |= PCIE_CORE_CTRL2_OB_WIN_ENABLE;
+       advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
+
+       /* Bypass the address window mapping for PIO */
+       reg = advk_readl(pcie, PIO_CTRL);
+       reg |= PIO_CTRL_ADDR_WIN_DISABLE;
+       advk_writel(pcie, reg, PIO_CTRL);
+
+       /* Start link training */
+       reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
+       reg |= PCIE_CORE_LINK_TRAINING;
+       advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
+
+       advk_pcie_wait_for_link(pcie);
+
+       reg = PCIE_CORE_LINK_L0S_ENTRY |
+               (1 << PCIE_CORE_LINK_WIDTH_SHIFT);
+       advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
+
+       reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
+       reg |= PCIE_CORE_CMD_MEM_ACCESS_EN |
+               PCIE_CORE_CMD_IO_ACCESS_EN |
+               PCIE_CORE_CMD_MEM_IO_REQ_EN;
+       advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG);
+}
+
+static void advk_pcie_check_pio_status(struct advk_pcie *pcie)
+{
+       u32 reg;
+       unsigned int status;
+       char *strcomp_status, *str_posted;
+
+       reg = advk_readl(pcie, PIO_STAT);
+       status = (reg & PIO_COMPLETION_STATUS_MASK) >>
+               PIO_COMPLETION_STATUS_SHIFT;
+
+       if (!status)
+               return;
+
+       switch (status) {
+       case PIO_COMPLETION_STATUS_UR:
+               strcomp_status = "UR";
+               break;
+       case PIO_COMPLETION_STATUS_CRS:
+               strcomp_status = "CRS";
+               break;
+       case PIO_COMPLETION_STATUS_CA:
+               strcomp_status = "CA";
+               break;
+       default:
+               strcomp_status = "Unknown";
+               break;
+       }
+
+       if (reg & PIO_NON_POSTED_REQ)
+               str_posted = "Non-posted";
+       else
+               str_posted = "Posted";
+
+       dev_err(&pcie->pdev->dev, "%s PIO Response Status: %s, %#x @ %#x\n",
+               str_posted, strcomp_status, reg, advk_readl(pcie, PIO_ADDR_LS));
+}
+
+static int advk_pcie_wait_pio(struct advk_pcie *pcie)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(PIO_TIMEOUT_MS);
+
+       while (time_before(jiffies, timeout)) {
+               u32 start, isr;
+
+               start = advk_readl(pcie, PIO_START);
+               isr = advk_readl(pcie, PIO_ISR);
+               if (!start && isr)
+                       return 0;
+       }
+
+       dev_err(&pcie->pdev->dev, "config read/write timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
+                            int where, int size, u32 *val)
+{
+       struct advk_pcie *pcie = bus->sysdata;
+       u32 reg;
+       int ret;
+
+       if (PCI_SLOT(devfn) != 0) {
+               *val = 0xffffffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       /* Start PIO */
+       advk_writel(pcie, 0, PIO_START);
+       advk_writel(pcie, 1, PIO_ISR);
+
+       /* Program the control register */
+       reg = advk_readl(pcie, PIO_CTRL);
+       reg &= ~PIO_CTRL_TYPE_MASK;
+       if (bus->number ==  pcie->root_bus_nr)
+               reg |= PCIE_CONFIG_RD_TYPE0;
+       else
+               reg |= PCIE_CONFIG_RD_TYPE1;
+       advk_writel(pcie, reg, PIO_CTRL);
+
+       /* Program the address registers */
+       reg = PCIE_BDF(devfn) | PCIE_CONF_REG(where);
+       advk_writel(pcie, reg, PIO_ADDR_LS);
+       advk_writel(pcie, 0, PIO_ADDR_MS);
+
+       /* Program the data strobe */
+       advk_writel(pcie, 0xf, PIO_WR_DATA_STRB);
+
+       /* Start the transfer */
+       advk_writel(pcie, 1, PIO_START);
+
+       ret = advk_pcie_wait_pio(pcie);
+       if (ret < 0)
+               return PCIBIOS_SET_FAILED;
+
+       advk_pcie_check_pio_status(pcie);
+
+       /* Get the read result */
+       *val = advk_readl(pcie, PIO_RD_DATA);
+       if (size == 1)
+               *val = (*val >> (8 * (where & 3))) & 0xff;
+       else if (size == 2)
+               *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+                               int where, int size, u32 val)
+{
+       struct advk_pcie *pcie = bus->sysdata;
+       u32 reg;
+       u32 data_strobe = 0x0;
+       int offset;
+       int ret;
+
+       if (PCI_SLOT(devfn) != 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       if (where % size)
+               return PCIBIOS_SET_FAILED;
+
+       /* Start PIO */
+       advk_writel(pcie, 0, PIO_START);
+       advk_writel(pcie, 1, PIO_ISR);
+
+       /* Program the control register */
+       reg = advk_readl(pcie, PIO_CTRL);
+       reg &= ~PIO_CTRL_TYPE_MASK;
+       if (bus->number == pcie->root_bus_nr)
+               reg |= PCIE_CONFIG_WR_TYPE0;
+       else
+               reg |= PCIE_CONFIG_WR_TYPE1;
+       advk_writel(pcie, reg, PIO_CTRL);
+
+       /* Program the address registers */
+       reg = PCIE_CONF_ADDR(bus->number, devfn, where);
+       advk_writel(pcie, reg, PIO_ADDR_LS);
+       advk_writel(pcie, 0, PIO_ADDR_MS);
+
+       /* Calculate the write strobe */
+       offset      = where & 0x3;
+       reg         = val << (8 * offset);
+       data_strobe = GENMASK(size - 1, 0) << offset;
+
+       /* Program the data register */
+       advk_writel(pcie, reg, PIO_WR_DATA);
+
+       /* Program the data strobe */
+       advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB);
+
+       /* Start the transfer */
+       advk_writel(pcie, 1, PIO_START);
+
+       ret = advk_pcie_wait_pio(pcie);
+       if (ret < 0)
+               return PCIBIOS_SET_FAILED;
+
+       advk_pcie_check_pio_status(pcie);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops advk_pcie_ops = {
+       .read = advk_pcie_rd_conf,
+       .write = advk_pcie_wr_conf,
+};
+
+static int advk_pcie_alloc_msi(struct advk_pcie *pcie)
+{
+       int hwirq;
+
+       mutex_lock(&pcie->msi_used_lock);
+       hwirq = find_first_zero_bit(pcie->msi_irq_in_use, MSI_IRQ_NUM);
+       if (hwirq >= MSI_IRQ_NUM)
+               hwirq = -ENOSPC;
+       else
+               set_bit(hwirq, pcie->msi_irq_in_use);
+       mutex_unlock(&pcie->msi_used_lock);
+
+       return hwirq;
+}
+
+static void advk_pcie_free_msi(struct advk_pcie *pcie, int hwirq)
+{
+       mutex_lock(&pcie->msi_used_lock);
+       if (!test_bit(hwirq, pcie->msi_irq_in_use))
+               dev_err(&pcie->pdev->dev, "trying to free unused MSI#%d\n",
+                       hwirq);
+       else
+               clear_bit(hwirq, pcie->msi_irq_in_use);
+       mutex_unlock(&pcie->msi_used_lock);
+}
+
+static int advk_pcie_setup_msi_irq(struct msi_controller *chip,
+                                  struct pci_dev *pdev,
+                                  struct msi_desc *desc)
+{
+       struct advk_pcie *pcie = pdev->bus->sysdata;
+       struct msi_msg msg;
+       int virq, hwirq;
+       phys_addr_t msi_msg_phys;
+
+       /* We support MSI, but not MSI-X */
+       if (desc->msi_attrib.is_msix)
+               return -EINVAL;
+
+       hwirq = advk_pcie_alloc_msi(pcie);
+       if (hwirq < 0)
+               return hwirq;
+
+       virq = irq_create_mapping(pcie->msi_domain, hwirq);
+       if (!virq) {
+               advk_pcie_free_msi(pcie, hwirq);
+               return -EINVAL;
+       }
+
+       irq_set_msi_desc(virq, desc);
+
+       msi_msg_phys = virt_to_phys(&pcie->msi_msg);
+
+       msg.address_lo = lower_32_bits(msi_msg_phys);
+       msg.address_hi = upper_32_bits(msi_msg_phys);
+       msg.data = virq;
+
+       pci_write_msi_msg(virq, &msg);
+
+       return 0;
+}
+
+static void advk_pcie_teardown_msi_irq(struct msi_controller *chip,
+                                      unsigned int irq)
+{
+       struct irq_data *d = irq_get_irq_data(irq);
+       struct msi_desc *msi = irq_data_get_msi_desc(d);
+       struct advk_pcie *pcie = msi_desc_to_pci_sysdata(msi);
+       unsigned long hwirq = d->hwirq;
+
+       irq_dispose_mapping(irq);
+       advk_pcie_free_msi(pcie, hwirq);
+}
+
+static int advk_pcie_msi_map(struct irq_domain *domain,
+                            unsigned int virq, irq_hw_number_t hw)
+{
+       struct advk_pcie *pcie = domain->host_data;
+
+       irq_set_chip_and_handler(virq, &pcie->msi_irq_chip,
+                                handle_simple_irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops advk_pcie_msi_irq_ops = {
+       .map = advk_pcie_msi_map,
+};
+
+static void advk_pcie_irq_mask(struct irq_data *d)
+{
+       struct advk_pcie *pcie = d->domain->host_data;
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
+       u32 mask;
+
+       mask = advk_readl(pcie, PCIE_ISR0_MASK_REG);
+       mask |= PCIE_ISR0_INTX_ASSERT(hwirq);
+       advk_writel(pcie, mask, PCIE_ISR0_MASK_REG);
+}
+
+static void advk_pcie_irq_unmask(struct irq_data *d)
+{
+       struct advk_pcie *pcie = d->domain->host_data;
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
+       u32 mask;
+
+       mask = advk_readl(pcie, PCIE_ISR0_MASK_REG);
+       mask &= ~PCIE_ISR0_INTX_ASSERT(hwirq);
+       advk_writel(pcie, mask, PCIE_ISR0_MASK_REG);
+}
+
+static int advk_pcie_irq_map(struct irq_domain *h,
+                            unsigned int virq, irq_hw_number_t hwirq)
+{
+       struct advk_pcie *pcie = h->host_data;
+
+       advk_pcie_irq_mask(irq_get_irq_data(virq));
+       irq_set_status_flags(virq, IRQ_LEVEL);
+       irq_set_chip_and_handler(virq, &pcie->irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(virq, pcie);
+
+       return 0;
+}
+
+static const struct irq_domain_ops advk_pcie_irq_domain_ops = {
+       .map = advk_pcie_irq_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct irq_chip *msi_irq_chip;
+       struct msi_controller *msi;
+       phys_addr_t msi_msg_phys;
+       int ret;
+
+       msi_irq_chip = &pcie->msi_irq_chip;
+
+       msi_irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-msi",
+                                           dev_name(dev));
+       if (!msi_irq_chip->name)
+               return -ENOMEM;
+
+       msi_irq_chip->irq_enable = pci_msi_unmask_irq;
+       msi_irq_chip->irq_disable = pci_msi_mask_irq;
+       msi_irq_chip->irq_mask = pci_msi_mask_irq;
+       msi_irq_chip->irq_unmask = pci_msi_unmask_irq;
+
+       msi = &pcie->msi;
+
+       msi->setup_irq = advk_pcie_setup_msi_irq;
+       msi->teardown_irq = advk_pcie_teardown_msi_irq;
+       msi->of_node = node;
+
+       mutex_init(&pcie->msi_used_lock);
+
+       msi_msg_phys = virt_to_phys(&pcie->msi_msg);
+
+       advk_writel(pcie, lower_32_bits(msi_msg_phys),
+                   PCIE_MSI_ADDR_LOW_REG);
+       advk_writel(pcie, upper_32_bits(msi_msg_phys),
+                   PCIE_MSI_ADDR_HIGH_REG);
+
+       pcie->msi_domain =
+               irq_domain_add_linear(NULL, MSI_IRQ_NUM,
+                                     &advk_pcie_msi_irq_ops, pcie);
+       if (!pcie->msi_domain)
+               return -ENOMEM;
+
+       ret = of_pci_msi_chip_add(msi);
+       if (ret < 0) {
+               irq_domain_remove(pcie->msi_domain);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void advk_pcie_remove_msi_irq_domain(struct advk_pcie *pcie)
+{
+       of_pci_msi_chip_remove(&pcie->msi);
+       irq_domain_remove(pcie->msi_domain);
+}
+
+static int advk_pcie_init_irq_domain(struct advk_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct device_node *pcie_intc_node;
+       struct irq_chip *irq_chip;
+
+       pcie_intc_node =  of_get_next_child(node, NULL);
+       if (!pcie_intc_node) {
+               dev_err(dev, "No PCIe Intc node found\n");
+               return -ENODEV;
+       }
+
+       irq_chip = &pcie->irq_chip;
+
+       irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq",
+                                       dev_name(dev));
+       if (!irq_chip->name) {
+               of_node_put(pcie_intc_node);
+               return -ENOMEM;
+       }
+
+       irq_chip->irq_mask = advk_pcie_irq_mask;
+       irq_chip->irq_mask_ack = advk_pcie_irq_mask;
+       irq_chip->irq_unmask = advk_pcie_irq_unmask;
+
+       pcie->irq_domain =
+               irq_domain_add_linear(pcie_intc_node, LEGACY_IRQ_NUM,
+                                     &advk_pcie_irq_domain_ops, pcie);
+       if (!pcie->irq_domain) {
+               dev_err(dev, "Failed to get a INTx IRQ domain\n");
+               of_node_put(pcie_intc_node);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie)
+{
+       irq_domain_remove(pcie->irq_domain);
+}
+
+static void advk_pcie_handle_msi(struct advk_pcie *pcie)
+{
+       u32 msi_val, msi_mask, msi_status, msi_idx;
+       u16 msi_data;
+
+       msi_mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
+       msi_val = advk_readl(pcie, PCIE_MSI_STATUS_REG);
+       msi_status = msi_val & ~msi_mask;
+
+       for (msi_idx = 0; msi_idx < MSI_IRQ_NUM; msi_idx++) {
+               if (!(BIT(msi_idx) & msi_status))
+                       continue;
+
+               advk_writel(pcie, BIT(msi_idx), PCIE_MSI_STATUS_REG);
+               msi_data = advk_readl(pcie, PCIE_MSI_PAYLOAD_REG) & 0xFF;
+               generic_handle_irq(msi_data);
+       }
+
+       advk_writel(pcie, PCIE_ISR0_MSI_INT_PENDING,
+                   PCIE_ISR0_REG);
+}
+
+static void advk_pcie_handle_int(struct advk_pcie *pcie)
+{
+       u32 val, mask, status;
+       int i, virq;
+
+       val = advk_readl(pcie, PCIE_ISR0_REG);
+       mask = advk_readl(pcie, PCIE_ISR0_MASK_REG);
+       status = val & ((~mask) & PCIE_ISR0_ALL_MASK);
+
+       if (!status) {
+               advk_writel(pcie, val, PCIE_ISR0_REG);
+               return;
+       }
+
+       /* Process MSI interrupts */
+       if (status & PCIE_ISR0_MSI_INT_PENDING)
+               advk_pcie_handle_msi(pcie);
+
+       /* Process legacy interrupts */
+       for (i = 0; i < LEGACY_IRQ_NUM; i++) {
+               if (!(status & PCIE_ISR0_INTX_ASSERT(i)))
+                       continue;
+
+               advk_writel(pcie, PCIE_ISR0_INTX_ASSERT(i),
+                           PCIE_ISR0_REG);
+
+               virq = irq_find_mapping(pcie->irq_domain, i);
+               generic_handle_irq(virq);
+       }
+}
+
+static irqreturn_t advk_pcie_irq_handler(int irq, void *arg)
+{
+       struct advk_pcie *pcie = arg;
+       u32 status;
+
+       status = advk_readl(pcie, HOST_CTRL_INT_STATUS_REG);
+       if (!(status & PCIE_IRQ_CORE_INT))
+               return IRQ_NONE;
+
+       advk_pcie_handle_int(pcie);
+
+       /* Clear interrupt */
+       advk_writel(pcie, PCIE_IRQ_CORE_INT, HOST_CTRL_INT_STATUS_REG);
+
+       return IRQ_HANDLED;
+}
+
+static int advk_pcie_parse_request_of_pci_ranges(struct advk_pcie *pcie)
+{
+       int err, res_valid = 0;
+       struct device *dev = &pcie->pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct resource_entry *win;
+       resource_size_t iobase;
+
+       INIT_LIST_HEAD(&pcie->resources);
+
+       err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pcie->resources,
+                                              &iobase);
+       if (err)
+               return err;
+
+       err = devm_request_pci_bus_resources(dev, &pcie->resources);
+       if (err)
+               goto out_release_res;
+
+       resource_list_for_each_entry(win, &pcie->resources) {
+               struct resource *res = win->res;
+
+               switch (resource_type(res)) {
+               case IORESOURCE_IO:
+                       advk_pcie_set_ob_win(pcie, 1,
+                                            upper_32_bits(res->start),
+                                            lower_32_bits(res->start),
+                                            0, 0xF8000000, 0,
+                                            lower_32_bits(res->start),
+                                            OB_PCIE_IO);
+                       err = pci_remap_iospace(res, iobase);
+                       if (err)
+                               dev_warn(dev, "error %d: failed to map resource %pR\n",
+                                        err, res);
+                       break;
+               case IORESOURCE_MEM:
+                       advk_pcie_set_ob_win(pcie, 0,
+                                            upper_32_bits(res->start),
+                                            lower_32_bits(res->start),
+                                            0x0, 0xF8000000, 0,
+                                            lower_32_bits(res->start),
+                                            (2 << 20) | OB_PCIE_MEM);
+                       res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+                       break;
+               case IORESOURCE_BUS:
+                       pcie->root_bus_nr = res->start;
+                       break;
+               }
+       }
+
+       if (!res_valid) {
+               dev_err(dev, "non-prefetchable memory resource required\n");
+               err = -EINVAL;
+               goto out_release_res;
+       }
+
+       return 0;
+
+out_release_res:
+       pci_free_resource_list(&pcie->resources);
+       return err;
+}
+
+static int advk_pcie_probe(struct platform_device *pdev)
+{
+       struct advk_pcie *pcie;
+       struct resource *res;
+       struct pci_bus *bus, *child;
+       struct msi_controller *msi;
+       struct device_node *msi_node;
+       int ret, irq;
+
+       pcie = devm_kzalloc(&pdev->dev, sizeof(struct advk_pcie),
+                           GFP_KERNEL);
+       if (!pcie)
+               return -ENOMEM;
+
+       pcie->pdev = pdev;
+       platform_set_drvdata(pdev, pcie);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pcie->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pcie->base)) {
+               dev_err(&pdev->dev, "Failed to map registers\n");
+               return PTR_ERR(pcie->base);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(&pdev->dev, irq, advk_pcie_irq_handler,
+                              IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie",
+                              pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register interrupt\n");
+               return ret;
+       }
+
+       ret = advk_pcie_parse_request_of_pci_ranges(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to parse resources\n");
+               return ret;
+       }
+
+       advk_pcie_setup_hw(pcie);
+
+       ret = advk_pcie_init_irq_domain(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize irq\n");
+               return ret;
+       }
+
+       ret = advk_pcie_init_msi_irq_domain(pcie);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize irq\n");
+               advk_pcie_remove_irq_domain(pcie);
+               return ret;
+       }
+
+       msi_node = of_parse_phandle(pdev->dev.of_node, "msi-parent", 0);
+       if (msi_node)
+               msi = of_pci_find_msi_chip_by_node(msi_node);
+       else
+               msi = NULL;
+
+       bus = pci_scan_root_bus_msi(&pdev->dev, 0, &advk_pcie_ops,
+                                   pcie, &pcie->resources, &pcie->msi);
+       if (!bus) {
+               advk_pcie_remove_msi_irq_domain(pcie);
+               advk_pcie_remove_irq_domain(pcie);
+               return -ENOMEM;
+       }
+
+       pci_bus_assign_resources(bus);
+
+       list_for_each_entry(child, &bus->children, node)
+               pcie_bus_configure_settings(child);
+
+       pci_bus_add_devices(bus);
+
+       return 0;
+}
+
+static const struct of_device_id advk_pcie_of_match_table[] = {
+       { .compatible = "marvell,armada-3700-pcie", },
+       {},
+};
+
+static struct platform_driver advk_pcie_driver = {
+       .driver = {
+               .name = "advk-pcie",
+               .of_match_table = advk_pcie_of_match_table,
+               /* Driver unloading/unbinding currently not supported */
+               .suppress_bind_attrs = true,
+       },
+       .probe = advk_pcie_probe,
+};
+builtin_platform_driver(advk_pcie_driver);
index f441130..81b3949 100644 (file)
@@ -181,14 +181,14 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
 
        if (!pcie_intc_node) {
                dev_err(dev, "No PCIe Intc node found\n");
-               return PTR_ERR(pcie_intc_node);
+               return -ENODEV;
        }
 
        pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
                                               &intx_domain_ops, pp);
        if (!pp->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
-               return PTR_ERR(pp->irq_domain);
+               return -ENODEV;
        }
 
        return 0;
index 8cba7ab..9d9d34e 100644 (file)
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
                       struct list_head *resources, struct resource **bus_range)
 {
@@ -36,44 +35,34 @@ static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, resources);
+       if (err)
+               return err;
+
        resource_list_for_each_entry(win, resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
                switch (resource_type(res)) {
                case IORESOURCE_IO:
-                       parent = &ioport_resource;
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
-                       parent = &iomem_resource;
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
                        break;
                case IORESOURCE_BUS:
                        *bus_range = res;
-               default:
-                       continue;
+                       break;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
-       }
-
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
        }
 
-       return 0;
+       if (res_valid)
+               return 0;
 
-out_release_res:
-       return err;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       return -EINVAL;
 }
 
 static void gen_pci_unmap_cfg(void *ptr)
@@ -155,7 +144,14 @@ int pci_host_common_probe(struct platform_device *pdev,
 
        pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
 
-       if (!pci_has_flag(PCI_PROBE_ONLY)) {
+       /*
+        * We insert PCI resources into the iomem_resource and
+        * ioport_resource trees in either pci_bus_claim_resources()
+        * or pci_bus_assign_resources().
+        */
+       if (pci_has_flag(PCI_PROBE_ONLY)) {
+               pci_bus_claim_resources(bus);
+       } else {
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
 
index 6eaceab..c05ea9d 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
        .bus_shift      = 16,
        .pci_ops        = {
@@ -46,8 +45,6 @@ static const struct of_device_id gen_pci_of_match[] = {
        { },
 };
 
-MODULE_DEVICE_TABLE(of, gen_pci_of_match);
-
 static int gen_pci_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id;
@@ -66,8 +63,4 @@ static struct platform_driver gen_pci_driver = {
        },
        .probe = gen_pci_probe,
 };
-module_platform_driver(gen_pci_driver);
-
-MODULE_DESCRIPTION("Generic PCI host driver");
-MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(gen_pci_driver);
index 7e9b2de..6955ffd 100644 (file)
@@ -732,16 +732,18 @@ static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info,
 
        pdev = msi_desc_to_pci_dev(msi);
        hbus = info->data;
-       hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
-       if (!hpdev)
+       int_desc = irq_data_get_irq_chip_data(irq_data);
+       if (!int_desc)
                return;
 
-       int_desc = irq_data_get_irq_chip_data(irq_data);
-       if (int_desc) {
-               irq_data->chip_data = NULL;
-               hv_int_desc_free(hpdev, int_desc);
+       irq_data->chip_data = NULL;
+       hpdev = get_pcichild_wslot(hbus, devfn_to_wslot(pdev->devfn));
+       if (!hpdev) {
+               kfree(int_desc);
+               return;
        }
 
+       hv_int_desc_free(hpdev, int_desc);
        put_pcichild(hpdev, hv_pcidev_ref_by_slot);
 }
 
@@ -1657,14 +1659,16 @@ static void hv_pci_onchannelcallback(void *context)
                        continue;
                }
 
+               /* Zero length indicates there are no more packets. */
+               if (ret || !bytes_recvd)
+                       break;
+
                /*
                 * All incoming packets must be at least as large as a
                 * response.
                 */
-               if (bytes_recvd <= sizeof(struct pci_response)) {
-                       kfree(buffer);
-                       return;
-               }
+               if (bytes_recvd <= sizeof(struct pci_response))
+                       continue;
                desc = (struct vmpacket_descriptor *)buffer;
 
                switch (desc->type) {
@@ -1679,8 +1683,7 @@ static void hv_pci_onchannelcallback(void *context)
                        comp_packet->completion_func(comp_packet->compl_ctxt,
                                                     response,
                                                     bytes_recvd);
-                       kfree(buffer);
-                       return;
+                       break;
 
                case VM_PKT_DATA_INBAND:
 
@@ -1727,8 +1730,9 @@ static void hv_pci_onchannelcallback(void *context)
                                desc->type, req_id, bytes_recvd);
                        break;
                }
-               break;
        }
+
+       kfree(buffer);
 }
 
 /**
index 6b8301e..8ba2883 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/of_irq.h>
 #include <linux/of.h>
@@ -360,7 +360,6 @@ static const struct of_device_id ks_pcie_of_match[] = {
        },
        { },
 };
-MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
 
 static int __exit ks_pcie_remove(struct platform_device *pdev)
 {
@@ -439,9 +438,4 @@ static struct platform_driver ks_pcie_driver __refdata = {
                .of_match_table = of_match_ptr(ks_pcie_of_match),
        },
 };
-
-module_platform_driver(ks_pcie_driver);
-
-MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
-MODULE_DESCRIPTION("Keystone PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(ks_pcie_driver);
index a21e229..114ba81 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
@@ -211,7 +211,6 @@ static const struct of_device_id ls_pcie_of_match[] = {
        { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
        { },
 };
-MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
 
 static int __init ls_add_pcie_port(struct pcie_port *pp,
                                   struct platform_device *pdev)
@@ -275,9 +274,4 @@ static struct platform_driver ls_pcie_driver = {
                .of_match_table = ls_pcie_of_match,
        },
 };
-
-module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe);
-
-MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>");
-MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver_probe(ls_pcie_driver, ls_pcie_probe);
index 6b451df..307f81d 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * PCIe driver for Marvell Armada 370 and Armada XP SoCs
  *
+ * Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
@@ -11,7 +13,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/mbus.h>
 #include <linux/msi.h>
 #include <linux/slab.h>
@@ -839,25 +841,22 @@ static struct pci_ops mvebu_pcie_ops = {
 static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
 {
        struct mvebu_pcie *pcie = sys_to_pcie(sys);
-       int i;
+       int err, i;
 
        pcie->mem.name = "PCI MEM";
        pcie->realio.name = "PCI I/O";
 
-       if (request_resource(&iomem_resource, &pcie->mem))
-               return 0;
-
-       if (resource_size(&pcie->realio) != 0) {
-               if (request_resource(&ioport_resource, &pcie->realio)) {
-                       release_resource(&pcie->mem);
-                       return 0;
-               }
+       if (resource_size(&pcie->realio) != 0)
                pci_add_resource_offset(&sys->resources, &pcie->realio,
                                        sys->io_offset);
-       }
+
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
+       err = devm_request_pci_bus_resources(&pcie->pdev->dev, &sys->resources);
+       if (err)
+               return 0;
+
        for (i = 0; i < pcie->nports; i++) {
                struct mvebu_pcie_port *port = &pcie->ports[i];
 
@@ -1298,7 +1297,6 @@ static const struct of_device_id mvebu_pcie_of_match_table[] = {
        { .compatible = "marvell,kirkwood-pcie", },
        {},
 };
-MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table);
 
 static const struct dev_pm_ops mvebu_pcie_pm_ops = {
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mvebu_pcie_suspend, mvebu_pcie_resume)
@@ -1314,8 +1312,4 @@ static struct platform_driver mvebu_pcie_driver = {
        },
        .probe = mvebu_pcie_probe,
 };
-module_platform_driver(mvebu_pcie_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell EBU PCIe driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(mvebu_pcie_driver);
index 9980a4b..597566f 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2013 Renesas Solutions Corp.
  * Copyright (C) 2013 Cogent Embedded, Inc.
  *
+ * Author: Valentine Barshak <valentine.barshak@cogentembedded.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.
@@ -14,7 +16,6 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 #include <linux/pci.h>
@@ -97,7 +98,6 @@
 struct rcar_pci_priv {
        struct device *dev;
        void __iomem *reg;
-       struct resource io_res;
        struct resource mem_res;
        struct resource *cfg_res;
        unsigned busnr;
@@ -194,6 +194,7 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
        struct rcar_pci_priv *priv = sys->private_data;
        void __iomem *reg = priv->reg;
        u32 val;
+       int ret;
 
        pm_runtime_enable(priv->dev);
        pm_runtime_get_sync(priv->dev);
@@ -273,8 +274,10 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
                rcar_pci_setup_errirq(priv);
 
        /* Add PCI resources */
-       pci_add_resource(&sys->resources, &priv->io_res);
        pci_add_resource(&sys->resources, &priv->mem_res);
+       ret = devm_request_pci_bus_resources(priv->dev, &sys->resources);
+       if (ret < 0)
+               return ret;
 
        /* Setup bus number based on platform device id / of bus-range */
        sys->busnr = priv->busnr;
@@ -371,14 +374,6 @@ static int rcar_pci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv->mem_res = *mem_res;
-       /*
-        * The controller does not support/use port I/O,
-        * so setup a dummy port I/O region here.
-        */
-       priv->io_res.start = priv->mem_res.start;
-       priv->io_res.end = priv->mem_res.end;
-       priv->io_res.flags = IORESOURCE_IO;
-
        priv->cfg_res = cfg_res;
 
        priv->irq = platform_get_irq(pdev, 0);
@@ -421,6 +416,7 @@ static int rcar_pci_probe(struct platform_device *pdev)
        hw_private[0] = priv;
        memset(&hw, 0, sizeof(hw));
        hw.nr_controllers = ARRAY_SIZE(hw_private);
+       hw.io_optional = 1;
        hw.private_data = hw_private;
        hw.map_irq = rcar_pci_map_irq;
        hw.ops = &rcar_pci_ops;
@@ -437,8 +433,6 @@ static struct of_device_id rcar_pci_of_match[] = {
        { },
 };
 
-MODULE_DEVICE_TABLE(of, rcar_pci_of_match);
-
 static struct platform_driver rcar_pci_driver = {
        .driver = {
                .name = "pci-rcar-gen2",
@@ -447,9 +441,4 @@ static struct platform_driver rcar_pci_driver = {
        },
        .probe = rcar_pci_probe,
 };
-
-module_platform_driver(rcar_pci_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
-MODULE_AUTHOR("Valentine Barshak <valentine.barshak@cogentembedded.com>");
+builtin_platform_driver(rcar_pci_driver);
index c388468..6de0757 100644 (file)
@@ -9,6 +9,8 @@
  *
  * Bits taken from arch/arm/mach-dove/pcie.c
  *
+ * Author: Thierry Reding <treding@nvidia.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
@@ -32,7 +34,7 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
 
 #define AFI_PEXBIAS_CTRL_0             0x168
 
-#define RP_VEND_XP     0x00000F00
+#define RP_VEND_XP     0x00000f00
 #define  RP_VEND_XP_DL_UP      (1 << 30)
 
-#define RP_PRIV_MISC   0x00000FE0
-#define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
-#define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+#define RP_PRIV_MISC   0x00000fe0
+#define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0)
+#define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0)
 
 #define RP_LINK_CONTROL_STATUS                 0x00000090
 #define  RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
 #define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK  0x3fff0000
 
-#define PADS_CTL_SEL           0x0000009C
+#define PADS_CTL_SEL           0x0000009c
 
-#define PADS_CTL               0x000000A0
+#define PADS_CTL               0x000000a0
 #define  PADS_CTL_IDDQ_1L      (1 << 0)
 #define  PADS_CTL_TX_DATA_EN_1L        (1 << 6)
 #define  PADS_CTL_RX_DATA_EN_1L        (1 << 10)
 
-#define PADS_PLL_CTL_TEGRA20                   0x000000B8
-#define PADS_PLL_CTL_TEGRA30                   0x000000B4
+#define PADS_PLL_CTL_TEGRA20                   0x000000b8
+#define PADS_PLL_CTL_TEGRA30                   0x000000b4
 #define  PADS_PLL_CTL_RST_B4SM                 (1 << 1)
 #define  PADS_PLL_CTL_LOCKDET                  (1 << 8)
 #define  PADS_PLL_CTL_REFCLK_MASK              (0x3 << 16)
 #define  PADS_PLL_CTL_TXCLKREF_DIV5            (1 << 20)
 #define  PADS_PLL_CTL_TXCLKREF_BUF_EN          (1 << 22)
 
-#define PADS_REFCLK_CFG0                       0x000000C8
-#define PADS_REFCLK_CFG1                       0x000000CC
-#define PADS_REFCLK_BIAS                       0x000000D0
+#define PADS_REFCLK_CFG0                       0x000000c8
+#define PADS_REFCLK_CFG1                       0x000000cc
+#define PADS_REFCLK_BIAS                       0x000000d0
 
 /*
  * Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
 #define PADS_REFCLK_CFG_PREDI_SHIFT            8  /* 11:8 */
 #define PADS_REFCLK_CFG_DRVI_SHIFT             12 /* 15:12 */
 
-/* Default value provided by HW engineering is 0xfa5c */
-#define PADS_REFCLK_CFG_VALUE \
-       ( \
-               (0x17 << PADS_REFCLK_CFG_TERM_SHIFT)   | \
-               (0    << PADS_REFCLK_CFG_E_TERM_SHIFT) | \
-               (0xa  << PADS_REFCLK_CFG_PREDI_SHIFT)  | \
-               (0xf  << PADS_REFCLK_CFG_DRVI_SHIFT)     \
-       )
-
 struct tegra_msi {
        struct msi_controller chip;
        DECLARE_BITMAP(used, INT_PCI_MSI_NR);
@@ -252,6 +245,8 @@ struct tegra_pcie_soc_data {
        unsigned int msi_base_shift;
        u32 pads_pll_ctl;
        u32 tx_ref_sel;
+       u32 pads_refclk_cfg0;
+       u32 pads_refclk_cfg1;
        bool has_pex_clkreq_en;
        bool has_pex_bias_ctrl;
        bool has_intr_prsnt_sense;
@@ -274,7 +269,6 @@ struct tegra_pcie {
        struct list_head buses;
        struct resource *cs;
 
-       struct resource all;
        struct resource io;
        struct resource pio;
        struct resource mem;
@@ -623,30 +617,21 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        sys->mem_offset = pcie->offset.mem;
        sys->io_offset = pcie->offset.io;
 
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->io);
-       if (err < 0)
-               return err;
-
-       err = devm_request_resource(pcie->dev, &ioport_resource, &pcie->pio);
-       if (err < 0)
-               return err;
-
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
+       err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->io);
        if (err < 0)
                return err;
 
-       err = devm_request_resource(pcie->dev, &pcie->all, &pcie->prefetch);
-       if (err)
-               return err;
-
        pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
        pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &pcie->prefetch,
                                sys->mem_offset);
        pci_add_resource(&sys->resources, &pcie->busn);
 
-       pci_ioremap_io(pcie->pio.start, pcie->io.start);
+       err = devm_request_pci_bus_resources(pcie->dev, &sys->resources);
+       if (err < 0)
+               return err;
 
+       pci_remap_iospace(&pcie->pio, pcie->io.start);
        return 1;
 }
 
@@ -838,12 +823,6 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
        value |= PADS_PLL_CTL_RST_B4SM;
        pads_writel(pcie, value, soc->pads_pll_ctl);
 
-       /* Configure the reference clock driver */
-       value = PADS_REFCLK_CFG_VALUE | (PADS_REFCLK_CFG_VALUE << 16);
-       pads_writel(pcie, value, PADS_REFCLK_CFG0);
-       if (soc->num_ports > 2)
-               pads_writel(pcie, PADS_REFCLK_CFG_VALUE, PADS_REFCLK_CFG1);
-
        /* wait for the PLL to lock */
        err = tegra_pcie_pll_wait(pcie, 500);
        if (err < 0) {
@@ -927,6 +906,7 @@ static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port)
 
 static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
 {
+       const struct tegra_pcie_soc_data *soc = pcie->soc_data;
        struct tegra_pcie_port *port;
        int err;
 
@@ -952,6 +932,12 @@ static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie)
                }
        }
 
+       /* Configure the reference clock driver */
+       pads_writel(pcie, soc->pads_refclk_cfg0, PADS_REFCLK_CFG0);
+
+       if (soc->num_ports > 2)
+               pads_writel(pcie, soc->pads_refclk_cfg1, PADS_REFCLK_CFG1);
+
        return 0;
 }
 
@@ -1822,12 +1808,6 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
        struct resource res;
        int err;
 
-       memset(&pcie->all, 0, sizeof(pcie->all));
-       pcie->all.flags = IORESOURCE_MEM;
-       pcie->all.name = np->full_name;
-       pcie->all.start = ~0;
-       pcie->all.end = 0;
-
        if (of_pci_range_parser_init(&parser, np)) {
                dev_err(pcie->dev, "missing \"ranges\" property\n");
                return -EINVAL;
@@ -1880,18 +1860,8 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
                        }
                        break;
                }
-
-               if (res.start <= pcie->all.start)
-                       pcie->all.start = res.start;
-
-               if (res.end >= pcie->all.end)
-                       pcie->all.end = res.end;
        }
 
-       err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->all);
-       if (err < 0)
-               return err;
-
        err = of_pci_parse_bus_range(np, &pcie->busn);
        if (err < 0) {
                dev_err(pcie->dev, "failed to parse ranges property: %d\n",
@@ -2078,6 +2048,7 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = {
        .msi_base_shift = 0,
        .pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
        .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
+       .pads_refclk_cfg0 = 0xfa5cfa5c,
        .has_pex_clkreq_en = false,
        .has_pex_bias_ctrl = false,
        .has_intr_prsnt_sense = false,
@@ -2090,6 +2061,8 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = {
        .msi_base_shift = 8,
        .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
        .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+       .pads_refclk_cfg0 = 0xfa5cfa5c,
+       .pads_refclk_cfg1 = 0xfa5cfa5c,
        .has_pex_clkreq_en = true,
        .has_pex_bias_ctrl = true,
        .has_intr_prsnt_sense = true,
@@ -2102,6 +2075,7 @@ static const struct tegra_pcie_soc_data tegra124_pcie_data = {
        .msi_base_shift = 8,
        .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
        .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+       .pads_refclk_cfg0 = 0x44ac44ac,
        .has_pex_clkreq_en = true,
        .has_pex_bias_ctrl = true,
        .has_intr_prsnt_sense = true,
@@ -2115,7 +2089,6 @@ static const struct of_device_id tegra_pcie_of_match[] = {
        { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie_data },
        { },
 };
-MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
 
 static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
 {
@@ -2249,8 +2222,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       pcibios_min_mem = 0;
-
        err = tegra_pcie_get_resources(pcie);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to request resources: %d\n", err);
@@ -2306,8 +2277,4 @@ static struct platform_driver tegra_pcie_driver = {
        },
        .probe = tegra_pcie_probe,
 };
-module_platform_driver(tegra_pcie_driver);
-
-MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra PCIe driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(tegra_pcie_driver);
index 540d030..d50a3dc 100644 (file)
@@ -7,14 +7,13 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/of_pci.h>
 #include <linux/of.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 static void set_val(u32 v, int where, int size, u32 *val)
 {
        int shift = (where & 3) * 8;
@@ -360,7 +359,6 @@ static const struct of_device_id thunder_ecam_of_match[] = {
        { .compatible = "cavium,pci-host-thunder-ecam" },
        { },
 };
-MODULE_DEVICE_TABLE(of, thunder_ecam_of_match);
 
 static int thunder_ecam_probe(struct platform_device *pdev)
 {
@@ -374,7 +372,4 @@ static struct platform_driver thunder_ecam_driver = {
        },
        .probe = thunder_ecam_probe,
 };
-module_platform_driver(thunder_ecam_driver);
-
-MODULE_DESCRIPTION("Thunder ECAM PCI host driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(thunder_ecam_driver);
index 9b8ab94..6abaf80 100644 (file)
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
 
-#include "../ecam.h"
-
 #define PEM_CFG_WR 0x28
 #define PEM_CFG_RD 0x30
 
@@ -285,8 +284,9 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
        return pci_generic_config_write(bus, devfn, where, size, val);
 }
 
-static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg)
+static int thunder_pem_init(struct pci_config_window *cfg)
 {
+       struct device *dev = cfg->parent;
        resource_size_t bar4_start;
        struct resource *res_pem;
        struct thunder_pem_pci *pem_pci;
@@ -346,7 +346,6 @@ static const struct of_device_id thunder_pem_of_match[] = {
        { .compatible = "cavium,pci-host-thunder-pem" },
        { },
 };
-MODULE_DEVICE_TABLE(of, thunder_pem_of_match);
 
 static int thunder_pem_probe(struct platform_device *pdev)
 {
@@ -360,7 +359,4 @@ static struct platform_driver thunder_pem_driver = {
        },
        .probe = thunder_pem_probe,
 };
-module_platform_driver(thunder_pem_driver);
-
-MODULE_DESCRIPTION("Thunder PEM PCIe host driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(thunder_pem_driver);
index f843a72..f234405 100644 (file)
@@ -80,21 +80,21 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, res);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, res) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
                switch (resource_type(res)) {
                case IORESOURCE_IO:
-                       parent = &ioport_resource;
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
-                       parent = &iomem_resource;
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
 
                        writel(res->start >> 28, PCI_IMAP(mem));
@@ -102,23 +102,14 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
                        mem++;
 
                        break;
-               case IORESOURCE_BUS:
-               default:
-                       continue;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
-       }
+       if (res_valid)
+               return 0;
 
-       return 0;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       err = -EINVAL;
 
 out_release_res:
        pci_free_resource_list(res);
index ae00ce2..a81273c 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/io.h>
 #include <linux/jiffies.h>
 #include <linux/memblock.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -540,14 +540,20 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+       if (ret)
+               goto error;
+
        ret = xgene_pcie_setup(port, &res, iobase);
        if (ret)
-               return ret;
+               goto error;
 
        bus = pci_create_root_bus(&pdev->dev, 0,
                                        &xgene_pcie_ops, port, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto error;
+       }
 
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
@@ -555,6 +561,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, port);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return ret;
 }
 
 static const struct of_device_id xgene_pcie_match_table[] = {
@@ -569,8 +579,4 @@ static struct platform_driver xgene_pcie_driver = {
        },
        .probe = xgene_pcie_probe_bridge,
 };
-module_platform_driver(xgene_pcie_driver);
-
-MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>");
-MODULE_DESCRIPTION("APM X-Gene PCIe driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(xgene_pcie_driver);
index dbac6fb..2b78376 100644 (file)
@@ -61,6 +61,8 @@
 #define TLP_LOOP                       500
 #define RP_DEVFN                       0
 
+#define LINK_UP_TIMEOUT                        5000
+
 #define INTX_NUM                       4
 
 #define DWORD_MASK                     3
@@ -81,9 +83,30 @@ struct tlp_rp_regpair_t {
        u32 reg1;
 };
 
+static inline void cra_writel(struct altera_pcie *pcie, const u32 value,
+                             const u32 reg)
+{
+       writel_relaxed(value, pcie->cra_base + reg);
+}
+
+static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
+{
+       return readl_relaxed(pcie->cra_base + reg);
+}
+
+static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
+{
+       return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
+}
+
 static void altera_pcie_retrain(struct pci_dev *dev)
 {
        u16 linkcap, linkstat;
+       struct altera_pcie *pcie = dev->bus->sysdata;
+       int timeout =  0;
+
+       if (!altera_pcie_link_is_up(pcie))
+               return;
 
        /*
         * Set the retrain bit if the PCIe rootport support > 2.5GB/s, but
@@ -95,9 +118,16 @@ static void altera_pcie_retrain(struct pci_dev *dev)
                return;
 
        pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &linkstat);
-       if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB)
+       if ((linkstat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
                pcie_capability_set_word(dev, PCI_EXP_LNKCTL,
                                         PCI_EXP_LNKCTL_RL);
+               while (!altera_pcie_link_is_up(pcie)) {
+                       timeout++;
+                       if (timeout > LINK_UP_TIMEOUT)
+                               break;
+                       udelay(5);
+               }
+       }
 }
 DECLARE_PCI_FIXUP_EARLY(0x1172, PCI_ANY_ID, altera_pcie_retrain);
 
@@ -120,17 +150,6 @@ static bool altera_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int  devfn,
        return false;
 }
 
-static inline void cra_writel(struct altera_pcie *pcie, const u32 value,
-                             const u32 reg)
-{
-       writel_relaxed(value, pcie->cra_base + reg);
-}
-
-static inline u32 cra_readl(struct altera_pcie *pcie, const u32 reg)
-{
-       return readl_relaxed(pcie->cra_base + reg);
-}
-
 static void tlp_write_tx(struct altera_pcie *pcie,
                         struct tlp_rp_regpair_t *tlp_rp_regdata)
 {
@@ -139,11 +158,6 @@ static void tlp_write_tx(struct altera_pcie *pcie,
        cra_writel(pcie, tlp_rp_regdata->ctrl, RP_TX_CNTRL);
 }
 
-static bool altera_pcie_link_is_up(struct altera_pcie *pcie)
-{
-       return !!((cra_readl(pcie, RP_LTSSM) & RP_LTSSM_MASK) == LTSSM_L0);
-}
-
 static bool altera_pcie_valid_config(struct altera_pcie *pcie,
                                     struct pci_bus *bus, int dev)
 {
@@ -415,11 +429,6 @@ static void altera_pcie_isr(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static void altera_pcie_release_of_pci_ranges(struct altera_pcie *pcie)
-{
-       pci_free_resource_list(&pcie->resources);
-}
-
 static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
 {
        int err, res_valid = 0;
@@ -432,33 +441,25 @@ static int altera_pcie_parse_request_of_pci_ranges(struct altera_pcie *pcie)
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, &pcie->resources);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, &pcie->resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
-               switch (resource_type(res)) {
-               case IORESOURCE_MEM:
-                       parent = &iomem_resource;
+               if (resource_type(res) == IORESOURCE_MEM)
                        res_valid |= !(res->flags & IORESOURCE_PREFETCH);
-                       break;
-               default:
-                       continue;
-               }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
-       if (!res_valid) {
-               dev_err(dev, "non-prefetchable memory resource required\n");
-               err = -EINVAL;
-               goto out_release_res;
-       }
+       if (res_valid)
+               return 0;
 
-       return 0;
+       dev_err(dev, "non-prefetchable memory resource required\n");
+       err = -EINVAL;
 
 out_release_res:
-       altera_pcie_release_of_pci_ranges(pcie);
+       pci_free_resource_list(&pcie->resources);
        return err;
 }
 
index 5572356..0f4f570 100644 (file)
@@ -5,6 +5,9 @@
  *
  * Copyright (C) 2016 Marvell Technology Group Ltd.
  *
+ * Author: Yehuda Yitshak <yehuday@marvell.com>
+ * Author: Shadi Ammouri <shadi@marvell.com>
+ *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
@@ -14,7 +17,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/pci.h>
 #include <linux/phy/phy.h>
@@ -244,7 +247,6 @@ static const struct of_device_id armada8k_pcie_of_match[] = {
        { .compatible = "marvell,armada8k-pcie", },
        {},
 };
-MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match);
 
 static struct platform_driver armada8k_pcie_driver = {
        .probe          = armada8k_pcie_probe,
@@ -253,10 +255,4 @@ static struct platform_driver armada8k_pcie_driver = {
                .of_match_table = of_match_ptr(armada8k_pcie_of_match),
        },
 };
-
-module_platform_driver(armada8k_pcie_driver);
-
-MODULE_DESCRIPTION("Armada 8k PCIe host controller driver");
-MODULE_AUTHOR("Yehuda Yitshak <yehuday@marvell.com>");
-MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada8k_pcie_driver);
diff --git a/drivers/pci/host/pcie-artpec6.c b/drivers/pci/host/pcie-artpec6.c
new file mode 100644 (file)
index 0000000..16ba70b
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * PCIe host controller driver for Axis ARTPEC-6 SoC
+ *
+ * Author: Niklas Cassel <niklas.cassel@axis.com>
+ *
+ * Based on work done by Phil Edworthy <phil@edworthys.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "pcie-designware.h"
+
+#define to_artpec6_pcie(x)     container_of(x, struct artpec6_pcie, pp)
+
+struct artpec6_pcie {
+       struct pcie_port        pp;
+       struct regmap           *regmap;
+       void __iomem            *phy_base;
+};
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PL_OFFSET                      0x700
+#define PCIE_PHY_DEBUG_R0              (PL_OFFSET + 0x28)
+#define PCIE_PHY_DEBUG_R1              (PL_OFFSET + 0x2c)
+
+#define MISC_CONTROL_1_OFF             (PL_OFFSET + 0x1bc)
+#define  DBI_RO_WR_EN                  1
+
+/* ARTPEC-6 specific registers */
+#define PCIECFG                                0x18
+#define  PCIECFG_DBG_OEN               (1 << 24)
+#define  PCIECFG_CORE_RESET_REQ                (1 << 21)
+#define  PCIECFG_LTSSM_ENABLE          (1 << 20)
+#define  PCIECFG_CLKREQ_B              (1 << 11)
+#define  PCIECFG_REFCLK_ENABLE         (1 << 10)
+#define  PCIECFG_PLL_ENABLE            (1 << 9)
+#define  PCIECFG_PCLK_ENABLE           (1 << 8)
+#define  PCIECFG_RISRCREN              (1 << 4)
+#define  PCIECFG_MODE_TX_DRV_EN                (1 << 3)
+#define  PCIECFG_CISRREN               (1 << 2)
+#define  PCIECFG_MACRO_ENABLE          (1 << 0)
+
+#define NOCCFG                         0x40
+#define NOCCFG_ENABLE_CLK_PCIE         (1 << 4)
+#define NOCCFG_POWER_PCIE_IDLEACK      (1 << 3)
+#define NOCCFG_POWER_PCIE_IDLE         (1 << 2)
+#define NOCCFG_POWER_PCIE_IDLEREQ      (1 << 1)
+
+#define PHY_STATUS                     0x118
+#define PHY_COSPLLLOCK                 (1 << 0)
+
+#define ARTPEC6_CPU_TO_BUS_ADDR                0x0fffffff
+
+static int artpec6_pcie_establish_link(struct pcie_port *pp)
+{
+       struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pp);
+       u32 val;
+       unsigned int retries;
+
+       /* Hold DW core in reset */
+       regmap_read(artpec6_pcie->regmap, PCIECFG, &val);
+       val |= PCIECFG_CORE_RESET_REQ;
+       regmap_write(artpec6_pcie->regmap, PCIECFG, val);
+
+       regmap_read(artpec6_pcie->regmap, PCIECFG, &val);
+       val |=  PCIECFG_RISRCREN |      /* Receiver term. 50 Ohm */
+               PCIECFG_MODE_TX_DRV_EN |
+               PCIECFG_CISRREN |       /* Reference clock term. 100 Ohm */
+               PCIECFG_MACRO_ENABLE;
+       val |= PCIECFG_REFCLK_ENABLE;
+       val &= ~PCIECFG_DBG_OEN;
+       val &= ~PCIECFG_CLKREQ_B;
+       regmap_write(artpec6_pcie->regmap, PCIECFG, val);
+       usleep_range(5000, 6000);
+
+       regmap_read(artpec6_pcie->regmap, NOCCFG, &val);
+       val |= NOCCFG_ENABLE_CLK_PCIE;
+       regmap_write(artpec6_pcie->regmap, NOCCFG, val);
+       usleep_range(20, 30);
+
+       regmap_read(artpec6_pcie->regmap, PCIECFG, &val);
+       val |= PCIECFG_PCLK_ENABLE | PCIECFG_PLL_ENABLE;
+       regmap_write(artpec6_pcie->regmap, PCIECFG, val);
+       usleep_range(6000, 7000);
+
+       regmap_read(artpec6_pcie->regmap, NOCCFG, &val);
+       val &= ~NOCCFG_POWER_PCIE_IDLEREQ;
+       regmap_write(artpec6_pcie->regmap, NOCCFG, val);
+
+       retries = 50;
+       do {
+               usleep_range(1000, 2000);
+               regmap_read(artpec6_pcie->regmap, NOCCFG, &val);
+               retries--;
+       } while (retries &&
+               (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE)));
+
+       retries = 50;
+       do {
+               usleep_range(1000, 2000);
+               val = readl(artpec6_pcie->phy_base + PHY_STATUS);
+               retries--;
+       } while (retries && !(val & PHY_COSPLLLOCK));
+
+       /* Take DW core out of reset */
+       regmap_read(artpec6_pcie->regmap, PCIECFG, &val);
+       val &= ~PCIECFG_CORE_RESET_REQ;
+       regmap_write(artpec6_pcie->regmap, PCIECFG, val);
+       usleep_range(100, 200);
+
+       /*
+        * Enable writing to config regs. This is required as the Synopsys
+        * driver changes the class code. That register needs DBI write enable.
+        */
+       writel(DBI_RO_WR_EN, pp->dbi_base + MISC_CONTROL_1_OFF);
+
+       pp->io_base &= ARTPEC6_CPU_TO_BUS_ADDR;
+       pp->mem_base &= ARTPEC6_CPU_TO_BUS_ADDR;
+       pp->cfg0_base &= ARTPEC6_CPU_TO_BUS_ADDR;
+       pp->cfg1_base &= ARTPEC6_CPU_TO_BUS_ADDR;
+
+       /* setup root complex */
+       dw_pcie_setup_rc(pp);
+
+       /* assert LTSSM enable */
+       regmap_read(artpec6_pcie->regmap, PCIECFG, &val);
+       val |= PCIECFG_LTSSM_ENABLE;
+       regmap_write(artpec6_pcie->regmap, PCIECFG, val);
+
+       /* check if the link is up or not */
+       if (!dw_pcie_wait_for_link(pp))
+               return 0;
+
+       dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
+               readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+               readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+
+       return -ETIMEDOUT;
+}
+
+static void artpec6_pcie_enable_interrupts(struct pcie_port *pp)
+{
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(pp);
+}
+
+static void artpec6_pcie_host_init(struct pcie_port *pp)
+{
+       artpec6_pcie_establish_link(pp);
+       artpec6_pcie_enable_interrupts(pp);
+}
+
+static int artpec6_pcie_link_up(struct pcie_port *pp)
+{
+       u32 rc;
+
+       /*
+        * Get status from Synopsys IP
+        * link is debug bit 36, debug register 1 starts at bit 32
+        */
+       rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
+       if (rc)
+               return 1;
+
+       return 0;
+}
+
+static struct pcie_host_ops artpec6_pcie_host_ops = {
+       .link_up = artpec6_pcie_link_up,
+       .host_init = artpec6_pcie_host_init,
+};
+
+static irqreturn_t artpec6_pcie_msi_handler(int irq, void *arg)
+{
+       struct pcie_port *pp = arg;
+
+       return dw_handle_msi_irq(pp);
+}
+
+static int __init artpec6_add_pcie_port(struct pcie_port *pp,
+                                       struct platform_device *pdev)
+{
+       int ret;
+
+       if (IS_ENABLED(CONFIG_PCI_MSI)) {
+               pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+               if (pp->msi_irq <= 0) {
+                       dev_err(&pdev->dev, "failed to get MSI irq\n");
+                       return -ENODEV;
+               }
+
+               ret = devm_request_irq(&pdev->dev, pp->msi_irq,
+                                      artpec6_pcie_msi_handler,
+                                      IRQF_SHARED | IRQF_NO_THREAD,
+                                      "artpec6-pcie-msi", pp);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request MSI irq\n");
+                       return ret;
+               }
+       }
+
+       pp->root_bus_nr = -1;
+       pp->ops = &artpec6_pcie_host_ops;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int artpec6_pcie_probe(struct platform_device *pdev)
+{
+       struct artpec6_pcie *artpec6_pcie;
+       struct pcie_port *pp;
+       struct resource *dbi_base;
+       struct resource *phy_base;
+       int ret;
+
+       artpec6_pcie = devm_kzalloc(&pdev->dev, sizeof(*artpec6_pcie),
+                                   GFP_KERNEL);
+       if (!artpec6_pcie)
+               return -ENOMEM;
+
+       pp = &artpec6_pcie->pp;
+       pp->dev = &pdev->dev;
+
+       dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+       pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
+       if (IS_ERR(pp->dbi_base))
+               return PTR_ERR(pp->dbi_base);
+
+       phy_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+       artpec6_pcie->phy_base = devm_ioremap_resource(&pdev->dev, phy_base);
+       if (IS_ERR(artpec6_pcie->phy_base))
+               return PTR_ERR(artpec6_pcie->phy_base);
+
+       artpec6_pcie->regmap =
+               syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                               "axis,syscon-pcie");
+       if (IS_ERR(artpec6_pcie->regmap))
+               return PTR_ERR(artpec6_pcie->regmap);
+
+       ret = artpec6_add_pcie_port(pp, pdev);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, artpec6_pcie);
+       return 0;
+}
+
+static const struct of_device_id artpec6_pcie_of_match[] = {
+       { .compatible = "axis,artpec6-pcie", },
+       {},
+};
+
+static struct platform_driver artpec6_pcie_driver = {
+       .probe = artpec6_pcie_probe,
+       .driver = {
+               .name   = "artpec6-pcie",
+               .of_match_table = artpec6_pcie_of_match,
+       },
+};
+builtin_platform_driver(artpec6_pcie_driver);
index b350099..c8079dc 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_gpio.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -121,7 +121,6 @@ static const struct of_device_id dw_plat_pcie_of_match[] = {
        { .compatible = "snps,dw-pcie", },
        {},
 };
-MODULE_DEVICE_TABLE(of, dw_plat_pcie_of_match);
 
 static struct platform_driver dw_plat_pcie_driver = {
        .driver = {
@@ -130,9 +129,4 @@ static struct platform_driver dw_plat_pcie_driver = {
        },
        .probe = dw_plat_pcie_probe,
 };
-
-module_platform_driver(dw_plat_pcie_driver);
-
-MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
-MODULE_DESCRIPTION("Synopsys PCIe host controller glue platform driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(dw_plat_pcie_driver);
index aafd766..12afce1 100644 (file)
@@ -452,6 +452,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
        if (ret)
                return ret;
 
+       ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+       if (ret)
+               goto error;
+
        /* Get the I/O and memory ranges from DT */
        resource_list_for_each_entry(win, &res) {
                switch (resource_type(win->res)) {
@@ -461,11 +465,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
                        pp->io_size = resource_size(pp->io);
                        pp->io_bus_addr = pp->io->start - win->offset;
                        ret = pci_remap_iospace(pp->io, pp->io_base);
-                       if (ret) {
+                       if (ret)
                                dev_warn(pp->dev, "error %d: failed to map resource %pR\n",
                                         ret, pp->io);
-                               continue;
-                       }
                        break;
                case IORESOURCE_MEM:
                        pp->mem = win->res;
@@ -483,8 +485,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
                case IORESOURCE_BUS:
                        pp->busn = win->res;
                        break;
-               default:
-                       continue;
                }
        }
 
@@ -493,7 +493,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                        resource_size(pp->cfg));
                if (!pp->dbi_base) {
                        dev_err(pp->dev, "error with ioremap\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -504,7 +505,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                pp->cfg0_size);
                if (!pp->va_cfg0_base) {
                        dev_err(pp->dev, "error with ioremap in function\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -513,7 +515,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                pp->cfg1_size);
                if (!pp->va_cfg1_base) {
                        dev_err(pp->dev, "error with ioremap\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
        }
 
@@ -528,7 +531,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
                                                &dw_pcie_msi_chip);
                        if (!pp->irq_domain) {
                                dev_err(pp->dev, "irq domain init failed\n");
-                               return -ENXIO;
+                               ret = -ENXIO;
+                               goto error;
                        }
 
                        for (i = 0; i < MAX_MSI_IRQS; i++)
@@ -536,7 +540,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
                } else {
                        ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
                        if (ret < 0)
-                               return ret;
+                               goto error;
                }
        }
 
@@ -552,8 +556,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
        } else
                bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
                                        pp, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               ret = -ENOMEM;
+               goto error;
+       }
 
        if (pp->ops->scan_bus)
                pp->ops->scan_bus(pp);
@@ -571,6 +577,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
        pci_bus_add_devices(bus);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return ret;
 }
 
 static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
index 3e98d4e..7ee9dfc 100644 (file)
@@ -12,7 +12,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -235,9 +235,6 @@ static const struct of_device_id hisi_pcie_of_match[] = {
        {},
 };
 
-
-MODULE_DEVICE_TABLE(of, hisi_pcie_of_match);
-
 static struct platform_driver hisi_pcie_driver = {
        .probe  = hisi_pcie_probe,
        .driver = {
@@ -245,10 +242,4 @@ static struct platform_driver hisi_pcie_driver = {
                   .of_match_table = hisi_pcie_of_match,
        },
 };
-
-module_platform_driver(hisi_pcie_driver);
-
-MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>");
-MODULE_AUTHOR("Dacai Zhu <zhudacai@hisilicon.com>");
-MODULE_AUTHOR("Gabriele Paoloni <gabriele.paoloni@huawei.com>");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(hisi_pcie_driver);
index a576aee..e167b2f 100644 (file)
@@ -462,6 +462,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
        if (!pcie || !pcie->dev || !pcie->base)
                return -EINVAL;
 
+       ret = devm_request_pci_bus_resources(pcie->dev, res);
+       if (ret)
+               return ret;
+
        ret = phy_init(pcie->phy);
        if (ret) {
                dev_err(pcie->dev, "unable to initialize PCIe PHY\n");
index 3509218..65db7a2 100644 (file)
@@ -7,6 +7,8 @@
  *  arch/sh/drivers/pci/ops-sh7786.c
  *  Copyright (C) 2009 - 2011  Paul Mundt
  *
+ * Author: Phil Edworthy <phil.edworthy@renesas.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.
@@ -18,7 +20,7 @@
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -936,12 +938,6 @@ static const struct of_device_id rcar_pcie_of_match[] = {
        { .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init },
        {},
 };
-MODULE_DEVICE_TABLE(of, rcar_pcie_of_match);
-
-static void rcar_pcie_release_of_pci_ranges(struct rcar_pcie *pci)
-{
-       pci_free_resource_list(&pci->resources);
-}
 
 static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
 {
@@ -955,37 +951,25 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci)
        if (err)
                return err;
 
+       err = devm_request_pci_bus_resources(dev, &pci->resources);
+       if (err)
+               goto out_release_res;
+
        resource_list_for_each_entry(win, &pci->resources) {
-               struct resource *parent, *res = win->res;
+               struct resource *res = win->res;
 
-               switch (resource_type(res)) {
-               case IORESOURCE_IO:
-                       parent = &ioport_resource;
+               if (resource_type(res) == IORESOURCE_IO) {
                        err = pci_remap_iospace(res, iobase);
-                       if (err) {
+                       if (err)
                                dev_warn(dev, "error %d: failed to map resource %pR\n",
                                         err, res);
-                               continue;
-                       }
-                       break;
-               case IORESOURCE_MEM:
-                       parent = &iomem_resource;
-                       break;
-
-               case IORESOURCE_BUS:
-               default:
-                       continue;
                }
-
-               err = devm_request_resource(dev, parent, res);
-               if (err)
-                       goto out_release_res;
        }
 
        return 0;
 
 out_release_res:
-       rcar_pcie_release_of_pci_ranges(pci);
+       pci_free_resource_list(&pci->resources);
        return err;
 }
 
@@ -1073,8 +1057,4 @@ static struct platform_driver rcar_pcie_driver = {
        },
        .probe = rcar_pcie_probe,
 };
-module_platform_driver(rcar_pcie_driver);
-
-MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
-MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(rcar_pcie_driver);
index 3479d30..0b597d9 100644 (file)
@@ -825,27 +825,33 @@ static int nwl_pcie_probe(struct platform_device *pdev)
 
        err = of_pci_get_host_bridge_resources(node, 0, 0xff, &res, &iobase);
        if (err) {
-               pr_err("Getting bridge resources failed\n");
+               dev_err(pcie->dev, "Getting bridge resources failed\n");
                return err;
        }
 
+       err = devm_request_pci_bus_resources(pcie->dev, &res);
+       if (err)
+               goto error;
+
        err = nwl_pcie_init_irq_domain(pcie);
        if (err) {
                dev_err(pcie->dev, "Failed creating IRQ Domain\n");
-               return err;
+               goto error;
        }
 
        bus = pci_create_root_bus(&pdev->dev, pcie->root_busno,
                                  &nwl_pcie_ops, pcie, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               err = -ENOMEM;
+               goto error;
+       }
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                err = nwl_pcie_enable_msi(pcie, bus);
                if (err < 0) {
                        dev_err(&pdev->dev,
                                "failed to enable MSI support: %d\n", err);
-                       return err;
+                       goto error;
                }
        }
        pci_scan_child_bus(bus);
@@ -855,6 +861,10 @@ static int nwl_pcie_probe(struct platform_device *pdev)
        pci_bus_add_devices(bus);
        platform_set_drvdata(pdev, pcie);
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return err;
 }
 
 static int nwl_pcie_remove(struct platform_device *pdev)
index 65f0fe0..a30e016 100644 (file)
@@ -550,7 +550,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
        pcie_intc_node = of_get_next_child(node, NULL);
        if (!pcie_intc_node) {
                dev_err(dev, "No PCIe Intc node found\n");
-               return PTR_ERR(pcie_intc_node);
+               return -ENODEV;
        }
 
        port->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
@@ -558,7 +558,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
                                                 port);
        if (!port->irq_domain) {
                dev_err(dev, "Failed to get a INTx IRQ domain\n");
-               return PTR_ERR(port->irq_domain);
+               return -ENODEV;
        }
 
        /* Setup MSI */
@@ -569,7 +569,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port)
                                                         &xilinx_pcie_msi_chip);
                if (!port->irq_domain) {
                        dev_err(dev, "Failed to get a MSI IRQ domain\n");
-                       return PTR_ERR(port->irq_domain);
+                       return -ENODEV;
                }
 
                xilinx_pcie_enable_msi(port);
@@ -660,7 +660,6 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
        struct xilinx_pcie_port *port;
        struct device *dev = &pdev->dev;
        struct pci_bus *bus;
-
        int err;
        resource_size_t iobase = 0;
        LIST_HEAD(res);
@@ -694,10 +693,17 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
                dev_err(dev, "Getting bridge resources failed\n");
                return err;
        }
+
+       err = devm_request_pci_bus_resources(dev, &res);
+       if (err)
+               goto error;
+
        bus = pci_create_root_bus(&pdev->dev, 0,
                                  &xilinx_pcie_ops, port, &res);
-       if (!bus)
-               return -ENOMEM;
+       if (!bus) {
+               err = -ENOMEM;
+               goto error;
+       }
 
 #ifdef CONFIG_PCI_MSI
        xilinx_pcie_msi_chip.dev = port->dev;
@@ -712,6 +718,10 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, port);
 
        return 0;
+
+error:
+       pci_free_resource_list(&res);
+       return err;
 }
 
 /**
index fa49f91..a46b585 100644 (file)
@@ -675,6 +675,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
        if (bridge->is_going_away)
                return;
 
+       if (bridge->pci_dev)
+               pm_runtime_get_sync(&bridge->pci_dev->dev);
+
        list_for_each_entry(slot, &bridge->slots, node) {
                struct pci_bus *bus = slot->bus;
                struct pci_dev *dev, *tmp;
@@ -694,6 +697,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                        disable_slot(slot);
                }
        }
+
+       if (bridge->pci_dev)
+               pm_runtime_put(&bridge->pci_dev->dev);
 }
 
 /*
index 5c24e93..08e84d6 100644 (file)
@@ -546,6 +546,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
        u8 present;
        bool link;
 
+       /* Interrupts cannot originate from a controller that's asleep */
+       if (pdev->current_state == PCI_D3cold)
+               return IRQ_NONE;
+
        /*
         * In order to guarantee that all interrupt events are
         * serviced, we need to re-inspect Slot Status register after
index a080f44..a02981e 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 2003-2004 Intel
  * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Copyright (C) 2016 Christoph Hellwig.
  */
 
 #include <linux/err.h>
@@ -207,6 +208,12 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
        desc->masked = __pci_msi_desc_mask_irq(desc, mask, flag);
 }
 
+static void __iomem *pci_msix_desc_addr(struct msi_desc *desc)
+{
+       return desc->mask_base +
+               desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+}
+
 /*
  * This internal function does not flush PCI writes to the device.
  * All users must ensure that they read from the device before either
@@ -217,8 +224,6 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
 u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
 {
        u32 mask_bits = desc->masked;
-       unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                                               PCI_MSIX_ENTRY_VECTOR_CTRL;
 
        if (pci_msi_ignore_mask)
                return 0;
@@ -226,7 +231,7 @@ u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
        mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
        if (flag)
                mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
-       writel(mask_bits, desc->mask_base + offset);
+       writel(mask_bits, pci_msix_desc_addr(desc) + PCI_MSIX_ENTRY_VECTOR_CTRL);
 
        return mask_bits;
 }
@@ -284,8 +289,7 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
        BUG_ON(dev->current_state != PCI_D0);
 
        if (entry->msi_attrib.is_msix) {
-               void __iomem *base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+               void __iomem *base = pci_msix_desc_addr(entry);
 
                msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR);
                msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR);
@@ -315,9 +319,7 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
        if (dev->current_state != PCI_D0) {
                /* Don't touch the hardware now */
        } else if (entry->msi_attrib.is_msix) {
-               void __iomem *base;
-               base = entry->mask_base +
-                       entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+               void __iomem *base = pci_msix_desc_addr(entry);
 
                writel(msg->address_lo, base + PCI_MSIX_ENTRY_LOWER_ADDR);
                writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR);
@@ -567,6 +569,7 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec)
        entry->msi_attrib.multi_cap     = (control & PCI_MSI_FLAGS_QMASK) >> 1;
        entry->msi_attrib.multiple      = ilog2(__roundup_pow_of_two(nvec));
        entry->nvec_used                = nvec;
+       entry->affinity                 = dev->irq_affinity;
 
        if (control & PCI_MSI_FLAGS_64BIT)
                entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
@@ -678,10 +681,18 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
 static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
                              struct msix_entry *entries, int nvec)
 {
+       const struct cpumask *mask = NULL;
        struct msi_desc *entry;
-       int i;
+       int cpu = -1, i;
 
        for (i = 0; i < nvec; i++) {
+               if (dev->irq_affinity) {
+                       cpu = cpumask_next(cpu, dev->irq_affinity);
+                       if (cpu >= nr_cpu_ids)
+                               cpu = cpumask_first(dev->irq_affinity);
+                       mask = cpumask_of(cpu);
+               }
+
                entry = alloc_msi_entry(&dev->dev);
                if (!entry) {
                        if (!i)
@@ -694,10 +705,14 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
 
                entry->msi_attrib.is_msix       = 1;
                entry->msi_attrib.is_64         = 1;
-               entry->msi_attrib.entry_nr      = entries[i].entry;
+               if (entries)
+                       entry->msi_attrib.entry_nr = entries[i].entry;
+               else
+                       entry->msi_attrib.entry_nr = i;
                entry->msi_attrib.default_irq   = dev->irq;
                entry->mask_base                = base;
                entry->nvec_used                = 1;
+               entry->affinity                 = mask;
 
                list_add_tail(&entry->list, dev_to_msi_list(&dev->dev));
        }
@@ -712,13 +727,11 @@ static void msix_program_entries(struct pci_dev *dev,
        int i = 0;
 
        for_each_pci_msi_entry(entry, dev) {
-               int offset = entries[i].entry * PCI_MSIX_ENTRY_SIZE +
-                                               PCI_MSIX_ENTRY_VECTOR_CTRL;
-
-               entries[i].vector = entry->irq;
-               entry->masked = readl(entry->mask_base + offset);
+               if (entries)
+                       entries[i++].vector = entry->irq;
+               entry->masked = readl(pci_msix_desc_addr(entry) +
+                               PCI_MSIX_ENTRY_VECTOR_CTRL);
                msix_mask_irq(entry, 1);
-               i++;
        }
 }
 
@@ -931,7 +944,7 @@ EXPORT_SYMBOL(pci_msix_vec_count);
 /**
  * pci_enable_msix - configure device's MSI-X capability structure
  * @dev: pointer to the pci_dev data structure of MSI-X device function
- * @entries: pointer to an array of MSI-X entries
+ * @entries: pointer to an array of MSI-X entries (optional)
  * @nvec: number of MSI-X irqs requested for allocation by device driver
  *
  * Setup the MSI-X capability structure of device function with the number
@@ -951,22 +964,21 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
        if (!pci_msi_supported(dev, nvec))
                return -EINVAL;
 
-       if (!entries)
-               return -EINVAL;
-
        nr_entries = pci_msix_vec_count(dev);
        if (nr_entries < 0)
                return nr_entries;
        if (nvec > nr_entries)
                return nr_entries;
 
-       /* Check for any invalid entries */
-       for (i = 0; i < nvec; i++) {
-               if (entries[i].entry >= nr_entries)
-                       return -EINVAL;         /* invalid entry */
-               for (j = i + 1; j < nvec; j++) {
-                       if (entries[i].entry == entries[j].entry)
-                               return -EINVAL; /* duplicate entry */
+       if (entries) {
+               /* Check for any invalid entries */
+               for (i = 0; i < nvec; i++) {
+                       if (entries[i].entry >= nr_entries)
+                               return -EINVAL;         /* invalid entry */
+                       for (j = i + 1; j < nvec; j++) {
+                               if (entries[i].entry == entries[j].entry)
+                                       return -EINVAL; /* duplicate entry */
+                       }
                }
        }
        WARN_ON(!!dev->msix_enabled);
@@ -1026,19 +1038,8 @@ int pci_msi_enabled(void)
 }
 EXPORT_SYMBOL(pci_msi_enabled);
 
-/**
- * pci_enable_msi_range - configure device's MSI capability structure
- * @dev: device to configure
- * @minvec: minimal number of interrupts to configure
- * @maxvec: maximum number of interrupts to configure
- *
- * This function tries to allocate a maximum possible number of interrupts in a
- * range between @minvec and @maxvec. It returns a negative errno if an error
- * occurs. If it succeeds, it returns the actual number of interrupts allocated
- * and updates the @dev's irq member to the lowest new interrupt number;
- * the other interrupt numbers allocated to this device are consecutive.
- **/
-int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
+static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec,
+               unsigned int flags)
 {
        int nvec;
        int rc;
@@ -1061,25 +1062,85 @@ int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
        nvec = pci_msi_vec_count(dev);
        if (nvec < 0)
                return nvec;
-       else if (nvec < minvec)
+       if (nvec < minvec)
                return -EINVAL;
-       else if (nvec > maxvec)
+
+       if (nvec > maxvec)
                nvec = maxvec;
 
-       do {
+       for (;;) {
+               if (!(flags & PCI_IRQ_NOAFFINITY)) {
+                       dev->irq_affinity = irq_create_affinity_mask(&nvec);
+                       if (nvec < minvec)
+                               return -ENOSPC;
+               }
+
                rc = msi_capability_init(dev, nvec);
-               if (rc < 0) {
+               if (rc == 0)
+                       return nvec;
+
+               kfree(dev->irq_affinity);
+               dev->irq_affinity = NULL;
+
+               if (rc < 0)
                        return rc;
-               } else if (rc > 0) {
-                       if (rc < minvec)
+               if (rc < minvec)
+                       return -ENOSPC;
+
+               nvec = rc;
+       }
+}
+
+/**
+ * pci_enable_msi_range - configure device's MSI capability structure
+ * @dev: device to configure
+ * @minvec: minimal number of interrupts to configure
+ * @maxvec: maximum number of interrupts to configure
+ *
+ * This function tries to allocate a maximum possible number of interrupts in a
+ * range between @minvec and @maxvec. It returns a negative errno if an error
+ * occurs. If it succeeds, it returns the actual number of interrupts allocated
+ * and updates the @dev's irq member to the lowest new interrupt number;
+ * the other interrupt numbers allocated to this device are consecutive.
+ **/
+int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
+{
+       return __pci_enable_msi_range(dev, minvec, maxvec, PCI_IRQ_NOAFFINITY);
+}
+EXPORT_SYMBOL(pci_enable_msi_range);
+
+static int __pci_enable_msix_range(struct pci_dev *dev,
+               struct msix_entry *entries, int minvec, int maxvec,
+               unsigned int flags)
+{
+       int nvec = maxvec;
+       int rc;
+
+       if (maxvec < minvec)
+               return -ERANGE;
+
+       for (;;) {
+               if (!(flags & PCI_IRQ_NOAFFINITY)) {
+                       dev->irq_affinity = irq_create_affinity_mask(&nvec);
+                       if (nvec < minvec)
                                return -ENOSPC;
-                       nvec = rc;
                }
-       } while (rc);
 
-       return nvec;
+               rc = pci_enable_msix(dev, entries, nvec);
+               if (rc == 0)
+                       return nvec;
+
+               kfree(dev->irq_affinity);
+               dev->irq_affinity = NULL;
+
+               if (rc < 0)
+                       return rc;
+               if (rc < minvec)
+                       return -ENOSPC;
+
+               nvec = rc;
+       }
 }
-EXPORT_SYMBOL(pci_enable_msi_range);
 
 /**
  * pci_enable_msix_range - configure device's MSI-X capability structure
@@ -1097,28 +1158,101 @@ EXPORT_SYMBOL(pci_enable_msi_range);
  * with new allocated MSI-X interrupts.
  **/
 int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
-                              int minvec, int maxvec)
+               int minvec, int maxvec)
 {
-       int nvec = maxvec;
-       int rc;
+       return __pci_enable_msix_range(dev, entries, minvec, maxvec,
+                       PCI_IRQ_NOAFFINITY);
+}
+EXPORT_SYMBOL(pci_enable_msix_range);
 
-       if (maxvec < minvec)
-               return -ERANGE;
+/**
+ * pci_alloc_irq_vectors - allocate multiple IRQs for a device
+ * @dev:               PCI device to operate on
+ * @min_vecs:          minimum number of vectors required (must be >= 1)
+ * @max_vecs:          maximum (desired) number of vectors
+ * @flags:             flags or quirks for the allocation
+ *
+ * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
+ * vectors if available, and fall back to a single legacy vector
+ * if neither is available.  Return the number of vectors allocated,
+ * (which might be smaller than @max_vecs) if successful, or a negative
+ * error code on error. If less than @min_vecs interrupt vectors are
+ * available for @dev the function will fail with -ENOSPC.
+ *
+ * To get the Linux IRQ number used for a vector that can be passed to
+ * request_irq() use the pci_irq_vector() helper.
+ */
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+               unsigned int max_vecs, unsigned int flags)
+{
+       int vecs = -ENOSPC;
 
-       do {
-               rc = pci_enable_msix(dev, entries, nvec);
-               if (rc < 0) {
-                       return rc;
-               } else if (rc > 0) {
-                       if (rc < minvec)
-                               return -ENOSPC;
-                       nvec = rc;
+       if (!(flags & PCI_IRQ_NOMSIX)) {
+               vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs,
+                               flags);
+               if (vecs > 0)
+                       return vecs;
+       }
+
+       if (!(flags & PCI_IRQ_NOMSI)) {
+               vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, flags);
+               if (vecs > 0)
+                       return vecs;
+       }
+
+       /* use legacy irq if allowed */
+       if (!(flags & PCI_IRQ_NOLEGACY) && min_vecs == 1)
+               return 1;
+       return vecs;
+}
+EXPORT_SYMBOL(pci_alloc_irq_vectors);
+
+/**
+ * pci_free_irq_vectors - free previously allocated IRQs for a device
+ * @dev:               PCI device to operate on
+ *
+ * Undoes the allocations and enabling in pci_alloc_irq_vectors().
+ */
+void pci_free_irq_vectors(struct pci_dev *dev)
+{
+       pci_disable_msix(dev);
+       pci_disable_msi(dev);
+}
+EXPORT_SYMBOL(pci_free_irq_vectors);
+
+/**
+ * pci_irq_vector - return Linux IRQ number of a device vector
+ * @dev: PCI device to operate on
+ * @nr: device-relative interrupt vector index (0-based).
+ */
+int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
+{
+       if (dev->msix_enabled) {
+               struct msi_desc *entry;
+               int i = 0;
+
+               for_each_pci_msi_entry(entry, dev) {
+                       if (i == nr)
+                               return entry->irq;
+                       i++;
                }
-       } while (rc);
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
 
-       return nvec;
+       if (dev->msi_enabled) {
+               struct msi_desc *entry = first_pci_msi_entry(dev);
+
+               if (WARN_ON_ONCE(nr >= entry->nvec_used))
+                       return -EINVAL;
+       } else {
+               if (WARN_ON_ONCE(nr > 0))
+                       return -EINVAL;
+       }
+
+       return dev->irq + nr;
 }
-EXPORT_SYMBOL(pci_enable_msix_range);
+EXPORT_SYMBOL(pci_irq_vector);
 
 struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
 {
index d7ffd66..e39a67c 100644 (file)
@@ -777,7 +777,7 @@ static int pci_pm_suspend_noirq(struct device *dev)
 
        if (!pci_dev->state_saved) {
                pci_save_state(pci_dev);
-               if (!pci_has_subordinate(pci_dev))
+               if (pci_power_manageable(pci_dev))
                        pci_prepare_to_sleep(pci_dev);
        }
 
@@ -1144,7 +1144,6 @@ static int pci_pm_runtime_suspend(struct device *dev)
                return -ENOSYS;
 
        pci_dev->state_saved = false;
-       pci_dev->no_d3cold = false;
        error = pm->runtime_suspend(dev);
        if (error) {
                /*
@@ -1161,8 +1160,6 @@ static int pci_pm_runtime_suspend(struct device *dev)
 
                return error;
        }
-       if (!pci_dev->d3cold_allowed)
-               pci_dev->no_d3cold = true;
 
        pci_fixup_device(pci_fixup_suspend, pci_dev);
 
index d319a9c..bcd10c7 100644 (file)
@@ -406,6 +406,11 @@ static ssize_t d3cold_allowed_store(struct device *dev,
                return -EINVAL;
 
        pdev->d3cold_allowed = !!val;
+       if (pdev->d3cold_allowed)
+               pci_d3cold_enable(pdev);
+       else
+               pci_d3cold_disable(pdev);
+
        pm_runtime_resume(dev);
 
        return count;
index badbddc..aab9d51 100644 (file)
@@ -7,8 +7,10 @@
  *     Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
  */
 
+#include <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_pci.h>
@@ -25,7 +27,9 @@
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pci_hotplug.h>
+#include <linux/vmalloc.h>
 #include <asm/setup.h>
+#include <asm/dma.h>
 #include <linux/aer.h>
 #include "pci.h"
 
@@ -81,6 +85,9 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
 unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
 
+#define DEFAULT_HOTPLUG_BUS_SIZE       1
+unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
+
 enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
 
 /*
@@ -101,6 +108,21 @@ unsigned int pcibios_max_latency = 255;
 /* If set, the PCIe ARI capability will not be used. */
 static bool pcie_ari_disabled;
 
+/* Disable bridge_d3 for all PCIe ports */
+static bool pci_bridge_d3_disable;
+/* Force bridge_d3 for all PCIe ports */
+static bool pci_bridge_d3_force;
+
+static int __init pcie_port_pm_setup(char *str)
+{
+       if (!strcmp(str, "off"))
+               pci_bridge_d3_disable = true;
+       else if (!strcmp(str, "force"))
+               pci_bridge_d3_force = true;
+       return 1;
+}
+__setup("pcie_port_pm=", pcie_port_pm_setup);
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -2155,6 +2177,164 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev)
                pm_runtime_put_sync(parent);
 }
 
+/**
+ * pci_bridge_d3_possible - Is it possible to put the bridge into D3
+ * @bridge: Bridge to check
+ *
+ * This function checks if it is possible to move the bridge to D3.
+ * Currently we only allow D3 for recent enough PCIe ports.
+ */
+static bool pci_bridge_d3_possible(struct pci_dev *bridge)
+{
+       unsigned int year;
+
+       if (!pci_is_pcie(bridge))
+               return false;
+
+       switch (pci_pcie_type(bridge)) {
+       case PCI_EXP_TYPE_ROOT_PORT:
+       case PCI_EXP_TYPE_UPSTREAM:
+       case PCI_EXP_TYPE_DOWNSTREAM:
+               if (pci_bridge_d3_disable)
+                       return false;
+               if (pci_bridge_d3_force)
+                       return true;
+
+               /*
+                * It should be safe to put PCIe ports from 2015 or newer
+                * to D3.
+                */
+               if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+                   year >= 2015) {
+                       return true;
+               }
+               break;
+       }
+
+       return false;
+}
+
+static int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
+{
+       bool *d3cold_ok = data;
+       bool no_d3cold;
+
+       /*
+        * The device needs to be allowed to go D3cold and if it is wake
+        * capable to do so from D3cold.
+        */
+       no_d3cold = dev->no_d3cold || !dev->d3cold_allowed ||
+               (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) ||
+               !pci_power_manageable(dev);
+
+       *d3cold_ok = !no_d3cold;
+
+       return no_d3cold;
+}
+
+/*
+ * pci_bridge_d3_update - Update bridge D3 capabilities
+ * @dev: PCI device which is changed
+ * @remove: Is the device being removed
+ *
+ * Update upstream bridge PM capabilities accordingly depending on if the
+ * device PM configuration was changed or the device is being removed.  The
+ * change is also propagated upstream.
+ */
+static void pci_bridge_d3_update(struct pci_dev *dev, bool remove)
+{
+       struct pci_dev *bridge;
+       bool d3cold_ok = true;
+
+       bridge = pci_upstream_bridge(dev);
+       if (!bridge || !pci_bridge_d3_possible(bridge))
+               return;
+
+       pci_dev_get(bridge);
+       /*
+        * If the device is removed we do not care about its D3cold
+        * capabilities.
+        */
+       if (!remove)
+               pci_dev_check_d3cold(dev, &d3cold_ok);
+
+       if (d3cold_ok) {
+               /*
+                * We need to go through all children to find out if all of
+                * them can still go to D3cold.
+                */
+               pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
+                            &d3cold_ok);
+       }
+
+       if (bridge->bridge_d3 != d3cold_ok) {
+               bridge->bridge_d3 = d3cold_ok;
+               /* Propagate change to upstream bridges */
+               pci_bridge_d3_update(bridge, false);
+       }
+
+       pci_dev_put(bridge);
+}
+
+/**
+ * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change
+ * @dev: PCI device that was changed
+ *
+ * If a device is added or its PM configuration, such as is it allowed to
+ * enter D3cold, is changed this function updates upstream bridge PM
+ * capabilities accordingly.
+ */
+void pci_bridge_d3_device_changed(struct pci_dev *dev)
+{
+       pci_bridge_d3_update(dev, false);
+}
+
+/**
+ * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove
+ * @dev: PCI device being removed
+ *
+ * Function updates upstream bridge PM capabilities based on other devices
+ * still left on the bus.
+ */
+void pci_bridge_d3_device_removed(struct pci_dev *dev)
+{
+       pci_bridge_d3_update(dev, true);
+}
+
+/**
+ * pci_d3cold_enable - Enable D3cold for device
+ * @dev: PCI device to handle
+ *
+ * This function can be used in drivers to enable D3cold from the device
+ * they handle.  It also updates upstream PCI bridge PM capabilities
+ * accordingly.
+ */
+void pci_d3cold_enable(struct pci_dev *dev)
+{
+       if (dev->no_d3cold) {
+               dev->no_d3cold = false;
+               pci_bridge_d3_device_changed(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(pci_d3cold_enable);
+
+/**
+ * pci_d3cold_disable - Disable D3cold for device
+ * @dev: PCI device to handle
+ *
+ * This function can be used in drivers to disable D3cold from the device
+ * they handle.  It also updates upstream PCI bridge PM capabilities
+ * accordingly.
+ */
+void pci_d3cold_disable(struct pci_dev *dev)
+{
+       if (!dev->no_d3cold) {
+               dev->no_d3cold = true;
+               pci_bridge_d3_device_changed(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(pci_d3cold_disable);
+
 /**
  * pci_pm_init - Initialize PM functions of given PCI device
  * @dev: PCI device to handle.
@@ -2189,6 +2369,7 @@ void pci_pm_init(struct pci_dev *dev)
        dev->pm_cap = pm;
        dev->d3_delay = PCI_PM_D3_WAIT;
        dev->d3cold_delay = PCI_PM_D3COLD_WAIT;
+       dev->bridge_d3 = pci_bridge_d3_possible(dev);
        dev->d3cold_allowed = true;
 
        dev->d1_support = false;
@@ -3165,6 +3346,23 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
 #endif
 }
 
+/**
+ *     pci_unmap_iospace - Unmap the memory mapped I/O space
+ *     @res: resource to be unmapped
+ *
+ *     Unmap the CPU virtual address @res from virtual address space.
+ *     Only architectures that have memory mapped IO functions defined
+ *     (and the PCI_IOBASE value defined) should call this function.
+ */
+void pci_unmap_iospace(struct resource *res)
+{
+#if defined(PCI_IOBASE) && defined(CONFIG_MMU)
+       unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start;
+
+       unmap_kernel_range(vaddr, resource_size(res));
+#endif
+}
+
 static void __pci_set_master(struct pci_dev *dev, bool enable)
 {
        u16 old_cmd, cmd;
@@ -4755,6 +4953,7 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
 static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
 {
        int seg, bus, slot, func, align_order, count;
+       unsigned short vendor, device, subsystem_vendor, subsystem_device;
        resource_size_t align = 0;
        char *p;
 
@@ -4768,28 +4967,55 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
                } else {
                        align_order = -1;
                }
-               if (sscanf(p, "%x:%x:%x.%x%n",
-                       &seg, &bus, &slot, &func, &count) != 4) {
-                       seg = 0;
-                       if (sscanf(p, "%x:%x.%x%n",
-                                       &bus, &slot, &func, &count) != 3) {
-                               /* Invalid format */
-                               printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
-                                       p);
+               if (strncmp(p, "pci:", 4) == 0) {
+                       /* PCI vendor/device (subvendor/subdevice) ids are specified */
+                       p += 4;
+                       if (sscanf(p, "%hx:%hx:%hx:%hx%n",
+                               &vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) {
+                               if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) {
+                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n",
+                                               p);
+                                       break;
+                               }
+                               subsystem_vendor = subsystem_device = 0;
+                       }
+                       p += count;
+                       if ((!vendor || (vendor == dev->vendor)) &&
+                               (!device || (device == dev->device)) &&
+                               (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
+                               (!subsystem_device || (subsystem_device == dev->subsystem_device))) {
+                               if (align_order == -1)
+                                       align = PAGE_SIZE;
+                               else
+                                       align = 1 << align_order;
+                               /* Found */
                                break;
                        }
                }
-               p += count;
-               if (seg == pci_domain_nr(dev->bus) &&
-                       bus == dev->bus->number &&
-                       slot == PCI_SLOT(dev->devfn) &&
-                       func == PCI_FUNC(dev->devfn)) {
-                       if (align_order == -1)
-                               align = PAGE_SIZE;
-                       else
-                               align = 1 << align_order;
-                       /* Found */
-                       break;
+               else {
+                       if (sscanf(p, "%x:%x:%x.%x%n",
+                               &seg, &bus, &slot, &func, &count) != 4) {
+                               seg = 0;
+                               if (sscanf(p, "%x:%x.%x%n",
+                                               &bus, &slot, &func, &count) != 3) {
+                                       /* Invalid format */
+                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
+                                               p);
+                                       break;
+                               }
+                       }
+                       p += count;
+                       if (seg == pci_domain_nr(dev->bus) &&
+                               bus == dev->bus->number &&
+                               slot == PCI_SLOT(dev->devfn) &&
+                               func == PCI_FUNC(dev->devfn)) {
+                               if (align_order == -1)
+                                       align = PAGE_SIZE;
+                               else
+                                       align = 1 << align_order;
+                               /* Found */
+                               break;
+                       }
                }
                if (*p != ';' && *p != ',') {
                        /* End of param or invalid format */
@@ -4897,7 +5123,7 @@ static ssize_t pci_resource_alignment_store(struct bus_type *bus,
        return pci_set_resource_alignment_param(buf, count);
 }
 
-BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
+static BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
                                        pci_resource_alignment_store);
 
 static int __init pci_resource_alignment_sysfs_init(void)
@@ -4923,7 +5149,7 @@ int pci_get_new_domain_nr(void)
 }
 
 #ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int of_pci_bus_find_domain_nr(struct device *parent)
 {
        static int use_dt_domains = -1;
        int domain = -1;
@@ -4967,7 +5193,13 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
                domain = -1;
        }
 
-       bus->domain_nr = domain;
+       return domain;
+}
+
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+       return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
+                              acpi_pci_bus_find_domain_nr(bus);
 }
 #endif
 #endif
@@ -5021,6 +5253,11 @@ static int __init pci_setup(char *str)
                                pci_hotplug_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
                                pci_hotplug_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "hpbussize=", 10)) {
+                               pci_hotplug_bus_size =
+                                       simple_strtoul(str + 10, &str, 0);
+                               if (pci_hotplug_bus_size > 0xff)
+                                       pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;
                        } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
                                pcie_bus_config = PCIE_BUS_TUNE_OFF;
                        } else if (!strncmp(str, "pcie_bus_safe", 13)) {
index a814bbb..9730c47 100644 (file)
@@ -82,6 +82,8 @@ void pci_pm_init(struct pci_dev *dev);
 void pci_ea_init(struct pci_dev *dev);
 void pci_allocate_cap_save_buffers(struct pci_dev *dev);
 void pci_free_cap_save_buffers(struct pci_dev *dev);
+void pci_bridge_d3_device_changed(struct pci_dev *dev);
+void pci_bridge_d3_device_removed(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -94,6 +96,15 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
        return !!(pci_dev->subordinate);
 }
 
+static inline bool pci_power_manageable(struct pci_dev *pci_dev)
+{
+       /*
+        * Currently we allow normal PCI devices and PCI bridges transition
+        * into D3 if their bridge_d3 is set.
+        */
+       return !pci_has_subordinate(pci_dev) || pci_dev->bridge_d3;
+}
+
 struct pci_vpd_ops {
        ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
        ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
index 22ca641..7fcea75 100644 (file)
@@ -83,7 +83,7 @@ config PCIE_PME
        depends on PCIEPORTBUS && PM
 
 config PCIE_DPC
-       tristate "PCIe Downstream Port Containment support"
+       bool "PCIe Downstream Port Containment support"
        depends on PCIEPORTBUS
        default n
        help
@@ -92,6 +92,3 @@ config PCIE_DPC
          will be handled by the DPC driver.  If your system doesn't
          have this capability or you do not want to use this feature,
          it is safe to answer N.
-
-         To compile this driver as a module, choose M here: the module
-         will be called pcie-dpc.
index 2dfe7fd..0ec649d 100644 (file)
@@ -139,7 +139,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
 static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
 {
        /* Don't enable Clock PM if the link is not Clock PM capable */
-       if (!link->clkpm_capable && enable)
+       if (!link->clkpm_capable)
                enable = 0;
        /* Need nothing if the specified equals to current state */
        if (link->clkpm_enabled == enable)
index ab552f1..250f878 100644 (file)
@@ -15,8 +15,8 @@
 
 struct dpc_dev {
        struct pcie_device      *dev;
-       struct work_struct      work;
-       int                     cap_pos;
+       struct work_struct      work;
+       int                     cap_pos;
 };
 
 static void dpc_wait_link_inactive(struct pci_dev *pdev)
@@ -89,7 +89,7 @@ static int dpc_probe(struct pcie_device *dev)
        int status;
        u16 ctl, cap;
 
-       dpc = kzalloc(sizeof(*dpc), GFP_KERNEL);
+       dpc = devm_kzalloc(&dev->device, sizeof(*dpc), GFP_KERNEL);
        if (!dpc)
                return -ENOMEM;
 
@@ -98,11 +98,12 @@ static int dpc_probe(struct pcie_device *dev)
        INIT_WORK(&dpc->work, interrupt_event_handler);
        set_service_data(dev, dpc);
 
-       status = request_irq(dev->irq, dpc_irq, IRQF_SHARED, "pcie-dpc", dpc);
+       status = devm_request_irq(&dev->device, dev->irq, dpc_irq, IRQF_SHARED,
+                                 "pcie-dpc", dpc);
        if (status) {
                dev_warn(&dev->device, "request IRQ%d failed: %d\n", dev->irq,
                         status);
-               goto out;
+               return status;
        }
 
        pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap);
@@ -117,9 +118,6 @@ static int dpc_probe(struct pcie_device *dev)
                FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf,
                FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
        return status;
- out:
-       kfree(dpc);
-       return status;
 }
 
 static void dpc_remove(struct pcie_device *dev)
@@ -131,14 +129,11 @@ static void dpc_remove(struct pcie_device *dev)
        pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
        ctl &= ~(PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN);
        pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
-
-       free_irq(dev->irq, dpc);
-       kfree(dpc);
 }
 
 static struct pcie_port_service_driver dpcdriver = {
        .name           = "dpc",
-       .port_type      = PCI_EXP_TYPE_ROOT_PORT | PCI_EXP_TYPE_DOWNSTREAM,
+       .port_type      = PCIE_ANY_PORT,
        .service        = PCIE_PORT_SERVICE_DPC,
        .probe          = dpc_probe,
        .remove         = dpc_remove,
index 32d4d0a..e9270b4 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
@@ -342,6 +343,8 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
                return retval;
        }
 
+       pm_runtime_no_callbacks(device);
+
        return 0;
 }
 
index be35da2..70d7ad8 100644 (file)
@@ -93,6 +93,26 @@ static int pcie_port_resume_noirq(struct device *dev)
        return 0;
 }
 
+static int pcie_port_runtime_suspend(struct device *dev)
+{
+       return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
+static int pcie_port_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static int pcie_port_runtime_idle(struct device *dev)
+{
+       /*
+        * Assume the PCI core has set bridge_d3 whenever it thinks the port
+        * should be good to go to D3.  Everything else, including moving
+        * the port to D3, is handled by the PCI core.
+        */
+       return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .suspend        = pcie_port_device_suspend,
        .resume         = pcie_port_device_resume,
@@ -101,6 +121,9 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .poweroff       = pcie_port_device_suspend,
        .restore        = pcie_port_device_resume,
        .resume_noirq   = pcie_port_resume_noirq,
+       .runtime_suspend = pcie_port_runtime_suspend,
+       .runtime_resume = pcie_port_runtime_resume,
+       .runtime_idle   = pcie_port_runtime_idle,
 };
 
 #define PCIE_PORTDRV_PM_OPS    (&pcie_portdrv_pm_ops)
@@ -134,16 +157,39 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
                return status;
 
        pci_save_state(dev);
+
        /*
-        * D3cold may not work properly on some PCIe port, so disable
-        * it by default.
+        * Prevent runtime PM if the port is advertising support for PCIe
+        * hotplug.  Otherwise the BIOS hotplug SMI code might not be able
+        * to enumerate devices behind this port properly (the port is
+        * powered down preventing all config space accesses to the
+        * subordinate devices).  We can't be sure for native PCIe hotplug
+        * either so prevent that as well.
         */
-       dev->d3cold_allowed = false;
+       if (!dev->is_hotplug_bridge) {
+               /*
+                * Keep the port resumed 100ms to make sure things like
+                * config space accesses from userspace (lspci) will not
+                * cause the port to repeatedly suspend and resume.
+                */
+               pm_runtime_set_autosuspend_delay(&dev->dev, 100);
+               pm_runtime_use_autosuspend(&dev->dev);
+               pm_runtime_mark_last_busy(&dev->dev);
+               pm_runtime_put_autosuspend(&dev->dev);
+               pm_runtime_allow(&dev->dev);
+       }
+
        return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
+       if (!dev->is_hotplug_bridge) {
+               pm_runtime_forbid(&dev->dev);
+               pm_runtime_get_noresume(&dev->dev);
+               pm_runtime_dont_use_autosuspend(&dev->dev);
+       }
+
        pcie_port_device_remove(dev);
 }
 
index 8e3ef72..93f280d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -832,6 +833,12 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
        u8 primary, secondary, subordinate;
        int broken = 0;
 
+       /*
+        * Make sure the bridge is powered on to be able to access config
+        * space of devices below it.
+        */
+       pm_runtime_get_sync(&dev->dev);
+
        pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
        primary = buses & 0xFF;
        secondary = (buses >> 8) & 0xFF;
@@ -1012,6 +1019,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 out:
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
 
+       pm_runtime_put(&dev->dev);
+
        return max;
 }
 EXPORT_SYMBOL(pci_scan_bridge);
@@ -2076,6 +2085,15 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
                                max = pci_scan_bridge(bus, dev, max, pass);
                }
 
+       /*
+        * Make sure a hotplug bridge has at least the minimum requested
+        * number of buses.
+        */
+       if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) {
+               if (max - bus->busn_res.start < pci_hotplug_bus_size - 1)
+                       max = bus->busn_res.start + pci_hotplug_bus_size - 1;
+       }
+
        /*
         * We've scanned the bus and so we know all about what's on
         * the other side of any bridges that may be on this bus plus
@@ -2127,7 +2145,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        b->sysdata = sysdata;
        b->ops = ops;
        b->number = b->busn_res.start = bus;
-       pci_bus_assign_domain_nr(b, parent);
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+       b->domain_nr = pci_bus_find_domain_nr(b, parent);
+#endif
        b2 = pci_find_bus(pci_domain_nr(b), bus);
        if (b2) {
                /* If we already got to this bus through a different bridge, ignore it */
index 3f155e7..2408abe 100644 (file)
@@ -231,7 +231,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct pci_dev *dev = PDE_DATA(file_inode(file));
        struct pci_filp_private *fpriv = file->private_data;
-       int i, ret;
+       int i, ret, write_combine;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
@@ -245,9 +245,12 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
        if (i >= PCI_ROM_RESOURCE)
                return -ENODEV;
 
+       if (fpriv->mmap_state == pci_mmap_mem)
+               write_combine = fpriv->write_combine;
+       else
+               write_combine = 0;
        ret = pci_mmap_page_range(dev, vma,
-                                 fpriv->mmap_state,
-                                 fpriv->write_combine);
+                                 fpriv->mmap_state, write_combine);
        if (ret < 0)
                return ret;
 
index ee72ebe..37ff015 100644 (file)
@@ -3189,13 +3189,15 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
 }
 
 /*
- * Atheros AR93xx chips do not behave after a bus reset.  The device will
- * throw a Link Down error on AER-capable systems and regardless of AER,
- * config space of the device is never accessible again and typically
- * causes the system to hang or reset when access is attempted.
+ * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
+ * The device will throw a Link Down error on AER-capable systems and
+ * regardless of AER, config space of the device is never accessible again
+ * and typically causes the system to hang or reset when access is attempted.
  * http://www.spinics.net/lists/linux-pci/msg34797.html
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
 
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
@@ -3711,6 +3713,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9172,
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c59 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x917a,
                         quirk_dma_func1_alias);
+/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c78 */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9182,
+                        quirk_dma_func1_alias);
 /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
                         quirk_dma_func1_alias);
@@ -3747,6 +3752,9 @@ static const struct pci_device_id fixed_dma_alias_tbl[] = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
                         PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */
          .driver_data = PCI_DEVFN(1, 0) },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
+                        PCI_VENDOR_ID_ADAPTEC2, 0x02bc), /* Adaptec 3805 */
+         .driver_data = PCI_DEVFN(1, 0) },
        { 0 }
 };
 
@@ -4087,6 +4095,7 @@ static const struct pci_dev_acs_enabled {
        { PCI_VENDOR_ID_AMD, 0x7809, pci_quirk_amd_sb_acs },
        { PCI_VENDOR_ID_SOLARFLARE, 0x0903, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_SOLARFLARE, 0x0923, pci_quirk_mf_endpoint_acs },
+       { PCI_VENDOR_ID_SOLARFLARE, 0x0A03, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10C6, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10DB, pci_quirk_mf_endpoint_acs },
        { PCI_VENDOR_ID_INTEL, 0x10DD, pci_quirk_mf_endpoint_acs },
index 8982026..d1ef7ac 100644 (file)
@@ -96,6 +96,8 @@ static void pci_remove_bus_device(struct pci_dev *dev)
                dev->subordinate = NULL;
        }
 
+       pci_bridge_d3_device_removed(dev);
+
        pci_destroy_dev(dev);
 }
 
index d678c46..c74059e 100644 (file)
@@ -1428,6 +1428,74 @@ void pci_bus_assign_resources(const struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
+static void pci_claim_device_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_resource(dev, i);
+       }
+}
+
+static void pci_claim_bridge_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_bridge_resource(dev, i);
+       }
+}
+
+static void pci_bus_allocate_dev_resources(struct pci_bus *b)
+{
+       struct pci_dev *dev;
+       struct pci_bus *child;
+
+       list_for_each_entry(dev, &b->devices, bus_list) {
+               pci_claim_device_resources(dev);
+
+               child = dev->subordinate;
+               if (child)
+                       pci_bus_allocate_dev_resources(child);
+       }
+}
+
+static void pci_bus_allocate_resources(struct pci_bus *b)
+{
+       struct pci_bus *child;
+
+       /*
+        * Carry out a depth-first search on the PCI bus
+        * tree to allocate bridge apertures. Read the
+        * programmed bridge bases and recursively claim
+        * the respective bridge resources.
+        */
+       if (b->self) {
+               pci_read_bridge_bases(b);
+               pci_claim_bridge_resources(b->self);
+       }
+
+       list_for_each_entry(child, &b->children, node)
+               pci_bus_allocate_resources(child);
+}
+
+void pci_bus_claim_resources(struct pci_bus *b)
+{
+       pci_bus_allocate_resources(b);
+       pci_bus_allocate_dev_resources(b);
+}
+EXPORT_SYMBOL(pci_bus_claim_resources);
+
 static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
                                          struct list_head *add_head,
                                          struct list_head *fail_head)
index 5f70fee..d6ff5e8 100644 (file)
@@ -1086,7 +1086,7 @@ out:
        return err;
 }
 
-static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev,
+static void __ref pcifront_backend_changed(struct xenbus_device *xdev,
                                                  enum xenbus_state be_state)
 {
        struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev);
index b6e161f..6c084b2 100644 (file)
@@ -380,3 +380,20 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
        return ret;
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
+
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+                           struct cros_ec_command *msg)
+{
+       int ret;
+
+       ret = cros_ec_cmd_xfer(ec_dev, msg);
+       if (ret < 0) {
+               dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
+       } else if (msg->result != EC_RES_SUCCESS) {
+               dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
+               return -EPROTO;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
index d2bc092..da2fe18 100644 (file)
@@ -110,8 +110,8 @@ static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = {
        /* BIOS error detected */
        { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
 
-       /* Unknown, defined in ACPI DSDT */
-       /* { KE_IGNORE, 0xe00e, { KEY_RESERVED } }, */
+       /* Battery was removed or inserted */
+       { KE_IGNORE, 0xe00e, { KEY_RESERVED } },
 
        /* Wifi Catcher */
        { KE_KEY,    0xe011, { KEY_PROG2 } },
index bedb361..c38a5b9 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include <linux/freezer.h>
+#include <linux/kmod.h>
 #include <linux/kthread.h>
 
 #include <asm/page.h>
index c182efc..80a566a 100644 (file)
@@ -74,6 +74,16 @@ config PWM_ATMEL_TCB
          To compile this driver as a module, choose M here: the module
          will be called pwm-atmel-tcb.
 
+config PWM_BCM_IPROC
+       tristate "iProc PWM support"
+       depends on ARCH_BCM_IPROC
+       help
+         Generic PWM framework driver for Broadcom iProc PWM block. This
+         block is used in Broadcom iProc SoC's.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-bcm-iproc.
+
 config PWM_BCM_KONA
        tristate "Kona PWM support"
        depends on ARCH_BCM_MOBILE
@@ -137,6 +147,13 @@ config PWM_CRC
          Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM
          control.
 
+config PWM_CROS_EC
+       tristate "ChromeOS EC PWM driver"
+       depends on MFD_CROS_EC
+       help
+         PWM driver for exposing a PWM attached to the ChromeOS Embedded
+         Controller.
+
 config PWM_EP93XX
        tristate "Cirrus Logic EP93xx PWM support"
        depends on ARCH_EP93XX
@@ -305,7 +322,7 @@ config PWM_PXA
 
 config PWM_RCAR
        tristate "Renesas R-Car PWM support"
-       depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST
+       depends on ARCH_RENESAS || COMPILE_TEST
        depends on HAS_IOMEM
        help
          This driver exposes the PWM Timer controller found in Renesas
@@ -362,6 +379,13 @@ config PWM_STI
          To compile this driver as a module, choose M here: the module
          will be called pwm-sti.
 
+config PWM_STMPE
+       bool "STMPE expander PWM export"
+       depends on MFD_STMPE
+       help
+         This enables support for the PWMs found in the STMPE I/O
+         expanders.
+
 config PWM_SUN4I
        tristate "Allwinner PWM support"
        depends on ARCH_SUNXI || COMPILE_TEST
index dd35bc1..feef1dd 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_PWM_AB8500)        += pwm-ab8500.o
 obj-$(CONFIG_PWM_ATMEL)                += pwm-atmel.o
 obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM)      += pwm-atmel-hlcdc.o
 obj-$(CONFIG_PWM_ATMEL_TCB)    += pwm-atmel-tcb.o
+obj-$(CONFIG_PWM_BCM_IPROC)    += pwm-bcm-iproc.o
 obj-$(CONFIG_PWM_BCM_KONA)     += pwm-bcm-kona.o
 obj-$(CONFIG_PWM_BCM2835)      += pwm-bcm2835.o
 obj-$(CONFIG_PWM_BERLIN)       += pwm-berlin.o
@@ -11,6 +12,7 @@ obj-$(CONFIG_PWM_BFIN)                += pwm-bfin.o
 obj-$(CONFIG_PWM_BRCMSTB)      += pwm-brcmstb.o
 obj-$(CONFIG_PWM_CLPS711X)     += pwm-clps711x.o
 obj-$(CONFIG_PWM_CRC)          += pwm-crc.o
+obj-$(CONFIG_PWM_CROS_EC)      += pwm-cros-ec.o
 obj-$(CONFIG_PWM_EP93XX)       += pwm-ep93xx.o
 obj-$(CONFIG_PWM_FSL_FTM)      += pwm-fsl-ftm.o
 obj-$(CONFIG_PWM_IMG)          += pwm-img.o
@@ -34,6 +36,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)    += pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
 obj-$(CONFIG_PWM_SPEAR)                += pwm-spear.o
 obj-$(CONFIG_PWM_STI)          += pwm-sti.o
+obj-$(CONFIG_PWM_STMPE)                += pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)                += pwm-sun4i.o
 obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
 obj-$(CONFIG_PWM_TIECAP)       += pwm-tiecap.o
index ed337a8..0dbd29e 100644 (file)
@@ -525,6 +525,33 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)
 }
 EXPORT_SYMBOL_GPL(pwm_apply_state);
 
+/**
+ * pwm_capture() - capture and report a PWM signal
+ * @pwm: PWM device
+ * @result: structure to fill with capture result
+ * @timeout: time to wait, in milliseconds, before giving up on capture
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
+               unsigned long timeout)
+{
+       int err;
+
+       if (!pwm || !pwm->chip->ops)
+               return -EINVAL;
+
+       if (!pwm->chip->ops->capture)
+               return -ENOSYS;
+
+       mutex_lock(&pwm_lock);
+       err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
+       mutex_unlock(&pwm_lock);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(pwm_capture);
+
 /**
  * pwm_adjust_config() - adjust the current PWM config to the PWM arguments
  * @pwm: PWM device
index 0e4bd4e..e6b8b1b 100644 (file)
@@ -64,7 +64,8 @@ struct atmel_pwm_chip {
        void __iomem *base;
 
        unsigned int updated_pwms;
-       struct mutex isr_lock; /* ISR is cleared when read, ensure only one thread does that */
+       /* ISR is cleared when read, ensure only one thread does that */
+       struct mutex isr_lock;
 
        void (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
                       unsigned long dty, unsigned long prd);
@@ -271,6 +272,16 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        mutex_unlock(&atmel_pwm->isr_lock);
        atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm);
 
+       /*
+        * Wait for the PWM channel disable operation to be effective before
+        * stopping the clock.
+        */
+       timeout = jiffies + 2 * HZ;
+
+       while ((atmel_pwm_readl(atmel_pwm, PWM_SR) & (1 << pwm->hwpwm)) &&
+              time_before(jiffies, timeout))
+               usleep_range(10, 100);
+
        clk_disable(atmel_pwm->clk);
 }
 
@@ -324,21 +335,14 @@ MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
 static inline const struct atmel_pwm_data *
 atmel_pwm_get_driver_data(struct platform_device *pdev)
 {
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-
-               match = of_match_device(atmel_pwm_dt_ids, &pdev->dev);
-               if (!match)
-                       return NULL;
+       const struct platform_device_id *id;
 
-               return match->data;
-       } else {
-               const struct platform_device_id *id;
+       if (pdev->dev.of_node)
+               return of_device_get_match_data(&pdev->dev);
 
-               id = platform_get_device_id(pdev);
+       id = platform_get_device_id(pdev);
 
-               return (struct atmel_pwm_data *)id->driver_data;
-       }
+       return (struct atmel_pwm_data *)id->driver_data;
 }
 
 static int atmel_pwm_probe(struct platform_device *pdev)
diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c
new file mode 100644 (file)
index 0000000..d961a82
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define IPROC_PWM_CTRL_OFFSET                  0x00
+#define IPROC_PWM_CTRL_TYPE_SHIFT(ch)          (15 + (ch))
+#define IPROC_PWM_CTRL_POLARITY_SHIFT(ch)      (8 + (ch))
+#define IPROC_PWM_CTRL_EN_SHIFT(ch)            (ch)
+
+#define IPROC_PWM_PERIOD_OFFSET(ch)            (0x04 + ((ch) << 3))
+#define IPROC_PWM_PERIOD_MIN                   0x02
+#define IPROC_PWM_PERIOD_MAX                   0xffff
+
+#define IPROC_PWM_DUTY_CYCLE_OFFSET(ch)                (0x08 + ((ch) << 3))
+#define IPROC_PWM_DUTY_CYCLE_MIN               0x00
+#define IPROC_PWM_DUTY_CYCLE_MAX               0xffff
+
+#define IPROC_PWM_PRESCALE_OFFSET              0x24
+#define IPROC_PWM_PRESCALE_BITS                        0x06
+#define IPROC_PWM_PRESCALE_SHIFT(ch)           ((3 - (ch)) * \
+                                                IPROC_PWM_PRESCALE_BITS)
+#define IPROC_PWM_PRESCALE_MASK(ch)            (IPROC_PWM_PRESCALE_MAX << \
+                                                IPROC_PWM_PRESCALE_SHIFT(ch))
+#define IPROC_PWM_PRESCALE_MIN                 0x00
+#define IPROC_PWM_PRESCALE_MAX                 0x3f
+
+struct iproc_pwmc {
+       struct pwm_chip chip;
+       void __iomem *base;
+       struct clk *clk;
+};
+
+static inline struct iproc_pwmc *to_iproc_pwmc(struct pwm_chip *chip)
+{
+       return container_of(chip, struct iproc_pwmc, chip);
+}
+
+static void iproc_pwmc_enable(struct iproc_pwmc *ip, unsigned int channel)
+{
+       u32 value;
+
+       value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
+       value |= 1 << IPROC_PWM_CTRL_EN_SHIFT(channel);
+       writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       /* must be a 400 ns delay between clearing and setting enable bit */
+       ndelay(400);
+}
+
+static void iproc_pwmc_disable(struct iproc_pwmc *ip, unsigned int channel)
+{
+       u32 value;
+
+       value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
+       value &= ~(1 << IPROC_PWM_CTRL_EN_SHIFT(channel));
+       writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       /* must be a 400 ns delay between clearing and setting enable bit */
+       ndelay(400);
+}
+
+static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+                                struct pwm_state *state)
+{
+       struct iproc_pwmc *ip = to_iproc_pwmc(chip);
+       u64 tmp, multi, rate;
+       u32 value, prescale;
+
+       rate = clk_get_rate(ip->clk);
+
+       value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       if (value & BIT(IPROC_PWM_CTRL_EN_SHIFT(pwm->hwpwm)))
+               state->enabled = true;
+       else
+               state->enabled = false;
+
+       if (value & BIT(IPROC_PWM_CTRL_POLARITY_SHIFT(pwm->hwpwm)))
+               state->polarity = PWM_POLARITY_NORMAL;
+       else
+               state->polarity = PWM_POLARITY_INVERSED;
+
+       value = readl(ip->base + IPROC_PWM_PRESCALE_OFFSET);
+       prescale = value >> IPROC_PWM_PRESCALE_SHIFT(pwm->hwpwm);
+       prescale &= IPROC_PWM_PRESCALE_MAX;
+
+       multi = NSEC_PER_SEC * (prescale + 1);
+
+       value = readl(ip->base + IPROC_PWM_PERIOD_OFFSET(pwm->hwpwm));
+       tmp = (value & IPROC_PWM_PERIOD_MAX) * multi;
+       state->period = div64_u64(tmp, rate);
+
+       value = readl(ip->base + IPROC_PWM_DUTY_CYCLE_OFFSET(pwm->hwpwm));
+       tmp = (value & IPROC_PWM_PERIOD_MAX) * multi;
+       state->duty_cycle = div64_u64(tmp, rate);
+}
+
+static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                           struct pwm_state *state)
+{
+       unsigned long prescale = IPROC_PWM_PRESCALE_MIN;
+       struct iproc_pwmc *ip = to_iproc_pwmc(chip);
+       u32 value, period, duty;
+       u64 rate;
+
+       rate = clk_get_rate(ip->clk);
+
+       /*
+        * Find period count, duty count and prescale to suit duty_cycle and
+        * period. This is done according to formulas described below:
+        *
+        * period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE
+        * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+        *
+        * PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
+        * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
+        */
+       while (1) {
+               u64 value, div;
+
+               div = NSEC_PER_SEC * (prescale + 1);
+               value = rate * state->period;
+               period = div64_u64(value, div);
+               value = rate * state->duty_cycle;
+               duty = div64_u64(value, div);
+
+               if (period < IPROC_PWM_PERIOD_MIN ||
+                   duty < IPROC_PWM_DUTY_CYCLE_MIN)
+                       return -EINVAL;
+
+               if (period <= IPROC_PWM_PERIOD_MAX &&
+                    duty <= IPROC_PWM_DUTY_CYCLE_MAX)
+                       break;
+
+               /* Otherwise, increase prescale and recalculate counts */
+               if (++prescale > IPROC_PWM_PRESCALE_MAX)
+                       return -EINVAL;
+       }
+
+       iproc_pwmc_disable(ip, pwm->hwpwm);
+
+       /* Set prescale */
+       value = readl(ip->base + IPROC_PWM_PRESCALE_OFFSET);
+       value &= ~IPROC_PWM_PRESCALE_MASK(pwm->hwpwm);
+       value |= prescale << IPROC_PWM_PRESCALE_SHIFT(pwm->hwpwm);
+       writel(value, ip->base + IPROC_PWM_PRESCALE_OFFSET);
+
+       /* set period and duty cycle */
+       writel(period, ip->base + IPROC_PWM_PERIOD_OFFSET(pwm->hwpwm));
+       writel(duty, ip->base + IPROC_PWM_DUTY_CYCLE_OFFSET(pwm->hwpwm));
+
+       /* set polarity */
+       value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       if (state->polarity == PWM_POLARITY_NORMAL)
+               value |= 1 << IPROC_PWM_CTRL_POLARITY_SHIFT(pwm->hwpwm);
+       else
+               value &= ~(1 << IPROC_PWM_CTRL_POLARITY_SHIFT(pwm->hwpwm));
+
+       writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       if (state->enabled)
+               iproc_pwmc_enable(ip, pwm->hwpwm);
+
+       return 0;
+}
+
+static const struct pwm_ops iproc_pwm_ops = {
+       .apply = iproc_pwmc_apply,
+       .get_state = iproc_pwmc_get_state,
+};
+
+static int iproc_pwmc_probe(struct platform_device *pdev)
+{
+       struct iproc_pwmc *ip;
+       struct resource *res;
+       unsigned int i;
+       u32 value;
+       int ret;
+
+       ip = devm_kzalloc(&pdev->dev, sizeof(*ip), GFP_KERNEL);
+       if (!ip)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, ip);
+
+       ip->chip.dev = &pdev->dev;
+       ip->chip.ops = &iproc_pwm_ops;
+       ip->chip.base = -1;
+       ip->chip.npwm = 4;
+       ip->chip.of_xlate = of_pwm_xlate_with_flags;
+       ip->chip.of_pwm_n_cells = 3;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ip->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ip->base))
+               return PTR_ERR(ip->base);
+
+       ip->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ip->clk)) {
+               dev_err(&pdev->dev, "failed to get clock: %ld\n",
+                       PTR_ERR(ip->clk));
+               return PTR_ERR(ip->clk);
+       }
+
+       ret = clk_prepare_enable(ip->clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
+               return ret;
+       }
+
+       /* Set full drive and normal polarity for all channels */
+       value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       for (i = 0; i < ip->chip.npwm; i++) {
+               value &= ~(1 << IPROC_PWM_CTRL_TYPE_SHIFT(i));
+               value |= 1 << IPROC_PWM_CTRL_POLARITY_SHIFT(i);
+       }
+
+       writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
+
+       ret = pwmchip_add(&ip->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+               clk_disable_unprepare(ip->clk);
+       }
+
+       return ret;
+}
+
+static int iproc_pwmc_remove(struct platform_device *pdev)
+{
+       struct iproc_pwmc *ip = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(ip->clk);
+
+       return pwmchip_remove(&ip->chip);
+}
+
+static const struct of_device_id bcm_iproc_pwmc_dt[] = {
+       { .compatible = "brcm,iproc-pwm" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_pwmc_dt);
+
+static struct platform_driver iproc_pwmc_driver = {
+       .driver = {
+               .name = "bcm-iproc-pwm",
+               .of_match_table = bcm_iproc_pwmc_dt,
+       },
+       .probe = iproc_pwmc_probe,
+       .remove = iproc_pwmc_remove,
+};
+module_platform_driver(iproc_pwmc_driver);
+
+MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iProc PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
new file mode 100644 (file)
index 0000000..99b9acc
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2, as published by
+ * the Free Software Foundation.
+ *
+ * Expose a PWM controlled by the ChromeOS EC to the host processor.
+ */
+
+#include <linux/module.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+/**
+ * struct cros_ec_pwm_device - Driver data for EC PWM
+ *
+ * @dev: Device node
+ * @ec: Pointer to EC device
+ * @chip: PWM controller chip
+ */
+struct cros_ec_pwm_device {
+       struct device *dev;
+       struct cros_ec_device *ec;
+       struct pwm_chip chip;
+};
+
+static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *c)
+{
+       return container_of(c, struct cros_ec_pwm_device, chip);
+}
+
+static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
+{
+       struct {
+               struct cros_ec_command msg;
+               struct ec_params_pwm_set_duty params;
+       } buf;
+       struct ec_params_pwm_set_duty *params = &buf.params;
+       struct cros_ec_command *msg = &buf.msg;
+
+       memset(&buf, 0, sizeof(buf));
+
+       msg->version = 0;
+       msg->command = EC_CMD_PWM_SET_DUTY;
+       msg->insize = 0;
+       msg->outsize = sizeof(*params);
+
+       params->duty = duty;
+       params->pwm_type = EC_PWM_TYPE_GENERIC;
+       params->index = index;
+
+       return cros_ec_cmd_xfer_status(ec, msg);
+}
+
+static int __cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index,
+                                 u32 *result)
+{
+       struct {
+               struct cros_ec_command msg;
+               union {
+                       struct ec_params_pwm_get_duty params;
+                       struct ec_response_pwm_get_duty resp;
+               };
+       } buf;
+       struct ec_params_pwm_get_duty *params = &buf.params;
+       struct ec_response_pwm_get_duty *resp = &buf.resp;
+       struct cros_ec_command *msg = &buf.msg;
+       int ret;
+
+       memset(&buf, 0, sizeof(buf));
+
+       msg->version = 0;
+       msg->command = EC_CMD_PWM_GET_DUTY;
+       msg->insize = sizeof(*params);
+       msg->outsize = sizeof(*resp);
+
+       params->pwm_type = EC_PWM_TYPE_GENERIC;
+       params->index = index;
+
+       ret = cros_ec_cmd_xfer_status(ec, msg);
+       if (result)
+               *result = msg->result;
+       if (ret < 0)
+               return ret;
+
+       return resp->duty;
+}
+
+static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
+{
+       return __cros_ec_pwm_get_duty(ec, index, NULL);
+}
+
+static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                            struct pwm_state *state)
+{
+       struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
+       int duty_cycle;
+
+       /* The EC won't let us change the period */
+       if (state->period != EC_PWM_MAX_DUTY)
+               return -EINVAL;
+
+       /*
+        * EC doesn't separate the concept of duty cycle and enabled, but
+        * kernel does. Translate.
+        */
+       duty_cycle = state->enabled ? state->duty_cycle : 0;
+
+       return cros_ec_pwm_set_duty(ec_pwm->ec, pwm->hwpwm, duty_cycle);
+}
+
+static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+                                 struct pwm_state *state)
+{
+       struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
+       int ret;
+
+       ret = cros_ec_pwm_get_duty(ec_pwm->ec, pwm->hwpwm);
+       if (ret < 0) {
+               dev_err(chip->dev, "error getting initial duty: %d\n", ret);
+               return;
+       }
+
+       state->enabled = (ret > 0);
+       state->period = EC_PWM_MAX_DUTY;
+
+       /* Note that "disabled" and "duty cycle == 0" are treated the same */
+       state->duty_cycle = ret;
+}
+
+static struct pwm_device *
+cros_ec_pwm_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       if (args->args[0] >= pc->npwm)
+               return ERR_PTR(-EINVAL);
+
+       pwm = pwm_request_from_chip(pc, args->args[0], NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       /* The EC won't let us change the period */
+       pwm->args.period = EC_PWM_MAX_DUTY;
+
+       return pwm;
+}
+
+static const struct pwm_ops cros_ec_pwm_ops = {
+       .get_state      = cros_ec_pwm_get_state,
+       .apply          = cros_ec_pwm_apply,
+       .owner          = THIS_MODULE,
+};
+
+static int cros_ec_num_pwms(struct cros_ec_device *ec)
+{
+       int i, ret;
+
+       /* The index field is only 8 bits */
+       for (i = 0; i <= U8_MAX; i++) {
+               u32 result = 0;
+
+               ret = __cros_ec_pwm_get_duty(ec, i, &result);
+               /* We want to parse EC protocol errors */
+               if (ret < 0 && !(ret == -EPROTO && result))
+                       return ret;
+
+               /*
+                * We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
+                * responses; everything else is treated as an error.
+                */
+               if (result == EC_RES_INVALID_COMMAND)
+                       return -ENODEV;
+               else if (result == EC_RES_INVALID_PARAM)
+                       return i;
+               else if (result)
+                       return -EPROTO;
+       }
+
+       return U8_MAX;
+}
+
+static int cros_ec_pwm_probe(struct platform_device *pdev)
+{
+       struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct cros_ec_pwm_device *ec_pwm;
+       struct pwm_chip *chip;
+       int ret;
+
+       if (!ec) {
+               dev_err(dev, "no parent EC device\n");
+               return -EINVAL;
+       }
+
+       ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
+       if (!ec_pwm)
+               return -ENOMEM;
+       chip = &ec_pwm->chip;
+       ec_pwm->ec = ec;
+
+       /* PWM chip */
+       chip->dev = dev;
+       chip->ops = &cros_ec_pwm_ops;
+       chip->of_xlate = cros_ec_pwm_xlate;
+       chip->of_pwm_n_cells = 1;
+       chip->base = -1;
+       ret = cros_ec_num_pwms(ec);
+       if (ret < 0) {
+               dev_err(dev, "Couldn't find PWMs: %d\n", ret);
+               return ret;
+       }
+       chip->npwm = ret;
+       dev_dbg(dev, "Probed %u PWMs\n", chip->npwm);
+
+       ret = pwmchip_add(chip);
+       if (ret < 0) {
+               dev_err(dev, "cannot register PWM: %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, ec_pwm);
+
+       return ret;
+}
+
+static int cros_ec_pwm_remove(struct platform_device *dev)
+{
+       struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev);
+       struct pwm_chip *chip = &ec_pwm->chip;
+
+       return pwmchip_remove(chip);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id cros_ec_pwm_of_match[] = {
+       { .compatible = "google,cros-ec-pwm" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
+#endif
+
+static struct platform_driver cros_ec_pwm_driver = {
+       .probe = cros_ec_pwm_probe,
+       .remove = cros_ec_pwm_remove,
+       .driver = {
+               .name = "cros-ec-pwm",
+               .of_match_table = of_match_ptr(cros_ec_pwm_of_match),
+       },
+};
+module_platform_driver(cros_ec_pwm_driver);
+
+MODULE_ALIAS("platform:cros-ec-pwm");
+MODULE_DESCRIPTION("ChromeOS EC PWM driver");
+MODULE_LICENSE("GPL v2");
index 4d470c1..a9b3cff 100644 (file)
@@ -25,6 +25,7 @@ struct lpc32xx_pwm_chip {
 };
 
 #define PWM_ENABLE     BIT(31)
+#define PWM_PIN_LEVEL  BIT(30)
 
 #define to_lpc32xx_pwm_chip(_chip) \
        container_of(_chip, struct lpc32xx_pwm_chip, chip)
@@ -103,6 +104,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
        struct lpc32xx_pwm_chip *lpc32xx;
        struct resource *res;
        int ret;
+       u32 val;
 
        lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL);
        if (!lpc32xx)
@@ -128,6 +130,11 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* When PWM is disable, configure the output to the default value */
+       val = readl(lpc32xx->base + (lpc32xx->chip.pwms[0].hwpwm << 2));
+       val &= ~PWM_PIN_LEVEL;
+       writel(val, lpc32xx->base + (lpc32xx->chip.pwms[0].hwpwm << 2));
+
        platform_set_drvdata(pdev, lpc32xx);
 
        return 0;
index 7160e8a..3622f09 100644 (file)
@@ -76,6 +76,7 @@ static const struct pci_device_id pwm_lpss_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info},
        { PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
        { PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
+       { PCI_VDEVICE(INTEL, 0x11a5), (unsigned long)&pwm_lpss_bxt_info},
        { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
        { PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
        { PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
index 295b963..72c0bce 100644 (file)
@@ -27,7 +27,6 @@
 #define PWM_SW_UPDATE                  BIT(30)
 #define PWM_BASE_UNIT_SHIFT            8
 #define PWM_ON_TIME_DIV_MASK           0x000000ff
-#define PWM_DIVISION_CORRECTION                0x2
 
 /* Size of each PWM register space if multiple */
 #define PWM_SIZE                       0x400
@@ -92,8 +91,8 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
                           int duty_ns, int period_ns)
 {
        struct pwm_lpss_chip *lpwm = to_lpwm(chip);
-       u8 on_time_div;
-       unsigned long c, base_unit_range;
+       unsigned long long on_time_div;
+       unsigned long c = lpwm->info->clk_rate, base_unit_range;
        unsigned long long base_unit, freq = NSEC_PER_SEC;
        u32 ctrl;
 
@@ -101,21 +100,18 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
        /*
         * The equation is:
-        * base_unit = ((freq / c) * base_unit_range) + correction
+        * base_unit = round(base_unit_range * freq / c)
         */
        base_unit_range = BIT(lpwm->info->base_unit_bits);
-       base_unit = freq * base_unit_range;
+       freq *= base_unit_range;
 
-       c = lpwm->info->clk_rate;
-       if (!c)
-               return -EINVAL;
-
-       do_div(base_unit, c);
-       base_unit += PWM_DIVISION_CORRECTION;
+       base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
 
        if (duty_ns <= 0)
                duty_ns = 1;
-       on_time_div = 255 - (255 * duty_ns / period_ns);
+       on_time_div = 255ULL * duty_ns;
+       do_div(on_time_div, period_ns);
+       on_time_div = 255ULL - on_time_div;
 
        pm_runtime_get_sync(chip->dev);
 
@@ -169,6 +165,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
                                     const struct pwm_lpss_boardinfo *info)
 {
        struct pwm_lpss_chip *lpwm;
+       unsigned long c;
        int ret;
 
        lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
@@ -180,6 +177,11 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
                return ERR_CAST(lpwm->regs);
 
        lpwm->info = info;
+
+       c = lpwm->info->clk_rate;
+       if (!c)
+               return ERR_PTR(-EINVAL);
+
        lpwm->chip.dev = dev;
        lpwm->chip.ops = &pwm_lpss_ops;
        lpwm->chip.base = -1;
index 7d9cc90..ef89df1 100644 (file)
@@ -47,10 +47,14 @@ struct rockchip_pwm_regs {
 struct rockchip_pwm_data {
        struct rockchip_pwm_regs regs;
        unsigned int prescaler;
+       bool supports_polarity;
        const struct pwm_ops *ops;
 
        void (*set_enable)(struct pwm_chip *chip,
-                          struct pwm_device *pwm, bool enable);
+                          struct pwm_device *pwm, bool enable,
+                          enum pwm_polarity polarity);
+       void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
+                         struct pwm_state *state);
 };
 
 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
@@ -59,7 +63,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
 }
 
 static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
-                                      struct pwm_device *pwm, bool enable)
+                                      struct pwm_device *pwm, bool enable,
+                                      enum pwm_polarity polarity)
 {
        struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
        u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
@@ -75,15 +80,29 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
        writel_relaxed(val, pc->base + pc->data->regs.ctrl);
 }
 
+static void rockchip_pwm_get_state_v1(struct pwm_chip *chip,
+                                     struct pwm_device *pwm,
+                                     struct pwm_state *state)
+{
+       struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+       u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
+       u32 val;
+
+       val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+       if ((val & enable_conf) == enable_conf)
+               state->enabled = true;
+}
+
 static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
-                                      struct pwm_device *pwm, bool enable)
+                                      struct pwm_device *pwm, bool enable,
+                                      enum pwm_polarity polarity)
 {
        struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
        u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
                          PWM_CONTINUOUS;
        u32 val;
 
-       if (pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED)
+       if (polarity == PWM_POLARITY_INVERSED)
                enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
        else
                enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
@@ -98,13 +117,59 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
        writel_relaxed(val, pc->base + pc->data->regs.ctrl);
 }
 
+static void rockchip_pwm_get_state_v2(struct pwm_chip *chip,
+                                     struct pwm_device *pwm,
+                                     struct pwm_state *state)
+{
+       struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+       u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+                         PWM_CONTINUOUS;
+       u32 val;
+
+       val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+       if ((val & enable_conf) != enable_conf)
+               return;
+
+       state->enabled = true;
+
+       if (!(val & PWM_DUTY_POSITIVE))
+               state->polarity = PWM_POLARITY_INVERSED;
+}
+
+static void rockchip_pwm_get_state(struct pwm_chip *chip,
+                                  struct pwm_device *pwm,
+                                  struct pwm_state *state)
+{
+       struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+       unsigned long clk_rate;
+       u64 tmp;
+       int ret;
+
+       ret = clk_enable(pc->clk);
+       if (ret)
+               return;
+
+       clk_rate = clk_get_rate(pc->clk);
+
+       tmp = readl_relaxed(pc->base + pc->data->regs.period);
+       tmp *= pc->data->prescaler * NSEC_PER_SEC;
+       state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+       tmp = readl_relaxed(pc->base + pc->data->regs.duty);
+       tmp *= pc->data->prescaler * NSEC_PER_SEC;
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate);
+
+       pc->data->get_state(chip, pwm, state);
+
+       clk_disable(pc->clk);
+}
+
 static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                               int duty_ns, int period_ns)
 {
        struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
        unsigned long period, duty;
        u64 clk_rate, div;
-       int ret;
 
        clk_rate = clk_get_rate(pc->clk);
 
@@ -114,74 +179,72 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
         * default prescaler value for all practical clock rate values.
         */
        div = clk_rate * period_ns;
-       do_div(div, pc->data->prescaler * NSEC_PER_SEC);
-       period = div;
+       period = DIV_ROUND_CLOSEST_ULL(div,
+                                      pc->data->prescaler * NSEC_PER_SEC);
 
        div = clk_rate * duty_ns;
-       do_div(div, pc->data->prescaler * NSEC_PER_SEC);
-       duty = div;
-
-       ret = clk_enable(pc->clk);
-       if (ret)
-               return ret;
+       duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC);
 
        writel(period, pc->base + pc->data->regs.period);
        writel(duty, pc->base + pc->data->regs.duty);
-       writel(0, pc->base + pc->data->regs.cntr);
-
-       clk_disable(pc->clk);
-
-       return 0;
-}
-
-static int rockchip_pwm_set_polarity(struct pwm_chip *chip,
-                                    struct pwm_device *pwm,
-                                    enum pwm_polarity polarity)
-{
-       /*
-        * No action needed here because pwm->polarity will be set by the core
-        * and the core will only change polarity when the PWM is not enabled.
-        * We'll handle things in set_enable().
-        */
 
        return 0;
 }
 
-static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                             struct pwm_state *state)
 {
        struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+       struct pwm_state curstate;
+       bool enabled;
        int ret;
 
+       pwm_get_state(pwm, &curstate);
+       enabled = curstate.enabled;
+
        ret = clk_enable(pc->clk);
        if (ret)
                return ret;
 
-       pc->data->set_enable(chip, pwm, true);
+       if (state->polarity != curstate.polarity && enabled) {
+               pc->data->set_enable(chip, pwm, false, state->polarity);
+               enabled = false;
+       }
 
-       return 0;
-}
+       ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period);
+       if (ret) {
+               if (enabled != curstate.enabled)
+                       pc->data->set_enable(chip, pwm, !enabled,
+                                            state->polarity);
 
-static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+               goto out;
+       }
+
+       if (state->enabled != enabled)
+               pc->data->set_enable(chip, pwm, state->enabled,
+                                    state->polarity);
 
-       pc->data->set_enable(chip, pwm, false);
+       /*
+        * Update the state with the real hardware, which can differ a bit
+        * because of period/duty_cycle approximation.
+        */
+       rockchip_pwm_get_state(chip, pwm, state);
 
+out:
        clk_disable(pc->clk);
+
+       return ret;
 }
 
 static const struct pwm_ops rockchip_pwm_ops_v1 = {
-       .config = rockchip_pwm_config,
-       .enable = rockchip_pwm_enable,
-       .disable = rockchip_pwm_disable,
+       .get_state = rockchip_pwm_get_state,
+       .apply = rockchip_pwm_apply,
        .owner = THIS_MODULE,
 };
 
 static const struct pwm_ops rockchip_pwm_ops_v2 = {
-       .config = rockchip_pwm_config,
-       .set_polarity = rockchip_pwm_set_polarity,
-       .enable = rockchip_pwm_enable,
-       .disable = rockchip_pwm_disable,
+       .get_state = rockchip_pwm_get_state,
+       .apply = rockchip_pwm_apply,
        .owner = THIS_MODULE,
 };
 
@@ -195,6 +258,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
        .prescaler = 2,
        .ops = &rockchip_pwm_ops_v1,
        .set_enable = rockchip_pwm_set_enable_v1,
+       .get_state = rockchip_pwm_get_state_v1,
 };
 
 static const struct rockchip_pwm_data pwm_data_v2 = {
@@ -205,8 +269,10 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
                .ctrl = 0x0c,
        },
        .prescaler = 1,
+       .supports_polarity = true,
        .ops = &rockchip_pwm_ops_v2,
        .set_enable = rockchip_pwm_set_enable_v2,
+       .get_state = rockchip_pwm_get_state_v2,
 };
 
 static const struct rockchip_pwm_data pwm_data_vop = {
@@ -217,8 +283,10 @@ static const struct rockchip_pwm_data pwm_data_vop = {
                .ctrl = 0x00,
        },
        .prescaler = 1,
+       .supports_polarity = true,
        .ops = &rockchip_pwm_ops_v2,
        .set_enable = rockchip_pwm_set_enable_v2,
+       .get_state = rockchip_pwm_get_state_v2,
 };
 
 static const struct of_device_id rockchip_pwm_dt_ids[] = {
@@ -253,7 +321,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(pc->clk))
                return PTR_ERR(pc->clk);
 
-       ret = clk_prepare(pc->clk);
+       ret = clk_prepare_enable(pc->clk);
        if (ret)
                return ret;
 
@@ -265,7 +333,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
        pc->chip.base = -1;
        pc->chip.npwm = 1;
 
-       if (pc->data->ops->set_polarity) {
+       if (pc->data->supports_polarity) {
                pc->chip.of_xlate = of_pwm_xlate_with_flags;
                pc->chip.of_pwm_n_cells = 3;
        }
@@ -276,6 +344,10 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
        }
 
+       /* Keep the PWM clk enabled if the PWM appears to be up and running. */
+       if (!pwm_is_enabled(pc->chip.pwms))
+               clk_disable(pc->clk);
+
        return ret;
 }
 
@@ -283,6 +355,20 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
 {
        struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       /*
+        * Disable the PWM clk before unpreparing it if the PWM device is still
+        * running. This should only happen when the last PWM user left it
+        * enabled, or when nobody requested a PWM that was previously enabled
+        * by the bootloader.
+        *
+        * FIXME: Maybe the core should disable all PWM devices in
+        * pwmchip_remove(). In this case we'd only have to call
+        * clk_unprepare() after pwmchip_remove().
+        *
+        */
+       if (pwm_is_enabled(pc->chip.pwms))
+               clk_disable(pc->clk);
+
        clk_unprepare(pc->clk);
 
        return pwmchip_remove(&pc->chip);
diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c
new file mode 100644 (file)
index 0000000..e464582
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2016 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define STMPE24XX_PWMCS                0x30
+#define PWMCS_EN_PWM0          BIT(0)
+#define PWMCS_EN_PWM1          BIT(1)
+#define PWMCS_EN_PWM2          BIT(2)
+#define STMPE24XX_PWMIC0       0x38
+#define STMPE24XX_PWMIC1       0x39
+#define STMPE24XX_PWMIC2       0x3a
+
+#define STMPE_PWM_24XX_PINBASE 21
+
+struct stmpe_pwm {
+       struct stmpe *stmpe;
+       struct pwm_chip chip;
+       u8 last_duty;
+};
+
+static inline struct stmpe_pwm *to_stmpe_pwm(struct pwm_chip *chip)
+{
+       return container_of(chip, struct stmpe_pwm, chip);
+}
+
+static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip);
+       u8 value;
+       int ret;
+
+       ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
+       if (ret < 0) {
+               dev_err(chip->dev, "error reading PWM#%u control\n",
+                       pwm->hwpwm);
+               return ret;
+       }
+
+       value = ret | BIT(pwm->hwpwm);
+
+       ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
+       if (ret) {
+               dev_err(chip->dev, "error writing PWM#%u control\n",
+                       pwm->hwpwm);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void stmpe_24xx_pwm_disable(struct pwm_chip *chip,
+                                  struct pwm_device *pwm)
+{
+       struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip);
+       u8 value;
+       int ret;
+
+       ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
+       if (ret < 0) {
+               dev_err(chip->dev, "error reading PWM#%u control\n",
+                       pwm->hwpwm);
+               return;
+       }
+
+       value = ret & ~BIT(pwm->hwpwm);
+
+       ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
+       if (ret) {
+               dev_err(chip->dev, "error writing PWM#%u control\n",
+                       pwm->hwpwm);
+               return;
+       }
+}
+
+/* STMPE 24xx PWM instructions */
+#define SMAX           0x007f
+#define SMIN           0x00ff
+#define GTS            0x0000
+#define LOAD           BIT(14) /* Only available on 2403 */
+#define RAMPUP         0x0000
+#define RAMPDOWN       BIT(7)
+#define PRESCALE_512   BIT(14)
+#define STEPTIME_1     BIT(8)
+#define BRANCH         (BIT(15) | BIT(13))
+
+static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                                int duty_ns, int period_ns)
+{
+       struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip);
+       unsigned int i, pin;
+       u16 program[3] = {
+               SMAX,
+               GTS,
+               GTS,
+       };
+       u8 offset;
+       int ret;
+
+       /* Make sure we are disabled */
+       if (pwm_is_enabled(pwm)) {
+               stmpe_24xx_pwm_disable(chip, pwm);
+       } else {
+               /* Connect the PWM to the pin */
+               pin = pwm->hwpwm;
+
+               /* On STMPE2401 and 2403 pins 21,22,23 are used */
+               if (stmpe_pwm->stmpe->partnum == STMPE2401 ||
+                   stmpe_pwm->stmpe->partnum == STMPE2403)
+                       pin += STMPE_PWM_24XX_PINBASE;
+
+               ret = stmpe_set_altfunc(stmpe_pwm->stmpe, BIT(pin),
+                                       STMPE_BLOCK_PWM);
+               if (ret) {
+                       dev_err(chip->dev, "unable to connect PWM#%u to pin\n",
+                               pwm->hwpwm);
+                       return ret;
+               }
+       }
+
+       /* STMPE24XX */
+       switch (pwm->hwpwm) {
+       case 0:
+               offset = STMPE24XX_PWMIC0;
+               break;
+
+       case 1:
+               offset = STMPE24XX_PWMIC1;
+               break;
+
+       case 2:
+               offset = STMPE24XX_PWMIC1;
+               break;
+
+       default:
+               /* Should not happen as npwm is 3 */
+               return -ENODEV;
+       }
+
+       dev_dbg(chip->dev, "PWM#%u: config duty %d ns, period %d ns\n",
+               pwm->hwpwm, duty_ns, period_ns);
+
+       if (duty_ns == 0) {
+               if (stmpe_pwm->stmpe->partnum == STMPE2401)
+                       program[0] = SMAX; /* off all the time */
+
+               if (stmpe_pwm->stmpe->partnum == STMPE2403)
+                       program[0] = LOAD | 0xff; /* LOAD 0xff */
+
+               stmpe_pwm->last_duty = 0x00;
+       } else if (duty_ns == period_ns) {
+               if (stmpe_pwm->stmpe->partnum == STMPE2401)
+                       program[0] = SMIN; /* on all the time */
+
+               if (stmpe_pwm->stmpe->partnum == STMPE2403)
+                       program[0] = LOAD | 0x00; /* LOAD 0x00 */
+
+               stmpe_pwm->last_duty = 0xff;
+       } else {
+               u8 value, last = stmpe_pwm->last_duty;
+               unsigned long duty;
+
+               /*
+                * Counter goes from 0x00 to 0xff repeatedly at 32768 Hz,
+                * (means a period of 30517 ns) then this is compared to the
+                * counter from the ramp, if this is >= PWM counter the output
+                * is high. With LOAD we can define how much of the cycle it
+                * is on.
+                *
+                * Prescale = 0 -> 2 kHz -> T = 1/f = 488281.25 ns
+                */
+
+               /* Scale to 0..0xff */
+               duty = duty_ns * 256;
+               duty = DIV_ROUND_CLOSEST(duty, period_ns);
+               value = duty;
+
+               if (value == last) {
+                       /* Run the old program */
+                       if (pwm_is_enabled(pwm))
+                               stmpe_24xx_pwm_enable(chip, pwm);
+
+                       return 0;
+               } else if (stmpe_pwm->stmpe->partnum == STMPE2403) {
+                       /* STMPE2403 can simply set the right PWM value */
+                       program[0] = LOAD | value;
+                       program[1] = 0x0000;
+               } else if (stmpe_pwm->stmpe->partnum == STMPE2401) {
+                       /* STMPE2401 need a complex program */
+                       u16 incdec = 0x0000;
+
+                       if (last < value)
+                               /* Count up */
+                               incdec = RAMPUP | (value - last);
+                       else
+                               /* Count down */
+                               incdec = RAMPDOWN | (last - value);
+
+                       /* Step to desired value, smoothly */
+                       program[0] = PRESCALE_512 | STEPTIME_1 | incdec;
+
+                       /* Loop eternally to 0x00 */
+                       program[1] = BRANCH;
+               }
+
+               dev_dbg(chip->dev,
+                       "PWM#%u: value = %02x, last_duty = %02x, program=%04x,%04x,%04x\n",
+                       pwm->hwpwm, value, last, program[0], program[1],
+                       program[2]);
+               stmpe_pwm->last_duty = value;
+       }
+
+       /*
+        * We can write programs of up to 64 16-bit words into this channel.
+        */
+       for (i = 0; i < ARRAY_SIZE(program); i++) {
+               u8 value;
+
+               value = (program[i] >> 8) & 0xff;
+
+               ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
+               if (ret) {
+                       dev_err(chip->dev, "error writing register %02x: %d\n",
+                               offset, ret);
+                       return ret;
+               }
+
+               value = program[i] & 0xff;
+
+               ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
+               if (ret) {
+                       dev_err(chip->dev, "error writing register %02x: %d\n",
+                               offset, ret);
+                       return ret;
+               }
+       }
+
+       /* If we were enabled, re-enable this PWM */
+       if (pwm_is_enabled(pwm))
+               stmpe_24xx_pwm_enable(chip, pwm);
+
+       /* Sleep for 200ms so we're sure it will take effect */
+       msleep(200);
+
+       dev_dbg(chip->dev, "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i);
+
+       return 0;
+}
+
+static const struct pwm_ops stmpe_24xx_pwm_ops = {
+       .config = stmpe_24xx_pwm_config,
+       .enable = stmpe_24xx_pwm_enable,
+       .disable = stmpe_24xx_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int __init stmpe_pwm_probe(struct platform_device *pdev)
+{
+       struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+       struct stmpe_pwm *pwm;
+       int ret;
+
+       pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+       if (!pwm)
+               return -ENOMEM;
+
+       pwm->stmpe = stmpe;
+       pwm->chip.dev = &pdev->dev;
+       pwm->chip.base = -1;
+
+       if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) {
+               pwm->chip.ops = &stmpe_24xx_pwm_ops;
+               pwm->chip.npwm = 3;
+       } else {
+               if (stmpe->partnum == STMPE1601)
+                       dev_err(&pdev->dev, "STMPE1601 not yet supported\n");
+               else
+                       dev_err(&pdev->dev, "Unknown STMPE PWM\n");
+
+               return -ENODEV;
+       }
+
+       ret = stmpe_enable(stmpe, STMPE_BLOCK_PWM);
+       if (ret)
+               return ret;
+
+       ret = pwmchip_add(&pwm->chip);
+       if (ret) {
+               stmpe_disable(stmpe, STMPE_BLOCK_PWM);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, pwm);
+
+       return 0;
+}
+
+static struct platform_driver stmpe_pwm_driver = {
+       .driver = {
+               .name = "stmpe-pwm",
+       },
+};
+builtin_platform_driver_probe(stmpe_pwm_driver, stmpe_pwm_probe);
index d4de060..e464784 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/pwm.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/reset.h>
 
 #define PWM_ENABLE     (1 << 31)
 #define PWM_DUTY_WIDTH 8
 #define PWM_SCALE_WIDTH        13
 #define PWM_SCALE_SHIFT        0
 
-#define NUM_PWM 4
+struct tegra_pwm_soc {
+       unsigned int num_channels;
+};
 
 struct tegra_pwm_chip {
-       struct pwm_chip         chip;
-       struct device           *dev;
+       struct pwm_chip chip;
+       struct device *dev;
+
+       struct clk *clk;
+       struct reset_control*rst;
 
-       struct clk              *clk;
+       void __iomem *regs;
 
-       void __iomem            *mmio_base;
+       const struct tegra_pwm_soc *soc;
 };
 
 static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
@@ -54,20 +61,20 @@ static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
 
 static inline u32 pwm_readl(struct tegra_pwm_chip *chip, unsigned int num)
 {
-       return readl(chip->mmio_base + (num << 4));
+       return readl(chip->regs + (num << 4));
 }
 
 static inline void pwm_writel(struct tegra_pwm_chip *chip, unsigned int num,
                             unsigned long val)
 {
-       writel(val, chip->mmio_base + (num << 4));
+       writel(val, chip->regs + (num << 4));
 }
 
 static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                            int duty_ns, int period_ns)
 {
        struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
-       unsigned long long c;
+       unsigned long long c = duty_ns;
        unsigned long rate, hz;
        u32 val = 0;
        int err;
@@ -77,7 +84,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
         * per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the
         * nearest integer during division.
         */
-       c = duty_ns * ((1 << PWM_DUTY_WIDTH) - 1) + period_ns / 2;
+       c *= (1 << PWM_DUTY_WIDTH);
+       c += period_ns / 2;
        do_div(c, period_ns);
 
        val = (u32)c << PWM_DUTY_SHIFT;
@@ -176,12 +184,13 @@ static int tegra_pwm_probe(struct platform_device *pdev)
        if (!pwm)
                return -ENOMEM;
 
+       pwm->soc = of_device_get_match_data(&pdev->dev);
        pwm->dev = &pdev->dev;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-       if (IS_ERR(pwm->mmio_base))
-               return PTR_ERR(pwm->mmio_base);
+       pwm->regs = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(pwm->regs))
+               return PTR_ERR(pwm->regs);
 
        platform_set_drvdata(pdev, pwm);
 
@@ -189,14 +198,24 @@ static int tegra_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(pwm->clk))
                return PTR_ERR(pwm->clk);
 
+       pwm->rst = devm_reset_control_get(&pdev->dev, "pwm");
+       if (IS_ERR(pwm->rst)) {
+               ret = PTR_ERR(pwm->rst);
+               dev_err(&pdev->dev, "Reset control is not found: %d\n", ret);
+               return ret;
+       }
+
+       reset_control_deassert(pwm->rst);
+
        pwm->chip.dev = &pdev->dev;
        pwm->chip.ops = &tegra_pwm_ops;
        pwm->chip.base = -1;
-       pwm->chip.npwm = NUM_PWM;
+       pwm->chip.npwm = pwm->soc->num_channels;
 
        ret = pwmchip_add(&pwm->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               reset_control_assert(pwm->rst);
                return ret;
        }
 
@@ -206,12 +225,17 @@ static int tegra_pwm_probe(struct platform_device *pdev)
 static int tegra_pwm_remove(struct platform_device *pdev)
 {
        struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
-       int i;
+       unsigned int i;
+       int err;
 
        if (WARN_ON(!pc))
                return -ENODEV;
 
-       for (i = 0; i < NUM_PWM; i++) {
+       err = clk_prepare_enable(pc->clk);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < pc->chip.npwm; i++) {
                struct pwm_device *pwm = &pc->chip.pwms[i];
 
                if (!pwm_is_enabled(pwm))
@@ -223,12 +247,23 @@ static int tegra_pwm_remove(struct platform_device *pdev)
                clk_disable_unprepare(pc->clk);
        }
 
+       reset_control_assert(pc->rst);
+       clk_disable_unprepare(pc->clk);
+
        return pwmchip_remove(&pc->chip);
 }
 
+static const struct tegra_pwm_soc tegra20_pwm_soc = {
+       .num_channels = 4,
+};
+
+static const struct tegra_pwm_soc tegra186_pwm_soc = {
+       .num_channels = 1,
+};
+
 static const struct of_device_id tegra_pwm_of_match[] = {
-       { .compatible = "nvidia,tegra20-pwm" },
-       { .compatible = "nvidia,tegra30-pwm" },
+       { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc },
+       { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc },
        { }
 };
 
index 616af76..6ec342d 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/pwm.h>
 #include <linux/of_device.h>
 
-#include "pwm-tipwmss.h"
-
 /* ECAP registers and bits definitions */
 #define CAP1                   0x08
 #define CAP2                   0x0C
@@ -195,6 +193,7 @@ static const struct pwm_ops ecap_pwm_ops = {
 };
 
 static const struct of_device_id ecap_of_match[] = {
+       { .compatible   = "ti,am3352-ecap" },
        { .compatible   = "ti,am33xx-ecap" },
        {},
 };
@@ -202,17 +201,24 @@ MODULE_DEVICE_TABLE(of, ecap_of_match);
 
 static int ecap_pwm_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ecap_pwm_chip *pc;
-       u16 status;
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc)
                return -ENOMEM;
 
        clk = devm_clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               if (of_device_is_compatible(np, "ti,am33xx-ecap")) {
+                       dev_warn(&pdev->dev, "Binding is obsolete.\n");
+                       clk = devm_clk_get(pdev->dev.parent, "fck");
+               }
+       }
+
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "failed to get clock\n");
                return PTR_ERR(clk);
@@ -243,40 +249,15 @@ static int ecap_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
-
-       status = pwmss_submodule_state_change(pdev->dev.parent,
-                       PWMSS_ECAPCLK_EN);
-       if (!(status & PWMSS_ECAPCLK_EN_ACK)) {
-               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
-               ret = -EINVAL;
-               goto pwmss_clk_failure;
-       }
-
-       pm_runtime_put_sync(&pdev->dev);
 
        platform_set_drvdata(pdev, pc);
        return 0;
-
-pwmss_clk_failure:
-       pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-       pwmchip_remove(&pc->chip);
-       return ret;
 }
 
 static int ecap_pwm_remove(struct platform_device *pdev)
 {
        struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
 
-       pm_runtime_get_sync(&pdev->dev);
-       /*
-        * Due to hardware misbehaviour, acknowledge of the stop_req
-        * is missing. Hence checking of the status bit skipped.
-        */
-       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
-       pm_runtime_put_sync(&pdev->dev);
-
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
 }
index 6a41e66..b5c6b06 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/of_device.h>
 
-#include "pwm-tipwmss.h"
-
 /* EHRPWM registers and bits definitions */
 
 /* Time base module registers */
@@ -426,6 +424,7 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
 };
 
 static const struct of_device_id ehrpwm_of_match[] = {
+       { .compatible   = "ti,am3352-ehrpwm" },
        { .compatible   = "ti,am33xx-ehrpwm" },
        {},
 };
@@ -433,17 +432,24 @@ MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
 
 static int ehrpwm_pwm_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ehrpwm_pwm_chip *pc;
-       u16 status;
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc)
                return -ENOMEM;
 
        clk = devm_clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               if (of_device_is_compatible(np, "ti,am33xx-ecap")) {
+                       dev_warn(&pdev->dev, "Binding is obsolete.\n");
+                       clk = devm_clk_get(pdev->dev.parent, "fck");
+               }
+       }
+
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "failed to get clock\n");
                return PTR_ERR(clk);
@@ -487,27 +493,9 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
-
-       status = pwmss_submodule_state_change(pdev->dev.parent,
-                       PWMSS_EPWMCLK_EN);
-       if (!(status & PWMSS_EPWMCLK_EN_ACK)) {
-               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
-               ret = -EINVAL;
-               goto pwmss_clk_failure;
-       }
-
-       pm_runtime_put_sync(&pdev->dev);
 
        platform_set_drvdata(pdev, pc);
        return 0;
-
-pwmss_clk_failure:
-       pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-       pwmchip_remove(&pc->chip);
-       clk_unprepare(pc->tbclk);
-       return ret;
 }
 
 static int ehrpwm_pwm_remove(struct platform_device *pdev)
@@ -516,14 +504,6 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
 
        clk_unprepare(pc->tbclk);
 
-       pm_runtime_get_sync(&pdev->dev);
-       /*
-        * Due to hardware misbehaviour, acknowledge of the stop_req
-        * is missing. Hence checking of the status bit skipped.
-        */
-       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ);
-       pm_runtime_put_sync(&pdev->dev);
-
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
index 5cf65a1..829f499 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/of_device.h>
 
-#include "pwm-tipwmss.h"
-
-#define PWMSS_CLKCONFIG                0x8     /* Clock gating reg */
-#define PWMSS_CLKSTATUS                0xc     /* Clock gating status reg */
-
-struct pwmss_info {
-       void __iomem    *mmio_base;
-       struct mutex    pwmss_lock;
-       u16             pwmss_clkconfig;
-};
-
-u16 pwmss_submodule_state_change(struct device *dev, int set)
-{
-       struct pwmss_info *info = dev_get_drvdata(dev);
-       u16 val;
-
-       mutex_lock(&info->pwmss_lock);
-       val = readw(info->mmio_base + PWMSS_CLKCONFIG);
-       val |= set;
-       writew(val , info->mmio_base + PWMSS_CLKCONFIG);
-       mutex_unlock(&info->pwmss_lock);
-
-       return readw(info->mmio_base + PWMSS_CLKSTATUS);
-}
-EXPORT_SYMBOL(pwmss_submodule_state_change);
-
 static const struct of_device_id pwmss_of_match[] = {
        { .compatible   = "ti,am33xx-pwmss" },
        {},
@@ -57,24 +31,10 @@ MODULE_DEVICE_TABLE(of, pwmss_of_match);
 static int pwmss_probe(struct platform_device *pdev)
 {
        int ret;
-       struct resource *r;
-       struct pwmss_info *info;
        struct device_node *node = pdev->dev.of_node;
 
-       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       mutex_init(&info->pwmss_lock);
-
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-       if (IS_ERR(info->mmio_base))
-               return PTR_ERR(info->mmio_base);
-
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
-       platform_set_drvdata(pdev, info);
 
        /* Populate all the child nodes here... */
        ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
@@ -86,30 +46,21 @@ static int pwmss_probe(struct platform_device *pdev)
 
 static int pwmss_remove(struct platform_device *pdev)
 {
-       struct pwmss_info *info = platform_get_drvdata(pdev);
-
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       mutex_destroy(&info->pwmss_lock);
        return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int pwmss_suspend(struct device *dev)
 {
-       struct pwmss_info *info = dev_get_drvdata(dev);
-
-       info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG);
        pm_runtime_put_sync(dev);
        return 0;
 }
 
 static int pwmss_resume(struct device *dev)
 {
-       struct pwmss_info *info = dev_get_drvdata(dev);
-
        pm_runtime_get_sync(dev);
-       writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG);
        return 0;
 }
 #endif
diff --git a/drivers/pwm/pwm-tipwmss.h b/drivers/pwm/pwm-tipwmss.h
deleted file mode 100644 (file)
index 10ad804..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * TI PWM Subsystem driver
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __TIPWMSS_H
-#define __TIPWMSS_H
-
-/* PWM substem clock gating */
-#define PWMSS_ECAPCLK_EN       BIT(0)
-#define PWMSS_ECAPCLK_STOP_REQ BIT(1)
-#define PWMSS_EPWMCLK_EN       BIT(8)
-#define PWMSS_EPWMCLK_STOP_REQ BIT(9)
-
-#define PWMSS_ECAPCLK_EN_ACK   BIT(0)
-#define PWMSS_EPWMCLK_EN_ACK   BIT(8)
-
-#ifdef CONFIG_PWM_TIPWMSS
-extern u16 pwmss_submodule_state_change(struct device *dev, int set);
-#else
-static inline u16 pwmss_submodule_state_change(struct device *dev, int set)
-{
-       /* return success status value */
-       return 0xFFFF;
-}
-#endif
-#endif /* __TIPWMSS_H */
index 01695d4..18ed725 100644 (file)
@@ -208,16 +208,33 @@ static ssize_t polarity_store(struct device *child,
        return ret ? : size;
 }
 
+static ssize_t capture_show(struct device *child,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct pwm_device *pwm = child_to_pwm_device(child);
+       struct pwm_capture result;
+       int ret;
+
+       ret = pwm_capture(pwm, &result, jiffies_to_msecs(HZ));
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u %u\n", result.period, result.duty_cycle);
+}
+
 static DEVICE_ATTR_RW(period);
 static DEVICE_ATTR_RW(duty_cycle);
 static DEVICE_ATTR_RW(enable);
 static DEVICE_ATTR_RW(polarity);
+static DEVICE_ATTR_RO(capture);
 
 static struct attribute *pwm_attrs[] = {
        &dev_attr_period.attr,
        &dev_attr_duty_cycle.attr,
        &dev_attr_enable.attr,
        &dev_attr_polarity.attr,
+       &dev_attr_capture.attr,
        NULL
 };
 ATTRIBUTE_GROUPS(pwm);
index b5a10d3..d6d2f20 100644 (file)
@@ -67,6 +67,15 @@ config RAPIDIO_ENUM_BASIC
 
 endchoice
 
+config RAPIDIO_CHMAN
+       tristate "RapidIO Channelized Messaging driver"
+       depends on RAPIDIO
+       help
+         This option includes RapidIO channelized messaging driver which
+         provides socket-like interface to allow sharing of single RapidIO
+         messaging mailbox between multiple user-space applications.
+         See "Documentation/rapidio/rio_cm.txt" for driver description.
+
 config RAPIDIO_MPORT_CDEV
        tristate "RapidIO /dev mport device driver"
        depends on RAPIDIO
index 6271ada..74dcea4 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_RAPIDIO) += rapidio.o
 rapidio-y := rio.o rio-access.o rio-driver.o rio-sysfs.o
 
 obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o
+obj-$(CONFIG_RAPIDIO_CHMAN)    += rio_cm.o
 
 obj-$(CONFIG_RAPIDIO)          += switches/
 obj-$(CONFIG_RAPIDIO)          += devices/
index e165b7c..436dfe8 100644 (file)
@@ -1813,7 +1813,7 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,
        if (rdev->pef & RIO_PEF_EXT_FEATURES) {
                rdev->efptr = rval & 0xffff;
                rdev->phys_efptr = rio_mport_get_physefb(mport, 0, destid,
-                                                        hopcount);
+                                               hopcount, &rdev->phys_rmap);
 
                rdev->em_efptr = rio_mport_get_feature(mport, 0, destid,
                                                hopcount, RIO_EFB_ERR_MGMNT);
@@ -2242,7 +2242,7 @@ static void mport_mm_open(struct vm_area_struct *vma)
 {
        struct rio_mport_mapping *map = vma->vm_private_data;
 
-rmcd_debug(MMAP, "0x%pad", &map->phys_addr);
+       rmcd_debug(MMAP, "%pad", &map->phys_addr);
        kref_get(&map->ref);
 }
 
@@ -2250,7 +2250,7 @@ static void mport_mm_close(struct vm_area_struct *vma)
 {
        struct rio_mport_mapping *map = vma->vm_private_data;
 
-rmcd_debug(MMAP, "0x%pad", &map->phys_addr);
+       rmcd_debug(MMAP, "%pad", &map->phys_addr);
        mutex_lock(&map->md->buf_mutex);
        kref_put(&map->ref, mport_release_mapping);
        mutex_unlock(&map->md->buf_mutex);
index b5b4556..32f0f01 100644 (file)
 #include "tsi721.h"
 
 #ifdef DEBUG
-u32 dbg_level = DBG_INIT | DBG_EXIT;
+u32 dbg_level;
 module_param(dbg_level, uint, S_IWUSR | S_IRUGO);
 MODULE_PARM_DESC(dbg_level, "Debugging output level (default 0 = none)");
 #endif
 
+static int pcie_mrrs = -1;
+module_param(pcie_mrrs, int, S_IRUGO);
+MODULE_PARM_DESC(pcie_mrrs, "PCIe MRRS override value (0...5)");
+
+static u8 mbox_sel = 0x0f;
+module_param(mbox_sel, byte, S_IRUGO);
+MODULE_PARM_DESC(mbox_sel,
+                "RIO Messaging MBOX Selection Mask (default: 0x0f = all)");
+
 static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
 static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);
 
@@ -1081,7 +1090,7 @@ static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv)
  * from rstart to lstart.
  */
 static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
-               u64 rstart, u32 size, u32 flags)
+               u64 rstart, u64 size, u32 flags)
 {
        struct tsi721_device *priv = mport->priv;
        int i, avail = -1;
@@ -1094,6 +1103,10 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
        struct tsi721_ib_win_mapping *map = NULL;
        int ret = -EBUSY;
 
+       /* Max IBW size supported by HW is 16GB */
+       if (size > 0x400000000UL)
+               return -EINVAL;
+
        if (direct) {
                /* Calculate minimal acceptable window size and base address */
 
@@ -1101,15 +1114,15 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
                ibw_start = lstart & ~(ibw_size - 1);
 
                tsi_debug(IBW, &priv->pdev->dev,
-                       "Direct (RIO_0x%llx -> PCIe_0x%pad), size=0x%x, ibw_start = 0x%llx",
+                       "Direct (RIO_0x%llx -> PCIe_%pad), size=0x%llx, ibw_start = 0x%llx",
                        rstart, &lstart, size, ibw_start);
 
                while ((lstart + size) > (ibw_start + ibw_size)) {
                        ibw_size *= 2;
                        ibw_start = lstart & ~(ibw_size - 1);
-                       if (ibw_size > 0x80000000) { /* Limit max size to 2GB */
+                       /* Check for crossing IBW max size 16GB */
+                       if (ibw_size > 0x400000000UL)
                                return -EBUSY;
-                       }
                }
 
                loc_start = ibw_start;
@@ -1120,7 +1133,7 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
 
        } else {
                tsi_debug(IBW, &priv->pdev->dev,
-                       "Translated (RIO_0x%llx -> PCIe_0x%pad), size=0x%x",
+                       "Translated (RIO_0x%llx -> PCIe_%pad), size=0x%llx",
                        rstart, &lstart, size);
 
                if (!is_power_of_2(size) || size < 0x1000 ||
@@ -1215,7 +1228,7 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
        priv->ibwin_cnt--;
 
        tsi_debug(IBW, &priv->pdev->dev,
-               "Configured IBWIN%d (RIO_0x%llx -> PCIe_0x%pad), size=0x%llx",
+               "Configured IBWIN%d (RIO_0x%llx -> PCIe_%pad), size=0x%llx",
                i, ibw_start, &loc_start, ibw_size);
 
        return 0;
@@ -1237,7 +1250,7 @@ static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport,
        int i;
 
        tsi_debug(IBW, &priv->pdev->dev,
-               "Unmap IBW mapped to PCIe_0x%pad", &lstart);
+               "Unmap IBW mapped to PCIe_%pad", &lstart);
 
        /* Search for matching active inbound translation window */
        for (i = 0; i < TSI721_IBWIN_NUM; i++) {
@@ -1877,6 +1890,11 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id,
                goto out;
        }
 
+       if ((mbox_sel & (1 << mbox)) == 0) {
+               rc = -ENODEV;
+               goto out;
+       }
+
        priv->omsg_ring[mbox].dev_id = dev_id;
        priv->omsg_ring[mbox].size = entries;
        priv->omsg_ring[mbox].sts_rdptr = 0;
@@ -2161,6 +2179,11 @@ static int tsi721_open_inb_mbox(struct rio_mport *mport, void *dev_id,
                goto out;
        }
 
+       if ((mbox_sel & (1 << mbox)) == 0) {
+               rc = -ENODEV;
+               goto out;
+       }
+
        /* Initialize IB Messaging Ring */
        priv->imsg_ring[mbox].dev_id = dev_id;
        priv->imsg_ring[mbox].size = entries;
@@ -2532,11 +2555,11 @@ static int tsi721_query_mport(struct rio_mport *mport,
        struct tsi721_device *priv = mport->priv;
        u32 rval;
 
-       rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_ERR_STS_CSR(0)));
+       rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_ERR_STS_CSR(0, 0));
        if (rval & RIO_PORT_N_ERR_STS_PORT_OK) {
-               rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL2_CSR(0)));
+               rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL2_CSR(0, 0));
                attr->link_speed = (rval & RIO_PORT_N_CTL2_SEL_BAUD) >> 28;
-               rval = ioread32(priv->regs + (0x100 + RIO_PORT_N_CTL_CSR(0)));
+               rval = ioread32(priv->regs + 0x100 + RIO_PORT_N_CTL_CSR(0, 0));
                attr->link_width = (rval & RIO_PORT_N_CTL_IPW) >> 27;
        } else
                attr->link_speed = RIO_LINK_DOWN;
@@ -2650,9 +2673,9 @@ static int tsi721_setup_mport(struct tsi721_device *priv)
        mport->ops = &tsi721_rio_ops;
        mport->index = 0;
        mport->sys_size = 0; /* small system */
-       mport->phy_type = RIO_PHY_SERIAL;
        mport->priv = (void *)priv;
        mport->phys_efptr = 0x100;
+       mport->phys_rmap = 1;
        mport->dev.parent = &pdev->dev;
        mport->dev.release = tsi721_mport_release;
 
@@ -2840,6 +2863,16 @@ static int tsi721_probe(struct pci_dev *pdev,
        pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
                PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
 
+       /* Override PCIe Maximum Read Request Size setting if requested */
+       if (pcie_mrrs >= 0) {
+               if (pcie_mrrs <= 5)
+                       pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
+                                       PCI_EXP_DEVCTL_READRQ, pcie_mrrs << 12);
+               else
+                       tsi_info(&pdev->dev,
+                                "Invalid MRRS override value %d", pcie_mrrs);
+       }
+
        /* Adjust PCIe completion timeout. */
        pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2);
 
index 5456dbd..5941437 100644 (file)
@@ -661,7 +661,7 @@ enum dma_rtype {
  */
 #define TSI721_DMA_CHNUM       TSI721_DMA_MAXCH
 
-#define TSI721_DMACH_MAINT     0       /* DMA channel for maint requests */
+#define TSI721_DMACH_MAINT     7       /* DMA channel for maint requests */
 #define TSI721_DMACH_MAINT_NBD 32      /* Number of BDs for maint requests */
 
 #define TSI721_DMACH_DMA       1       /* DMA channel for data transfers */
index 155cae1..e2a4185 100644 (file)
 
 #include "tsi721.h"
 
-#define TSI721_DMA_TX_QUEUE_SZ 16      /* number of transaction descriptors */
-
 #ifdef CONFIG_PCI_MSI
 static irqreturn_t tsi721_bdma_msix(int irq, void *ptr);
 #endif
 static int tsi721_submit_sg(struct tsi721_tx_desc *desc);
 
 static unsigned int dma_desc_per_channel = 128;
-module_param(dma_desc_per_channel, uint, S_IWUSR | S_IRUGO);
+module_param(dma_desc_per_channel, uint, S_IRUGO);
 MODULE_PARM_DESC(dma_desc_per_channel,
                 "Number of DMA descriptors per channel (default: 128)");
 
+static unsigned int dma_txqueue_sz = 16;
+module_param(dma_txqueue_sz, uint, S_IRUGO);
+MODULE_PARM_DESC(dma_txqueue_sz,
+                "DMA Transactions Queue Size (default: 16)");
+
+static u8 dma_sel = 0x7f;
+module_param(dma_sel, byte, S_IRUGO);
+MODULE_PARM_DESC(dma_sel,
+                "DMA Channel Selection Mask (default: 0x7f = all)");
+
 static inline struct tsi721_bdma_chan *to_tsi721_chan(struct dma_chan *chan)
 {
        return container_of(chan, struct tsi721_bdma_chan, dchan);
@@ -718,6 +726,7 @@ static dma_cookie_t tsi721_tx_submit(struct dma_async_tx_descriptor *txd)
        cookie = dma_cookie_assign(txd);
        desc->status = DMA_IN_PROGRESS;
        list_add_tail(&desc->desc_node, &bdma_chan->queue);
+       tsi721_advance_work(bdma_chan, NULL);
 
        spin_unlock_bh(&bdma_chan->lock);
        return cookie;
@@ -732,7 +741,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        tsi_debug(DMA, &dchan->dev->device, "DMAC%d", bdma_chan->id);
 
        if (bdma_chan->bd_base)
-               return TSI721_DMA_TX_QUEUE_SZ;
+               return dma_txqueue_sz;
 
        /* Initialize BDMA channel */
        if (tsi721_bdma_ch_init(bdma_chan, dma_desc_per_channel)) {
@@ -742,7 +751,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        }
 
        /* Allocate queue of transaction descriptors */
-       desc = kcalloc(TSI721_DMA_TX_QUEUE_SZ, sizeof(struct tsi721_tx_desc),
+       desc = kcalloc(dma_txqueue_sz, sizeof(struct tsi721_tx_desc),
                        GFP_ATOMIC);
        if (!desc) {
                tsi_err(&dchan->dev->device,
@@ -754,7 +763,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
 
        bdma_chan->tx_desc = desc;
 
-       for (i = 0; i < TSI721_DMA_TX_QUEUE_SZ; i++) {
+       for (i = 0; i < dma_txqueue_sz; i++) {
                dma_async_tx_descriptor_init(&desc[i].txd, dchan);
                desc[i].txd.tx_submit = tsi721_tx_submit;
                desc[i].txd.flags = DMA_CTRL_ACK;
@@ -766,7 +775,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        bdma_chan->active = true;
        tsi721_bdma_interrupt_enable(bdma_chan, 1);
 
-       return TSI721_DMA_TX_QUEUE_SZ;
+       return dma_txqueue_sz;
 }
 
 static void tsi721_sync_dma_irq(struct tsi721_bdma_chan *bdma_chan)
@@ -962,7 +971,7 @@ void tsi721_dma_stop_all(struct tsi721_device *priv)
        int i;
 
        for (i = 0; i < TSI721_DMA_MAXCH; i++) {
-               if (i != TSI721_DMACH_MAINT)
+               if ((i != TSI721_DMACH_MAINT) && (dma_sel & (1 << i)))
                        tsi721_dma_stop(&priv->bdma[i]);
        }
 }
@@ -979,7 +988,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
        for (i = 0; i < TSI721_DMA_MAXCH; i++) {
                struct tsi721_bdma_chan *bdma_chan = &priv->bdma[i];
 
-               if (i == TSI721_DMACH_MAINT)
+               if ((i == TSI721_DMACH_MAINT) || (dma_sel & (1 << i)) == 0)
                        continue;
 
                bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i);
index a63a380..23429bd 100644 (file)
@@ -49,15 +49,6 @@ struct rio_id_table {
 static int next_destid = 0;
 static int next_comptag = 1;
 
-static int rio_mport_phys_table[] = {
-       RIO_EFB_PAR_EP_ID,
-       RIO_EFB_PAR_EP_REC_ID,
-       RIO_EFB_SER_EP_ID,
-       RIO_EFB_SER_EP_REC_ID,
-       -1,
-};
-
-
 /**
  * rio_destid_alloc - Allocate next available destID for given network
  * @net: RIO network
@@ -380,10 +371,15 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
        if (rdev->pef & RIO_PEF_EXT_FEATURES) {
                rdev->efptr = result & 0xffff;
                rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
-                                                        hopcount);
+                                               hopcount, &rdev->phys_rmap);
+               pr_debug("RIO: %s Register Map %d device\n",
+                        __func__, rdev->phys_rmap);
 
                rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
                                                hopcount, RIO_EFB_ERR_MGMNT);
+               if (!rdev->em_efptr)
+                       rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
+                                               hopcount, RIO_EFB_ERR_MGMNT_HS);
        }
 
        rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
@@ -445,7 +441,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
                        rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0);
        } else {
                if (do_enum)
-                       /*Enable Input Output Port (transmitter reviever)*/
+                       /*Enable Input Output Port (transmitter receiver)*/
                        rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
 
                dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
@@ -481,10 +477,8 @@ cleanup:
 
 /**
  * rio_sport_is_active- Tests if a switch port has an active connection.
- * @port: Master port to send transaction
- * @destid: Associated destination ID for switch
- * @hopcount: Hopcount to reach switch
- * @sport: Switch port number
+ * @rdev: RapidIO device object
+ * @sp: Switch port number
  *
  * Reads the port error status CSR for a particular switch port to
  * determine if the port has an active link.  Returns
@@ -492,31 +486,12 @@ cleanup:
  * inactive.
  */
 static int
-rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
+rio_sport_is_active(struct rio_dev *rdev, int sp)
 {
        u32 result = 0;
-       u32 ext_ftr_ptr;
 
-       ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);
-
-       while (ext_ftr_ptr) {
-               rio_mport_read_config_32(port, destid, hopcount,
-                                        ext_ftr_ptr, &result);
-               result = RIO_GET_BLOCK_ID(result);
-               if ((result == RIO_EFB_SER_EP_FREE_ID) ||
-                   (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
-                   (result == RIO_EFB_SER_EP_FREC_ID))
-                       break;
-
-               ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
-                                               ext_ftr_ptr);
-       }
-
-       if (ext_ftr_ptr)
-               rio_mport_read_config_32(port, destid, hopcount,
-                                        ext_ftr_ptr +
-                                        RIO_PORT_N_ERR_STS_CSR(sport),
-                                        &result);
+       rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, sp),
+                          &result);
 
        return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
@@ -655,9 +630,7 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
 
                        cur_destid = next_destid;
 
-                       if (rio_sport_is_active
-                           (port, RIO_ANY_DESTID(port->sys_size), hopcount,
-                            port_num)) {
+                       if (rio_sport_is_active(rdev, port_num)) {
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
@@ -785,8 +758,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
                        if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num)
                                continue;
 
-                       if (rio_sport_is_active
-                           (port, destid, hopcount, port_num)) {
+                       if (rio_sport_is_active(rdev, port_num)) {
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
@@ -831,21 +803,11 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
 static int rio_mport_is_active(struct rio_mport *port)
 {
        u32 result = 0;
-       u32 ext_ftr_ptr;
-       int *entry = rio_mport_phys_table;
-
-       do {
-               if ((ext_ftr_ptr =
-                    rio_mport_get_feature(port, 1, 0, 0, *entry)))
-                       break;
-       } while (*++entry >= 0);
-
-       if (ext_ftr_ptr)
-               rio_local_read_config_32(port,
-                                        ext_ftr_ptr +
-                                        RIO_PORT_N_ERR_STS_CSR(port->index),
-                                        &result);
 
+       rio_local_read_config_32(port,
+               port->phys_efptr +
+                       RIO_PORT_N_ERR_STS_CSR(port->index, port->phys_rmap),
+               &result);
        return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
 
index 0dcaa66..3704285 100644 (file)
@@ -268,6 +268,12 @@ int rio_request_inb_mbox(struct rio_mport *mport,
                mport->inb_msg[mbox].mcback = minb;
 
                rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries);
+               if (rc) {
+                       mport->inb_msg[mbox].mcback = NULL;
+                       mport->inb_msg[mbox].res = NULL;
+                       release_resource(res);
+                       kfree(res);
+               }
        } else
                rc = -ENOMEM;
 
@@ -285,13 +291,22 @@ int rio_request_inb_mbox(struct rio_mport *mport,
  */
 int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
 {
-       if (mport->ops->close_inb_mbox) {
-               mport->ops->close_inb_mbox(mport, mbox);
+       int rc;
 
-               /* Release the mailbox resource */
-               return release_resource(mport->inb_msg[mbox].res);
-       } else
-               return -ENOSYS;
+       if (!mport->ops->close_inb_mbox || !mport->inb_msg[mbox].res)
+               return -EINVAL;
+
+       mport->ops->close_inb_mbox(mport, mbox);
+       mport->inb_msg[mbox].mcback = NULL;
+
+       rc = release_resource(mport->inb_msg[mbox].res);
+       if (rc)
+               return rc;
+
+       kfree(mport->inb_msg[mbox].res);
+       mport->inb_msg[mbox].res = NULL;
+
+       return 0;
 }
 
 /**
@@ -336,6 +351,12 @@ int rio_request_outb_mbox(struct rio_mport *mport,
                mport->outb_msg[mbox].mcback = moutb;
 
                rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries);
+               if (rc) {
+                       mport->outb_msg[mbox].mcback = NULL;
+                       mport->outb_msg[mbox].res = NULL;
+                       release_resource(res);
+                       kfree(res);
+               }
        } else
                rc = -ENOMEM;
 
@@ -353,13 +374,22 @@ int rio_request_outb_mbox(struct rio_mport *mport,
  */
 int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
 {
-       if (mport->ops->close_outb_mbox) {
-               mport->ops->close_outb_mbox(mport, mbox);
+       int rc;
 
-               /* Release the mailbox resource */
-               return release_resource(mport->outb_msg[mbox].res);
-       } else
-               return -ENOSYS;
+       if (!mport->ops->close_outb_mbox || !mport->outb_msg[mbox].res)
+               return -EINVAL;
+
+       mport->ops->close_outb_mbox(mport, mbox);
+       mport->outb_msg[mbox].mcback = NULL;
+
+       rc = release_resource(mport->outb_msg[mbox].res);
+       if (rc)
+               return rc;
+
+       kfree(mport->outb_msg[mbox].res);
+       mport->outb_msg[mbox].res = NULL;
+
+       return 0;
 }
 
 /**
@@ -756,10 +786,11 @@ EXPORT_SYMBOL_GPL(rio_unmap_outb_region);
  * @local: Indicate a local master port or remote device access
  * @destid: Destination ID of the device
  * @hopcount: Number of switch hops to the device
+ * @rmap: pointer to location to store register map type info
  */
 u32
 rio_mport_get_physefb(struct rio_mport *port, int local,
-                     u16 destid, u8 hopcount)
+                     u16 destid, u8 hopcount, u32 *rmap)
 {
        u32 ext_ftr_ptr;
        u32 ftr_header;
@@ -777,14 +808,21 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
                ftr_header = RIO_GET_BLOCK_ID(ftr_header);
                switch (ftr_header) {
 
-               case RIO_EFB_SER_EP_ID_V13P:
-               case RIO_EFB_SER_EP_REC_ID_V13P:
-               case RIO_EFB_SER_EP_FREE_ID_V13P:
                case RIO_EFB_SER_EP_ID:
                case RIO_EFB_SER_EP_REC_ID:
                case RIO_EFB_SER_EP_FREE_ID:
-               case RIO_EFB_SER_EP_FREC_ID:
+               case RIO_EFB_SER_EP_M1_ID:
+               case RIO_EFB_SER_EP_SW_M1_ID:
+               case RIO_EFB_SER_EPF_M1_ID:
+               case RIO_EFB_SER_EPF_SW_M1_ID:
+                       *rmap = 1;
+                       return ext_ftr_ptr;
 
+               case RIO_EFB_SER_EP_M2_ID:
+               case RIO_EFB_SER_EP_SW_M2_ID:
+               case RIO_EFB_SER_EPF_M2_ID:
+               case RIO_EFB_SER_EPF_SW_M2_ID:
+                       *rmap = 2;
                        return ext_ftr_ptr;
 
                default:
@@ -843,16 +881,16 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
        u32 regval;
 
        rio_read_config_32(rdev,
-                                rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
-                                &regval);
+               RIO_DEV_PORT_N_CTL_CSR(rdev, pnum),
+               &regval);
        if (lock)
                regval |= RIO_PORT_N_CTL_LOCKOUT;
        else
                regval &= ~RIO_PORT_N_CTL_LOCKOUT;
 
        rio_write_config_32(rdev,
-                                 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
-                                 regval);
+               RIO_DEV_PORT_N_CTL_CSR(rdev, pnum),
+               regval);
        return 0;
 }
 EXPORT_SYMBOL_GPL(rio_set_port_lockout);
@@ -876,6 +914,7 @@ int rio_enable_rx_tx_port(struct rio_mport *port,
 #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
        u32 regval;
        u32 ext_ftr_ptr;
+       u32 rmap;
 
        /*
        * enable rx input tx output port
@@ -883,34 +922,29 @@ int rio_enable_rx_tx_port(struct rio_mport *port,
        pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
                 "%d, port_num = %d)\n", local, destid, hopcount, port_num);
 
-       ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
+       ext_ftr_ptr = rio_mport_get_physefb(port, local, destid,
+                                           hopcount, &rmap);
 
        if (local) {
-               rio_local_read_config_32(port, ext_ftr_ptr +
-                               RIO_PORT_N_CTL_CSR(0),
+               rio_local_read_config_32(port,
+                               ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap),
                                &regval);
        } else {
                if (rio_mport_read_config_32(port, destid, hopcount,
-               ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
+                       ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap),
+                               &regval) < 0)
                        return -EIO;
        }
 
-       if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
-               /* serial */
-               regval = regval | RIO_PORT_N_CTL_EN_RX_SER
-                               | RIO_PORT_N_CTL_EN_TX_SER;
-       } else {
-               /* parallel */
-               regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
-                               | RIO_PORT_N_CTL_EN_TX_PAR;
-       }
+       regval = regval | RIO_PORT_N_CTL_EN_RX | RIO_PORT_N_CTL_EN_TX;
 
        if (local) {
-               rio_local_write_config_32(port, ext_ftr_ptr +
-                                         RIO_PORT_N_CTL_CSR(0), regval);
+               rio_local_write_config_32(port,
+                       ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap), regval);
        } else {
                if (rio_mport_write_config_32(port, destid, hopcount,
-                   ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
+                       ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap),
+                               regval) < 0)
                        return -EIO;
        }
 #endif
@@ -1012,14 +1046,14 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
                /* Read from link maintenance response register
                 * to clear valid bit */
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+                       RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum),
                        &regval);
                udelay(50);
        }
 
        /* Issue Input-status command */
        rio_write_config_32(rdev,
-               rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
+               RIO_DEV_PORT_N_MNT_REQ_CSR(rdev, pnum),
                RIO_MNT_REQ_CMD_IS);
 
        /* Exit if the response is not expected */
@@ -1030,7 +1064,7 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
        while (checkcount--) {
                udelay(50);
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+                       RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum),
                        &regval);
                if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
                        *lnkresp = regval;
@@ -1046,6 +1080,13 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
  * @rdev: Pointer to RIO device control structure
  * @pnum: Switch port number to clear errors
  * @err_status: port error status (if 0 reads register from device)
+ *
+ * TODO: Currently this routine is not compatible with recovery process
+ * specified for idt_gen3 RapidIO switch devices. It has to be reviewed
+ * to implement universal recovery process that is compatible full range
+ * off available devices.
+ * IDT gen3 switch driver now implements HW-specific error handler that
+ * issues soft port reset to the port to reset ERR_STOP bits and ackIDs.
  */
 static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
 {
@@ -1055,10 +1096,10 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
 
        if (err_status == 0)
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+                       RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum),
                        &err_status);
 
-       if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
+       if (err_status & RIO_PORT_N_ERR_STS_OUT_ES) {
                pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
                /*
                 * Send a Link-Request/Input-Status control symbol
@@ -1073,7 +1114,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
                far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
                far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
+                       RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum),
                        &regval);
                pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
                near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
@@ -1091,43 +1132,43 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
                         * far inbound.
                         */
                        rio_write_config_32(rdev,
-                               rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
+                               RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum),
                                (near_ackid << 24) |
                                        (far_ackid << 8) | far_ackid);
                        /* Align far outstanding/outbound ackIDs with
                         * near inbound.
                         */
                        far_ackid++;
-                       if (nextdev)
-                               rio_write_config_32(nextdev,
-                                       nextdev->phys_efptr +
-                                       RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)),
-                                       (far_ackid << 24) |
-                                       (near_ackid << 8) | near_ackid);
-                       else
-                               pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
+                       if (!nextdev) {
+                               pr_debug("RIO_EM: nextdev pointer == NULL\n");
+                               goto rd_err;
+                       }
+
+                       rio_write_config_32(nextdev,
+                               RIO_DEV_PORT_N_ACK_STS_CSR(nextdev,
+                                       RIO_GET_PORT_NUM(nextdev->swpinfo)),
+                               (far_ackid << 24) |
+                               (near_ackid << 8) | near_ackid);
                }
 rd_err:
-               rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
-                       &err_status);
+               rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum),
+                                  &err_status);
                pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
        }
 
-       if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) {
+       if ((err_status & RIO_PORT_N_ERR_STS_INP_ES) && nextdev) {
                pr_debug("RIO_EM: servicing Input Error-Stopped state\n");
                rio_get_input_status(nextdev,
                                     RIO_GET_PORT_NUM(nextdev->swpinfo), NULL);
                udelay(50);
 
-               rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
-                       &err_status);
+               rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum),
+                                  &err_status);
                pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
        }
 
-       return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
-                             RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0;
+       return (err_status & (RIO_PORT_N_ERR_STS_OUT_ES |
+                             RIO_PORT_N_ERR_STS_INP_ES)) ? 1 : 0;
 }
 
 /**
@@ -1227,9 +1268,8 @@ int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
        if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle)
                rdev->rswitch->ops->em_handle(rdev, portnum);
 
-       rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
-                       &err_status);
+       rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum),
+                          &err_status);
        pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
 
        if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
@@ -1246,8 +1286,8 @@ int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
                 * Depending on the link partner state, two attempts
                 * may be needed for successful recovery.
                 */
-               if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
-                                 RIO_PORT_N_ERR_STS_PW_INP_ES)) {
+               if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES |
+                                 RIO_PORT_N_ERR_STS_INP_ES)) {
                        if (rio_clr_err_stopped(rdev, portnum, err_status))
                                rio_clr_err_stopped(rdev, portnum, 0);
                }
@@ -1257,10 +1297,18 @@ int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
                        rdev->rswitch->port_ok &= ~(1 << portnum);
                        rio_set_port_lockout(rdev, portnum, 1);
 
+                       if (rdev->phys_rmap == 1) {
                        rio_write_config_32(rdev,
-                               rdev->phys_efptr +
-                                       RIO_PORT_N_ACK_STS_CSR(portnum),
+                               RIO_DEV_PORT_N_ACK_STS_CSR(rdev, portnum),
                                RIO_PORT_N_ACK_CLEAR);
+                       } else {
+                               rio_write_config_32(rdev,
+                                       RIO_DEV_PORT_N_OB_ACK_CSR(rdev, portnum),
+                                       RIO_PORT_N_OB_ACK_CLEAR);
+                               rio_write_config_32(rdev,
+                                       RIO_DEV_PORT_N_IB_ACK_CSR(rdev, portnum),
+                                       0);
+                       }
 
                        /* Schedule Extraction Service */
                        pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
@@ -1289,9 +1337,8 @@ int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
        }
 
        /* Clear remaining error bits and Port-Write Pending bit */
-       rio_write_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
-                       err_status);
+       rio_write_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum),
+                           err_status);
 
        return 0;
 }
@@ -1342,20 +1389,7 @@ EXPORT_SYMBOL_GPL(rio_mport_get_efb);
  * Tell if a device supports a given RapidIO capability.
  * Returns the offset of the requested extended feature
  * block within the device's RIO configuration space or
- * 0 in case the device does not support it.  Possible
- * values for @ftr:
- *
- * %RIO_EFB_PAR_EP_ID          LP/LVDS EP Devices
- *
- * %RIO_EFB_PAR_EP_REC_ID      LP/LVDS EP Recovery Devices
- *
- * %RIO_EFB_PAR_EP_FREE_ID     LP/LVDS EP Free Devices
- *
- * %RIO_EFB_SER_EP_ID          LP/Serial EP Devices
- *
- * %RIO_EFB_SER_EP_REC_ID      LP/Serial EP Recovery Devices
- *
- * %RIO_EFB_SER_EP_FREE_ID     LP/Serial EP Free Devices
+ * 0 in case the device does not support it.
  */
 u32
 rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
@@ -1848,7 +1882,9 @@ EXPORT_SYMBOL_GPL(rio_release_dma);
  * Initializes RapidIO capable DMA channel for the specified data transfer.
  * Uses DMA channel private extension to pass information related to remote
  * target RIO device.
- * Returns pointer to DMA transaction descriptor or NULL if failed.
+ *
+ * Returns: pointer to DMA transaction descriptor if successful,
+ *          error-valued pointer or NULL if failed.
  */
 struct dma_async_tx_descriptor *rio_dma_prep_xfer(struct dma_chan *dchan,
        u16 destid, struct rio_dma_data *data,
@@ -1883,7 +1919,9 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_xfer);
  * Initializes RapidIO capable DMA channel for the specified data transfer.
  * Uses DMA channel private extension to pass information related to remote
  * target RIO device.
- * Returns pointer to DMA transaction descriptor or NULL if failed.
+ *
+ * Returns: pointer to DMA transaction descriptor if successful,
+ *          error-valued pointer or NULL if failed.
  */
 struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev,
        struct dma_chan *dchan, struct rio_dma_data *data,
index 625d09a..9796b3f 100644 (file)
@@ -22,7 +22,7 @@
 extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
                                 u8 hopcount, int ftr);
 extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
-                                u16 destid, u8 hopcount);
+                                u16 destid, u8 hopcount, u32 *rmap);
 extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
                             u8 hopcount, u32 from);
 extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c
new file mode 100644 (file)
index 0000000..3fa17ac
--- /dev/null
@@ -0,0 +1,2368 @@
+/*
+ * rio_cm - RapidIO Channelized Messaging Driver
+ *
+ * Copyright 2013-2016 Integrated Device Technology, Inc.
+ * Copyright (c) 2015, Prodrive Technologies
+ * Copyright (c) 2015, RapidIO Trade Association
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
+ * BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  SEE THE
+ * GNU GENERAL PUBLIC LICENSE FOR MORE DETAILS.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/reboot.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+#include <linux/rio_cm_cdev.h>
+
+#define DRV_NAME        "rio_cm"
+#define DRV_VERSION     "1.0.0"
+#define DRV_AUTHOR      "Alexandre Bounine <alexandre.bounine@idt.com>"
+#define DRV_DESC        "RapidIO Channelized Messaging Driver"
+#define DEV_NAME       "rio_cm"
+
+/* Debug output filtering masks */
+enum {
+       DBG_NONE        = 0,
+       DBG_INIT        = BIT(0), /* driver init */
+       DBG_EXIT        = BIT(1), /* driver exit */
+       DBG_MPORT       = BIT(2), /* mport add/remove */
+       DBG_RDEV        = BIT(3), /* RapidIO device add/remove */
+       DBG_CHOP        = BIT(4), /* channel operations */
+       DBG_WAIT        = BIT(5), /* waiting for events */
+       DBG_TX          = BIT(6), /* message TX */
+       DBG_TX_EVENT    = BIT(7), /* message TX event */
+       DBG_RX_DATA     = BIT(8), /* inbound data messages */
+       DBG_RX_CMD      = BIT(9), /* inbound REQ/ACK/NACK messages */
+       DBG_ALL         = ~0,
+};
+
+#ifdef DEBUG
+#define riocm_debug(level, fmt, arg...) \
+       do { \
+               if (DBG_##level & dbg_level) \
+                       pr_debug(DRV_NAME ": %s " fmt "\n", \
+                               __func__, ##arg); \
+       } while (0)
+#else
+#define riocm_debug(level, fmt, arg...) \
+               no_printk(KERN_DEBUG pr_fmt(DRV_NAME fmt "\n"), ##arg)
+#endif
+
+#define riocm_warn(fmt, arg...) \
+       pr_warn(DRV_NAME ": %s WARNING " fmt "\n", __func__, ##arg)
+
+#define riocm_error(fmt, arg...) \
+       pr_err(DRV_NAME ": %s ERROR " fmt "\n", __func__, ##arg)
+
+
+static int cmbox = 1;
+module_param(cmbox, int, S_IRUGO);
+MODULE_PARM_DESC(cmbox, "RapidIO Mailbox number (default 1)");
+
+static int chstart = 256;
+module_param(chstart, int, S_IRUGO);
+MODULE_PARM_DESC(chstart,
+                "Start channel number for dynamic allocation (default 256)");
+
+#ifdef DEBUG
+static u32 dbg_level = DBG_NONE;
+module_param(dbg_level, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(dbg_level, "Debugging output level (default 0 = none)");
+#endif
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define RIOCM_TX_RING_SIZE     128
+#define RIOCM_RX_RING_SIZE     128
+#define RIOCM_CONNECT_TO       3 /* connect response TO (in sec) */
+
+#define RIOCM_MAX_CHNUM                0xffff /* Use full range of u16 field */
+#define RIOCM_CHNUM_AUTO       0
+#define RIOCM_MAX_EP_COUNT     0x10000 /* Max number of endpoints */
+
+enum rio_cm_state {
+       RIO_CM_IDLE,
+       RIO_CM_CONNECT,
+       RIO_CM_CONNECTED,
+       RIO_CM_DISCONNECT,
+       RIO_CM_CHAN_BOUND,
+       RIO_CM_LISTEN,
+       RIO_CM_DESTROYING,
+};
+
+enum rio_cm_pkt_type {
+       RIO_CM_SYS      = 0xaa,
+       RIO_CM_CHAN     = 0x55,
+};
+
+enum rio_cm_chop {
+       CM_CONN_REQ,
+       CM_CONN_ACK,
+       CM_CONN_CLOSE,
+       CM_DATA_MSG,
+};
+
+struct rio_ch_base_bhdr {
+       u32 src_id;
+       u32 dst_id;
+#define RIO_HDR_LETTER_MASK 0xffff0000
+#define RIO_HDR_MBOX_MASK   0x0000ffff
+       u8  src_mbox;
+       u8  dst_mbox;
+       u8  type;
+} __attribute__((__packed__));
+
+struct rio_ch_chan_hdr {
+       struct rio_ch_base_bhdr bhdr;
+       u8 ch_op;
+       u16 dst_ch;
+       u16 src_ch;
+       u16 msg_len;
+       u16 rsrvd;
+} __attribute__((__packed__));
+
+struct tx_req {
+       struct list_head node;
+       struct rio_dev   *rdev;
+       void             *buffer;
+       size_t           len;
+};
+
+struct cm_dev {
+       struct list_head        list;
+       struct rio_mport        *mport;
+       void                    *rx_buf[RIOCM_RX_RING_SIZE];
+       int                     rx_slots;
+       struct mutex            rx_lock;
+
+       void                    *tx_buf[RIOCM_TX_RING_SIZE];
+       int                     tx_slot;
+       int                     tx_cnt;
+       int                     tx_ack_slot;
+       struct list_head        tx_reqs;
+       spinlock_t              tx_lock;
+
+       struct list_head        peers;
+       u32                     npeers;
+       struct workqueue_struct *rx_wq;
+       struct work_struct      rx_work;
+};
+
+struct chan_rx_ring {
+       void    *buf[RIOCM_RX_RING_SIZE];
+       int     head;
+       int     tail;
+       int     count;
+
+       /* Tracking RX buffers reported to upper level */
+       void    *inuse[RIOCM_RX_RING_SIZE];
+       int     inuse_cnt;
+};
+
+struct rio_channel {
+       u16                     id;     /* local channel ID */
+       struct kref             ref;    /* channel refcount */
+       struct file             *filp;
+       struct cm_dev           *cmdev; /* associated CM device object */
+       struct rio_dev          *rdev;  /* remote RapidIO device */
+       enum rio_cm_state       state;
+       int                     error;
+       spinlock_t              lock;
+       void                    *context;
+       u32                     loc_destid;     /* local destID */
+       u32                     rem_destid;     /* remote destID */
+       u16                     rem_channel;    /* remote channel ID */
+       struct list_head        accept_queue;
+       struct list_head        ch_node;
+       struct completion       comp;
+       struct completion       comp_close;
+       struct chan_rx_ring     rx_ring;
+};
+
+struct cm_peer {
+       struct list_head node;
+       struct rio_dev *rdev;
+};
+
+struct rio_cm_work {
+       struct work_struct work;
+       struct cm_dev *cm;
+       void *data;
+};
+
+struct conn_req {
+       struct list_head node;
+       u32 destid;     /* requester destID */
+       u16 chan;       /* requester channel ID */
+       struct cm_dev *cmdev;
+};
+
+/*
+ * A channel_dev structure represents a CM_CDEV
+ * @cdev       Character device
+ * @dev                Associated device object
+ */
+struct channel_dev {
+       struct cdev     cdev;
+       struct device   *dev;
+};
+
+static struct rio_channel *riocm_ch_alloc(u16 ch_num);
+static void riocm_ch_free(struct kref *ref);
+static int riocm_post_send(struct cm_dev *cm, struct rio_dev *rdev,
+                          void *buffer, size_t len);
+static int riocm_ch_close(struct rio_channel *ch);
+
+static DEFINE_SPINLOCK(idr_lock);
+static DEFINE_IDR(ch_idr);
+
+static LIST_HEAD(cm_dev_list);
+static DECLARE_RWSEM(rdev_sem);
+
+static struct class *dev_class;
+static unsigned int dev_major;
+static unsigned int dev_minor_base;
+static dev_t dev_number;
+static struct channel_dev riocm_cdev;
+
+#define is_msg_capable(src_ops, dst_ops)                       \
+                       ((src_ops & RIO_SRC_OPS_DATA_MSG) &&    \
+                        (dst_ops & RIO_DST_OPS_DATA_MSG))
+#define dev_cm_capable(dev) \
+       is_msg_capable(dev->src_ops, dev->dst_ops)
+
+static int riocm_cmp(struct rio_channel *ch, enum rio_cm_state cmp)
+{
+       int ret;
+
+       spin_lock_bh(&ch->lock);
+       ret = (ch->state == cmp);
+       spin_unlock_bh(&ch->lock);
+       return ret;
+}
+
+static int riocm_cmp_exch(struct rio_channel *ch,
+                          enum rio_cm_state cmp, enum rio_cm_state exch)
+{
+       int ret;
+
+       spin_lock_bh(&ch->lock);
+       ret = (ch->state == cmp);
+       if (ret)
+               ch->state = exch;
+       spin_unlock_bh(&ch->lock);
+       return ret;
+}
+
+static enum rio_cm_state riocm_exch(struct rio_channel *ch,
+                                   enum rio_cm_state exch)
+{
+       enum rio_cm_state old;
+
+       spin_lock_bh(&ch->lock);
+       old = ch->state;
+       ch->state = exch;
+       spin_unlock_bh(&ch->lock);
+       return old;
+}
+
+static struct rio_channel *riocm_get_channel(u16 nr)
+{
+       struct rio_channel *ch;
+
+       spin_lock_bh(&idr_lock);
+       ch = idr_find(&ch_idr, nr);
+       if (ch)
+               kref_get(&ch->ref);
+       spin_unlock_bh(&idr_lock);
+       return ch;
+}
+
+static void riocm_put_channel(struct rio_channel *ch)
+{
+       kref_put(&ch->ref, riocm_ch_free);
+}
+
+static void *riocm_rx_get_msg(struct cm_dev *cm)
+{
+       void *msg;
+       int i;
+
+       msg = rio_get_inb_message(cm->mport, cmbox);
+       if (msg) {
+               for (i = 0; i < RIOCM_RX_RING_SIZE; i++) {
+                       if (cm->rx_buf[i] == msg) {
+                               cm->rx_buf[i] = NULL;
+                               cm->rx_slots++;
+                               break;
+                       }
+               }
+
+               if (i == RIOCM_RX_RING_SIZE)
+                       riocm_warn("no record for buffer 0x%p", msg);
+       }
+
+       return msg;
+}
+
+/*
+ * riocm_rx_fill - fills a ring of receive buffers for given cm device
+ * @cm: cm_dev object
+ * @nent: max number of entries to fill
+ *
+ * Returns: none
+ */
+static void riocm_rx_fill(struct cm_dev *cm, int nent)
+{
+       int i;
+
+       if (cm->rx_slots == 0)
+               return;
+
+       for (i = 0; i < RIOCM_RX_RING_SIZE && cm->rx_slots && nent; i++) {
+               if (cm->rx_buf[i] == NULL) {
+                       cm->rx_buf[i] = kmalloc(RIO_MAX_MSG_SIZE, GFP_KERNEL);
+                       if (cm->rx_buf[i] == NULL)
+                               break;
+                       rio_add_inb_buffer(cm->mport, cmbox, cm->rx_buf[i]);
+                       cm->rx_slots--;
+                       nent--;
+               }
+       }
+}
+
+/*
+ * riocm_rx_free - frees all receive buffers associated with given cm device
+ * @cm: cm_dev object
+ *
+ * Returns: none
+ */
+static void riocm_rx_free(struct cm_dev *cm)
+{
+       int i;
+
+       for (i = 0; i < RIOCM_RX_RING_SIZE; i++) {
+               if (cm->rx_buf[i] != NULL) {
+                       kfree(cm->rx_buf[i]);
+                       cm->rx_buf[i] = NULL;
+               }
+       }
+}
+
+/*
+ * riocm_req_handler - connection request handler
+ * @cm: cm_dev object
+ * @req_data: pointer to the request packet
+ *
+ * Returns: 0 if success, or
+ *          -EINVAL if channel is not in correct state,
+ *          -ENODEV if cannot find a channel with specified ID,
+ *          -ENOMEM if unable to allocate memory to store the request
+ */
+static int riocm_req_handler(struct cm_dev *cm, void *req_data)
+{
+       struct rio_channel *ch;
+       struct conn_req *req;
+       struct rio_ch_chan_hdr *hh = req_data;
+       u16 chnum;
+
+       chnum = ntohs(hh->dst_ch);
+
+       ch = riocm_get_channel(chnum);
+
+       if (!ch)
+               return -ENODEV;
+
+       if (ch->state != RIO_CM_LISTEN) {
+               riocm_debug(RX_CMD, "channel %d is not in listen state", chnum);
+               riocm_put_channel(ch);
+               return -EINVAL;
+       }
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req) {
+               riocm_put_channel(ch);
+               return -ENOMEM;
+       }
+
+       req->destid = ntohl(hh->bhdr.src_id);
+       req->chan = ntohs(hh->src_ch);
+       req->cmdev = cm;
+
+       spin_lock_bh(&ch->lock);
+       list_add_tail(&req->node, &ch->accept_queue);
+       spin_unlock_bh(&ch->lock);
+       complete(&ch->comp);
+       riocm_put_channel(ch);
+
+       return 0;
+}
+
+/*
+ * riocm_resp_handler - response to connection request handler
+ * @resp_data: pointer to the response packet
+ *
+ * Returns: 0 if success, or
+ *          -EINVAL if channel is not in correct state,
+ *          -ENODEV if cannot find a channel with specified ID,
+ */
+static int riocm_resp_handler(void *resp_data)
+{
+       struct rio_channel *ch;
+       struct rio_ch_chan_hdr *hh = resp_data;
+       u16 chnum;
+
+       chnum = ntohs(hh->dst_ch);
+       ch = riocm_get_channel(chnum);
+       if (!ch)
+               return -ENODEV;
+
+       if (ch->state != RIO_CM_CONNECT) {
+               riocm_put_channel(ch);
+               return -EINVAL;
+       }
+
+       riocm_exch(ch, RIO_CM_CONNECTED);
+       ch->rem_channel = ntohs(hh->src_ch);
+       complete(&ch->comp);
+       riocm_put_channel(ch);
+
+       return 0;
+}
+
+/*
+ * riocm_close_handler - channel close request handler
+ * @req_data: pointer to the request packet
+ *
+ * Returns: 0 if success, or
+ *          -ENODEV if cannot find a channel with specified ID,
+ *            + error codes returned by riocm_ch_close.
+ */
+static int riocm_close_handler(void *data)
+{
+       struct rio_channel *ch;
+       struct rio_ch_chan_hdr *hh = data;
+       int ret;
+
+       riocm_debug(RX_CMD, "for ch=%d", ntohs(hh->dst_ch));
+
+       spin_lock_bh(&idr_lock);
+       ch = idr_find(&ch_idr, ntohs(hh->dst_ch));
+       if (!ch) {
+               spin_unlock_bh(&idr_lock);
+               return -ENODEV;
+       }
+       idr_remove(&ch_idr, ch->id);
+       spin_unlock_bh(&idr_lock);
+
+       riocm_exch(ch, RIO_CM_DISCONNECT);
+
+       ret = riocm_ch_close(ch);
+       if (ret)
+               riocm_debug(RX_CMD, "riocm_ch_close() returned %d", ret);
+
+       return 0;
+}
+
+/*
+ * rio_cm_handler - function that services request (non-data) packets
+ * @cm: cm_dev object
+ * @data: pointer to the packet
+ */
+static void rio_cm_handler(struct cm_dev *cm, void *data)
+{
+       struct rio_ch_chan_hdr *hdr;
+
+       if (!rio_mport_is_running(cm->mport))
+               goto out;
+
+       hdr = data;
+
+       riocm_debug(RX_CMD, "OP=%x for ch=%d from %d",
+                   hdr->ch_op, ntohs(hdr->dst_ch), ntohs(hdr->src_ch));
+
+       switch (hdr->ch_op) {
+       case CM_CONN_REQ:
+               riocm_req_handler(cm, data);
+               break;
+       case CM_CONN_ACK:
+               riocm_resp_handler(data);
+               break;
+       case CM_CONN_CLOSE:
+               riocm_close_handler(data);
+               break;
+       default:
+               riocm_error("Invalid packet header");
+               break;
+       }
+out:
+       kfree(data);
+}
+
+/*
+ * rio_rx_data_handler - received data packet handler
+ * @cm: cm_dev object
+ * @buf: data packet
+ *
+ * Returns: 0 if success, or
+ *          -ENODEV if cannot find a channel with specified ID,
+ *          -EIO if channel is not in CONNECTED state,
+ *          -ENOMEM if channel RX queue is full (packet discarded)
+ */
+static int rio_rx_data_handler(struct cm_dev *cm, void *buf)
+{
+       struct rio_ch_chan_hdr *hdr;
+       struct rio_channel *ch;
+
+       hdr = buf;
+
+       riocm_debug(RX_DATA, "for ch=%d", ntohs(hdr->dst_ch));
+
+       ch = riocm_get_channel(ntohs(hdr->dst_ch));
+       if (!ch) {
+               /* Discard data message for non-existing channel */
+               kfree(buf);
+               return -ENODEV;
+       }
+
+       /* Place pointer to the buffer into channel's RX queue */
+       spin_lock(&ch->lock);
+
+       if (ch->state != RIO_CM_CONNECTED) {
+               /* Channel is not ready to receive data, discard a packet */
+               riocm_debug(RX_DATA, "ch=%d is in wrong state=%d",
+                           ch->id, ch->state);
+               spin_unlock(&ch->lock);
+               kfree(buf);
+               riocm_put_channel(ch);
+               return -EIO;
+       }
+
+       if (ch->rx_ring.count == RIOCM_RX_RING_SIZE) {
+               /* If RX ring is full, discard a packet */
+               riocm_debug(RX_DATA, "ch=%d is full", ch->id);
+               spin_unlock(&ch->lock);
+               kfree(buf);
+               riocm_put_channel(ch);
+               return -ENOMEM;
+       }
+
+       ch->rx_ring.buf[ch->rx_ring.head] = buf;
+       ch->rx_ring.head++;
+       ch->rx_ring.count++;
+       ch->rx_ring.head %= RIOCM_RX_RING_SIZE;
+
+       complete(&ch->comp);
+
+       spin_unlock(&ch->lock);
+       riocm_put_channel(ch);
+
+       return 0;
+}
+
+/*
+ * rio_ibmsg_handler - inbound message packet handler
+ */
+static void rio_ibmsg_handler(struct work_struct *work)
+{
+       struct cm_dev *cm = container_of(work, struct cm_dev, rx_work);
+       void *data;
+       struct rio_ch_chan_hdr *hdr;
+
+       if (!rio_mport_is_running(cm->mport))
+               return;
+
+       while (1) {
+               mutex_lock(&cm->rx_lock);
+               data = riocm_rx_get_msg(cm);
+               if (data)
+                       riocm_rx_fill(cm, 1);
+               mutex_unlock(&cm->rx_lock);
+
+               if (data == NULL)
+                       break;
+
+               hdr = data;
+
+               if (hdr->bhdr.type != RIO_CM_CHAN) {
+                       /* For now simply discard packets other than channel */
+                       riocm_error("Unsupported TYPE code (0x%x). Msg dropped",
+                                   hdr->bhdr.type);
+                       kfree(data);
+                       continue;
+               }
+
+               /* Process a channel message */
+               if (hdr->ch_op == CM_DATA_MSG)
+                       rio_rx_data_handler(cm, data);
+               else
+                       rio_cm_handler(cm, data);
+       }
+}
+
+static void riocm_inb_msg_event(struct rio_mport *mport, void *dev_id,
+                               int mbox, int slot)
+{
+       struct cm_dev *cm = dev_id;
+
+       if (rio_mport_is_running(cm->mport) && !work_pending(&cm->rx_work))
+               queue_work(cm->rx_wq, &cm->rx_work);
+}
+
+/*
+ * rio_txcq_handler - TX completion handler
+ * @cm: cm_dev object
+ * @slot: TX queue slot
+ *
+ * TX completion handler also ensures that pending request packets are placed
+ * into transmit queue as soon as a free slot becomes available. This is done
+ * to give higher priority to request packets during high intensity data flow.
+ */
+static void rio_txcq_handler(struct cm_dev *cm, int slot)
+{
+       int ack_slot;
+
+       /* ATTN: Add TX completion notification if/when direct buffer
+        * transfer is implemented. At this moment only correct tracking
+        * of tx_count is important.
+        */
+       riocm_debug(TX_EVENT, "for mport_%d slot %d tx_cnt %d",
+                   cm->mport->id, slot, cm->tx_cnt);
+
+       spin_lock(&cm->tx_lock);
+       ack_slot = cm->tx_ack_slot;
+
+       if (ack_slot == slot)
+               riocm_debug(TX_EVENT, "slot == ack_slot");
+
+       while (cm->tx_cnt && ((ack_slot != slot) ||
+              (cm->tx_cnt == RIOCM_TX_RING_SIZE))) {
+
+               cm->tx_buf[ack_slot] = NULL;
+               ++ack_slot;
+               ack_slot &= (RIOCM_TX_RING_SIZE - 1);
+               cm->tx_cnt--;
+       }
+
+       if (cm->tx_cnt < 0 || cm->tx_cnt > RIOCM_TX_RING_SIZE)
+               riocm_error("tx_cnt %d out of sync", cm->tx_cnt);
+
+       WARN_ON((cm->tx_cnt < 0) || (cm->tx_cnt > RIOCM_TX_RING_SIZE));
+
+       cm->tx_ack_slot = ack_slot;
+
+       /*
+        * If there are pending requests, insert them into transmit queue
+        */
+       if (!list_empty(&cm->tx_reqs) && (cm->tx_cnt < RIOCM_TX_RING_SIZE)) {
+               struct tx_req *req, *_req;
+               int rc;
+
+               list_for_each_entry_safe(req, _req, &cm->tx_reqs, node) {
+                       list_del(&req->node);
+                       cm->tx_buf[cm->tx_slot] = req->buffer;
+                       rc = rio_add_outb_message(cm->mport, req->rdev, cmbox,
+                                                 req->buffer, req->len);
+                       kfree(req->buffer);
+                       kfree(req);
+
+                       ++cm->tx_cnt;
+                       ++cm->tx_slot;
+                       cm->tx_slot &= (RIOCM_TX_RING_SIZE - 1);
+                       if (cm->tx_cnt == RIOCM_TX_RING_SIZE)
+                               break;
+               }
+       }
+
+       spin_unlock(&cm->tx_lock);
+}
+
+static void riocm_outb_msg_event(struct rio_mport *mport, void *dev_id,
+                                int mbox, int slot)
+{
+       struct cm_dev *cm = dev_id;
+
+       if (cm && rio_mport_is_running(cm->mport))
+               rio_txcq_handler(cm, slot);
+}
+
+static int riocm_queue_req(struct cm_dev *cm, struct rio_dev *rdev,
+                          void *buffer, size_t len)
+{
+       unsigned long flags;
+       struct tx_req *treq;
+
+       treq = kzalloc(sizeof(*treq), GFP_KERNEL);
+       if (treq == NULL)
+               return -ENOMEM;
+
+       treq->rdev = rdev;
+       treq->buffer = buffer;
+       treq->len = len;
+
+       spin_lock_irqsave(&cm->tx_lock, flags);
+       list_add_tail(&treq->node, &cm->tx_reqs);
+       spin_unlock_irqrestore(&cm->tx_lock, flags);
+       return 0;
+}
+
+/*
+ * riocm_post_send - helper function that places packet into msg TX queue
+ * @cm: cm_dev object
+ * @rdev: target RapidIO device object (required by outbound msg interface)
+ * @buffer: pointer to a packet buffer to send
+ * @len: length of data to transfer
+ * @req: request priority flag
+ *
+ * Returns: 0 if success, or error code otherwise.
+ */
+static int riocm_post_send(struct cm_dev *cm, struct rio_dev *rdev,
+                          void *buffer, size_t len)
+{
+       int rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cm->tx_lock, flags);
+
+       if (cm->mport == NULL) {
+               rc = -ENODEV;
+               goto err_out;
+       }
+
+       if (cm->tx_cnt == RIOCM_TX_RING_SIZE) {
+               riocm_debug(TX, "Tx Queue is full");
+               rc = -EBUSY;
+               goto err_out;
+       }
+
+       cm->tx_buf[cm->tx_slot] = buffer;
+       rc = rio_add_outb_message(cm->mport, rdev, cmbox, buffer, len);
+
+       riocm_debug(TX, "Add buf@%p destid=%x tx_slot=%d tx_cnt=%d",
+                buffer, rdev->destid, cm->tx_slot, cm->tx_cnt);
+
+       ++cm->tx_cnt;
+       ++cm->tx_slot;
+       cm->tx_slot &= (RIOCM_TX_RING_SIZE - 1);
+
+err_out:
+       spin_unlock_irqrestore(&cm->tx_lock, flags);
+       return rc;
+}
+
+/*
+ * riocm_ch_send - sends a data packet to a remote device
+ * @ch_id: local channel ID
+ * @buf: pointer to a data buffer to send (including CM header)
+ * @len: length of data to transfer (including CM header)
+ *
+ * ATTN: ASSUMES THAT THE HEADER SPACE IS RESERVED PART OF THE DATA PACKET
+ *
+ * Returns: 0 if success, or
+ *          -EINVAL if one or more input parameters is/are not valid,
+ *          -ENODEV if cannot find a channel with specified ID,
+ *          -EAGAIN if a channel is not in CONNECTED state,
+ *         + error codes returned by HW send routine.
+ */
+static int riocm_ch_send(u16 ch_id, void *buf, int len)
+{
+       struct rio_channel *ch;
+       struct rio_ch_chan_hdr *hdr;
+       int ret;
+
+       if (buf == NULL || ch_id == 0 || len == 0 || len > RIO_MAX_MSG_SIZE)
+               return -EINVAL;
+
+       ch = riocm_get_channel(ch_id);
+       if (!ch) {
+               riocm_error("%s(%d) ch_%d not found", current->comm,
+                           task_pid_nr(current), ch_id);
+               return -ENODEV;
+       }
+
+       if (!riocm_cmp(ch, RIO_CM_CONNECTED)) {
+               ret = -EAGAIN;
+               goto err_out;
+       }
+
+       /*
+        * Fill buffer header section with corresponding channel data
+        */
+       hdr = buf;
+
+       hdr->bhdr.src_id = htonl(ch->loc_destid);
+       hdr->bhdr.dst_id = htonl(ch->rem_destid);
+       hdr->bhdr.src_mbox = cmbox;
+       hdr->bhdr.dst_mbox = cmbox;
+       hdr->bhdr.type = RIO_CM_CHAN;
+       hdr->ch_op = CM_DATA_MSG;
+       hdr->dst_ch = htons(ch->rem_channel);
+       hdr->src_ch = htons(ch->id);
+       hdr->msg_len = htons((u16)len);
+
+       /* ATTN: the function call below relies on the fact that underlying
+        * HW-specific add_outb_message() routine copies TX data into its own
+        * internal transfer buffer (true for all RIONET compatible mport
+        * drivers). Must be reviewed if mport driver uses the buffer directly.
+        */
+
+       ret = riocm_post_send(ch->cmdev, ch->rdev, buf, len);
+       if (ret)
+               riocm_debug(TX, "ch %d send_err=%d", ch->id, ret);
+err_out:
+       riocm_put_channel(ch);
+       return ret;
+}
+
+static int riocm_ch_free_rxbuf(struct rio_channel *ch, void *buf)
+{
+       int i, ret = -EINVAL;
+
+       spin_lock_bh(&ch->lock);
+
+       for (i = 0; i < RIOCM_RX_RING_SIZE; i++) {
+               if (ch->rx_ring.inuse[i] == buf) {
+                       ch->rx_ring.inuse[i] = NULL;
+                       ch->rx_ring.inuse_cnt--;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       spin_unlock_bh(&ch->lock);
+
+       if (!ret)
+               kfree(buf);
+
+       return ret;
+}
+
+/*
+ * riocm_ch_receive - fetch a data packet received for the specified channel
+ * @ch: local channel ID
+ * @buf: pointer to a packet buffer
+ * @timeout: timeout to wait for incoming packet (in jiffies)
+ *
+ * Returns: 0 and valid buffer pointer if success, or NULL pointer and one of:
+ *          -EAGAIN if a channel is not in CONNECTED state,
+ *          -ENOMEM if in-use tracking queue is full,
+ *          -ETIME if wait timeout expired,
+ *         -EINTR if wait was interrupted.
+ */
+static int riocm_ch_receive(struct rio_channel *ch, void **buf, long timeout)
+{
+       void *rxmsg = NULL;
+       int i, ret = 0;
+       long wret;
+
+       if (!riocm_cmp(ch, RIO_CM_CONNECTED)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       if (ch->rx_ring.inuse_cnt == RIOCM_RX_RING_SIZE) {
+               /* If we do not have entries to track buffers given to upper
+                * layer, reject request.
+                */
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wret = wait_for_completion_interruptible_timeout(&ch->comp, timeout);
+
+       riocm_debug(WAIT, "wait on %d returned %ld", ch->id, wret);
+
+       if (!wret)
+               ret = -ETIME;
+       else if (wret == -ERESTARTSYS)
+               ret = -EINTR;
+       else
+               ret = riocm_cmp(ch, RIO_CM_CONNECTED) ? 0 : -ECONNRESET;
+
+       if (ret)
+               goto out;
+
+       spin_lock_bh(&ch->lock);
+
+       rxmsg = ch->rx_ring.buf[ch->rx_ring.tail];
+       ch->rx_ring.buf[ch->rx_ring.tail] = NULL;
+       ch->rx_ring.count--;
+       ch->rx_ring.tail++;
+       ch->rx_ring.tail %= RIOCM_RX_RING_SIZE;
+       ret = -ENOMEM;
+
+       for (i = 0; i < RIOCM_RX_RING_SIZE; i++) {
+               if (ch->rx_ring.inuse[i] == NULL) {
+                       ch->rx_ring.inuse[i] = rxmsg;
+                       ch->rx_ring.inuse_cnt++;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret) {
+               /* We have no entry to store pending message: drop it */
+               kfree(rxmsg);
+               rxmsg = NULL;
+       }
+
+       spin_unlock_bh(&ch->lock);
+out:
+       *buf = rxmsg;
+       return ret;
+}
+
+/*
+ * riocm_ch_connect - sends a connect request to a remote device
+ * @loc_ch: local channel ID
+ * @cm: CM device to send connect request
+ * @peer: target RapidIO device
+ * @rem_ch: remote channel ID
+ *
+ * Returns: 0 if success, or
+ *          -EINVAL if the channel is not in IDLE state,
+ *          -EAGAIN if no connection request available immediately,
+ *          -ETIME if ACK response timeout expired,
+ *          -EINTR if wait for response was interrupted.
+ */
+static int riocm_ch_connect(u16 loc_ch, struct cm_dev *cm,
+                           struct cm_peer *peer, u16 rem_ch)
+{
+       struct rio_channel *ch = NULL;
+       struct rio_ch_chan_hdr *hdr;
+       int ret;
+       long wret;
+
+       ch = riocm_get_channel(loc_ch);
+       if (!ch)
+               return -ENODEV;
+
+       if (!riocm_cmp_exch(ch, RIO_CM_IDLE, RIO_CM_CONNECT)) {
+               ret = -EINVAL;
+               goto conn_done;
+       }
+
+       ch->cmdev = cm;
+       ch->rdev = peer->rdev;
+       ch->context = NULL;
+       ch->loc_destid = cm->mport->host_deviceid;
+       ch->rem_channel = rem_ch;
+
+       /*
+        * Send connect request to the remote RapidIO device
+        */
+
+       hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+       if (hdr == NULL) {
+               ret = -ENOMEM;
+               goto conn_done;
+       }
+
+       hdr->bhdr.src_id = htonl(ch->loc_destid);
+       hdr->bhdr.dst_id = htonl(peer->rdev->destid);
+       hdr->bhdr.src_mbox = cmbox;
+       hdr->bhdr.dst_mbox = cmbox;
+       hdr->bhdr.type = RIO_CM_CHAN;
+       hdr->ch_op = CM_CONN_REQ;
+       hdr->dst_ch = htons(rem_ch);
+       hdr->src_ch = htons(loc_ch);
+
+       /* ATTN: the function call below relies on the fact that underlying
+        * HW-specific add_outb_message() routine copies TX data into its
+        * internal transfer buffer. Must be reviewed if mport driver uses
+        * this buffer directly.
+        */
+       ret = riocm_post_send(cm, peer->rdev, hdr, sizeof(*hdr));
+
+       if (ret != -EBUSY) {
+               kfree(hdr);
+       } else {
+               ret = riocm_queue_req(cm, peer->rdev, hdr, sizeof(*hdr));
+               if (ret)
+                       kfree(hdr);
+       }
+
+       if (ret) {
+               riocm_cmp_exch(ch, RIO_CM_CONNECT, RIO_CM_IDLE);
+               goto conn_done;
+       }
+
+       /* Wait for connect response from the remote device */
+       wret = wait_for_completion_interruptible_timeout(&ch->comp,
+                                                        RIOCM_CONNECT_TO * HZ);
+       riocm_debug(WAIT, "wait on %d returns %ld", ch->id, wret);
+
+       if (!wret)
+               ret = -ETIME;
+       else if (wret == -ERESTARTSYS)
+               ret = -EINTR;
+       else
+               ret = riocm_cmp(ch, RIO_CM_CONNECTED) ? 0 : -1;
+
+conn_done:
+       riocm_put_channel(ch);
+       return ret;
+}
+
+static int riocm_send_ack(struct rio_channel *ch)
+{
+       struct rio_ch_chan_hdr *hdr;
+       int ret;
+
+       hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+       if (hdr == NULL)
+               return -ENOMEM;
+
+       hdr->bhdr.src_id = htonl(ch->loc_destid);
+       hdr->bhdr.dst_id = htonl(ch->rem_destid);
+       hdr->dst_ch = htons(ch->rem_channel);
+       hdr->src_ch = htons(ch->id);
+       hdr->bhdr.src_mbox = cmbox;
+       hdr->bhdr.dst_mbox = cmbox;
+       hdr->bhdr.type = RIO_CM_CHAN;
+       hdr->ch_op = CM_CONN_ACK;
+
+       /* ATTN: the function call below relies on the fact that underlying
+        * add_outb_message() routine copies TX data into its internal transfer
+        * buffer. Review if switching to direct buffer version.
+        */
+       ret = riocm_post_send(ch->cmdev, ch->rdev, hdr, sizeof(*hdr));
+
+       if (ret == -EBUSY && !riocm_queue_req(ch->cmdev,
+                                             ch->rdev, hdr, sizeof(*hdr)))
+               return 0;
+       kfree(hdr);
+
+       if (ret)
+               riocm_error("send ACK to ch_%d on %s failed (ret=%d)",
+                           ch->id, rio_name(ch->rdev), ret);
+       return ret;
+}
+
+/*
+ * riocm_ch_accept - accept incoming connection request
+ * @ch_id: channel ID
+ * @new_ch_id: local mport device
+ * @timeout: wait timeout (if 0 non-blocking call, do not wait if connection
+ *           request is not available).
+ *
+ * Returns: pointer to new channel struct if success, or error-valued pointer:
+ *          -ENODEV - cannot find specified channel or mport,
+ *          -EINVAL - the channel is not in IDLE state,
+ *          -EAGAIN - no connection request available immediately (timeout=0),
+ *          -ENOMEM - unable to allocate new channel,
+ *          -ETIME - wait timeout expired,
+ *          -EINTR - wait was interrupted.
+ */
+static struct rio_channel *riocm_ch_accept(u16 ch_id, u16 *new_ch_id,
+                                          long timeout)
+{
+       struct rio_channel *ch;
+       struct rio_channel *new_ch;
+       struct conn_req *req;
+       struct cm_peer *peer;
+       int found = 0;
+       int err = 0;
+       long wret;
+
+       ch = riocm_get_channel(ch_id);
+       if (!ch)
+               return ERR_PTR(-EINVAL);
+
+       if (!riocm_cmp(ch, RIO_CM_LISTEN)) {
+               err = -EINVAL;
+               goto err_put;
+       }
+
+       /* Don't sleep if this is a non blocking call */
+       if (!timeout) {
+               if (!try_wait_for_completion(&ch->comp)) {
+                       err = -EAGAIN;
+                       goto err_put;
+               }
+       } else {
+               riocm_debug(WAIT, "on %d", ch->id);
+
+               wret = wait_for_completion_interruptible_timeout(&ch->comp,
+                                                                timeout);
+               if (!wret) {
+                       err = -ETIME;
+                       goto err_put;
+               } else if (wret == -ERESTARTSYS) {
+                       err = -EINTR;
+                       goto err_put;
+               }
+       }
+
+       spin_lock_bh(&ch->lock);
+
+       if (ch->state != RIO_CM_LISTEN) {
+               err = -ECANCELED;
+       } else if (list_empty(&ch->accept_queue)) {
+               riocm_debug(WAIT, "on %d accept_queue is empty on completion",
+                           ch->id);
+               err = -EIO;
+       }
+
+       spin_unlock_bh(&ch->lock);
+
+       if (err) {
+               riocm_debug(WAIT, "on %d returns %d", ch->id, err);
+               goto err_put;
+       }
+
+       /* Create new channel for this connection */
+       new_ch = riocm_ch_alloc(RIOCM_CHNUM_AUTO);
+
+       if (IS_ERR(new_ch)) {
+               riocm_error("failed to get channel for new req (%ld)",
+                       PTR_ERR(new_ch));
+               err = -ENOMEM;
+               goto err_put;
+       }
+
+       spin_lock_bh(&ch->lock);
+
+       req = list_first_entry(&ch->accept_queue, struct conn_req, node);
+       list_del(&req->node);
+       new_ch->cmdev = ch->cmdev;
+       new_ch->loc_destid = ch->loc_destid;
+       new_ch->rem_destid = req->destid;
+       new_ch->rem_channel = req->chan;
+
+       spin_unlock_bh(&ch->lock);
+       riocm_put_channel(ch);
+       ch = NULL;
+       kfree(req);
+
+       down_read(&rdev_sem);
+       /* Find requester's device object */
+       list_for_each_entry(peer, &new_ch->cmdev->peers, node) {
+               if (peer->rdev->destid == new_ch->rem_destid) {
+                       riocm_debug(RX_CMD, "found matching device(%s)",
+                                   rio_name(peer->rdev));
+                       found = 1;
+                       break;
+               }
+       }
+       up_read(&rdev_sem);
+
+       if (!found) {
+               /* If peer device object not found, simply ignore the request */
+               err = -ENODEV;
+               goto err_put_new_ch;
+       }
+
+       new_ch->rdev = peer->rdev;
+       new_ch->state = RIO_CM_CONNECTED;
+       spin_lock_init(&new_ch->lock);
+
+       /* Acknowledge the connection request. */
+       riocm_send_ack(new_ch);
+
+       *new_ch_id = new_ch->id;
+       return new_ch;
+
+err_put_new_ch:
+       spin_lock_bh(&idr_lock);
+       idr_remove(&ch_idr, new_ch->id);
+       spin_unlock_bh(&idr_lock);
+       riocm_put_channel(new_ch);
+
+err_put:
+       if (ch)
+               riocm_put_channel(ch);
+       *new_ch_id = 0;
+       return ERR_PTR(err);
+}
+
+/*
+ * riocm_ch_listen - puts a channel into LISTEN state
+ * @ch_id: channel ID
+ *
+ * Returns: 0 if success, or
+ *          -EINVAL if the specified channel does not exists or
+ *                  is not in CHAN_BOUND state.
+ */
+static int riocm_ch_listen(u16 ch_id)
+{
+       struct rio_channel *ch = NULL;
+       int ret = 0;
+
+       riocm_debug(CHOP, "(ch_%d)", ch_id);
+
+       ch = riocm_get_channel(ch_id);
+       if (!ch || !riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN))
+               ret = -EINVAL;
+       riocm_put_channel(ch);
+       return ret;
+}
+
+/*
+ * riocm_ch_bind - associate a channel object and an mport device
+ * @ch_id: channel ID
+ * @mport_id: local mport device ID
+ * @context: pointer to the additional caller's context
+ *
+ * Returns: 0 if success, or
+ *          -ENODEV if cannot find specified mport,
+ *          -EINVAL if the specified channel does not exist or
+ *                  is not in IDLE state.
+ */
+static int riocm_ch_bind(u16 ch_id, u8 mport_id, void *context)
+{
+       struct rio_channel *ch = NULL;
+       struct cm_dev *cm;
+       int rc = -ENODEV;
+
+       riocm_debug(CHOP, "ch_%d to mport_%d", ch_id, mport_id);
+
+       /* Find matching cm_dev object */
+       down_read(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if ((cm->mport->id == mport_id) &&
+                    rio_mport_is_running(cm->mport)) {
+                       rc = 0;
+                       break;
+               }
+       }
+
+       if (rc)
+               goto exit;
+
+       ch = riocm_get_channel(ch_id);
+       if (!ch) {
+               rc = -EINVAL;
+               goto exit;
+       }
+
+       spin_lock_bh(&ch->lock);
+       if (ch->state != RIO_CM_IDLE) {
+               spin_unlock_bh(&ch->lock);
+               rc = -EINVAL;
+               goto err_put;
+       }
+
+       ch->cmdev = cm;
+       ch->loc_destid = cm->mport->host_deviceid;
+       ch->context = context;
+       ch->state = RIO_CM_CHAN_BOUND;
+       spin_unlock_bh(&ch->lock);
+err_put:
+       riocm_put_channel(ch);
+exit:
+       up_read(&rdev_sem);
+       return rc;
+}
+
+/*
+ * riocm_ch_alloc - channel object allocation helper routine
+ * @ch_num: channel ID (1 ... RIOCM_MAX_CHNUM, 0 = automatic)
+ *
+ * Return value: pointer to newly created channel object,
+ *               or error-valued pointer
+ */
+static struct rio_channel *riocm_ch_alloc(u16 ch_num)
+{
+       int id;
+       int start, end;
+       struct rio_channel *ch;
+
+       ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+       if (!ch)
+               return ERR_PTR(-ENOMEM);
+
+       if (ch_num) {
+               /* If requested, try to obtain the specified channel ID */
+               start = ch_num;
+               end = ch_num + 1;
+       } else {
+               /* Obtain channel ID from the dynamic allocation range */
+               start = chstart;
+               end = RIOCM_MAX_CHNUM + 1;
+       }
+
+       idr_preload(GFP_KERNEL);
+       spin_lock_bh(&idr_lock);
+       id = idr_alloc_cyclic(&ch_idr, ch, start, end, GFP_NOWAIT);
+       spin_unlock_bh(&idr_lock);
+       idr_preload_end();
+
+       if (id < 0) {
+               kfree(ch);
+               return ERR_PTR(id == -ENOSPC ? -EBUSY : id);
+       }
+
+       ch->id = (u16)id;
+       ch->state = RIO_CM_IDLE;
+       spin_lock_init(&ch->lock);
+       INIT_LIST_HEAD(&ch->accept_queue);
+       INIT_LIST_HEAD(&ch->ch_node);
+       init_completion(&ch->comp);
+       init_completion(&ch->comp_close);
+       kref_init(&ch->ref);
+       ch->rx_ring.head = 0;
+       ch->rx_ring.tail = 0;
+       ch->rx_ring.count = 0;
+       ch->rx_ring.inuse_cnt = 0;
+
+       return ch;
+}
+
+/*
+ * riocm_ch_create - creates a new channel object and allocates ID for it
+ * @ch_num: channel ID (1 ... RIOCM_MAX_CHNUM, 0 = automatic)
+ *
+ * Allocates and initializes a new channel object. If the parameter ch_num > 0
+ * and is within the valid range, riocm_ch_create tries to allocate the
+ * specified ID for the new channel. If ch_num = 0, channel ID will be assigned
+ * automatically from the range (chstart ... RIOCM_MAX_CHNUM).
+ * Module parameter 'chstart' defines start of an ID range available for dynamic
+ * allocation. Range below 'chstart' is reserved for pre-defined ID numbers.
+ * Available channel numbers are limited by 16-bit size of channel numbers used
+ * in the packet header.
+ *
+ * Return value: PTR to rio_channel structure if successful (with channel number
+ *               updated via pointer) or error-valued pointer if error.
+ */
+static struct rio_channel *riocm_ch_create(u16 *ch_num)
+{
+       struct rio_channel *ch = NULL;
+
+       ch = riocm_ch_alloc(*ch_num);
+
+       if (IS_ERR(ch))
+               riocm_debug(CHOP, "Failed to allocate channel %d (err=%ld)",
+                           *ch_num, PTR_ERR(ch));
+       else
+               *ch_num = ch->id;
+
+       return ch;
+}
+
+/*
+ * riocm_ch_free - channel object release routine
+ * @ref: pointer to a channel's kref structure
+ */
+static void riocm_ch_free(struct kref *ref)
+{
+       struct rio_channel *ch = container_of(ref, struct rio_channel, ref);
+       int i;
+
+       riocm_debug(CHOP, "(ch_%d)", ch->id);
+
+       if (ch->rx_ring.inuse_cnt) {
+               for (i = 0;
+                    i < RIOCM_RX_RING_SIZE && ch->rx_ring.inuse_cnt; i++) {
+                       if (ch->rx_ring.inuse[i] != NULL) {
+                               kfree(ch->rx_ring.inuse[i]);
+                               ch->rx_ring.inuse_cnt--;
+                       }
+               }
+       }
+
+       if (ch->rx_ring.count)
+               for (i = 0; i < RIOCM_RX_RING_SIZE && ch->rx_ring.count; i++) {
+                       if (ch->rx_ring.buf[i] != NULL) {
+                               kfree(ch->rx_ring.buf[i]);
+                               ch->rx_ring.count--;
+                       }
+               }
+
+       complete(&ch->comp_close);
+}
+
+static int riocm_send_close(struct rio_channel *ch)
+{
+       struct rio_ch_chan_hdr *hdr;
+       int ret;
+
+       /*
+        * Send CH_CLOSE notification to the remote RapidIO device
+        */
+
+       hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+       if (hdr == NULL)
+               return -ENOMEM;
+
+       hdr->bhdr.src_id = htonl(ch->loc_destid);
+       hdr->bhdr.dst_id = htonl(ch->rem_destid);
+       hdr->bhdr.src_mbox = cmbox;
+       hdr->bhdr.dst_mbox = cmbox;
+       hdr->bhdr.type = RIO_CM_CHAN;
+       hdr->ch_op = CM_CONN_CLOSE;
+       hdr->dst_ch = htons(ch->rem_channel);
+       hdr->src_ch = htons(ch->id);
+
+       /* ATTN: the function call below relies on the fact that underlying
+        * add_outb_message() routine copies TX data into its internal transfer
+        * buffer. Needs to be reviewed if switched to direct buffer mode.
+        */
+       ret = riocm_post_send(ch->cmdev, ch->rdev, hdr, sizeof(*hdr));
+
+       if (ret == -EBUSY && !riocm_queue_req(ch->cmdev, ch->rdev,
+                                             hdr, sizeof(*hdr)))
+               return 0;
+       kfree(hdr);
+
+       if (ret)
+               riocm_error("ch(%d) send CLOSE failed (ret=%d)", ch->id, ret);
+
+       return ret;
+}
+
+/*
+ * riocm_ch_close - closes a channel object with specified ID (by local request)
+ * @ch: channel to be closed
+ */
+static int riocm_ch_close(struct rio_channel *ch)
+{
+       unsigned long tmo = msecs_to_jiffies(3000);
+       enum rio_cm_state state;
+       long wret;
+       int ret = 0;
+
+       riocm_debug(CHOP, "ch_%d by %s(%d)",
+                   ch->id, current->comm, task_pid_nr(current));
+
+       state = riocm_exch(ch, RIO_CM_DESTROYING);
+       if (state == RIO_CM_CONNECTED)
+               riocm_send_close(ch);
+
+       complete_all(&ch->comp);
+
+       riocm_put_channel(ch);
+       wret = wait_for_completion_interruptible_timeout(&ch->comp_close, tmo);
+
+       riocm_debug(WAIT, "wait on %d returns %ld", ch->id, wret);
+
+       if (wret == 0) {
+               /* Timeout on wait occurred */
+               riocm_debug(CHOP, "%s(%d) timed out waiting for ch %d",
+                      current->comm, task_pid_nr(current), ch->id);
+               ret = -ETIMEDOUT;
+       } else if (wret == -ERESTARTSYS) {
+               /* Wait_for_completion was interrupted by a signal */
+               riocm_debug(CHOP, "%s(%d) wait for ch %d was interrupted",
+                       current->comm, task_pid_nr(current), ch->id);
+               ret = -EINTR;
+       }
+
+       if (!ret) {
+               riocm_debug(CHOP, "ch_%d resources released", ch->id);
+               kfree(ch);
+       } else {
+               riocm_debug(CHOP, "failed to release ch_%d resources", ch->id);
+       }
+
+       return ret;
+}
+
+/*
+ * riocm_cdev_open() - Open character device
+ */
+static int riocm_cdev_open(struct inode *inode, struct file *filp)
+{
+       riocm_debug(INIT, "by %s(%d) filp=%p ",
+                   current->comm, task_pid_nr(current), filp);
+
+       if (list_empty(&cm_dev_list))
+               return -ENODEV;
+
+       return 0;
+}
+
+/*
+ * riocm_cdev_release() - Release character device
+ */
+static int riocm_cdev_release(struct inode *inode, struct file *filp)
+{
+       struct rio_channel *ch, *_c;
+       unsigned int i;
+       LIST_HEAD(list);
+
+       riocm_debug(EXIT, "by %s(%d) filp=%p",
+                   current->comm, task_pid_nr(current), filp);
+
+       /* Check if there are channels associated with this file descriptor */
+       spin_lock_bh(&idr_lock);
+       idr_for_each_entry(&ch_idr, ch, i) {
+               if (ch && ch->filp == filp) {
+                       riocm_debug(EXIT, "ch_%d not released by %s(%d)",
+                                   ch->id, current->comm,
+                                   task_pid_nr(current));
+                       idr_remove(&ch_idr, ch->id);
+                       list_add(&ch->ch_node, &list);
+               }
+       }
+       spin_unlock_bh(&idr_lock);
+
+       if (!list_empty(&list)) {
+               list_for_each_entry_safe(ch, _c, &list, ch_node) {
+                       list_del(&ch->ch_node);
+                       riocm_ch_close(ch);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * cm_ep_get_list_size() - Reports number of endpoints in the network
+ */
+static int cm_ep_get_list_size(void __user *arg)
+{
+       u32 __user *p = arg;
+       u32 mport_id;
+       u32 count = 0;
+       struct cm_dev *cm;
+
+       if (get_user(mport_id, p))
+               return -EFAULT;
+       if (mport_id >= RIO_MAX_MPORTS)
+               return -EINVAL;
+
+       /* Find a matching cm_dev object */
+       down_read(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (cm->mport->id == mport_id) {
+                       count = cm->npeers;
+                       up_read(&rdev_sem);
+                       if (copy_to_user(arg, &count, sizeof(u32)))
+                               return -EFAULT;
+                       return 0;
+               }
+       }
+       up_read(&rdev_sem);
+
+       return -ENODEV;
+}
+
+/*
+ * cm_ep_get_list() - Returns list of attached endpoints
+ */
+static int cm_ep_get_list(void __user *arg)
+{
+       struct cm_dev *cm;
+       struct cm_peer *peer;
+       u32 info[2];
+       void *buf;
+       u32 nent;
+       u32 *entry_ptr;
+       u32 i = 0;
+       int ret = 0;
+
+       if (copy_from_user(&info, arg, sizeof(info)))
+               return -EFAULT;
+
+       if (info[1] >= RIO_MAX_MPORTS || info[0] > RIOCM_MAX_EP_COUNT)
+               return -EINVAL;
+
+       /* Find a matching cm_dev object */
+       down_read(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list)
+               if (cm->mport->id == (u8)info[1])
+                       goto found;
+
+       up_read(&rdev_sem);
+       return -ENODEV;
+
+found:
+       nent = min(info[0], cm->npeers);
+       buf = kcalloc(nent + 2, sizeof(u32), GFP_KERNEL);
+       if (!buf) {
+               up_read(&rdev_sem);
+               return -ENOMEM;
+       }
+
+       entry_ptr = (u32 *)((uintptr_t)buf + 2*sizeof(u32));
+
+       list_for_each_entry(peer, &cm->peers, node) {
+               *entry_ptr = (u32)peer->rdev->destid;
+               entry_ptr++;
+               if (++i == nent)
+                       break;
+       }
+       up_read(&rdev_sem);
+
+       ((u32 *)buf)[0] = i; /* report an updated number of entries */
+       ((u32 *)buf)[1] = info[1]; /* put back an mport ID */
+       if (copy_to_user(arg, buf, sizeof(u32) * (info[0] + 2)))
+               ret = -EFAULT;
+
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * cm_mport_get_list() - Returns list of available local mport devices
+ */
+static int cm_mport_get_list(void __user *arg)
+{
+       int ret = 0;
+       u32 entries;
+       void *buf;
+       struct cm_dev *cm;
+       u32 *entry_ptr;
+       int count = 0;
+
+       if (copy_from_user(&entries, arg, sizeof(entries)))
+               return -EFAULT;
+       if (entries == 0 || entries > RIO_MAX_MPORTS)
+               return -EINVAL;
+       buf = kcalloc(entries + 1, sizeof(u32), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       /* Scan all registered cm_dev objects */
+       entry_ptr = (u32 *)((uintptr_t)buf + sizeof(u32));
+       down_read(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (count++ < entries) {
+                       *entry_ptr = (cm->mport->id << 16) |
+                                     cm->mport->host_deviceid;
+                       entry_ptr++;
+               }
+       }
+       up_read(&rdev_sem);
+
+       *((u32 *)buf) = count; /* report a real number of entries */
+       if (copy_to_user(arg, buf, sizeof(u32) * (count + 1)))
+               ret = -EFAULT;
+
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * cm_chan_create() - Create a message exchange channel
+ */
+static int cm_chan_create(struct file *filp, void __user *arg)
+{
+       u16 __user *p = arg;
+       u16 ch_num;
+       struct rio_channel *ch;
+
+       if (get_user(ch_num, p))
+               return -EFAULT;
+
+       riocm_debug(CHOP, "ch_%d requested by %s(%d)",
+                   ch_num, current->comm, task_pid_nr(current));
+       ch = riocm_ch_create(&ch_num);
+       if (IS_ERR(ch))
+               return PTR_ERR(ch);
+
+       ch->filp = filp;
+       riocm_debug(CHOP, "ch_%d created by %s(%d)",
+                   ch_num, current->comm, task_pid_nr(current));
+       return put_user(ch_num, p);
+}
+
+/*
+ * cm_chan_close() - Close channel
+ * @filp:      Pointer to file object
+ * @arg:       Channel to close
+ */
+static int cm_chan_close(struct file *filp, void __user *arg)
+{
+       u16 __user *p = arg;
+       u16 ch_num;
+       struct rio_channel *ch;
+
+       if (get_user(ch_num, p))
+               return -EFAULT;
+
+       riocm_debug(CHOP, "ch_%d by %s(%d)",
+                   ch_num, current->comm, task_pid_nr(current));
+
+       spin_lock_bh(&idr_lock);
+       ch = idr_find(&ch_idr, ch_num);
+       if (!ch) {
+               spin_unlock_bh(&idr_lock);
+               return 0;
+       }
+       if (ch->filp != filp) {
+               spin_unlock_bh(&idr_lock);
+               return -EINVAL;
+       }
+       idr_remove(&ch_idr, ch->id);
+       spin_unlock_bh(&idr_lock);
+
+       return riocm_ch_close(ch);
+}
+
+/*
+ * cm_chan_bind() - Bind channel
+ * @arg:       Channel number
+ */
+static int cm_chan_bind(void __user *arg)
+{
+       struct rio_cm_channel chan;
+
+       if (copy_from_user(&chan, arg, sizeof(chan)))
+               return -EFAULT;
+       if (chan.mport_id >= RIO_MAX_MPORTS)
+               return -EINVAL;
+
+       return riocm_ch_bind(chan.id, chan.mport_id, NULL);
+}
+
+/*
+ * cm_chan_listen() - Listen on channel
+ * @arg:       Channel number
+ */
+static int cm_chan_listen(void __user *arg)
+{
+       u16 __user *p = arg;
+       u16 ch_num;
+
+       if (get_user(ch_num, p))
+               return -EFAULT;
+
+       return riocm_ch_listen(ch_num);
+}
+
+/*
+ * cm_chan_accept() - Accept incoming connection
+ * @filp:      Pointer to file object
+ * @arg:       Channel number
+ */
+static int cm_chan_accept(struct file *filp, void __user *arg)
+{
+       struct rio_cm_accept param;
+       long accept_to;
+       struct rio_channel *ch;
+
+       if (copy_from_user(&param, arg, sizeof(param)))
+               return -EFAULT;
+
+       riocm_debug(CHOP, "on ch_%d by %s(%d)",
+                   param.ch_num, current->comm, task_pid_nr(current));
+
+       accept_to = param.wait_to ?
+                       msecs_to_jiffies(param.wait_to) : 0;
+
+       ch = riocm_ch_accept(param.ch_num, &param.ch_num, accept_to);
+       if (IS_ERR(ch))
+               return PTR_ERR(ch);
+       ch->filp = filp;
+
+       riocm_debug(CHOP, "new ch_%d for %s(%d)",
+                   ch->id, current->comm, task_pid_nr(current));
+
+       if (copy_to_user(arg, &param, sizeof(param)))
+               return -EFAULT;
+       return 0;
+}
+
+/*
+ * cm_chan_connect() - Connect on channel
+ * @arg:       Channel information
+ */
+static int cm_chan_connect(void __user *arg)
+{
+       struct rio_cm_channel chan;
+       struct cm_dev *cm;
+       struct cm_peer *peer;
+       int ret = -ENODEV;
+
+       if (copy_from_user(&chan, arg, sizeof(chan)))
+               return -EFAULT;
+       if (chan.mport_id >= RIO_MAX_MPORTS)
+               return -EINVAL;
+
+       down_read(&rdev_sem);
+
+       /* Find matching cm_dev object */
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (cm->mport->id == chan.mport_id) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret)
+               goto err_out;
+
+       if (chan.remote_destid >= RIO_ANY_DESTID(cm->mport->sys_size)) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       /* Find corresponding RapidIO endpoint device object */
+       ret = -ENODEV;
+
+       list_for_each_entry(peer, &cm->peers, node) {
+               if (peer->rdev->destid == chan.remote_destid) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret)
+               goto err_out;
+
+       up_read(&rdev_sem);
+
+       return riocm_ch_connect(chan.id, cm, peer, chan.remote_channel);
+err_out:
+       up_read(&rdev_sem);
+       return ret;
+}
+
+/*
+ * cm_chan_msg_send() - Send a message through channel
+ * @arg:       Outbound message information
+ */
+static int cm_chan_msg_send(void __user *arg)
+{
+       struct rio_cm_msg msg;
+       void *buf;
+       int ret = 0;
+
+       if (copy_from_user(&msg, arg, sizeof(msg)))
+               return -EFAULT;
+       if (msg.size > RIO_MAX_MSG_SIZE)
+               return -EINVAL;
+
+       buf = kmalloc(msg.size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, (void __user *)(uintptr_t)msg.msg, msg.size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ret = riocm_ch_send(msg.ch_num, buf, msg.size);
+out:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ * cm_chan_msg_rcv() - Receive a message through channel
+ * @arg:       Inbound message information
+ */
+static int cm_chan_msg_rcv(void __user *arg)
+{
+       struct rio_cm_msg msg;
+       struct rio_channel *ch;
+       void *buf;
+       long rxto;
+       int ret = 0, msg_size;
+
+       if (copy_from_user(&msg, arg, sizeof(msg)))
+               return -EFAULT;
+
+       if (msg.ch_num == 0 || msg.size == 0)
+               return -EINVAL;
+
+       ch = riocm_get_channel(msg.ch_num);
+       if (!ch)
+               return -ENODEV;
+
+       rxto = msg.rxto ? msecs_to_jiffies(msg.rxto) : MAX_SCHEDULE_TIMEOUT;
+
+       ret = riocm_ch_receive(ch, &buf, rxto);
+       if (ret)
+               goto out;
+
+       msg_size = min(msg.size, (u16)(RIO_MAX_MSG_SIZE));
+
+       if (copy_to_user((void __user *)(uintptr_t)msg.msg, buf, msg_size))
+               ret = -EFAULT;
+
+       riocm_ch_free_rxbuf(ch, buf);
+out:
+       riocm_put_channel(ch);
+       return ret;
+}
+
+/*
+ * riocm_cdev_ioctl() - IOCTL requests handler
+ */
+static long
+riocm_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case RIO_CM_EP_GET_LIST_SIZE:
+               return cm_ep_get_list_size((void __user *)arg);
+       case RIO_CM_EP_GET_LIST:
+               return cm_ep_get_list((void __user *)arg);
+       case RIO_CM_CHAN_CREATE:
+               return cm_chan_create(filp, (void __user *)arg);
+       case RIO_CM_CHAN_CLOSE:
+               return cm_chan_close(filp, (void __user *)arg);
+       case RIO_CM_CHAN_BIND:
+               return cm_chan_bind((void __user *)arg);
+       case RIO_CM_CHAN_LISTEN:
+               return cm_chan_listen((void __user *)arg);
+       case RIO_CM_CHAN_ACCEPT:
+               return cm_chan_accept(filp, (void __user *)arg);
+       case RIO_CM_CHAN_CONNECT:
+               return cm_chan_connect((void __user *)arg);
+       case RIO_CM_CHAN_SEND:
+               return cm_chan_msg_send((void __user *)arg);
+       case RIO_CM_CHAN_RECEIVE:
+               return cm_chan_msg_rcv((void __user *)arg);
+       case RIO_CM_MPORT_GET_LIST:
+               return cm_mport_get_list((void __user *)arg);
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct file_operations riocm_cdev_fops = {
+       .owner          = THIS_MODULE,
+       .open           = riocm_cdev_open,
+       .release        = riocm_cdev_release,
+       .unlocked_ioctl = riocm_cdev_ioctl,
+};
+
+/*
+ * riocm_add_dev - add new remote RapidIO device into channel management core
+ * @dev: device object associated with RapidIO device
+ * @sif: subsystem interface
+ *
+ * Adds the specified RapidIO device (if applicable) into peers list of
+ * the corresponding channel management device (cm_dev).
+ */
+static int riocm_add_dev(struct device *dev, struct subsys_interface *sif)
+{
+       struct cm_peer *peer;
+       struct rio_dev *rdev = to_rio_dev(dev);
+       struct cm_dev *cm;
+
+       /* Check if the remote device has capabilities required to support CM */
+       if (!dev_cm_capable(rdev))
+               return 0;
+
+       riocm_debug(RDEV, "(%s)", rio_name(rdev));
+
+       peer = kmalloc(sizeof(*peer), GFP_KERNEL);
+       if (!peer)
+               return -ENOMEM;
+
+       /* Find a corresponding cm_dev object */
+       down_write(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (cm->mport == rdev->net->hport)
+                       goto found;
+       }
+
+       up_write(&rdev_sem);
+       kfree(peer);
+       return -ENODEV;
+
+found:
+       peer->rdev = rdev;
+       list_add_tail(&peer->node, &cm->peers);
+       cm->npeers++;
+
+       up_write(&rdev_sem);
+       return 0;
+}
+
+/*
+ * riocm_remove_dev - remove remote RapidIO device from channel management core
+ * @dev: device object associated with RapidIO device
+ * @sif: subsystem interface
+ *
+ * Removes the specified RapidIO device (if applicable) from peers list of
+ * the corresponding channel management device (cm_dev).
+ */
+static void riocm_remove_dev(struct device *dev, struct subsys_interface *sif)
+{
+       struct rio_dev *rdev = to_rio_dev(dev);
+       struct cm_dev *cm;
+       struct cm_peer *peer;
+       struct rio_channel *ch, *_c;
+       unsigned int i;
+       bool found = false;
+       LIST_HEAD(list);
+
+       /* Check if the remote device has capabilities required to support CM */
+       if (!dev_cm_capable(rdev))
+               return;
+
+       riocm_debug(RDEV, "(%s)", rio_name(rdev));
+
+       /* Find matching cm_dev object */
+       down_write(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (cm->mport == rdev->net->hport) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               up_write(&rdev_sem);
+               return;
+       }
+
+       /* Remove remote device from the list of peers */
+       found = false;
+       list_for_each_entry(peer, &cm->peers, node) {
+               if (peer->rdev == rdev) {
+                       riocm_debug(RDEV, "removing peer %s", rio_name(rdev));
+                       found = true;
+                       list_del(&peer->node);
+                       cm->npeers--;
+                       kfree(peer);
+                       break;
+               }
+       }
+
+       up_write(&rdev_sem);
+
+       if (!found)
+               return;
+
+       /*
+        * Release channels associated with this peer
+        */
+
+       spin_lock_bh(&idr_lock);
+       idr_for_each_entry(&ch_idr, ch, i) {
+               if (ch && ch->rdev == rdev) {
+                       if (atomic_read(&rdev->state) != RIO_DEVICE_SHUTDOWN)
+                               riocm_exch(ch, RIO_CM_DISCONNECT);
+                       idr_remove(&ch_idr, ch->id);
+                       list_add(&ch->ch_node, &list);
+               }
+       }
+       spin_unlock_bh(&idr_lock);
+
+       if (!list_empty(&list)) {
+               list_for_each_entry_safe(ch, _c, &list, ch_node) {
+                       list_del(&ch->ch_node);
+                       riocm_ch_close(ch);
+               }
+       }
+}
+
+/*
+ * riocm_cdev_add() - Create rio_cm char device
+ * @devno: device number assigned to device (MAJ + MIN)
+ */
+static int riocm_cdev_add(dev_t devno)
+{
+       int ret;
+
+       cdev_init(&riocm_cdev.cdev, &riocm_cdev_fops);
+       riocm_cdev.cdev.owner = THIS_MODULE;
+       ret = cdev_add(&riocm_cdev.cdev, devno, 1);
+       if (ret < 0) {
+               riocm_error("Cannot register a device with error %d", ret);
+               return ret;
+       }
+
+       riocm_cdev.dev = device_create(dev_class, NULL, devno, NULL, DEV_NAME);
+       if (IS_ERR(riocm_cdev.dev)) {
+               cdev_del(&riocm_cdev.cdev);
+               return PTR_ERR(riocm_cdev.dev);
+       }
+
+       riocm_debug(MPORT, "Added %s cdev(%d:%d)",
+                   DEV_NAME, MAJOR(devno), MINOR(devno));
+
+       return 0;
+}
+
+/*
+ * riocm_add_mport - add new local mport device into channel management core
+ * @dev: device object associated with mport
+ * @class_intf: class interface
+ *
+ * When a new mport device is added, CM immediately reserves inbound and
+ * outbound RapidIO mailboxes that will be used.
+ */
+static int riocm_add_mport(struct device *dev,
+                          struct class_interface *class_intf)
+{
+       int rc;
+       int i;
+       struct cm_dev *cm;
+       struct rio_mport *mport = to_rio_mport(dev);
+
+       riocm_debug(MPORT, "add mport %s", mport->name);
+
+       cm = kzalloc(sizeof(*cm), GFP_KERNEL);
+       if (!cm)
+               return -ENOMEM;
+
+       cm->mport = mport;
+
+       rc = rio_request_outb_mbox(mport, cm, cmbox,
+                                  RIOCM_TX_RING_SIZE, riocm_outb_msg_event);
+       if (rc) {
+               riocm_error("failed to allocate OBMBOX_%d on %s",
+                           cmbox, mport->name);
+               kfree(cm);
+               return -ENODEV;
+       }
+
+       rc = rio_request_inb_mbox(mport, cm, cmbox,
+                                 RIOCM_RX_RING_SIZE, riocm_inb_msg_event);
+       if (rc) {
+               riocm_error("failed to allocate IBMBOX_%d on %s",
+                           cmbox, mport->name);
+               rio_release_outb_mbox(mport, cmbox);
+               kfree(cm);
+               return -ENODEV;
+       }
+
+       /*
+        * Allocate and register inbound messaging buffers to be ready
+        * to receive channel and system management requests
+        */
+       for (i = 0; i < RIOCM_RX_RING_SIZE; i++)
+               cm->rx_buf[i] = NULL;
+
+       cm->rx_slots = RIOCM_RX_RING_SIZE;
+       mutex_init(&cm->rx_lock);
+       riocm_rx_fill(cm, RIOCM_RX_RING_SIZE);
+       cm->rx_wq = create_workqueue(DRV_NAME "/rxq");
+       INIT_WORK(&cm->rx_work, rio_ibmsg_handler);
+
+       cm->tx_slot = 0;
+       cm->tx_cnt = 0;
+       cm->tx_ack_slot = 0;
+       spin_lock_init(&cm->tx_lock);
+
+       INIT_LIST_HEAD(&cm->peers);
+       cm->npeers = 0;
+       INIT_LIST_HEAD(&cm->tx_reqs);
+
+       down_write(&rdev_sem);
+       list_add_tail(&cm->list, &cm_dev_list);
+       up_write(&rdev_sem);
+
+       return 0;
+}
+
+/*
+ * riocm_remove_mport - remove local mport device from channel management core
+ * @dev: device object associated with mport
+ * @class_intf: class interface
+ *
+ * Removes a local mport device from the list of registered devices that provide
+ * channel management services. Returns an error if the specified mport is not
+ * registered with the CM core.
+ */
+static void riocm_remove_mport(struct device *dev,
+                              struct class_interface *class_intf)
+{
+       struct rio_mport *mport = to_rio_mport(dev);
+       struct cm_dev *cm;
+       struct cm_peer *peer, *temp;
+       struct rio_channel *ch, *_c;
+       unsigned int i;
+       bool found = false;
+       LIST_HEAD(list);
+
+       riocm_debug(MPORT, "%s", mport->name);
+
+       /* Find a matching cm_dev object */
+       down_write(&rdev_sem);
+       list_for_each_entry(cm, &cm_dev_list, list) {
+               if (cm->mport == mport) {
+                       list_del(&cm->list);
+                       found = true;
+                       break;
+               }
+       }
+       up_write(&rdev_sem);
+       if (!found)
+               return;
+
+       flush_workqueue(cm->rx_wq);
+       destroy_workqueue(cm->rx_wq);
+
+       /* Release channels bound to this mport */
+       spin_lock_bh(&idr_lock);
+       idr_for_each_entry(&ch_idr, ch, i) {
+               if (ch->cmdev == cm) {
+                       riocm_debug(RDEV, "%s drop ch_%d",
+                                   mport->name, ch->id);
+                       idr_remove(&ch_idr, ch->id);
+                       list_add(&ch->ch_node, &list);
+               }
+       }
+       spin_unlock_bh(&idr_lock);
+
+       if (!list_empty(&list)) {
+               list_for_each_entry_safe(ch, _c, &list, ch_node) {
+                       list_del(&ch->ch_node);
+                       riocm_ch_close(ch);
+               }
+       }
+
+       rio_release_inb_mbox(mport, cmbox);
+       rio_release_outb_mbox(mport, cmbox);
+
+       /* Remove and free peer entries */
+       if (!list_empty(&cm->peers))
+               riocm_debug(RDEV, "ATTN: peer list not empty");
+       list_for_each_entry_safe(peer, temp, &cm->peers, node) {
+               riocm_debug(RDEV, "removing peer %s", rio_name(peer->rdev));
+               list_del(&peer->node);
+               kfree(peer);
+       }
+
+       riocm_rx_free(cm);
+       kfree(cm);
+       riocm_debug(MPORT, "%s done", mport->name);
+}
+
+static int rio_cm_shutdown(struct notifier_block *nb, unsigned long code,
+       void *unused)
+{
+       struct rio_channel *ch;
+       unsigned int i;
+
+       riocm_debug(EXIT, ".");
+
+       spin_lock_bh(&idr_lock);
+       idr_for_each_entry(&ch_idr, ch, i) {
+               riocm_debug(EXIT, "close ch %d", ch->id);
+               if (ch->state == RIO_CM_CONNECTED)
+                       riocm_send_close(ch);
+       }
+       spin_unlock_bh(&idr_lock);
+
+       return NOTIFY_DONE;
+}
+
+/*
+ * riocm_interface handles addition/removal of remote RapidIO devices
+ */
+static struct subsys_interface riocm_interface = {
+       .name           = "rio_cm",
+       .subsys         = &rio_bus_type,
+       .add_dev        = riocm_add_dev,
+       .remove_dev     = riocm_remove_dev,
+};
+
+/*
+ * rio_mport_interface handles addition/removal local mport devices
+ */
+static struct class_interface rio_mport_interface __refdata = {
+       .class = &rio_mport_class,
+       .add_dev = riocm_add_mport,
+       .remove_dev = riocm_remove_mport,
+};
+
+static struct notifier_block rio_cm_notifier = {
+       .notifier_call = rio_cm_shutdown,
+};
+
+static int __init riocm_init(void)
+{
+       int ret;
+
+       /* Create device class needed by udev */
+       dev_class = class_create(THIS_MODULE, DRV_NAME);
+       if (IS_ERR(dev_class)) {
+               riocm_error("Cannot create " DRV_NAME " class");
+               return PTR_ERR(dev_class);
+       }
+
+       ret = alloc_chrdev_region(&dev_number, 0, 1, DRV_NAME);
+       if (ret) {
+               class_destroy(dev_class);
+               return ret;
+       }
+
+       dev_major = MAJOR(dev_number);
+       dev_minor_base = MINOR(dev_number);
+       riocm_debug(INIT, "Registered class with %d major", dev_major);
+
+       /*
+        * Register as rapidio_port class interface to get notifications about
+        * mport additions and removals.
+        */
+       ret = class_interface_register(&rio_mport_interface);
+       if (ret) {
+               riocm_error("class_interface_register error: %d", ret);
+               goto err_reg;
+       }
+
+       /*
+        * Register as RapidIO bus interface to get notifications about
+        * addition/removal of remote RapidIO devices.
+        */
+       ret = subsys_interface_register(&riocm_interface);
+       if (ret) {
+               riocm_error("subsys_interface_register error: %d", ret);
+               goto err_cl;
+       }
+
+       ret = register_reboot_notifier(&rio_cm_notifier);
+       if (ret) {
+               riocm_error("failed to register reboot notifier (err=%d)", ret);
+               goto err_sif;
+       }
+
+       ret = riocm_cdev_add(dev_number);
+       if (ret) {
+               unregister_reboot_notifier(&rio_cm_notifier);
+               ret = -ENODEV;
+               goto err_sif;
+       }
+
+       return 0;
+err_sif:
+       subsys_interface_unregister(&riocm_interface);
+err_cl:
+       class_interface_unregister(&rio_mport_interface);
+err_reg:
+       unregister_chrdev_region(dev_number, 1);
+       class_destroy(dev_class);
+       return ret;
+}
+
+static void __exit riocm_exit(void)
+{
+       riocm_debug(EXIT, "enter");
+       unregister_reboot_notifier(&rio_cm_notifier);
+       subsys_interface_unregister(&riocm_interface);
+       class_interface_unregister(&rio_mport_interface);
+       idr_destroy(&ch_idr);
+
+       device_unregister(riocm_cdev.dev);
+       cdev_del(&(riocm_cdev.cdev));
+
+       class_destroy(dev_class);
+       unregister_chrdev_region(dev_number, 1);
+}
+
+late_initcall(riocm_init);
+module_exit(riocm_exit);
index 3458415..92767fd 100644 (file)
@@ -22,3 +22,9 @@ config RAPIDIO_CPS_GEN2
        default n
        ---help---
          Includes support for ITD CPS Gen.2 serial RapidIO switches.
+
+config RAPIDIO_RXS_GEN3
+       tristate "IDT RXS Gen.3 SRIO switch support"
+       default n
+       ---help---
+         Includes support for ITD RXS Gen.3 serial RapidIO switches.
index 051cc6b..6bdd54c 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_RAPIDIO_TSI57X)    += tsi57x.o
 obj-$(CONFIG_RAPIDIO_CPS_XX)   += idtcps.o
 obj-$(CONFIG_RAPIDIO_TSI568)   += tsi568.o
 obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
+obj-$(CONFIG_RAPIDIO_RXS_GEN3) += idt_gen3.o
index 9f7fe21..e67b923 100644 (file)
@@ -436,10 +436,11 @@ static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id)
                                    RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE);
        }
 
+       spin_unlock(&rdev->rswitch->lock);
+
        /* Create device-specific sysfs attributes */
        idtg2_sysfs(rdev, true);
 
-       spin_unlock(&rdev->rswitch->lock);
        return 0;
 }
 
@@ -452,11 +453,9 @@ static void idtg2_remove(struct rio_dev *rdev)
                return;
        }
        rdev->rswitch->ops = NULL;
-
+       spin_unlock(&rdev->rswitch->lock);
        /* Remove device-specific sysfs attributes */
        idtg2_sysfs(rdev, false);
-
-       spin_unlock(&rdev->rswitch->lock);
 }
 
 static struct rio_device_id idtg2_id_table[] = {
diff --git a/drivers/rapidio/switches/idt_gen3.c b/drivers/rapidio/switches/idt_gen3.c
new file mode 100644 (file)
index 0000000..c5923a5
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * IDT RXS Gen.3 Serial RapidIO switch family support
+ *
+ * Copyright 2016 Integrated Device Technology, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+
+#include <asm/page.h>
+#include "../rio.h"
+
+#define RIO_EM_PW_STAT         0x40020
+#define RIO_PW_CTL             0x40204
+#define RIO_PW_CTL_PW_TMR              0xffffff00
+#define RIO_PW_ROUTE           0x40208
+
+#define RIO_EM_DEV_INT_EN      0x40030
+
+#define RIO_PLM_SPx_IMP_SPEC_CTL(x)    (0x10100 + (x)*0x100)
+#define RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST      0x02000000
+
+#define RIO_PLM_SPx_PW_EN(x)   (0x10118 + (x)*0x100)
+#define RIO_PLM_SPx_PW_EN_OK2U 0x40000000
+#define RIO_PLM_SPx_PW_EN_LINIT 0x10000000
+
+#define RIO_BC_L2_Gn_ENTRYx_CSR(n, x)  (0x31000 + (n)*0x400 + (x)*0x4)
+#define RIO_SPx_L2_Gn_ENTRYy_CSR(x, n, y) \
+                               (0x51000 + (x)*0x2000 + (n)*0x400 + (y)*0x4)
+
+static int
+idtg3_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       u32 rval;
+       u32 entry = route_port;
+       int err = 0;
+
+       pr_debug("RIO: %s t=0x%x did_%x to p_%x\n",
+                __func__, table, route_destid, entry);
+
+       if (route_destid > 0xFF)
+               return -EINVAL;
+
+       if (route_port == RIO_INVALID_ROUTE)
+               entry = RIO_RT_ENTRY_DROP_PKT;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               /* Use broadcast register to update all per-port tables */
+               err = rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_BC_L2_Gn_ENTRYx_CSR(0, route_destid),
+                               entry);
+               return err;
+       }
+
+       /*
+        * Verify that specified port/table number is valid
+        */
+       err = rio_mport_read_config_32(mport, destid, hopcount,
+                                      RIO_SWP_INFO_CAR, &rval);
+       if (err)
+               return err;
+
+       if (table >= RIO_GET_TOTAL_PORTS(rval))
+               return -EINVAL;
+
+       err = rio_mport_write_config_32(mport, destid, hopcount,
+                       RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid),
+                       entry);
+       return err;
+}
+
+static int
+idtg3_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       u32 rval;
+       int err;
+
+       if (route_destid > 0xFF)
+               return -EINVAL;
+
+       err = rio_mport_read_config_32(mport, destid, hopcount,
+                                      RIO_SWP_INFO_CAR, &rval);
+       if (err)
+               return err;
+
+       /*
+        * This switch device does not have the dedicated global routing table.
+        * It is substituted by reading routing table of the ingress port of
+        * maintenance read requests.
+        */
+       if (table == RIO_GLOBAL_TABLE)
+               table = RIO_GET_PORT_NUM(rval);
+       else if (table >= RIO_GET_TOTAL_PORTS(rval))
+               return -EINVAL;
+
+       err = rio_mport_read_config_32(mport, destid, hopcount,
+                       RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid),
+                       &rval);
+       if (err)
+               return err;
+
+       if (rval == RIO_RT_ENTRY_DROP_PKT)
+               *route_port = RIO_INVALID_ROUTE;
+       else
+               *route_port = (u8)rval;
+
+       return 0;
+}
+
+static int
+idtg3_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 i;
+       u32 rval;
+       int err;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               for (i = 0; i <= 0xff; i++) {
+                       err = rio_mport_write_config_32(mport, destid, hopcount,
+                                               RIO_BC_L2_Gn_ENTRYx_CSR(0, i),
+                                               RIO_RT_ENTRY_DROP_PKT);
+                       if (err)
+                               break;
+               }
+
+               return err;
+       }
+
+       err = rio_mport_read_config_32(mport, destid, hopcount,
+                                      RIO_SWP_INFO_CAR, &rval);
+       if (err)
+               return err;
+
+       if (table >= RIO_GET_TOTAL_PORTS(rval))
+               return -EINVAL;
+
+       for (i = 0; i <= 0xff; i++) {
+               err = rio_mport_write_config_32(mport, destid, hopcount,
+                                       RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, i),
+                                       RIO_RT_ENTRY_DROP_PKT);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+/*
+ * This routine performs device-specific initialization only.
+ * All standard EM configuration should be performed at upper level.
+ */
+static int
+idtg3_em_init(struct rio_dev *rdev)
+{
+       int i, tmp;
+       u32 rval;
+
+       pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
+
+       /* Disable assertion of interrupt signal */
+       rio_write_config_32(rdev, RIO_EM_DEV_INT_EN, 0);
+
+       /* Disable port-write event notifications during initialization */
+       rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL,
+                           RIO_EM_PW_TX_CTRL_PW_DIS);
+
+       /* Configure Port-Write notifications for hot-swap events */
+       tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+       for (i = 0; i < tmp; i++) {
+
+               rio_read_config_32(rdev,
+                       RIO_DEV_PORT_N_ERR_STS_CSR(rdev, i),
+                       &rval);
+               if (rval & RIO_PORT_N_ERR_STS_PORT_UA)
+                       continue;
+
+               /* Clear events signaled before enabling notification */
+               rio_write_config_32(rdev,
+                       rdev->em_efptr + RIO_EM_PN_ERR_DETECT(i), 0);
+
+               /* Enable event notifications */
+               rio_write_config_32(rdev,
+                       rdev->em_efptr + RIO_EM_PN_ERRRATE_EN(i),
+                       RIO_EM_PN_ERRRATE_EN_OK2U | RIO_EM_PN_ERRRATE_EN_U2OK);
+               /* Enable port-write generation on events */
+               rio_write_config_32(rdev, RIO_PLM_SPx_PW_EN(i),
+                       RIO_PLM_SPx_PW_EN_OK2U | RIO_PLM_SPx_PW_EN_LINIT);
+
+       }
+
+       /* Set Port-Write destination port */
+       tmp = RIO_GET_PORT_NUM(rdev->swpinfo);
+       rio_write_config_32(rdev, RIO_PW_ROUTE, 1 << tmp);
+
+
+       /* Enable sending port-write event notifications */
+       rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0);
+
+       /* set TVAL = ~50us */
+       rio_write_config_32(rdev,
+               rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+       return 0;
+}
+
+
+/*
+ * idtg3_em_handler - device-specific error handler
+ *
+ * If the link is down (PORT_UNINIT) does nothing - this is considered
+ * as link partner removal from the port.
+ *
+ * If the link is up (PORT_OK) - situation is handled as *new* device insertion.
+ * In this case ERR_STOP bits are cleared by issuing soft reset command to the
+ * reporting port. Inbound and outbound ackIDs are cleared by the reset as well.
+ * This way the port is synchronized with freshly inserted device (assuming it
+ * was reset/powered-up on insertion).
+ *
+ * TODO: This is not sufficient in a situation when a link between two devices
+ * was down and up again (e.g. cable disconnect). For that situation full ackID
+ * realignment process has to be implemented.
+ */
+static int
+idtg3_em_handler(struct rio_dev *rdev, u8 pnum)
+{
+       u32 err_status;
+       u32 rval;
+
+       rio_read_config_32(rdev,
+                       RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum),
+                       &err_status);
+
+       /* Do nothing for device/link removal */
+       if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT)
+               return 0;
+
+       /* When link is OK we have a device insertion.
+        * Request port soft reset to clear errors if they present.
+        * Inbound and outbound ackIDs will be 0 after reset.
+        */
+       if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES |
+                               RIO_PORT_N_ERR_STS_INP_ES)) {
+               rio_read_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), &rval);
+               rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum),
+                                   rval | RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST);
+               udelay(10);
+               rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), rval);
+               msleep(500);
+       }
+
+       return 0;
+}
+
+static struct rio_switch_ops idtg3_switch_ops = {
+       .owner = THIS_MODULE,
+       .add_entry = idtg3_route_add_entry,
+       .get_entry = idtg3_route_get_entry,
+       .clr_table = idtg3_route_clr_table,
+       .em_init   = idtg3_em_init,
+       .em_handle = idtg3_em_handler,
+};
+
+static int idtg3_probe(struct rio_dev *rdev, const struct rio_device_id *id)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (rdev->rswitch->ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return -EINVAL;
+       }
+
+       rdev->rswitch->ops = &idtg3_switch_ops;
+
+       if (rdev->do_enum) {
+               /* Disable hierarchical routing support: Existing fabric
+                * enumeration/discovery process (see rio-scan.c) uses 8-bit
+                * flat destination ID routing only.
+                */
+               rio_write_config_32(rdev, 0x5000 + RIO_BC_RT_CTL_CSR, 0);
+       }
+
+       spin_unlock(&rdev->rswitch->lock);
+
+       return 0;
+}
+
+static void idtg3_remove(struct rio_dev *rdev)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       spin_lock(&rdev->rswitch->lock);
+       if (rdev->rswitch->ops == &idtg3_switch_ops)
+               rdev->rswitch->ops = NULL;
+       spin_unlock(&rdev->rswitch->lock);
+}
+
+/*
+ * Gen3 switches repeat sending PW messages until a corresponding event flag
+ * is cleared. Use shutdown notification to disable generation of port-write
+ * messages if their destination node is shut down.
+ */
+static void idtg3_shutdown(struct rio_dev *rdev)
+{
+       int i;
+       u32 rval;
+       u16 destid;
+
+       /* Currently the enumerator node acts also as PW handler */
+       if (!rdev->do_enum)
+               return;
+
+       pr_debug("RIO: %s(%s)\n", __func__, rio_name(rdev));
+
+       rio_read_config_32(rdev, RIO_PW_ROUTE, &rval);
+       i = RIO_GET_PORT_NUM(rdev->swpinfo);
+
+       /* Check port-write destination port */
+       if (!((1 << i) & rval))
+               return;
+
+       /* Disable sending port-write event notifications if PW destID
+        * matches to one of the enumerator node
+        */
+       rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TGT_DEVID, &rval);
+
+       if (rval & RIO_EM_PW_TGT_DEVID_DEV16)
+               destid = rval >> 16;
+       else
+               destid = ((rval & RIO_EM_PW_TGT_DEVID_D8) >> 16);
+
+       if (rdev->net->hport->host_deviceid == destid) {
+               rio_write_config_32(rdev,
+                                   rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0);
+               pr_debug("RIO: %s(%s) PW transmission disabled\n",
+                        __func__, rio_name(rdev));
+       }
+}
+
+static struct rio_device_id idtg3_id_table[] = {
+       {RIO_DEVICE(RIO_DID_IDTRXS1632, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTRXS2448, RIO_VID_IDT)},
+       { 0, }  /* terminate list */
+};
+
+static struct rio_driver idtg3_driver = {
+       .name = "idt_gen3",
+       .id_table = idtg3_id_table,
+       .probe = idtg3_probe,
+       .remove = idtg3_remove,
+       .shutdown = idtg3_shutdown,
+};
+
+static int __init idtg3_init(void)
+{
+       return rio_register_driver(&idtg3_driver);
+}
+
+static void __exit idtg3_exit(void)
+{
+       pr_debug("RIO: %s\n", __func__);
+       rio_unregister_driver(&idtg3_driver);
+       pr_debug("RIO: %s done\n", __func__);
+}
+
+device_initcall(idtg3_init);
+module_exit(idtg3_exit);
+
+MODULE_DESCRIPTION("IDT RXS Gen.3 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
index 42c8b01..2700d15 100644 (file)
@@ -175,12 +175,10 @@ tsi57x_em_init(struct rio_dev *rdev)
 
                /* Clear all pending interrupts */
                rio_read_config_32(rdev,
-                               rdev->phys_efptr +
-                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum),
                                &regval);
                rio_write_config_32(rdev,
-                               rdev->phys_efptr +
-                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum),
                                regval & 0x07120214);
 
                rio_read_config_32(rdev,
@@ -198,7 +196,7 @@ tsi57x_em_init(struct rio_dev *rdev)
 
                /* Skip next (odd) port if the current port is in x4 mode */
                rio_read_config_32(rdev,
-                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               RIO_DEV_PORT_N_CTL_CSR(rdev, portnum),
                                &regval);
                if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
                        portnum++;
@@ -221,23 +219,23 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
        u32 regval;
 
        rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum),
                        &err_status);
 
        if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
-           (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
-                         RIO_PORT_N_ERR_STS_PW_INP_ES))) {
+           (err_status & (RIO_PORT_N_ERR_STS_OUT_ES |
+                         RIO_PORT_N_ERR_STS_INP_ES))) {
                /* Remove any queued packets by locking/unlocking port */
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                       RIO_DEV_PORT_N_CTL_CSR(rdev, portnum),
                        &regval);
                if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
                        rio_write_config_32(rdev,
-                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               RIO_DEV_PORT_N_CTL_CSR(rdev, portnum),
                                regval | RIO_PORT_N_CTL_LOCKOUT);
                        udelay(50);
                        rio_write_config_32(rdev,
-                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               RIO_DEV_PORT_N_CTL_CSR(rdev, portnum),
                                regval);
                }
 
@@ -245,7 +243,7 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
                 * valid bit
                 */
                rio_read_config_32(rdev,
-                       rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
+                       RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, portnum),
                        &regval);
 
                /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
@@ -259,8 +257,8 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
                        while (checkcount--) {
                                udelay(50);
                                rio_read_config_32(rdev,
-                                       rdev->phys_efptr +
-                                               RIO_PORT_N_MNT_RSP_CSR(portnum),
+                                       RIO_DEV_PORT_N_MNT_RSP_CSR(rdev,
+                                                                  portnum),
                                        &regval);
                                if (regval & RIO_PORT_N_MNT_RSP_RVAL)
                                        goto exit_es;
index 666bc3b..c245242 100644 (file)
 #include <linux/pwm.h>
 #include <linux/gpio/consumer.h>
 
+struct pwm_continuous_reg_data {
+       unsigned int min_uV_dutycycle;
+       unsigned int max_uV_dutycycle;
+       unsigned int dutycycle_unit;
+};
+
 struct pwm_regulator_data {
        /*  Shared */
        struct pwm_device *pwm;
@@ -29,6 +35,9 @@ struct pwm_regulator_data {
        /* Voltage table */
        struct pwm_voltages *duty_cycle_table;
 
+       /* Continuous mode info */
+       struct pwm_continuous_reg_data continuous;
+
        /* regulator descriptor */
        struct regulator_desc desc;
 
@@ -37,9 +46,6 @@ struct pwm_regulator_data {
 
        int state;
 
-       /* Continuous voltage */
-       int volt_uV;
-
        /* Enable GPIO */
        struct gpio_desc *enb_gpio;
 };
@@ -52,10 +58,31 @@ struct pwm_voltages {
 /**
  * Voltage table call-backs
  */
+static void pwm_regulator_init_state(struct regulator_dev *rdev)
+{
+       struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+       struct pwm_state pwm_state;
+       unsigned int dutycycle;
+       int i;
+
+       pwm_get_state(drvdata->pwm, &pwm_state);
+       dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);
+
+       for (i = 0; i < rdev->desc->n_voltages; i++) {
+               if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {
+                       drvdata->state = i;
+                       return;
+               }
+       }
+}
+
 static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
 
+       if (drvdata->state < 0)
+               pwm_regulator_init_state(rdev);
+
        return drvdata->state;
 }
 
@@ -63,16 +90,14 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
                                         unsigned selector)
 {
        struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
-       struct pwm_args pargs;
-       int dutycycle;
+       struct pwm_state pstate;
        int ret;
 
-       pwm_get_args(drvdata->pwm, &pargs);
-
-       dutycycle = (pargs.period *
-                   drvdata->duty_cycle_table[selector].dutycycle) / 100;
+       pwm_init_state(drvdata->pwm, &pstate);
+       pwm_set_relative_duty_cycle(&pstate,
+                       drvdata->duty_cycle_table[selector].dutycycle, 100);
 
-       ret = pwm_config(drvdata->pwm, dutycycle, pargs.period);
+       ret = pwm_apply_state(drvdata->pwm, &pstate);
        if (ret) {
                dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
                return ret;
@@ -129,57 +154,90 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev)
 static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
 {
        struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+       unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
+       unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
+       unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
+       int min_uV = rdev->constraints->min_uV;
+       int max_uV = rdev->constraints->max_uV;
+       int diff_uV = max_uV - min_uV;
+       struct pwm_state pstate;
+       unsigned int diff_duty;
+       unsigned int voltage;
+
+       pwm_get_state(drvdata->pwm, &pstate);
+
+       voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);
+
+       /*
+        * The dutycycle for min_uV might be greater than the one for max_uV.
+        * This is happening when the user needs an inversed polarity, but the
+        * PWM device does not support inversing it in hardware.
+        */
+       if (max_uV_duty < min_uV_duty) {
+               voltage = min_uV_duty - voltage;
+               diff_duty = min_uV_duty - max_uV_duty;
+       } else {
+               voltage = voltage - min_uV_duty;
+               diff_duty = max_uV_duty - min_uV_duty;
+       }
 
-       return drvdata->volt_uV;
+       voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);
+
+       return voltage + min_uV;
 }
 
 static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
-                                       int min_uV, int max_uV,
-                                       unsigned *selector)
+                                    int req_min_uV, int req_max_uV,
+                                    unsigned int *selector)
 {
        struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+       unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
+       unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
+       unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
        unsigned int ramp_delay = rdev->constraints->ramp_delay;
-       struct pwm_args pargs;
-       unsigned int req_diff = min_uV - rdev->constraints->min_uV;
-       unsigned int diff;
-       unsigned int duty_pulse;
-       u64 req_period;
-       u32 rem;
+       int min_uV = rdev->constraints->min_uV;
+       int max_uV = rdev->constraints->max_uV;
+       int diff_uV = max_uV - min_uV;
+       struct pwm_state pstate;
        int old_uV = pwm_regulator_get_voltage(rdev);
+       unsigned int diff_duty;
+       unsigned int dutycycle;
        int ret;
 
-       pwm_get_args(drvdata->pwm, &pargs);
-       diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
+       pwm_init_state(drvdata->pwm, &pstate);
 
-       /* First try to find out if we get the iduty cycle time which is
-        * factor of PWM period time. If (request_diff_to_min * pwm_period)
-        * is perfect divided by voltage_range_diff then it is possible to
-        * get duty cycle time which is factor of PWM period. This will help
-        * to get output voltage nearer to requested value as there is no
-        * calculation loss.
+       /*
+        * The dutycycle for min_uV might be greater than the one for max_uV.
+        * This is happening when the user needs an inversed polarity, but the
+        * PWM device does not support inversing it in hardware.
         */
-       req_period = req_diff * pargs.period;
-       div_u64_rem(req_period, diff, &rem);
-       if (!rem) {
-               do_div(req_period, diff);
-               duty_pulse = (unsigned int)req_period;
-       } else {
-               duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff);
-       }
+       if (max_uV_duty < min_uV_duty)
+               diff_duty = min_uV_duty - max_uV_duty;
+       else
+               diff_duty = max_uV_duty - min_uV_duty;
+
+       dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *
+                                         diff_duty,
+                                         diff_uV);
+
+       if (max_uV_duty < min_uV_duty)
+               dutycycle = min_uV_duty - dutycycle;
+       else
+               dutycycle = min_uV_duty + dutycycle;
+
+       pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
 
-       ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period);
+       ret = pwm_apply_state(drvdata->pwm, &pstate);
        if (ret) {
                dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
                return ret;
        }
 
-       drvdata->volt_uV = min_uV;
-
        if ((ramp_delay == 0) || !pwm_regulator_is_enabled(rdev))
                return 0;
 
        /* Ramp delay is in uV/uS. Adjust to uS and delay */
-       ramp_delay = DIV_ROUND_UP(abs(min_uV - old_uV), ramp_delay);
+       ramp_delay = DIV_ROUND_UP(abs(req_min_uV - old_uV), ramp_delay);
        usleep_range(ramp_delay, ramp_delay + DIV_ROUND_UP(ramp_delay, 10));
 
        return 0;
@@ -239,6 +297,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
                return ret;
        }
 
+       drvdata->state                  = -EINVAL;
        drvdata->duty_cycle_table       = duty_cycle_table;
        memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
               sizeof(drvdata->ops));
@@ -251,11 +310,28 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
 static int pwm_regulator_init_continuous(struct platform_device *pdev,
                                         struct pwm_regulator_data *drvdata)
 {
+       u32 dutycycle_range[2] = { 0, 100 };
+       u32 dutycycle_unit = 100;
+
        memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
               sizeof(drvdata->ops));
        drvdata->desc.ops = &drvdata->ops;
        drvdata->desc.continuous_voltage_range = true;
 
+       of_property_read_u32_array(pdev->dev.of_node,
+                                  "pwm-dutycycle-range",
+                                  dutycycle_range, 2);
+       of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",
+                            &dutycycle_unit);
+
+       if (dutycycle_range[0] > dutycycle_unit ||
+           dutycycle_range[1] > dutycycle_unit)
+               return -EINVAL;
+
+       drvdata->continuous.dutycycle_unit = dutycycle_unit;
+       drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];
+       drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];
+
        return 0;
 }
 
@@ -316,11 +392,9 @@ static int pwm_regulator_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /*
-        * FIXME: pwm_apply_args() should be removed when switching to the
-        * atomic PWM API.
-        */
-       pwm_apply_args(drvdata->pwm);
+       ret = pwm_adjust_config(drvdata->pwm);
+       if (ret)
+               return ret;
 
        regulator = devm_regulator_register(&pdev->dev,
                                            &drvdata->desc, &config);
index 2479188..2a1b2c7 100644 (file)
@@ -349,13 +349,12 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
 
 static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
 {
-       DEFINE_DMA_ATTRS(attrs);
+       unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
        dma_addr_t phys;
        void *ptr;
        int ret;
 
-       dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
-       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
+       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs);
        if (!ptr) {
                dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
@@ -372,7 +371,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
        else if (ret < 0)
                dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
 
-       dma_free_attrs(qproc->dev, fw->size, ptr, phys, &attrs);
+       dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);
 
        return ret < 0 ? ret : 0;
 }
index 18639e0..e215f50 100644 (file)
@@ -5,6 +5,10 @@
 config RTC_LIB
        bool
 
+config RTC_MC146818_LIB
+       bool
+       select RTC_LIB
+
 menuconfig RTC_CLASS
        bool "Real Time Clock"
        default n
@@ -574,10 +578,10 @@ config RTC_DRV_EM3027
          will be called rtc-em3027.
 
 config RTC_DRV_RV8803
-       tristate "Micro Crystal RV8803"
+       tristate "Micro Crystal RV8803, Epson RX8900"
        help
-         If you say yes here you get support for the Micro Crystal
-         RV8803 RTC chips.
+         If you say yes here you get support for the Micro Crystal RV8803 and
+         Epson RX8900 RTC chips.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-rv8803.
@@ -670,6 +674,18 @@ config RTC_DRV_DS1390
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1390.
 
+config RTC_DRV_MAX6916
+       tristate "Maxim MAX6916"
+       help
+         If you say yes here you will get support for the
+         Maxim MAX6916 SPI RTC chip.
+
+         This driver only supports the RTC feature, and not other chip
+         features such as alarms.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-max6916.
+
 config RTC_DRV_R9701
        tristate "Epson RTC-9701JE"
        help
@@ -795,8 +811,9 @@ comment "Platform RTC drivers"
 
 config RTC_DRV_CMOS
        tristate "PC-style 'CMOS'"
-       depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
+       depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || MN10300
        default y if X86
+       select RTC_MC146818_LIB
        help
          Say "yes" here to get direct support for the real time clock
          found in every PC or ACPI-based system, and some other boards.
@@ -815,6 +832,7 @@ config RTC_DRV_CMOS
 config RTC_DRV_ALPHA
        bool "Alpha PC-style CMOS"
        depends on ALPHA
+       select RTC_MC146818_LIB
        default y
        help
          Direct support for the real-time clock found on every Alpha
index ea28337..7cf7ad5 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_RTC_LIB)           += rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
 obj-$(CONFIG_RTC_SYSTOHC)      += systohc.o
 obj-$(CONFIG_RTC_CLASS)                += rtc-core.o
+obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
 rtc-core-y                     := class.o interface.o
 
 ifdef CONFIG_RTC_DRV_EFI
@@ -85,6 +86,7 @@ obj-$(CONFIG_RTC_DRV_M48T59)  += rtc-m48t59.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_MAX6900)  += rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MAX6916)  += rtc-max6916.o
 obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
 obj-$(CONFIG_RTC_DRV_MAX8907)  += rtc-max8907.o
 obj-$(CONFIG_RTC_DRV_MAX8925)  += rtc-max8925.o
index 9ef5f6f..84a52db 100644 (file)
@@ -104,7 +104,17 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
        else if (!rtc->ops->read_alarm)
                err = -EINVAL;
        else {
-               memset(alarm, 0, sizeof(struct rtc_wkalrm));
+               alarm->enabled = 0;
+               alarm->pending = 0;
+               alarm->time.tm_sec = -1;
+               alarm->time.tm_min = -1;
+               alarm->time.tm_hour = -1;
+               alarm->time.tm_mday = -1;
+               alarm->time.tm_mon = -1;
+               alarm->time.tm_year = -1;
+               alarm->time.tm_wday = -1;
+               alarm->time.tm_yday = -1;
+               alarm->time.tm_isdst = -1;
                err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
        }
 
@@ -383,7 +393,7 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
        rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
        rtc->aie_timer.period = ktime_set(0, 0);
 
-       /* Alarm has to be enabled & in the futrure for us to enqueue it */
+       /* Alarm has to be enabled & in the future for us to enqueue it */
        if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
                         rtc->aie_timer.node.expires.tv64)) {
 
@@ -395,8 +405,6 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 }
 EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
 
-
-
 int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 {
        int err = mutex_lock_interruptible(&rtc->ops_lock);
@@ -748,9 +756,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
  */
 static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 {
+       struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
+       struct rtc_time tm;
+       ktime_t now;
+
        timer->enabled = 1;
+       __rtc_read_time(rtc, &tm);
+       now = rtc_tm_to_ktime(tm);
+
+       /* Skip over expired timers */
+       while (next) {
+               if (next->expires.tv64 >= now.tv64)
+                       break;
+               next = timerqueue_iterate_next(next);
+       }
+
        timerqueue_add(&rtc->timerqueue, &timer->node);
-       if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
+       if (!next) {
                struct rtc_wkalrm alarm;
                int err;
                alarm.time = rtc_ktime_to_tm(timer->node.expires);
index ba0d619..fea9a60 100644 (file)
@@ -643,17 +643,15 @@ static int abx80x_probe(struct i2c_client *client,
                return err;
        }
 
-       err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group,
-                             &client->dev);
-       if (err) {
-               rtc_calib_remove_sysfs_group(&client->dev);
+       err = devm_add_action_or_reset(&client->dev,
+                                      rtc_calib_remove_sysfs_group,
+                                      &client->dev);
+       if (err)
                dev_err(&client->dev,
                        "Failed to add sysfs cleanup action: %d\n",
                        err);
-               return err;
-       }
 
-       return 0;
+       return err;
 }
 
 static int abx80x_remove(struct i2c_client *client)
index 355fdb9..5219916 100644 (file)
@@ -343,7 +343,6 @@ static struct platform_driver asm9260_rtc_driver = {
        .remove         = asm9260_rtc_remove,
        .driver         = {
                .name   = "asm9260-rtc",
-               .owner  = THIS_MODULE,
                .of_match_table = asm9260_dt_ids,
        },
 };
index 99732e6..7418a76 100644 (file)
@@ -375,6 +375,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
        if (!rtc)
                return -ENOMEM;
 
+       spin_lock_init(&rtc->lock);
        rtc->irq = irq;
 
        /* platform setup code should have handled this; sigh */
index fbe9c72..43745ca 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/of_platform.h>
 
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
-#include <asm-generic/rtc.h>
+#include <linux/mc146818rtc.h>
 
 struct cmos_rtc {
        struct rtc_device       *rtc;
@@ -190,10 +190,10 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
 static int cmos_read_time(struct device *dev, struct rtc_time *t)
 {
        /* REVISIT:  if the clock has a "century" register, use
-        * that instead of the heuristic in get_rtc_time().
+        * that instead of the heuristic in mc146818_get_time().
         * That'll make Y3K compatility (year > 2070) easy!
         */
-       get_rtc_time(t);
+       mc146818_get_time(t);
        return 0;
 }
 
@@ -205,7 +205,7 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t)
         * takes effect exactly 500ms after we write the register.
         * (Also queueing and other delays before we get this far.)
         */
-       return set_rtc_time(t);
+       return mc146818_set_time(t);
 }
 
 static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -220,8 +220,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
         * Some also support day and month, for alarms up to a year in
         * the future.
         */
-       t->time.tm_mday = -1;
-       t->time.tm_mon = -1;
 
        spin_lock_irq(&rtc_lock);
        t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
@@ -272,7 +270,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                        }
                }
        }
-       t->time.tm_year = -1;
 
        t->enabled = !!(rtc_control & RTC_AIE);
        t->pending = 0;
@@ -630,7 +627,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        address_space = 64;
 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
                        || defined(__sparc__) || defined(__mips__) \
-                       || defined(__powerpc__)
+                       || defined(__powerpc__) || defined(CONFIG_MN10300)
        address_space = 128;
 #else
 #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -1142,14 +1139,14 @@ static __init void cmos_of_init(struct platform_device *pdev)
        if (val)
                CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
 
-       get_rtc_time(&time);
+       cmos_read_time(&pdev->dev, &time);
        ret = rtc_valid_tm(&time);
        if (ret) {
                struct rtc_time def_time = {
                        .tm_year = 1,
                        .tm_mday = 1,
                };
-               set_rtc_time(&def_time);
+               cmos_set_time(&pdev->dev, &def_time);
        }
 }
 #else
index a20bcf0..4273377 100644 (file)
@@ -85,6 +85,7 @@ static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
                        rtc_tm->tm_mday = v[0][2] & DA9052_RTC_DAY;
                        rtc_tm->tm_hour = v[0][1] & DA9052_RTC_HOUR;
                        rtc_tm->tm_min  = v[0][0] & DA9052_RTC_MIN;
+                       rtc_tm->tm_sec = 0;
 
                        ret = rtc_valid_tm(rtc_tm);
                        return ret;
index 7ec0872..678af86 100644 (file)
@@ -74,6 +74,7 @@ static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
        rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY;
        rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR;
        rtc_tm->tm_min  = v[0] & DA9055_RTC_ALM_MIN;
+       rtc_tm->tm_sec = 0;
 
        return rtc_valid_tm(rtc_tm);
 }
index c5432bf..dba60c1 100644 (file)
@@ -388,6 +388,8 @@ static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        u8 day0, day1;
        unsigned long flags;
 
+       alm->time.tm_sec = 0;
+
        spin_lock_irqsave(&davinci_rtc_lock, flags);
 
        davinci_rtcss_calendar_wait(davinci_rtc);
index 756e509..ef75c34 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 #include <linux/bcd.h>
-#include <linux/ds1286.h>
+#include <linux/rtc/ds1286.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 
index 8e41c46..72b2293 100644 (file)
@@ -313,13 +313,6 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
        alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
        alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
        alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
-       alm->time.tm_mday = -1;
-       alm->time.tm_mon = -1;
-       alm->time.tm_year = -1;
-       /* next three fields are unused by Linux */
-       alm->time.tm_wday = -1;
-       alm->time.tm_mday = -1;
-       alm->time.tm_isdst = -1;
 
        return 0;
 }
index 821d9c0..8e1c5cb 100644 (file)
@@ -482,11 +482,6 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
        t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
        t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-       t->time.tm_wday = -1;
-       t->time.tm_yday = -1;
-       t->time.tm_isdst = -1;
 
        /* ... and status */
        t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
@@ -602,6 +597,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
  * Alarm support for mcp794xx devices.
  */
 
+#define MCP794XX_REG_WEEKDAY           0x3
+#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
 #define MCP794XX_REG_CONTROL           0x07
 #      define MCP794XX_BIT_ALM0_EN     0x10
 #      define MCP794XX_BIT_ALM1_EN     0x20
@@ -1231,13 +1228,16 @@ static int ds1307_probe(struct i2c_client *client,
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
-       int                     tmp;
+       int                     tmp, wday;
        struct chip_desc        *chip = &chips[id->driver_data];
        struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
        unsigned char           *buf;
        struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct rtc_time         tm;
+       unsigned long           timestamp;
+
        irq_handler_t   irq_handler = ds1307_irq;
 
        static const int        bbsqi_bitpos[] = {
@@ -1526,6 +1526,27 @@ read_rtc:
                                bin2bcd(tmp));
        }
 
+       /*
+        * Some IPs have weekday reset value = 0x1 which might not correct
+        * hence compute the wday using the current date/month/year values
+        */
+       ds1307_get_time(&client->dev, &tm);
+       wday = tm.tm_wday;
+       timestamp = rtc_tm_to_time64(&tm);
+       rtc_time64_to_tm(timestamp, &tm);
+
+       /*
+        * Check if reset wday is different from the computed wday
+        * If different then set the wday which we computed using
+        * timestamp
+        */
+       if (wday != tm.tm_wday) {
+               wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
+               wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
+               wday = wday | (tm.tm_wday + 1);
+               i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
+       }
+
        if (want_irq) {
                device_set_wakeup_capable(&client->dev, true);
                set_bit(HAS_ALARM, &ds1307->flags);
index 23fa9f0..895fbee 100644 (file)
@@ -504,12 +504,6 @@ static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour;
        alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday;
 
-       alarm->time.tm_mon = -1;
-       alarm->time.tm_year = -1;
-       alarm->time.tm_wday = -1;
-       alarm->time.tm_yday = -1;
-       alarm->time.tm_isdst = -1;
-
 out:
        mutex_unlock(&priv->mutex);
        return res;
index b3ce3c6..ed43b43 100644 (file)
@@ -102,6 +102,26 @@ ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask)
        return (val & bin_mask);
 }
 
+/**
+ * s1685_rtc_check_mday - check validity of the day of month.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @mday: day of month.
+ *
+ * Returns -EDOM if the day of month is not within 1..31 range.
+ */
+static inline int
+ds1685_rtc_check_mday(struct ds1685_priv *rtc, u8 mday)
+{
+       if (rtc->bcd_mode) {
+               if (mday < 0x01 || mday > 0x31 || (mday & 0x0f) > 0x09)
+                       return -EDOM;
+       } else {
+               if (mday < 1 || mday > 31)
+                       return -EDOM;
+       }
+       return 0;
+}
+
 /**
  * ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0.
  * @rtc: pointer to the ds1685 rtc structure.
@@ -377,6 +397,7 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct platform_device *pdev = to_platform_device(dev);
        struct ds1685_priv *rtc = platform_get_drvdata(pdev);
        u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
+       int ret;
 
        /* Fetch the alarm info from the RTC alarm registers. */
        ds1685_rtc_begin_data_access(rtc);
@@ -388,34 +409,29 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        ctrlc   = rtc->read(rtc, RTC_CTRL_C);
        ds1685_rtc_end_data_access(rtc);
 
-       /* Check month date. */
-       if (!(mday >= 1) && (mday <= 31))
-               return -EDOM;
+       /* Check the month date for validity. */
+       ret = ds1685_rtc_check_mday(rtc, mday);
+       if (ret)
+               return ret;
 
        /*
         * Check the three alarm bytes.
         *
         * The Linux RTC system doesn't support the "don't care" capability
         * of this RTC chip.  We check for it anyways in case support is
-        * added in the future.
+        * added in the future and only assign when we care.
         */
-       if (unlikely(seconds >= 0xc0))
-               alrm->time.tm_sec = -1;
-       else
+       if (likely(seconds < 0xc0))
                alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
                                                       RTC_SECS_BCD_MASK,
                                                       RTC_SECS_BIN_MASK);
 
-       if (unlikely(minutes >= 0xc0))
-               alrm->time.tm_min = -1;
-       else
+       if (likely(minutes < 0xc0))
                alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
                                                       RTC_MINS_BCD_MASK,
                                                       RTC_MINS_BIN_MASK);
 
-       if (unlikely(hours >= 0xc0))
-               alrm->time.tm_hour = -1;
-       else
+       if (likely(hours < 0xc0))
                alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
                                                        RTC_HRS_24_BCD_MASK,
                                                        RTC_HRS_24_BIN_MASK);
@@ -423,11 +439,6 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        /* Write the data to rtc_wkalrm. */
        alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
                                                RTC_MDAY_BIN_MASK);
-       alrm->time.tm_mon = -1;
-       alrm->time.tm_year = -1;
-       alrm->time.tm_wday = -1;
-       alrm->time.tm_yday = -1;
-       alrm->time.tm_isdst = -1;
        alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE);
        alrm->pending = !!(ctrlc & RTC_CTRL_C_AF);
 
@@ -445,6 +456,7 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct platform_device *pdev = to_platform_device(dev);
        struct ds1685_priv *rtc = platform_get_drvdata(pdev);
        u8 ctrlb, seconds, minutes, hours, mday;
+       int ret;
 
        /* Fetch the alarm info and convert to BCD. */
        seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec,
@@ -461,8 +473,9 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
                                     RTC_MDAY_BCD_MASK);
 
        /* Check the month date for validity. */
-       if (!(mday >= 1) && (mday <= 31))
-               return -EDOM;
+       ret = ds1685_rtc_check_mday(rtc, mday);
+       if (ret)
+               return ret;
 
        /*
         * Check the three alarm bytes.
index 16310fe..9a1582e 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/rtc.h>
 #include <linux/types.h>
 #include <linux/bcd.h>
-#include <linux/rtc-ds2404.h>
+#include <linux/platform_data/rtc-ds2404.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
index 04fbd7f..b1f20d8 100644 (file)
@@ -197,12 +197,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
        alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
 
-       alarm->time.tm_mon = -1;
-       alarm->time.tm_year = -1;
-       alarm->time.tm_wday = -1;
-       alarm->time.tm_yday = -1;
-       alarm->time.tm_isdst = -1;
-
        alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
        alarm->pending = !!(stat & DS3232_REG_SR_A1F);
 
index 96d3860..0130afd 100644 (file)
@@ -259,6 +259,12 @@ static const struct rtc_class_ops efi_rtc_ops = {
 static int __init efi_rtc_probe(struct platform_device *dev)
 {
        struct rtc_device *rtc;
+       efi_time_t eft;
+       efi_time_cap_t cap;
+
+       /* First check if the RTC is usable */
+       if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
+               return -ENODEV;
 
        rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
                                        THIS_MODULE);
index d726c6a..1bf5d23 100644 (file)
@@ -9,44 +9,10 @@
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 
-#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \
-    defined(CONFIG_PPC) || defined(CONFIG_SUPERH32)
-#include <asm/rtc.h>
-
-static int generic_get_time(struct device *dev, struct rtc_time *tm)
-{
-       unsigned int ret = get_rtc_time(tm);
-
-       if (ret & RTC_BATT_BAD)
-               return -EOPNOTSUPP;
-
-       return rtc_valid_tm(tm);
-}
-
-static int generic_set_time(struct device *dev, struct rtc_time *tm)
-{
-       if (set_rtc_time(tm) < 0)
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
-static const struct rtc_class_ops generic_rtc_ops = {
-       .read_time = generic_get_time,
-       .set_time = generic_set_time,
-};
-#else
-#define generic_rtc_ops *(struct rtc_class_ops*)NULL
-#endif
-
 static int __init generic_rtc_probe(struct platform_device *dev)
 {
        struct rtc_device *rtc;
-       const struct rtc_class_ops *ops;
-
-       ops = dev_get_platdata(&dev->dev);
-       if (!ops)
-               ops = &generic_rtc_ops;
+       const struct rtc_class_ops *ops = dev_get_platdata(&dev->dev);
 
        rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
                                        ops, THIS_MODULE);
index 2072703..e5ad527 100644 (file)
@@ -198,7 +198,7 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
                return ret;
 
        /* The alarm only has a minute accuracy */
-       alm_tm->tm_sec = -1;
+       alm_tm->tm_sec = 0;
 
        alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ?
                                        -1 :
@@ -213,9 +213,6 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
                                        -1 :
                                        bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK);
 
-       alm_tm->tm_mon = -1;
-       alm_tm->tm_year = -1;
-
        ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2);
        if (ret < 0)
                return ret;
index 54328d4..0e7f0f5 100644 (file)
@@ -245,8 +245,7 @@ static int isl12057_rtc_update_alarm(struct device *dev, int enable)
 static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 {
        struct isl12057_rtc_data *data = dev_get_drvdata(dev);
-       struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
-       unsigned long rtc_secs, alarm_secs;
+       struct rtc_time *alarm_tm = &alarm->time;
        u8 regs[ISL12057_A1_SEC_LEN];
        unsigned int ir;
        int ret;
@@ -264,36 +263,6 @@ static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        alarm_tm->tm_min  = bcd2bin(regs[1] & 0x7f);
        alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f);
        alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f);
-       alarm_tm->tm_wday = -1;
-
-       /*
-        * The alarm section does not store year/month. We use the ones in rtc
-        * section as a basis and increment month and then year if needed to get
-        * alarm after current time.
-        */
-       ret = _isl12057_rtc_read_time(dev, &rtc_tm);
-       if (ret)
-               goto err_unlock;
-
-       alarm_tm->tm_year = rtc_tm.tm_year;
-       alarm_tm->tm_mon = rtc_tm.tm_mon;
-
-       ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
-       if (ret)
-               goto err_unlock;
-
-       ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
-       if (ret)
-               goto err_unlock;
-
-       if (alarm_secs < rtc_secs) {
-               if (alarm_tm->tm_mon == 11) {
-                       alarm_tm->tm_mon = 0;
-                       alarm_tm->tm_year += 1;
-               } else {
-                       alarm_tm->tm_mon += 1;
-               }
-       }
 
        ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir);
        if (ret) {
index d1bf93a..58698d2 100644 (file)
@@ -244,7 +244,7 @@ static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
        if (retval < 0) {
-               dev_info(dev, "Unable to enable alarm IRQ %d\n", retval);
+               dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
                return retval;
        }
        return 0;
@@ -320,10 +320,8 @@ static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        alrm->time.tm_sec  = bcd2bin(alarmvals[4] & 0x7f);
        alrm->time.tm_min  = bcd2bin(alarmvals[3] & 0x7f);
        alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
-       alrm->time.tm_wday = -1;
        alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
        alrm->time.tm_mon  = bcd2bin(alarmvals[0] & 0x3f);
-       alrm->time.tm_year = -1;
 
        alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
        alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
@@ -337,6 +335,30 @@ static struct rtc_class_ops m41t80_rtc_ops = {
        .proc = m41t80_rtc_proc,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int m41t80_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (client->irq >= 0 && device_may_wakeup(dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int m41t80_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (client->irq >= 0 && device_may_wakeup(dev))
+               disable_irq_wake(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
+
 static ssize_t flags_show(struct device *dev,
                          struct device_attribute *attr, char *buf)
 {
@@ -831,10 +853,9 @@ static int m41t80_probe(struct i2c_client *client,
                return rc;
        }
 
-       rc = devm_add_action(&client->dev, m41t80_remove_sysfs_group,
-                            &client->dev);
+       rc = devm_add_action_or_reset(&client->dev, m41t80_remove_sysfs_group,
+                                     &client->dev);
        if (rc) {
-               m41t80_remove_sysfs_group(&client->dev);
                dev_err(&client->dev,
                        "Failed to add sysfs cleanup action: %d\n", rc);
                return rc;
@@ -873,6 +894,7 @@ static int m41t80_remove(struct i2c_client *client)
 static struct i2c_driver m41t80_driver = {
        .driver = {
                .name = "rtc-m41t80",
+               .pm = &m41t80_pm,
        },
        .probe = m41t80_probe,
        .remove = m41t80_remove,
index f72b91f..0eeb571 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
-#include <linux/m48t86.h>
+#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/bcd.h>
 
 #define M48T86_REG_SEC         0x00
diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c
new file mode 100644 (file)
index 0000000..623ab27
--- /dev/null
@@ -0,0 +1,164 @@
+/* rtc-max6916.c
+ *
+ * Driver for MAXIM  max6916 Low Current, SPI Compatible
+ * Real Time Clock
+ *
+ * Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+/* Registers in max6916 rtc */
+
+#define MAX6916_SECONDS_REG    0x01
+#define MAX6916_MINUTES_REG    0x02
+#define MAX6916_HOURS_REG      0x03
+#define MAX6916_DATE_REG       0x04
+#define MAX6916_MONTH_REG      0x05
+#define MAX6916_DAY_REG        0x06
+#define MAX6916_YEAR_REG       0x07
+#define MAX6916_CONTROL_REG    0x08
+#define MAX6916_STATUS_REG     0x0C
+#define MAX6916_CLOCK_BURST    0x3F
+
+static int max6916_read_reg(struct device *dev, unsigned char address,
+                           unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       *data = address | 0x80;
+
+       return spi_write_then_read(spi, data, 1, data, 1);
+}
+
+static int max6916_write_reg(struct device *dev, unsigned char address,
+                            unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       buf[0] = address & 0x7F;
+       buf[1] = data;
+
+       return spi_write_then_read(spi, buf, 2, NULL, 0);
+}
+
+static int max6916_read_time(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       int err;
+       unsigned char buf[8];
+
+       buf[0] = MAX6916_CLOCK_BURST | 0x80;
+
+       err = spi_write_then_read(spi, buf, 1, buf, 8);
+
+       if (err)
+               return err;
+
+       dt->tm_sec = bcd2bin(buf[0]);
+       dt->tm_min = bcd2bin(buf[1]);
+       dt->tm_hour = bcd2bin(buf[2] & 0x3F);
+       dt->tm_mday = bcd2bin(buf[3]);
+       dt->tm_mon = bcd2bin(buf[4]) - 1;
+       dt->tm_wday = bcd2bin(buf[5]) - 1;
+       dt->tm_year = bcd2bin(buf[6]) + 100;
+
+       return rtc_valid_tm(dt);
+}
+
+static int max6916_set_time(struct device *dev, struct rtc_time *dt)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[9];
+
+       if (dt->tm_year < 100 || dt->tm_year > 199) {
+               dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n",
+                       dt->tm_year + 1900);
+       return -EINVAL;
+       }
+
+       buf[0] = MAX6916_CLOCK_BURST & 0x7F;
+       buf[1] = bin2bcd(dt->tm_sec);
+       buf[2] = bin2bcd(dt->tm_min);
+       buf[3] = (bin2bcd(dt->tm_hour) & 0X3F);
+       buf[4] = bin2bcd(dt->tm_mday);
+       buf[5] = bin2bcd(dt->tm_mon + 1);
+       buf[6] = bin2bcd(dt->tm_wday + 1);
+       buf[7] = bin2bcd(dt->tm_year % 100);
+       buf[8] = bin2bcd(0x00);
+
+       /* write the rtc settings */
+       return spi_write_then_read(spi, buf, 9, NULL, 0);
+}
+
+static const struct rtc_class_ops max6916_rtc_ops = {
+       .read_time = max6916_read_time,
+       .set_time = max6916_set_time,
+};
+
+static int max6916_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char data;
+       int res;
+
+       /* spi setup with max6916 in mode 3 and bits per word as 8 */
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+
+       /* RTC Settings */
+       res = max6916_read_reg(&spi->dev, MAX6916_SECONDS_REG, &data);
+       if (res)
+               return res;
+
+       /* Disable the write protect of rtc */
+       max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
+       data = data & ~(1 << 7);
+       max6916_write_reg(&spi->dev, MAX6916_CONTROL_REG, data);
+
+       /*Enable oscillator,disable oscillator stop flag, glitch filter*/
+       max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
+       data = data & 0x1B;
+       max6916_write_reg(&spi->dev, MAX6916_STATUS_REG, data);
+
+       /* display the settings */
+       max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
+       dev_info(&spi->dev, "MAX6916 RTC CTRL Reg = 0x%02x\n", data);
+
+       max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
+       dev_info(&spi->dev, "MAX6916 RTC Status Reg = 0x%02x\n", data);
+
+       rtc = devm_rtc_device_register(&spi->dev, "max6916",
+                                      &max6916_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       spi_set_drvdata(spi, rtc);
+
+       return 0;
+}
+
+static struct spi_driver max6916_driver = {
+       .driver = {
+               .name = "max6916",
+       },
+       .probe = max6916_probe,
+};
+module_spi_driver(max6916_driver);
+
+MODULE_DESCRIPTION("MAX6916 SPI RTC DRIVER");
+MODULE_AUTHOR("Venkat Prashanth B U <venkat.prashanth2498@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c
new file mode 100644 (file)
index 0000000..2f1772a
--- /dev/null
@@ -0,0 +1,198 @@
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/mc146818rtc.h>
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif
+
+/*
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char mc146818_is_updating(void)
+{
+       unsigned char uip;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc_lock, flags);
+       uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+       return uip;
+}
+
+unsigned int mc146818_get_time(struct rtc_time *time)
+{
+       unsigned char ctrl;
+       unsigned long flags;
+       unsigned char century = 0;
+
+#ifdef CONFIG_MACH_DECSTATION
+       unsigned int real_year;
+#endif
+
+       /*
+        * read RTC once any update in progress is done. The update
+        * can take just over 2ms. We wait 20ms. There is no need to
+        * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+        * If you need to know *exactly* when a second has started, enable
+        * periodic update complete interrupts, (via ioctl) and then
+        * immediately read /dev/rtc which will block until you get the IRQ.
+        * Once the read clears, read the RTC time (again via ioctl). Easy.
+        */
+       if (mc146818_is_updating())
+               mdelay(20);
+
+       /*
+        * Only the values that we read from the RTC are set. We leave
+        * tm_wday, tm_yday and tm_isdst untouched. Even though the
+        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+        * by the RTC when initially set to a non-zero value.
+        */
+       spin_lock_irqsave(&rtc_lock, flags);
+       time->tm_sec = CMOS_READ(RTC_SECONDS);
+       time->tm_min = CMOS_READ(RTC_MINUTES);
+       time->tm_hour = CMOS_READ(RTC_HOURS);
+       time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+       time->tm_mon = CMOS_READ(RTC_MONTH);
+       time->tm_year = CMOS_READ(RTC_YEAR);
+#ifdef CONFIG_MACH_DECSTATION
+       real_year = CMOS_READ(RTC_DEC_YEAR);
+#endif
+#ifdef CONFIG_ACPI
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+           acpi_gbl_FADT.century)
+               century = CMOS_READ(acpi_gbl_FADT.century);
+#endif
+       ctrl = CMOS_READ(RTC_CONTROL);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
+       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+       {
+               time->tm_sec = bcd2bin(time->tm_sec);
+               time->tm_min = bcd2bin(time->tm_min);
+               time->tm_hour = bcd2bin(time->tm_hour);
+               time->tm_mday = bcd2bin(time->tm_mday);
+               time->tm_mon = bcd2bin(time->tm_mon);
+               time->tm_year = bcd2bin(time->tm_year);
+               century = bcd2bin(century);
+       }
+
+#ifdef CONFIG_MACH_DECSTATION
+       time->tm_year += real_year - 72;
+#endif
+
+       if (century)
+               time->tm_year += (century - 19) * 100;
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+       if (time->tm_year <= 69)
+               time->tm_year += 100;
+
+       time->tm_mon--;
+
+       return RTC_24H;
+}
+EXPORT_SYMBOL_GPL(mc146818_get_time);
+
+/* Set the current date and time in the real time clock. */
+int mc146818_set_time(struct rtc_time *time)
+{
+       unsigned long flags;
+       unsigned char mon, day, hrs, min, sec;
+       unsigned char save_control, save_freq_select;
+       unsigned int yrs;
+#ifdef CONFIG_MACH_DECSTATION
+       unsigned int real_yrs, leap_yr;
+#endif
+       unsigned char century = 0;
+
+       yrs = time->tm_year;
+       mon = time->tm_mon + 1;   /* tm_mon starts at zero */
+       day = time->tm_mday;
+       hrs = time->tm_hour;
+       min = time->tm_min;
+       sec = time->tm_sec;
+
+       if (yrs > 255)  /* They are unsigned */
+               return -EINVAL;
+
+       spin_lock_irqsave(&rtc_lock, flags);
+#ifdef CONFIG_MACH_DECSTATION
+       real_yrs = yrs;
+       leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
+                       !((yrs + 1900) % 400));
+       yrs = 72;
+
+       /*
+        * We want to keep the year set to 73 until March
+        * for non-leap years, so that Feb, 29th is handled
+        * correctly.
+        */
+       if (!leap_yr && mon < 3) {
+               real_yrs--;
+               yrs = 73;
+       }
+#endif
+
+#ifdef CONFIG_ACPI
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+           acpi_gbl_FADT.century) {
+               century = (yrs + 1900) / 100;
+               yrs %= 100;
+       }
+#endif
+
+       /* These limits and adjustments are independent of
+        * whether the chip is in binary mode or not.
+        */
+       if (yrs > 169) {
+               spin_unlock_irqrestore(&rtc_lock, flags);
+               return -EINVAL;
+       }
+
+       if (yrs >= 100)
+               yrs -= 100;
+
+       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+           || RTC_ALWAYS_BCD) {
+               sec = bin2bcd(sec);
+               min = bin2bcd(min);
+               hrs = bin2bcd(hrs);
+               day = bin2bcd(day);
+               mon = bin2bcd(mon);
+               yrs = bin2bcd(yrs);
+               century = bin2bcd(century);
+       }
+
+       save_control = CMOS_READ(RTC_CONTROL);
+       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+#ifdef CONFIG_MACH_DECSTATION
+       CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
+#endif
+       CMOS_WRITE(yrs, RTC_YEAR);
+       CMOS_WRITE(mon, RTC_MONTH);
+       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+       CMOS_WRITE(hrs, RTC_HOURS);
+       CMOS_WRITE(min, RTC_MINUTES);
+       CMOS_WRITE(sec, RTC_SECONDS);
+#ifdef CONFIG_ACPI
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+           acpi_gbl_FADT.century)
+               CMOS_WRITE(century, acpi_gbl_FADT.century);
+#endif
+
+       CMOS_WRITE(save_control, RTC_CONTROL);
+       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mc146818_set_time);
index 0094d9b..7334c44 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
 
-#include <asm-generic/rtc.h>
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
 #include <asm/intel_mid_vrtc.h>
@@ -149,14 +149,6 @@ static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        if (mrst->irq <= 0)
                return -EIO;
 
-       /* Basic alarms only support hour, minute, and seconds fields.
-        * Some also support day and month, for alarms up to a year in
-        * the future.
-        */
-       t->time.tm_mday = -1;
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-
        /* vRTC only supports binary mode */
        spin_lock_irq(&rtc_lock);
        t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM);
index f22e060..b4478cc 100644 (file)
@@ -96,7 +96,7 @@
 #define CD_TMR_TE              BIT(3)  /* Countdown timer enable */
 
 /* PCF2123_REG_OFFSET BITS */
-#define OFFSET_SIGN_BIT                BIT(6)  /* 2's complement sign bit */
+#define OFFSET_SIGN_BIT                6       /* 2's complement sign bit */
 #define OFFSET_COARSE          BIT(7)  /* Coarse mode offset */
 #define OFFSET_STEP            (2170)  /* Offset step in parts per billion */
 
@@ -217,7 +217,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
        if (reg & OFFSET_COARSE)
                reg <<= 1; /* multiply by 2 and sign extend */
        else
-               reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */
+               reg = sign_extend32(reg, OFFSET_SIGN_BIT);
 
        *offset = ((long)reg) * OFFSET_STEP;
 
index e8ddbb3..efb0a08 100644 (file)
 #include <linux/rtc.h>
 #include <linux/module.h>
 
+/*
+ * Information for this driver was pulled from the following datasheets.
+ *
+ *  http://www.nxp.com/documents/data_sheet/PCF85063A.pdf
+ *  http://www.nxp.com/documents/data_sheet/PCF85063TP.pdf
+ *
+ *  PCF85063A -- Rev. 6 — 18 November 2015
+ *  PCF85063TP -- Rev. 4 — 6 May 2015
+*/
+
 #define PCF85063_REG_CTRL1             0x00 /* status */
 #define PCF85063_REG_CTRL1_STOP                BIT(5)
 #define PCF85063_REG_CTRL2             0x01
@@ -55,10 +65,22 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
        return 0;
 }
 
-/*
- * In the routines that deal directly with the pcf85063 hardware, we use
- * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
- */
+static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
+{
+       s32 ret;
+
+       /* start the clock */
+       ctrl1 &= PCF85063_REG_CTRL1_STOP;
+
+       ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failing to start the clock\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
        int rc;
@@ -90,8 +112,7 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
        tm->tm_wday = regs[4] & 0x07;
        tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
        tm->tm_year = bcd2bin(regs[6]);
-       if (tm->tm_year < 70)
-               tm->tm_year += 100;     /* assume we are in 1970...2069 */
+       tm->tm_year += 100;
 
        return rtc_valid_tm(tm);
 }
@@ -99,13 +120,17 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
        int rc;
-       u8 regs[8];
+       u8 regs[7];
+       u8 ctrl1;
+
+       if ((tm->tm_year < 100) || (tm->tm_year > 199))
+               return -EINVAL;
 
        /*
         * to accurately set the time, reset the divider chain and keep it in
         * reset state until all time/date registers are written
         */
-       rc = pcf85063_stop_clock(client, &regs[7]);
+       rc = pcf85063_stop_clock(client, &ctrl1);
        if (rc != 0)
                return rc;
 
@@ -125,14 +150,7 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
        regs[5] = bin2bcd(tm->tm_mon + 1);
 
        /* year and century */
-       regs[6] = bin2bcd(tm->tm_year % 100);
-
-       /*
-        * after all time/date registers are written, let the 'address auto
-        * increment' feature wrap around and write register CTRL1 to re-enable
-        * the clock divider chain again
-        */
-       regs[7] &= ~PCF85063_REG_CTRL1_STOP;
+       regs[6] = bin2bcd(tm->tm_year - 100);
 
        /* write all registers at once */
        rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
@@ -142,6 +160,15 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
                return rc;
        }
 
+       /*
+        * Write the control register as a separate action since the size of
+        * the register space is different between the PCF85063TP and
+        * PCF85063A devices.  The rollover point can not be used.
+        */
+       rc = pcf85063_start_clock(client, ctrl1);
+       if (rc != 0)
+               return rc;
+
        return 0;
 }
 
index b9ddbb0..1227cea 100644 (file)
@@ -341,14 +341,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
                "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
                __func__, buf[0], buf[1], buf[2], buf[3]);
 
+       tm->time.tm_sec = 0;
        tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
        tm->time.tm_hour = bcd2bin(buf[1] & 0x3F);
        tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
        tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
-       tm->time.tm_mon = -1;
-       tm->time.tm_year = -1;
-       tm->time.tm_yday = -1;
-       tm->time.tm_isdst = -1;
 
        err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
        if (err < 0)
index f28d577..68ce774 100644 (file)
@@ -128,6 +128,7 @@ static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
                return ret;
        }
 
+       alm->time.tm_sec = 0;
        alm->time.tm_min = bcd2bin(alarm_data[0]);
        alm->time.tm_hour = bcd2bin(alarm_data[1]);
        alm->time.tm_mday = bcd2bin(alarm_data[2]);
index ef86229..c8c7574 100644 (file)
@@ -341,12 +341,6 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        t->time.tm_sec = 0;
        t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
        t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
-       t->time.tm_mday = -1;
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-       t->time.tm_wday = -1;
-       t->time.tm_yday = -1;
-       t->time.tm_isdst = -1;
 
        /* ... and status */
        t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
index f623038..9a2f6a9 100644 (file)
 
 #include <linux/bcd.h>
 #include <linux/bitops.h>
+#include <linux/log2.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
 
+#define RV8803_I2C_TRY_COUNT           4
+
 #define RV8803_SEC                     0x00
 #define RV8803_MIN                     0x01
 #define RV8803_HOUR                    0x02
@@ -56,19 +59,85 @@ struct rv8803_data {
        u8 ctrl;
 };
 
+static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
+{
+       int try = RV8803_I2C_TRY_COUNT;
+       s32 ret;
+
+       /*
+        * There is a 61µs window during which the RTC does not acknowledge I2C
+        * transfers. In that case, ensure that there are multiple attempts.
+        */
+       do
+               ret = i2c_smbus_read_byte_data(client, reg);
+       while ((ret == -ENXIO || ret == -EIO) && --try);
+       if (ret < 0)
+               dev_err(&client->dev, "Unable to read register 0x%02x\n", reg);
+
+       return ret;
+}
+
+static int rv8803_read_regs(const struct i2c_client *client,
+                           u8 reg, u8 count, u8 *values)
+{
+       int try = RV8803_I2C_TRY_COUNT;
+       s32 ret;
+
+       do
+               ret = i2c_smbus_read_i2c_block_data(client, reg, count, values);
+       while ((ret == -ENXIO || ret == -EIO) && --try);
+       if (ret != count) {
+               dev_err(&client->dev,
+                       "Unable to read registers 0x%02x..0x%02x\n",
+                       reg, reg + count - 1);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       return 0;
+}
+
+static int rv8803_write_reg(const struct i2c_client *client, u8 reg, u8 value)
+{
+       int try = RV8803_I2C_TRY_COUNT;
+       s32 ret;
+
+       do
+               ret = i2c_smbus_write_byte_data(client, reg, value);
+       while ((ret == -ENXIO || ret == -EIO) && --try);
+       if (ret)
+               dev_err(&client->dev, "Unable to write register 0x%02x\n", reg);
+
+       return ret;
+}
+
+static int rv8803_write_regs(const struct i2c_client *client,
+                            u8 reg, u8 count, const u8 *values)
+{
+       int try = RV8803_I2C_TRY_COUNT;
+       s32 ret;
+
+       do
+               ret = i2c_smbus_write_i2c_block_data(client, reg, count,
+                                                    values);
+       while ((ret == -ENXIO || ret == -EIO) && --try);
+       if (ret)
+               dev_err(&client->dev,
+                       "Unable to write registers 0x%02x..0x%02x\n",
+                       reg, reg + count - 1);
+
+       return ret;
+}
+
 static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
 {
        struct i2c_client *client = dev_id;
        struct rv8803_data *rv8803 = i2c_get_clientdata(client);
        unsigned long events = 0;
-       int flags, try = 0;
+       int flags;
 
        mutex_lock(&rv8803->flags_lock);
 
-       do {
-               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
-               try++;
-       } while ((flags == -ENXIO) && (try < 3));
+       flags = rv8803_read_reg(client, RV8803_FLAG);
        if (flags <= 0) {
                mutex_unlock(&rv8803->flags_lock);
                return IRQ_NONE;
@@ -100,9 +169,8 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
 
        if (events) {
                rtc_update_irq(rv8803->rtc, 1, events);
-               i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
-               i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
-                                         rv8803->ctrl);
+               rv8803_write_reg(client, RV8803_FLAG, flags);
+               rv8803_write_reg(rv8803->client, RV8803_CTRL, rv8803->ctrl);
        }
 
        mutex_unlock(&rv8803->flags_lock);
@@ -118,7 +186,7 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
        u8 *date = date1;
        int ret, flags;
 
-       flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
+       flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
        if (flags < 0)
                return flags;
 
@@ -127,16 +195,14 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
                return -EINVAL;
        }
 
-       ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
-                                           7, date);
-       if (ret != 7)
-               return ret < 0 ? ret : -EIO;
+       ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date);
+       if (ret)
+               return ret;
 
        if ((date1[RV8803_SEC] & 0x7f) == bin2bcd(59)) {
-               ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
-                                                   7, date2);
-               if (ret != 7)
-                       return ret < 0 ? ret : -EIO;
+               ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date2);
+               if (ret)
+                       return ret;
 
                if ((date2[RV8803_SEC] & 0x7f) != bin2bcd(59))
                        date = date2;
@@ -145,23 +211,33 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
        tm->tm_sec  = bcd2bin(date[RV8803_SEC] & 0x7f);
        tm->tm_min  = bcd2bin(date[RV8803_MIN] & 0x7f);
        tm->tm_hour = bcd2bin(date[RV8803_HOUR] & 0x3f);
-       tm->tm_wday = ffs(date[RV8803_WEEK] & 0x7f);
+       tm->tm_wday = ilog2(date[RV8803_WEEK] & 0x7f);
        tm->tm_mday = bcd2bin(date[RV8803_DAY] & 0x3f);
        tm->tm_mon  = bcd2bin(date[RV8803_MONTH] & 0x1f) - 1;
        tm->tm_year = bcd2bin(date[RV8803_YEAR]) + 100;
 
-       return rtc_valid_tm(tm);
+       return 0;
 }
 
 static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct rv8803_data *rv8803 = dev_get_drvdata(dev);
        u8 date[7];
-       int flags, ret;
+       int ctrl, flags, ret;
 
        if ((tm->tm_year < 100) || (tm->tm_year > 199))
                return -EINVAL;
 
+       ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL);
+       if (ctrl < 0)
+               return ctrl;
+
+       /* Stop the clock */
+       ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
+                              ctrl | RV8803_CTRL_RESET);
+       if (ret)
+               return ret;
+
        date[RV8803_SEC]   = bin2bcd(tm->tm_sec);
        date[RV8803_MIN]   = bin2bcd(tm->tm_min);
        date[RV8803_HOUR]  = bin2bcd(tm->tm_hour);
@@ -170,21 +246,26 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
        date[RV8803_MONTH] = bin2bcd(tm->tm_mon + 1);
        date[RV8803_YEAR]  = bin2bcd(tm->tm_year - 100);
 
-       ret = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_SEC,
-                                            7, date);
-       if (ret < 0)
+       ret = rv8803_write_regs(rv8803->client, RV8803_SEC, 7, date);
+       if (ret)
+               return ret;
+
+       /* Restart the clock */
+       ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
+                              ctrl & ~RV8803_CTRL_RESET);
+       if (ret)
                return ret;
 
        mutex_lock(&rv8803->flags_lock);
 
-       flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
+       flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
        if (flags < 0) {
                mutex_unlock(&rv8803->flags_lock);
                return flags;
        }
 
-       ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
-                                       flags & ~RV8803_FLAG_V2F);
+       ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
+                              flags & ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F));
 
        mutex_unlock(&rv8803->flags_lock);
 
@@ -198,22 +279,18 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        u8 alarmvals[3];
        int flags, ret;
 
-       ret = i2c_smbus_read_i2c_block_data(client, RV8803_ALARM_MIN,
-                                           3, alarmvals);
-       if (ret != 3)
-               return ret < 0 ? ret : -EIO;
+       ret = rv8803_read_regs(client, RV8803_ALARM_MIN, 3, alarmvals);
+       if (ret)
+               return ret;
 
-       flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+       flags = rv8803_read_reg(client, RV8803_FLAG);
        if (flags < 0)
                return flags;
 
        alrm->time.tm_sec  = 0;
        alrm->time.tm_min  = bcd2bin(alarmvals[0] & 0x7f);
        alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
-       alrm->time.tm_wday = -1;
        alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
-       alrm->time.tm_mon  = -1;
-       alrm->time.tm_year = -1;
 
        alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
        alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
@@ -239,10 +316,10 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        mutex_lock(&rv8803->flags_lock);
 
-       ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
-       if (ret != 2) {
+       ret = rv8803_read_regs(client, RV8803_FLAG, 2, ctrl);
+       if (ret) {
                mutex_unlock(&rv8803->flags_lock);
-               return ret < 0 ? ret : -EIO;
+               return ret;
        }
 
        alarmvals[0] = bin2bcd(alrm->time.tm_min);
@@ -251,8 +328,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        if (rv8803->ctrl & (RV8803_CTRL_AIE | RV8803_CTRL_UIE)) {
                rv8803->ctrl &= ~(RV8803_CTRL_AIE | RV8803_CTRL_UIE);
-               err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
-                                               rv8803->ctrl);
+               err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
+                                      rv8803->ctrl);
                if (err) {
                        mutex_unlock(&rv8803->flags_lock);
                        return err;
@@ -260,13 +337,12 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        }
 
        ctrl[1] &= ~RV8803_FLAG_AF;
-       err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
+       err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]);
        mutex_unlock(&rv8803->flags_lock);
        if (err)
                return err;
 
-       err = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_ALARM_MIN,
-                                            3, alarmvals);
+       err = rv8803_write_regs(rv8803->client, RV8803_ALARM_MIN, 3, alarmvals);
        if (err)
                return err;
 
@@ -276,8 +352,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
                if (rv8803->rtc->aie_timer.enabled)
                        rv8803->ctrl |= RV8803_CTRL_AIE;
 
-               err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
-                                               rv8803->ctrl);
+               err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
+                                      rv8803->ctrl);
                if (err)
                        return err;
        }
@@ -306,21 +382,20 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
        }
 
        mutex_lock(&rv8803->flags_lock);
-       flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+       flags = rv8803_read_reg(client, RV8803_FLAG);
        if (flags < 0) {
                mutex_unlock(&rv8803->flags_lock);
                return flags;
        }
        flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
-       err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
+       err = rv8803_write_reg(client, RV8803_FLAG, flags);
        mutex_unlock(&rv8803->flags_lock);
        if (err)
                return err;
 
        if (ctrl != rv8803->ctrl) {
                rv8803->ctrl = ctrl;
-               err = i2c_smbus_write_byte_data(client, RV8803_CTRL,
-                                               rv8803->ctrl);
+               err = rv8803_write_reg(client, RV8803_CTRL, rv8803->ctrl);
                if (err)
                        return err;
        }
@@ -336,7 +411,7 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
        case RTC_VL_READ:
-               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+               flags = rv8803_read_reg(client, RV8803_FLAG);
                if (flags < 0)
                        return flags;
 
@@ -355,16 +430,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 
        case RTC_VL_CLR:
                mutex_lock(&rv8803->flags_lock);
-               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
+               flags = rv8803_read_reg(client, RV8803_FLAG);
                if (flags < 0) {
                        mutex_unlock(&rv8803->flags_lock);
                        return flags;
                }
 
                flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
-               ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
+               ret = rv8803_write_reg(client, RV8803_FLAG, flags);
                mutex_unlock(&rv8803->flags_lock);
-               if (ret < 0)
+               if (ret)
                        return ret;
 
                return 0;
@@ -382,8 +457,8 @@ static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
        struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = i2c_smbus_write_byte_data(client, RV8803_RAM, buf[0]);
-       if (ret < 0)
+       ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
+       if (ret)
                return ret;
 
        return 1;
@@ -397,7 +472,7 @@ static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
        struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = i2c_smbus_read_byte_data(client, RV8803_RAM);
+       ret = rv8803_read_reg(client, RV8803_RAM);
        if (ret < 0)
                return ret;
 
@@ -427,7 +502,7 @@ static int rv8803_probe(struct i2c_client *client,
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct rv8803_data *rv8803;
-       int err, flags, try = 0;
+       int err, flags;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_I2C_BLOCK)) {
@@ -444,16 +519,7 @@ static int rv8803_probe(struct i2c_client *client,
        rv8803->client = client;
        i2c_set_clientdata(client, rv8803);
 
-       /*
-        * There is a 60µs window where the RTC may not reply on the i2c bus in
-        * that case, the transfer is not ACKed. In that case, ensure there are
-        * multiple attempts.
-        */
-       do {
-               flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
-               try++;
-       } while ((flags == -ENXIO) && (try < 3));
-
+       flags = rv8803_read_reg(client, RV8803_FLAG);
        if (flags < 0)
                return flags;
 
@@ -488,12 +554,7 @@ static int rv8803_probe(struct i2c_client *client,
                return PTR_ERR(rv8803->rtc);
        }
 
-       try = 0;
-       do {
-               err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
-                                               RV8803_EXT_WADA);
-               try++;
-       } while ((err == -ENXIO) && (try < 3));
+       err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
        if (err)
                return err;
 
index 772d221..7163b91 100644 (file)
@@ -272,15 +272,9 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
        t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
 
-       if (alarmvals[2] & RX8010_ALARM_AE)
-               t->time.tm_mday = -1;
-       else
+       if (!(alarmvals[2] & RX8010_ALARM_AE))
                t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f);
 
-       t->time.tm_wday = -1;
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-
        t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
        t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
 
index 9f105ef..2b85cc7 100644 (file)
@@ -319,11 +319,6 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12
                        + (ald[1] & 0x20 ? 12 : 0);
 
-       t->time.tm_wday = -1;
-       t->time.tm_mday = -1;
-       t->time.tm_mon = -1;
-       t->time.tm_year = -1;
-
        dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n",
                __func__,
                t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
index f40afdd..5dab466 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/bitrev.h>
 #include <linux/bcd.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define S35390A_CMD_STATUS1    0
 #define S35390A_CMD_STATUS2    1
 #define S35390A_ALRM_BYTE_HOURS        1
 #define S35390A_ALRM_BYTE_MINS 2
 
+/* flags for STATUS1 */
 #define S35390A_FLAG_POC       0x01
 #define S35390A_FLAG_BLD       0x02
+#define S35390A_FLAG_INT2      0x04
 #define S35390A_FLAG_24H       0x40
 #define S35390A_FLAG_RESET     0x80
+
+/* flag for STATUS2 */
 #define S35390A_FLAG_TEST      0x01
 
 #define S35390A_INT2_MODE_MASK         0xF0
@@ -94,19 +99,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
        return 0;
 }
 
-static int s35390a_reset(struct s35390a *s35390a)
+/*
+ * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
+ * To keep the information if an irq is pending, pass the value read from
+ * STATUS1 to the caller.
+ */
+static int s35390a_reset(struct s35390a *s35390a, char *status1)
 {
-       char buf[1];
-
-       if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
-               return -EIO;
-
-       if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
+       char buf;
+       int ret;
+       unsigned initcount = 0;
+
+       ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
+       if (ret < 0)
+               return ret;
+
+       if (*status1 & S35390A_FLAG_POC)
+               /*
+                * Do not communicate for 0.5 seconds since the power-on
+                * detection circuit is in operation.
+                */
+               msleep(500);
+       else if (!(*status1 & S35390A_FLAG_BLD))
+               /*
+                * If both POC and BLD are unset everything is fine.
+                */
                return 0;
 
-       buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
-       buf[0] &= 0xf0;
-       return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
+       /*
+        * At least one of POC and BLD are set, so reinitialise chip. Keeping
+        * this information in the hardware to know later that the time isn't
+        * valid is unfortunately not possible because POC and BLD are cleared
+        * on read. So the reset is best done now.
+        *
+        * The 24H bit is kept over reset, so set it already here.
+        */
+initialize:
+       *status1 = S35390A_FLAG_24H;
+       buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
+       ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+
+       if (ret < 0)
+               return ret;
+
+       ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
+               /* Try up to five times to reset the chip */
+               if (initcount < 5) {
+                       ++initcount;
+                       goto initialize;
+               } else
+                       return -EIO;
+       }
+
+       return 1;
 }
 
 static int s35390a_disable_test_mode(struct s35390a *s35390a)
@@ -217,12 +266,12 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
                alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
                alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
 
-       /* disable interrupt */
+       /* disable interrupt (which deasserts the irq line) */
        err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
        if (err < 0)
                return err;
 
-       /* clear pending interrupt, if any */
+       /* clear pending interrupt (in STATUS1 only), if any */
        err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
        if (err < 0)
                return err;
@@ -242,6 +291,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
 
        if (alm->time.tm_wday != -1)
                buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
+       else
+               buf[S35390A_ALRM_BYTE_WDAY] = 0;
 
        buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
                        alm->time.tm_hour) | 0x80;
@@ -269,23 +320,43 @@ static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
        if (err < 0)
                return err;
 
-       if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
-               return -EINVAL;
+       if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
+               /*
+                * When the alarm isn't enabled, the register to configure
+                * the alarm time isn't accessible.
+                */
+               alm->enabled = 0;
+               return 0;
+       } else {
+               alm->enabled = 1;
+       }
 
        err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
        if (err < 0)
                return err;
 
        /* This chip returns the bits of each byte in reverse order */
-       for (i = 0; i < 3; ++i) {
+       for (i = 0; i < 3; ++i)
                buf[i] = bitrev8(buf[i]);
-               buf[i] &= ~0x80;
-       }
 
-       alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
-       alm->time.tm_hour = s35390a_reg2hr(s35390a,
-                                               buf[S35390A_ALRM_BYTE_HOURS]);
-       alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
+       /*
+        * B0 of the three matching registers is an enable flag. Iff it is set
+        * the configured value is used for matching.
+        */
+       if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
+               alm->time.tm_wday =
+                       bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
+
+       if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
+               alm->time.tm_hour =
+                       s35390a_reg2hr(s35390a,
+                                      buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
+
+       if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
+               alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
+
+       /* alarm triggers always at s=0 */
+       alm->time.tm_sec = 0;
 
        dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
                        __func__, alm->time.tm_min, alm->time.tm_hour,
@@ -327,11 +398,11 @@ static struct i2c_driver s35390a_driver;
 static int s35390a_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       int err;
+       int err, err_reset;
        unsigned int i;
        struct s35390a *s35390a;
        struct rtc_time tm;
-       char buf[1];
+       char buf, status1;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
@@ -360,29 +431,35 @@ static int s35390a_probe(struct i2c_client *client,
                }
        }
 
-       err = s35390a_reset(s35390a);
-       if (err < 0) {
+       err_reset = s35390a_reset(s35390a, &status1);
+       if (err_reset < 0) {
+               err = err_reset;
                dev_err(&client->dev, "error resetting chip\n");
                goto exit_dummy;
        }
 
-       err = s35390a_disable_test_mode(s35390a);
-       if (err < 0) {
-               dev_err(&client->dev, "error disabling test mode\n");
-               goto exit_dummy;
-       }
-
-       err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
-       if (err < 0) {
-               dev_err(&client->dev, "error checking 12/24 hour mode\n");
-               goto exit_dummy;
-       }
-       if (buf[0] & S35390A_FLAG_24H)
+       if (status1 & S35390A_FLAG_24H)
                s35390a->twentyfourhour = 1;
        else
                s35390a->twentyfourhour = 0;
 
-       if (s35390a_get_datetime(client, &tm) < 0)
+       if (status1 & S35390A_FLAG_INT2) {
+               /* disable alarm (and maybe test mode) */
+               buf = 0;
+               err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
+               if (err < 0) {
+                       dev_err(&client->dev, "error disabling alarm");
+                       goto exit_dummy;
+               }
+       } else {
+               err = s35390a_disable_test_mode(s35390a);
+               if (err < 0) {
+                       dev_err(&client->dev, "error disabling test mode\n");
+                       goto exit_dummy;
+               }
+       }
+
+       if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
                dev_warn(&client->dev, "clock needs to be set\n");
 
        device_set_wakeup_capable(&client->dev, 1);
@@ -395,6 +472,10 @@ static int s35390a_probe(struct i2c_client *client,
                err = PTR_ERR(s35390a->rtc);
                goto exit_dummy;
        }
+
+       if (status1 & S35390A_FLAG_INT2)
+               rtc_update_irq(s35390a->rtc, 1, RTC_AF);
+
        return 0;
 
 exit_dummy:
index d01ad7e..d44fb34 100644 (file)
@@ -149,12 +149,14 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
        if (!is_power_of_2(freq))
                return -EINVAL;
 
+       s3c_rtc_enable_clk(info);
        spin_lock_irq(&info->pie_lock);
 
        if (info->data->set_freq)
                info->data->set_freq(info, freq);
 
        spin_unlock_irq(&info->pie_lock);
+       s3c_rtc_disable_clk(info);
 
        return 0;
 }
@@ -264,35 +266,23 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        /* decode the alarm enable field */
        if (alm_en & S3C2410_RTCALM_SECEN)
                alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
-       else
-               alm_tm->tm_sec = -1;
 
        if (alm_en & S3C2410_RTCALM_MINEN)
                alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
-       else
-               alm_tm->tm_min = -1;
 
        if (alm_en & S3C2410_RTCALM_HOUREN)
                alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
-       else
-               alm_tm->tm_hour = -1;
 
        if (alm_en & S3C2410_RTCALM_DAYEN)
                alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
-       else
-               alm_tm->tm_mday = -1;
 
        if (alm_en & S3C2410_RTCALM_MONEN) {
                alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
                alm_tm->tm_mon -= 1;
-       } else {
-               alm_tm->tm_mon = -1;
        }
 
        if (alm_en & S3C2410_RTCALM_YEAREN)
                alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
-       else
-               alm_tm->tm_year = -1;
 
        return 0;
 }
@@ -577,8 +567,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        s3c_rtc_setfreq(info, 1);
 
-       s3c_rtc_disable_clk(info);
-
        return 0;
 
  err_nortc:
index a45845a..17b6235 100644 (file)
@@ -481,7 +481,6 @@ static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
        tm->tm_mon      = sh_rtc_read_alarm_value(rtc, RMONAR);
        if (tm->tm_mon > 0)
                tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
-       tm->tm_year     = 0xffff;
 
        wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;
 
@@ -500,52 +499,13 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
                writeb(bin2bcd(value) | AR_ENB,  rtc->regbase + reg_off);
 }
 
-static int sh_rtc_check_alarm(struct rtc_time *tm)
-{
-       /*
-        * The original rtc says anything > 0xc0 is "don't care" or "match
-        * all" - most users use 0xff but rtc-dev uses -1 for the same thing.
-        * The original rtc doesn't support years - some things use -1 and
-        * some 0xffff. We use -1 to make out tests easier.
-        */
-       if (tm->tm_year == 0xffff)
-               tm->tm_year = -1;
-       if (tm->tm_mon >= 0xff)
-               tm->tm_mon = -1;
-       if (tm->tm_mday >= 0xff)
-               tm->tm_mday = -1;
-       if (tm->tm_wday >= 0xff)
-               tm->tm_wday = -1;
-       if (tm->tm_hour >= 0xff)
-               tm->tm_hour = -1;
-       if (tm->tm_min >= 0xff)
-               tm->tm_min = -1;
-       if (tm->tm_sec >= 0xff)
-               tm->tm_sec = -1;
-
-       if (tm->tm_year > 9999 ||
-               tm->tm_mon >= 12 ||
-               tm->tm_mday == 0 || tm->tm_mday >= 32 ||
-               tm->tm_wday >= 7 ||
-               tm->tm_hour >= 24 ||
-               tm->tm_min >= 60 ||
-               tm->tm_sec >= 60)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct sh_rtc *rtc = platform_get_drvdata(pdev);
        unsigned int rcr1;
        struct rtc_time *tm = &wkalrm->time;
-       int mon, err;
-
-       err = sh_rtc_check_alarm(tm);
-       if (unlikely(err < 0))
-               return err;
+       int mon;
 
        spin_lock_irq(&rtc->lock);
 
index 60232bd..15ac597 100644 (file)
@@ -179,12 +179,6 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        if (sec == 0) {
                /* alarm is disabled. */
                alarm->enabled = 0;
-               alarm->time.tm_mon = -1;
-               alarm->time.tm_mday = -1;
-               alarm->time.tm_year = -1;
-               alarm->time.tm_hour = -1;
-               alarm->time.tm_min = -1;
-               alarm->time.tm_sec = -1;
        } else {
                /* alarm is enabled. */
                alarm->enabled = 1;
index 7a04363..1f3117b 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/rtc.h>
 #include <linux/types.h>
 #include <linux/bcd.h>
-#include <linux/rtc-v3020.h>
+#include <linux/platform_data/rtc-v3020.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
index 0ac520d..c71df0c 100644 (file)
@@ -46,7 +46,8 @@ struct read_info_sccb {
        u64     rnmax2;                 /* 104-111 */
        u8      _pad_112[116 - 112];    /* 112-115 */
        u8      fac116;                 /* 116 */
-       u8      _pad_117[119 - 117];    /* 117-118 */
+       u8      fac117;                 /* 117 */
+       u8      _pad_118;               /* 118 */
        u8      fac119;                 /* 119 */
        u16     hcpua;                  /* 120-121 */
        u8      _pad_122[124 - 122];    /* 122-123 */
@@ -114,7 +115,12 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
        sclp.facilities = sccb->facilities;
        sclp.has_sprp = !!(sccb->fac84 & 0x02);
        sclp.has_core_type = !!(sccb->fac84 & 0x01);
+       sclp.has_gsls = !!(sccb->fac85 & 0x80);
+       sclp.has_64bscao = !!(sccb->fac116 & 0x80);
+       sclp.has_cmma = !!(sccb->fac116 & 0x40);
        sclp.has_esca = !!(sccb->fac116 & 0x08);
+       sclp.has_pfmfi = !!(sccb->fac117 & 0x40);
+       sclp.has_ibs = !!(sccb->fac117 & 0x20);
        sclp.has_hvs = !!(sccb->fac119 & 0x80);
        if (sccb->fac85 & 0x02)
                S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
@@ -145,6 +151,10 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
                sclp.has_siif = cpue->siif;
                sclp.has_sigpif = cpue->sigpif;
                sclp.has_sief2 = cpue->sief2;
+               sclp.has_gpere = cpue->gpere;
+               sclp.has_ib = cpue->ib;
+               sclp.has_cei = cpue->cei;
+               sclp.has_skey = cpue->skey;
                break;
        }
 
index 2553db0..f59b717 100644 (file)
@@ -26,7 +26,7 @@
 #define OCF_LENGTH_CPC_NAME 8UL
 
 static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
-static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
+static char cpc_name[OCF_LENGTH_CPC_NAME]; /* in EBCDIC */
 
 static DEFINE_SPINLOCK(sclp_ocf_lock);
 static struct work_struct sclp_ocf_change_work;
@@ -72,9 +72,8 @@ static void sclp_ocf_handler(struct evbuf_header *evbuf)
        }
        if (cpc) {
                size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
+               memset(cpc_name, 0, OCF_LENGTH_CPC_NAME);
                memcpy(cpc_name, cpc + 1, size);
-               EBCASC(cpc_name, size);
-               cpc_name[size] = 0;
        }
        spin_unlock(&sclp_ocf_lock);
        schedule_work(&sclp_ocf_change_work);
@@ -85,15 +84,23 @@ static struct sclp_register sclp_ocf_event = {
        .receiver_fn = sclp_ocf_handler,
 };
 
+void sclp_ocf_cpc_name_copy(char *dst)
+{
+       spin_lock_irq(&sclp_ocf_lock);
+       memcpy(dst, cpc_name, OCF_LENGTH_CPC_NAME);
+       spin_unlock_irq(&sclp_ocf_lock);
+}
+EXPORT_SYMBOL(sclp_ocf_cpc_name_copy);
+
 static ssize_t cpc_name_show(struct kobject *kobj,
                             struct kobj_attribute *attr, char *page)
 {
-       int rc;
+       char name[OCF_LENGTH_CPC_NAME + 1];
 
-       spin_lock_irq(&sclp_ocf_lock);
-       rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
-       spin_unlock_irq(&sclp_ocf_lock);
-       return rc;
+       sclp_ocf_cpc_name_copy(name);
+       name[OCF_LENGTH_CPC_NAME] = 0;
+       EBCASC(name, OCF_LENGTH_CPC_NAME);
+       return snprintf(page, PAGE_SIZE, "%s\n", name);
 }
 
 static struct kobj_attribute cpc_name_attr =
index 241891a..df40692 100644 (file)
@@ -6,4 +6,8 @@
 # it under the terms of the GNU General Public License (version 2 only)
 # as published by the Free Software Foundation.
 
-obj-$(CONFIG_S390_GUEST) += kvm_virtio.o virtio_ccw.o
+s390-virtio-objs := virtio_ccw.o
+ifdef CONFIG_S390_GUEST_OLD_TRANSPORT
+s390-virtio-objs += kvm_virtio.o
+endif
+obj-$(CONFIG_S390_GUEST) += $(s390-virtio-objs)
index 1d060fd..5e5c11f 100644 (file)
@@ -458,6 +458,8 @@ static int __init kvm_devices_init(void)
        if (test_devices_support(total_memory_size) < 0)
                return -ENODEV;
 
+       pr_warn("The s390-virtio transport is deprecated. Please switch to a modern host providing virtio-ccw.\n");
+
        rc = vmem_add_mapping(total_memory_size, PAGE_SIZE);
        if (rc)
                return rc;
@@ -482,7 +484,7 @@ static int __init kvm_devices_init(void)
 }
 
 /* code for early console output with virtio_console */
-static __init int early_put_chars(u32 vtermno, const char *buf, int count)
+static int early_put_chars(u32 vtermno, const char *buf, int count)
 {
        char scratch[17];
        unsigned int len = count;
index 1918f54..7d1b431 100644 (file)
@@ -838,6 +838,23 @@ config SCSI_IBMVSCSI
          To compile this driver as a module, choose M here: the
          module will be called ibmvscsi.
 
+config SCSI_IBMVSCSIS
+       tristate "IBM Virtual SCSI Server support"
+       depends on PPC_PSERIES && TARGET_CORE && SCSI && PCI
+       help
+         This is the IBM POWER Virtual SCSI Target Server
+         This driver uses the SRP protocol for communication betwen servers
+         guest and/or the host that run on the same server.
+         More information on VSCSI protocol can be found at www.power.org
+
+         The userspace configuration needed to initialize the driver can be
+         be found here:
+
+         https://github.com/powervm/ibmvscsis/wiki/Configuration
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmvscsis.
+
 config SCSI_IBMVFC
        tristate "IBM Virtual FC support"
        depends on PPC_PSERIES && SCSI
index 862ab4e..d539798 100644 (file)
@@ -128,6 +128,7 @@ obj-$(CONFIG_SCSI_SNI_53C710)       += 53c700.o sni_53c710.o
 obj-$(CONFIG_SCSI_NSP32)       += nsp32.o
 obj-$(CONFIG_SCSI_IPR)         += ipr.o
 obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvscsi_tgt/
 obj-$(CONFIG_SCSI_IBMVFC)      += ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)      += hptiop.o
 obj-$(CONFIG_SCSI_STEX)                += stex.o
index 860008d..661bb94 100644 (file)
@@ -778,7 +778,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
 {
        struct afu *afu = cfg->afu;
        struct device *dev = &cfg->dev->dev;
-       struct sisl_global_map __iomem *global = &afu->afu_map->global;
+       struct sisl_global_map __iomem *global;
        struct dev_dependent_vals *ddv;
        u64 reg, status;
        int i, retry_cnt = 0;
@@ -787,6 +787,14 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
        if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN))
                return;
 
+       if (!afu || !afu->afu_map) {
+               dev_dbg(dev, "%s: The problem state area is not mapped\n",
+                       __func__);
+               return;
+       }
+
+       global = &afu->afu_map->global;
+
        /* Notify AFU */
        for (i = 0; i < NUM_FC_PORTS; i++) {
                reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]);
index c8a4305..9bd41a3 100644 (file)
@@ -92,6 +92,8 @@ static struct fcoe_interface
 
 static int fcoe_fip_recv(struct sk_buff *, struct net_device *,
                         struct packet_type *, struct net_device *);
+static int fcoe_fip_vlan_recv(struct sk_buff *, struct net_device *,
+                             struct packet_type *, struct net_device *);
 
 static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *);
 static void fcoe_update_src_mac(struct fc_lport *, u8 *);
@@ -363,6 +365,12 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
        fcoe->fip_packet_type.dev = netdev;
        dev_add_pack(&fcoe->fip_packet_type);
 
+       if (netdev != real_dev) {
+               fcoe->fip_vlan_packet_type.func = fcoe_fip_vlan_recv;
+               fcoe->fip_vlan_packet_type.type = htons(ETH_P_FIP);
+               fcoe->fip_vlan_packet_type.dev = real_dev;
+               dev_add_pack(&fcoe->fip_vlan_packet_type);
+       }
        return 0;
 }
 
@@ -450,6 +458,8 @@ static void fcoe_interface_remove(struct fcoe_interface *fcoe)
         */
        __dev_remove_pack(&fcoe->fcoe_packet_type);
        __dev_remove_pack(&fcoe->fip_packet_type);
+       if (netdev != fcoe->realdev)
+               __dev_remove_pack(&fcoe->fip_vlan_packet_type);
        synchronize_net();
 
        /* Delete secondary MAC addresses */
@@ -519,6 +529,29 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
        return 0;
 }
 
+/**
+ * fcoe_fip_vlan_recv() - Handler for received FIP VLAN discovery frames
+ * @skb:      The receive skb
+ * @netdev:   The associated net device
+ * @ptype:    The packet_type structure which was used to register this handler
+ * @orig_dev: The original net_device the the skb was received on.
+ *           (in case dev is a bond)
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_fip_vlan_recv(struct sk_buff *skb, struct net_device *netdev,
+                             struct packet_type *ptype,
+                             struct net_device *orig_dev)
+{
+       struct fcoe_interface *fcoe;
+       struct fcoe_ctlr *ctlr;
+
+       fcoe = container_of(ptype, struct fcoe_interface, fip_vlan_packet_type);
+       ctlr = fcoe_to_ctlr(fcoe);
+       fcoe_ctlr_recv(ctlr, skb);
+       return 0;
+}
+
 /**
  * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame
  * @port: The FCoE port
@@ -539,7 +572,21 @@ static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb)
  */
 static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
-       skb->dev = fcoe_from_ctlr(fip)->netdev;
+       struct fcoe_interface *fcoe = fcoe_from_ctlr(fip);
+       struct fip_frame {
+               struct ethhdr eth;
+               struct fip_header fip;
+       } __packed *frame;
+
+       /*
+        * Use default VLAN for FIP VLAN discovery protocol
+        */
+       frame = (struct fip_frame *)skb->data;
+       if (frame->fip.fip_op == ntohs(FIP_OP_VLAN) &&
+           fcoe->realdev != fcoe->netdev)
+               skb->dev = fcoe->realdev;
+       else
+               skb->dev = fcoe->netdev;
        fcoe_port_send(lport_priv(fip->lp), skb);
 }
 
@@ -2448,7 +2495,7 @@ static int __init fcoe_init(void)
        if (rc) {
                printk(KERN_ERR "failed to register an fcoe transport, check "
                        "if libfcoe is loaded\n");
-               return rc;
+               goto out_destroy;
        }
 
        mutex_lock(&fcoe_config_mutex);
@@ -2471,6 +2518,7 @@ static int __init fcoe_init(void)
 
 out_free:
        mutex_unlock(&fcoe_config_mutex);
+out_destroy:
        destroy_workqueue(fcoe_wq);
        return rc;
 }
index 2b53672..6aa4820 100644 (file)
@@ -80,6 +80,7 @@ struct fcoe_interface {
        struct net_device  *realdev;
        struct packet_type fcoe_packet_type;
        struct packet_type fip_packet_type;
+       struct packet_type fip_vlan_packet_type;
        struct fc_exch_mgr *oem;
        u8      removed;
        u8      priority;
index 8fae032..5c70a52 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/list.h>
 #include <linux/types.h>
-#include "viosrp.h"
+#include <scsi/viosrp.h>
 
 #define IBMVFC_NAME    "ibmvfc"
 #define IBMVFC_DRIVER_VERSION          "1.0.11"
index 1067367..e0f6c3a 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/list.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
-#include "viosrp.h"
+#include <scsi/viosrp.h>
 
 struct scsi_cmnd;
 struct Scsi_Host;
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
deleted file mode 100644 (file)
index c1ab8a4..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*****************************************************************************/
-/* srp.h -- SCSI RDMA Protocol definitions                                   */
-/*                                                                           */
-/* Written By: Colin Devilbis, IBM Corporation                               */
-/*                                                                           */
-/* Copyright (C) 2003 IBM Corporation                                        */
-/*                                                                           */
-/* This program is free software; you can redistribute it and/or modify      */
-/* it under the terms of the GNU General Public License as published by      */
-/* the Free Software Foundation; either version 2 of the License, or         */
-/* (at your option) any later version.                                       */
-/*                                                                           */
-/* This program is distributed in the hope that it will be useful,           */
-/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
-/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
-/* GNU General Public License for more details.                              */
-/*                                                                           */
-/* You should have received a copy of the GNU General Public License         */
-/* along with this program; if not, write to the Free Software               */
-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-/*                                                                           */
-/*                                                                           */
-/* This file contains structures and definitions for IBM RPA (RS/6000        */
-/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
-/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
-/* commands between logical partitions.                                      */
-/*                                                                           */
-/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
-/* between partitions.  The definitions in this file are architected,        */
-/* and cannot be changed without breaking compatibility with other versions  */
-/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
-/* between logical partitions                                                */
-/*****************************************************************************/
-#ifndef VIOSRP_H
-#define VIOSRP_H
-#include <scsi/srp.h>
-
-#define SRP_VERSION "16.a"
-#define SRP_MAX_IU_LEN 256
-#define SRP_MAX_LOC_LEN 32
-
-union srp_iu {
-       struct srp_login_req login_req;
-       struct srp_login_rsp login_rsp;
-       struct srp_login_rej login_rej;
-       struct srp_i_logout i_logout;
-       struct srp_t_logout t_logout;
-       struct srp_tsk_mgmt tsk_mgmt;
-       struct srp_cmd cmd;
-       struct srp_rsp rsp;
-       u8 reserved[SRP_MAX_IU_LEN];
-};
-
-enum viosrp_crq_headers {
-       VIOSRP_CRQ_FREE = 0x00,
-       VIOSRP_CRQ_CMD_RSP = 0x80,
-       VIOSRP_CRQ_INIT_RSP = 0xC0,
-       VIOSRP_CRQ_XPORT_EVENT = 0xFF
-};
-
-enum viosrp_crq_init_formats {
-       VIOSRP_CRQ_INIT = 0x01,
-       VIOSRP_CRQ_INIT_COMPLETE = 0x02
-};
-
-enum viosrp_crq_formats {
-       VIOSRP_SRP_FORMAT = 0x01,
-       VIOSRP_MAD_FORMAT = 0x02,
-       VIOSRP_OS400_FORMAT = 0x03,
-       VIOSRP_AIX_FORMAT = 0x04,
-       VIOSRP_LINUX_FORMAT = 0x05,
-       VIOSRP_INLINE_FORMAT = 0x06
-};
-
-enum viosrp_crq_status {
-       VIOSRP_OK = 0x0,
-       VIOSRP_NONRECOVERABLE_ERR = 0x1,
-       VIOSRP_VIOLATES_MAX_XFER = 0x2,
-       VIOSRP_PARTNER_PANIC = 0x3,
-       VIOSRP_DEVICE_BUSY = 0x8,
-       VIOSRP_ADAPTER_FAIL = 0x10,
-       VIOSRP_OK2 = 0x99,
-};
-
-struct viosrp_crq {
-       u8 valid;               /* used by RPA */
-       u8 format;              /* SCSI vs out-of-band */
-       u8 reserved;
-       u8 status;              /* non-scsi failure? (e.g. DMA failure) */
-       __be16 timeout;         /* in seconds */
-       __be16 IU_length;               /* in bytes */
-       __be64 IU_data_ptr;     /* the TCE for transferring data */
-};
-
-/* MADs are Management requests above and beyond the IUs defined in the SRP
- * standard.  
- */
-enum viosrp_mad_types {
-       VIOSRP_EMPTY_IU_TYPE = 0x01,
-       VIOSRP_ERROR_LOG_TYPE = 0x02,
-       VIOSRP_ADAPTER_INFO_TYPE = 0x03,
-       VIOSRP_CAPABILITIES_TYPE = 0x05,
-       VIOSRP_ENABLE_FAST_FAIL = 0x08,
-};
-
-enum viosrp_mad_status {
-       VIOSRP_MAD_SUCCESS = 0x00,
-       VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
-       VIOSRP_MAD_FAILED = 0xF7,
-};
-
-enum viosrp_capability_type {
-       MIGRATION_CAPABILITIES = 0x01,
-       RESERVATION_CAPABILITIES = 0x02,
-};
-
-enum viosrp_capability_support {
-       SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
-       SERVER_SUPPORTS_CAP = 0x01,
-       SERVER_CAP_DATA = 0x02,
-};
-
-enum viosrp_reserve_type {
-       CLIENT_RESERVE_SCSI_2 = 0x01,
-};
-
-enum viosrp_capability_flag {
-       CLIENT_MIGRATED = 0x01,
-       CLIENT_RECONNECT = 0x02,
-       CAP_LIST_SUPPORTED = 0x04,
-       CAP_LIST_DATA = 0x08,
-};
-
-/* 
- * Common MAD header
- */
-struct mad_common {
-       __be32 type;
-       __be16 status;
-       __be16 length;
-       __be64 tag;
-};
-
-/*
- * All SRP (and MAD) requests normally flow from the
- * client to the server.  There is no way for the server to send
- * an asynchronous message back to the client.  The Empty IU is used
- * to hang out a meaningless request to the server so that it can respond
- * asynchrouously with something like a SCSI AER 
- */
-struct viosrp_empty_iu {
-       struct mad_common common;
-       __be64 buffer;
-       __be32 port;
-};
-
-struct viosrp_error_log {
-       struct mad_common common;
-       __be64 buffer;
-};
-
-struct viosrp_adapter_info {
-       struct mad_common common;
-       __be64 buffer;
-};
-
-struct viosrp_fast_fail {
-       struct mad_common common;
-};
-
-struct viosrp_capabilities {
-       struct mad_common common;
-       __be64 buffer;
-};
-
-struct mad_capability_common {
-       __be32 cap_type;
-       __be16 length;
-       __be16 server_support;
-};
-
-struct mad_reserve_cap {
-       struct mad_capability_common common;
-       __be32 type;
-};
-
-struct mad_migration_cap {
-       struct mad_capability_common common;
-       __be32 ecl;
-};
-
-struct capabilities{
-       __be32 flags;
-       char name[SRP_MAX_LOC_LEN];
-       char loc[SRP_MAX_LOC_LEN];
-       struct mad_migration_cap migration;
-       struct mad_reserve_cap reserve;
-};
-
-union mad_iu {
-       struct viosrp_empty_iu empty_iu;
-       struct viosrp_error_log error_log;
-       struct viosrp_adapter_info adapter_info;
-       struct viosrp_fast_fail fast_fail;
-       struct viosrp_capabilities capabilities;
-};
-
-union viosrp_iu {
-       union srp_iu srp;
-       union mad_iu mad;
-};
-
-struct mad_adapter_info_data {
-       char srp_version[8];
-       char partition_name[96];
-       __be32 partition_number;
-#define SRP_MAD_VERSION_1 1
-       __be32 mad_version;
-#define SRP_MAD_OS_LINUX 2
-#define SRP_MAD_OS_AIX 3
-       __be32 os_type;
-       __be32 port_max_txu[8]; /* per-port maximum transfer */
-};
-
-#endif
diff --git a/drivers/scsi/ibmvscsi_tgt/Makefile b/drivers/scsi/ibmvscsi_tgt/Makefile
new file mode 100644 (file)
index 0000000..0c060ce
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvscsis.o
+
+ibmvscsis-y := libsrp.o ibmvscsi_tgt.o
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
new file mode 100644 (file)
index 0000000..b29fef9
--- /dev/null
@@ -0,0 +1,4087 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *                        Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *                        Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ * Authors: Michael Cyr <mikecyr@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/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/string.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include <scsi/viosrp.h>
+
+#include "ibmvscsi_tgt.h"
+
+#define IBMVSCSIS_VERSION      "v0.2"
+
+#define        INITIAL_SRP_LIMIT       800
+#define        DEFAULT_MAX_SECTORS     256
+
+static uint max_vdma_size = MAX_H_COPY_RDMA;
+
+static char system_id[SYS_ID_NAME_LEN] = "";
+static char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
+static uint partition_number = -1;
+
+/* Adapter list and lock to control it */
+static DEFINE_SPINLOCK(ibmvscsis_dev_lock);
+static LIST_HEAD(ibmvscsis_dev_list);
+
+static long ibmvscsis_parse_command(struct scsi_info *vscsi,
+                                   struct viosrp_crq *crq);
+
+static void ibmvscsis_adapter_idle(struct scsi_info *vscsi);
+
+static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+                                     struct srp_rsp *rsp)
+{
+       u32 residual_count = se_cmd->residual_count;
+
+       if (!residual_count)
+               return;
+
+       if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+               if (se_cmd->data_direction == DMA_TO_DEVICE) {
+                       /* residual data from an underflow write */
+                       rsp->flags = SRP_RSP_FLAG_DOUNDER;
+                       rsp->data_out_res_cnt = cpu_to_be32(residual_count);
+               } else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+                       /* residual data from an underflow read */
+                       rsp->flags = SRP_RSP_FLAG_DIUNDER;
+                       rsp->data_in_res_cnt = cpu_to_be32(residual_count);
+               }
+       } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+               if (se_cmd->data_direction == DMA_TO_DEVICE) {
+                       /*  residual data from an overflow write */
+                       rsp->flags = SRP_RSP_FLAG_DOOVER;
+                       rsp->data_out_res_cnt = cpu_to_be32(residual_count);
+               } else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+                       /* residual data from an overflow read */
+                       rsp->flags = SRP_RSP_FLAG_DIOVER;
+                       rsp->data_in_res_cnt = cpu_to_be32(residual_count);
+               }
+       }
+}
+
+/**
+ * connection_broken() - Determine if the connection to the client is good
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * This function attempts to send a ping MAD to the client. If the call to
+ * queue the request returns H_CLOSED then the connection has been broken
+ * and the function returns TRUE.
+ *
+ * EXECUTION ENVIRONMENT:
+ *      Interrupt or Process environment
+ */
+static bool connection_broken(struct scsi_info *vscsi)
+{
+       struct viosrp_crq *crq;
+       u64 buffer[2] = { 0, 0 };
+       long h_return_code;
+       bool rc = false;
+
+       /* create a PING crq */
+       crq = (struct viosrp_crq *)&buffer;
+       crq->valid = VALID_CMD_RESP_EL;
+       crq->format = MESSAGE_IN_CRQ;
+       crq->status = PING;
+
+       h_return_code = h_send_crq(vscsi->dds.unit_id,
+                                  cpu_to_be64(buffer[MSG_HI]),
+                                  cpu_to_be64(buffer[MSG_LOW]));
+
+       pr_debug("connection_broken: rc %ld\n", h_return_code);
+
+       if (h_return_code == H_CLOSED)
+               rc = true;
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_unregister_command_q() - Helper Function-Unregister Command Queue
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * This function calls h_free_q then frees the interrupt bit etc.
+ * It must release the lock before doing so because of the time it can take
+ * for h_free_crq in PHYP
+ * NOTE: the caller must make sure that state and or flags will prevent
+ *      interrupt handler from scheduling work.
+ * NOTE: anyone calling this function may need to set the CRQ_CLOSED flag
+ *      we can't do it here, because we don't have the lock
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level
+ */
+static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
+{
+       long qrc;
+       long rc = ADAPT_SUCCESS;
+       int ticks = 0;
+
+       do {
+               qrc = h_free_crq(vscsi->dds.unit_id);
+               switch (qrc) {
+               case H_SUCCESS:
+                       break;
+
+               case H_HARDWARE:
+               case H_PARAMETER:
+                       dev_err(&vscsi->dev, "unregister_command_q: error from h_free_crq %ld\n",
+                               qrc);
+                       rc = ERROR;
+                       break;
+
+               case H_BUSY:
+               case H_LONG_BUSY_ORDER_1_MSEC:
+                       /* msleep not good for small values */
+                       usleep_range(1000, 2000);
+                       ticks += 1;
+                       break;
+               case H_LONG_BUSY_ORDER_10_MSEC:
+                       usleep_range(10000, 20000);
+                       ticks += 10;
+                       break;
+               case H_LONG_BUSY_ORDER_100_MSEC:
+                       msleep(100);
+                       ticks += 100;
+                       break;
+               case H_LONG_BUSY_ORDER_1_SEC:
+                       ssleep(1);
+                       ticks += 1000;
+                       break;
+               case H_LONG_BUSY_ORDER_10_SEC:
+                       ssleep(10);
+                       ticks += 10000;
+                       break;
+               case H_LONG_BUSY_ORDER_100_SEC:
+                       ssleep(100);
+                       ticks += 100000;
+                       break;
+               default:
+                       dev_err(&vscsi->dev, "unregister_command_q: unknown error %ld from h_free_crq\n",
+                               qrc);
+                       rc = ERROR;
+                       break;
+               }
+
+               /*
+                * dont wait more then 300 seconds
+                * ticks are in milliseconds more or less
+                */
+               if (ticks > 300000 && qrc != H_SUCCESS) {
+                       rc = ERROR;
+                       dev_err(&vscsi->dev, "Excessive wait for h_free_crq\n");
+               }
+       } while (qrc != H_SUCCESS && rc == ADAPT_SUCCESS);
+
+       pr_debug("Freeing CRQ: phyp rc %ld, rc %ld\n", qrc, rc);
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_delete_client_info() - Helper function to Delete Client Info
+ * @vscsi:     Pointer to our adapter structure
+ * @client_closed:     True if client closed its queue
+ *
+ * Deletes information specific to the client when the client goes away
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt or Process
+ */
+static void ibmvscsis_delete_client_info(struct scsi_info *vscsi,
+                                        bool client_closed)
+{
+       vscsi->client_cap = 0;
+
+       /*
+        * Some things we don't want to clear if we're closing the queue,
+        * because some clients don't resend the host handshake when they
+        * get a transport event.
+        */
+       if (client_closed)
+               vscsi->client_data.os_type = 0;
+}
+
+/**
+ * ibmvscsis_free_command_q() - Free Command Queue
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * This function calls unregister_command_q, then clears interrupts and
+ * any pending interrupt acknowledgments associated with the command q.
+ * It also clears memory if there is no error.
+ *
+ * PHYP did not meet the PAPR architecture so that we must give up the
+ * lock. This causes a timing hole regarding state change.  To close the
+ * hole this routine does accounting on any change that occurred during
+ * the time the lock is not held.
+ * NOTE: must give up and then acquire the interrupt lock, the caller must
+ *      make sure that state and or flags will prevent interrupt handler from
+ *      scheduling work.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level, interrupt lock is held
+ */
+static long ibmvscsis_free_command_q(struct scsi_info *vscsi)
+{
+       int bytes;
+       u32 flags_under_lock;
+       u16 state_under_lock;
+       long rc = ADAPT_SUCCESS;
+
+       if (!(vscsi->flags & CRQ_CLOSED)) {
+               vio_disable_interrupts(vscsi->dma_dev);
+
+               state_under_lock = vscsi->new_state;
+               flags_under_lock = vscsi->flags;
+               vscsi->phyp_acr_state = 0;
+               vscsi->phyp_acr_flags = 0;
+
+               spin_unlock_bh(&vscsi->intr_lock);
+               rc = ibmvscsis_unregister_command_q(vscsi);
+               spin_lock_bh(&vscsi->intr_lock);
+
+               if (state_under_lock != vscsi->new_state)
+                       vscsi->phyp_acr_state = vscsi->new_state;
+
+               vscsi->phyp_acr_flags = ((~flags_under_lock) & vscsi->flags);
+
+               if (rc == ADAPT_SUCCESS) {
+                       bytes = vscsi->cmd_q.size * PAGE_SIZE;
+                       memset(vscsi->cmd_q.base_addr, 0, bytes);
+                       vscsi->cmd_q.index = 0;
+                       vscsi->flags |= CRQ_CLOSED;
+
+                       ibmvscsis_delete_client_info(vscsi, false);
+               }
+
+               pr_debug("free_command_q: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
+                        vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
+                        vscsi->phyp_acr_state);
+       }
+       return rc;
+}
+
+/**
+ * ibmvscsis_cmd_q_dequeue() - Get valid Command element
+ * @mask:      Mask to use in case index wraps
+ * @current_index:     Current index into command queue
+ * @base_addr: Pointer to start of command queue
+ *
+ * Returns a pointer to a valid command element or NULL, if the command
+ * queue is empty
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt environment, interrupt lock held
+ */
+static struct viosrp_crq *ibmvscsis_cmd_q_dequeue(uint mask,
+                                                 uint *current_index,
+                                                 struct viosrp_crq *base_addr)
+{
+       struct viosrp_crq *ptr;
+
+       ptr = base_addr + *current_index;
+
+       if (ptr->valid) {
+               *current_index = (*current_index + 1) & mask;
+               dma_rmb();
+       } else {
+               ptr = NULL;
+       }
+
+       return ptr;
+}
+
+/**
+ * ibmvscsis_send_init_message() -  send initialize message to the client
+ * @vscsi:     Pointer to our adapter structure
+ * @format:    Which Init Message format to send
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt environment interrupt lock held
+ */
+static long ibmvscsis_send_init_message(struct scsi_info *vscsi, u8 format)
+{
+       struct viosrp_crq *crq;
+       u64 buffer[2] = { 0, 0 };
+       long rc;
+
+       crq = (struct viosrp_crq *)&buffer;
+       crq->valid = VALID_INIT_MSG;
+       crq->format = format;
+       rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
+                       cpu_to_be64(buffer[MSG_LOW]));
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_check_init_msg() - Check init message valid
+ * @vscsi:     Pointer to our adapter structure
+ * @format:    Pointer to return format of Init Message, if any.
+ *             Set to UNUSED_FORMAT if no Init Message in queue.
+ *
+ * Checks if an initialize message was queued by the initiatior
+ * after the queue was created and before the interrupt was enabled.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level only, interrupt lock held
+ */
+static long ibmvscsis_check_init_msg(struct scsi_info *vscsi, uint *format)
+{
+       struct viosrp_crq *crq;
+       long rc = ADAPT_SUCCESS;
+
+       crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask, &vscsi->cmd_q.index,
+                                     vscsi->cmd_q.base_addr);
+       if (!crq) {
+               *format = (uint)UNUSED_FORMAT;
+       } else if (crq->valid == VALID_INIT_MSG && crq->format == INIT_MSG) {
+               *format = (uint)INIT_MSG;
+               crq->valid = INVALIDATE_CMD_RESP_EL;
+               dma_rmb();
+
+               /*
+                * the caller has ensured no initialize message was
+                * sent after the queue was
+                * created so there should be no other message on the queue.
+                */
+               crq = ibmvscsis_cmd_q_dequeue(vscsi->cmd_q.mask,
+                                             &vscsi->cmd_q.index,
+                                             vscsi->cmd_q.base_addr);
+               if (crq) {
+                       *format = (uint)(crq->format);
+                       rc =  ERROR;
+                       crq->valid = INVALIDATE_CMD_RESP_EL;
+                       dma_rmb();
+               }
+       } else {
+               *format = (uint)(crq->format);
+               rc =  ERROR;
+               crq->valid = INVALIDATE_CMD_RESP_EL;
+               dma_rmb();
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_establish_new_q() - Establish new CRQ queue
+ * @vscsi:     Pointer to our adapter structure
+ * @new_state: New state being established after resetting the queue
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_establish_new_q(struct scsi_info *vscsi,  uint new_state)
+{
+       long rc = ADAPT_SUCCESS;
+       uint format;
+
+       vscsi->flags &= PRESERVE_FLAG_FIELDS;
+       vscsi->rsp_q_timer.timer_pops = 0;
+       vscsi->debit = 0;
+       vscsi->credit = 0;
+
+       rc = vio_enable_interrupts(vscsi->dma_dev);
+       if (rc) {
+               pr_warn("reset_queue: failed to enable interrupts, rc %ld\n",
+                       rc);
+               return rc;
+       }
+
+       rc = ibmvscsis_check_init_msg(vscsi, &format);
+       if (rc) {
+               dev_err(&vscsi->dev, "reset_queue: check_init_msg failed, rc %ld\n",
+                       rc);
+               return rc;
+       }
+
+       if (format == UNUSED_FORMAT && new_state == WAIT_CONNECTION) {
+               rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+               switch (rc) {
+               case H_SUCCESS:
+               case H_DROPPED:
+               case H_CLOSED:
+                       rc = ADAPT_SUCCESS;
+                       break;
+
+               case H_PARAMETER:
+               case H_HARDWARE:
+                       break;
+
+               default:
+                       vscsi->state = UNDEFINED;
+                       rc = H_HARDWARE;
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_reset_queue() - Reset CRQ Queue
+ * @vscsi:     Pointer to our adapter structure
+ * @new_state: New state to establish after resetting the queue
+ *
+ * This function calls h_free_q and then calls h_reg_q and does all
+ * of the bookkeeping to get us back to where we can communicate.
+ *
+ * Actually, we don't always call h_free_crq.  A problem was discovered
+ * where one partition would close and reopen his queue, which would
+ * cause his partner to get a transport event, which would cause him to
+ * close and reopen his queue, which would cause the original partition
+ * to get a transport event, etc., etc.  To prevent this, we don't
+ * actually close our queue if the client initiated the reset, (i.e.
+ * either we got a transport event or we have detected that the client's
+ * queue is gone)
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process environment, called with interrupt lock held
+ */
+static void ibmvscsis_reset_queue(struct scsi_info *vscsi, uint new_state)
+{
+       int bytes;
+       long rc = ADAPT_SUCCESS;
+
+       pr_debug("reset_queue: flags 0x%x\n", vscsi->flags);
+
+       /* don't reset, the client did it for us */
+       if (vscsi->flags & (CLIENT_FAILED | TRANS_EVENT)) {
+               vscsi->flags &=  PRESERVE_FLAG_FIELDS;
+               vscsi->rsp_q_timer.timer_pops = 0;
+               vscsi->debit = 0;
+               vscsi->credit = 0;
+               vscsi->state = new_state;
+               vio_enable_interrupts(vscsi->dma_dev);
+       } else {
+               rc = ibmvscsis_free_command_q(vscsi);
+               if (rc == ADAPT_SUCCESS) {
+                       vscsi->state = new_state;
+
+                       bytes = vscsi->cmd_q.size * PAGE_SIZE;
+                       rc = h_reg_crq(vscsi->dds.unit_id,
+                                      vscsi->cmd_q.crq_token, bytes);
+                       if (rc == H_CLOSED || rc == H_SUCCESS) {
+                               rc = ibmvscsis_establish_new_q(vscsi,
+                                                              new_state);
+                       }
+
+                       if (rc != ADAPT_SUCCESS) {
+                               pr_debug("reset_queue: reg_crq rc %ld\n", rc);
+
+                               vscsi->state = ERR_DISCONNECTED;
+                               vscsi->flags |=  RESPONSE_Q_DOWN;
+                               ibmvscsis_free_command_q(vscsi);
+                       }
+               } else {
+                       vscsi->state = ERR_DISCONNECTED;
+                       vscsi->flags |= RESPONSE_Q_DOWN;
+               }
+       }
+}
+
+/**
+ * ibmvscsis_free_cmd_resources() - Free command resources
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Command which is not longer in use
+ *
+ * Must be called with interrupt lock held.
+ */
+static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
+                                        struct ibmvscsis_cmd *cmd)
+{
+       struct iu_entry *iue = cmd->iue;
+
+       switch (cmd->type) {
+       case TASK_MANAGEMENT:
+       case SCSI_CDB:
+               /*
+                * When the queue goes down this value is cleared, so it
+                * cannot be cleared in this general purpose function.
+                */
+               if (vscsi->debit)
+                       vscsi->debit -= 1;
+               break;
+       case ADAPTER_MAD:
+               vscsi->flags &= ~PROCESSING_MAD;
+               break;
+       case UNSET_TYPE:
+               break;
+       default:
+               dev_err(&vscsi->dev, "free_cmd_resources unknown type %d\n",
+                       cmd->type);
+               break;
+       }
+
+       cmd->iue = NULL;
+       list_add_tail(&cmd->list, &vscsi->free_cmd);
+       srp_iu_put(iue);
+
+       if (list_empty(&vscsi->active_q) && list_empty(&vscsi->schedule_q) &&
+           list_empty(&vscsi->waiting_rsp) && (vscsi->flags & WAIT_FOR_IDLE)) {
+               vscsi->flags &= ~WAIT_FOR_IDLE;
+               complete(&vscsi->wait_idle);
+       }
+}
+
+/**
+ * ibmvscsis_disconnect() - Helper function to disconnect
+ * @work:      Pointer to work_struct, gives access to our adapter structure
+ *
+ * An error has occurred or the driver received a Transport event,
+ * and the driver is requesting that the command queue be de-registered
+ * in a safe manner. If there is no outstanding I/O then we can stop the
+ * queue. If we are restarting the queue it will be reflected in the
+ * the state of the adapter.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process environment
+ */
+static void ibmvscsis_disconnect(struct work_struct *work)
+{
+       struct scsi_info *vscsi = container_of(work, struct scsi_info,
+                                              proc_work);
+       u16 new_state;
+       bool wait_idle = false;
+       long rc = ADAPT_SUCCESS;
+
+       spin_lock_bh(&vscsi->intr_lock);
+       new_state = vscsi->new_state;
+       vscsi->new_state = 0;
+
+       pr_debug("disconnect: flags 0x%x, state 0x%hx\n", vscsi->flags,
+                vscsi->state);
+
+       /*
+        * check which state we are in and see if we
+        * should transitition to the new state
+        */
+       switch (vscsi->state) {
+       /*  Should never be called while in this state. */
+       case NO_QUEUE:
+       /*
+        * Can never transition from this state;
+        * igonore errors and logout.
+        */
+       case UNCONFIGURING:
+               break;
+
+       /* can transition from this state to UNCONFIGURING */
+       case ERR_DISCONNECT:
+               if (new_state == UNCONFIGURING)
+                       vscsi->state = new_state;
+               break;
+
+       /*
+        * Can transition from this state to to unconfiguring
+        * or err disconnect.
+        */
+       case ERR_DISCONNECT_RECONNECT:
+               switch (new_state) {
+               case UNCONFIGURING:
+               case ERR_DISCONNECT:
+                       vscsi->state = new_state;
+                       break;
+
+               case WAIT_IDLE:
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       /* can transition from this state to UNCONFIGURING */
+       case ERR_DISCONNECTED:
+               if (new_state == UNCONFIGURING)
+                       vscsi->state = new_state;
+               break;
+
+       /*
+        * If this is a transition into an error state.
+        * a client is attempting to establish a connection
+        * and has violated the RPA protocol.
+        * There can be nothing pending on the adapter although
+        * there can be requests in the command queue.
+        */
+       case WAIT_ENABLED:
+       case PART_UP_WAIT_ENAB:
+               switch (new_state) {
+               case ERR_DISCONNECT:
+                       vscsi->flags |= RESPONSE_Q_DOWN;
+                       vscsi->state = new_state;
+                       vscsi->flags &= ~(SCHEDULE_DISCONNECT |
+                                         DISCONNECT_SCHEDULED);
+                       ibmvscsis_free_command_q(vscsi);
+                       break;
+               case ERR_DISCONNECT_RECONNECT:
+                       ibmvscsis_reset_queue(vscsi, WAIT_ENABLED);
+                       break;
+
+               /* should never happen */
+               case WAIT_IDLE:
+                       rc = ERROR;
+                       dev_err(&vscsi->dev, "disconnect: invalid state %d for WAIT_IDLE\n",
+                               vscsi->state);
+                       break;
+               }
+               break;
+
+       case WAIT_IDLE:
+               switch (new_state) {
+               case ERR_DISCONNECT:
+               case ERR_DISCONNECT_RECONNECT:
+                       vscsi->state = new_state;
+                       break;
+               }
+               break;
+
+       /*
+        * Initiator has not done a successful srp login
+        * or has done a successful srp logout ( adapter was not
+        * busy). In the first case there can be responses queued
+        * waiting for space on the initiators response queue (MAD)
+        * The second case the adapter is idle. Assume the worse case,
+        * i.e. the second case.
+        */
+       case WAIT_CONNECTION:
+       case CONNECTED:
+       case SRP_PROCESSING:
+               wait_idle = true;
+               vscsi->state = new_state;
+               break;
+
+       /* can transition from this state to UNCONFIGURING */
+       case UNDEFINED:
+               if (new_state == UNCONFIGURING)
+                       vscsi->state = new_state;
+               break;
+       default:
+               break;
+       }
+
+       if (wait_idle) {
+               pr_debug("disconnect start wait, active %d, sched %d\n",
+                        (int)list_empty(&vscsi->active_q),
+                        (int)list_empty(&vscsi->schedule_q));
+               if (!list_empty(&vscsi->active_q) ||
+                   !list_empty(&vscsi->schedule_q)) {
+                       vscsi->flags |= WAIT_FOR_IDLE;
+                       pr_debug("disconnect flags 0x%x\n", vscsi->flags);
+                       /*
+                        * This routine is can not be called with the interrupt
+                        * lock held.
+                        */
+                       spin_unlock_bh(&vscsi->intr_lock);
+                       wait_for_completion(&vscsi->wait_idle);
+                       spin_lock_bh(&vscsi->intr_lock);
+               }
+               pr_debug("disconnect stop wait\n");
+
+               ibmvscsis_adapter_idle(vscsi);
+       }
+
+       spin_unlock_bh(&vscsi->intr_lock);
+}
+
+/**
+ * ibmvscsis_post_disconnect() - Schedule the disconnect
+ * @vscsi:     Pointer to our adapter structure
+ * @new_state: State to move to after disconnecting
+ * @flag_bits: Flags to turn on in adapter structure
+ *
+ * If it's already been scheduled, then see if we need to "upgrade"
+ * the new state (if the one passed in is more "severe" than the
+ * previous one).
+ *
+ * PRECONDITION:
+ *     interrupt lock is held
+ */
+static void ibmvscsis_post_disconnect(struct scsi_info *vscsi, uint new_state,
+                                     uint flag_bits)
+{
+       uint state;
+
+       /* check the validity of the new state */
+       switch (new_state) {
+       case UNCONFIGURING:
+       case ERR_DISCONNECT:
+       case ERR_DISCONNECT_RECONNECT:
+       case WAIT_IDLE:
+               break;
+
+       default:
+               dev_err(&vscsi->dev, "post_disconnect: Invalid new state %d\n",
+                       new_state);
+               return;
+       }
+
+       vscsi->flags |= flag_bits;
+
+       pr_debug("post_disconnect: new_state 0x%x, flag_bits 0x%x, vscsi->flags 0x%x, state %hx\n",
+                new_state, flag_bits, vscsi->flags, vscsi->state);
+
+       if (!(vscsi->flags & (DISCONNECT_SCHEDULED | SCHEDULE_DISCONNECT))) {
+               vscsi->flags |= SCHEDULE_DISCONNECT;
+               vscsi->new_state = new_state;
+
+               INIT_WORK(&vscsi->proc_work, ibmvscsis_disconnect);
+               (void)queue_work(vscsi->work_q, &vscsi->proc_work);
+       } else {
+               if (vscsi->new_state)
+                       state = vscsi->new_state;
+               else
+                       state = vscsi->state;
+
+               switch (state) {
+               case NO_QUEUE:
+               case UNCONFIGURING:
+                       break;
+
+               case ERR_DISCONNECTED:
+               case ERR_DISCONNECT:
+               case UNDEFINED:
+                       if (new_state == UNCONFIGURING)
+                               vscsi->new_state = new_state;
+                       break;
+
+               case ERR_DISCONNECT_RECONNECT:
+                       switch (new_state) {
+                       case UNCONFIGURING:
+                       case ERR_DISCONNECT:
+                               vscsi->new_state = new_state;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+
+               case WAIT_ENABLED:
+               case PART_UP_WAIT_ENAB:
+               case WAIT_IDLE:
+               case WAIT_CONNECTION:
+               case CONNECTED:
+               case SRP_PROCESSING:
+                       vscsi->new_state = new_state;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       pr_debug("Leaving post_disconnect: flags 0x%x, new_state 0x%x\n",
+                vscsi->flags, vscsi->new_state);
+}
+
+/**
+ * ibmvscsis_trans_event() - Handle a Transport Event
+ * @vscsi:     Pointer to our adapter structure
+ * @crq:       Pointer to CRQ entry containing the Transport Event
+ *
+ * Do the logic to close the I_T nexus.  This function may not
+ * behave to specification.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_trans_event(struct scsi_info *vscsi,
+                                 struct viosrp_crq *crq)
+{
+       long rc = ADAPT_SUCCESS;
+
+       pr_debug("trans_event: format %d, flags 0x%x, state 0x%hx\n",
+                (int)crq->format, vscsi->flags, vscsi->state);
+
+       switch (crq->format) {
+       case MIGRATED:
+       case PARTNER_FAILED:
+       case PARTNER_DEREGISTER:
+               ibmvscsis_delete_client_info(vscsi, true);
+               break;
+
+       default:
+               rc = ERROR;
+               dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
+                       (uint)crq->format);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
+                                         RESPONSE_Q_DOWN);
+               break;
+       }
+
+       if (rc == ADAPT_SUCCESS) {
+               switch (vscsi->state) {
+               case NO_QUEUE:
+               case ERR_DISCONNECTED:
+               case UNDEFINED:
+                       break;
+
+               case UNCONFIGURING:
+                       vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
+                       break;
+
+               case WAIT_ENABLED:
+                       break;
+
+               case WAIT_CONNECTION:
+                       break;
+
+               case CONNECTED:
+                       ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
+                                                 (RESPONSE_Q_DOWN |
+                                                  TRANS_EVENT));
+                       break;
+
+               case PART_UP_WAIT_ENAB:
+                       vscsi->state = WAIT_ENABLED;
+                       break;
+
+               case SRP_PROCESSING:
+                       if ((vscsi->debit > 0) ||
+                           !list_empty(&vscsi->schedule_q) ||
+                           !list_empty(&vscsi->waiting_rsp) ||
+                           !list_empty(&vscsi->active_q)) {
+                               pr_debug("debit %d, sched %d, wait %d, active %d\n",
+                                        vscsi->debit,
+                                        (int)list_empty(&vscsi->schedule_q),
+                                        (int)list_empty(&vscsi->waiting_rsp),
+                                        (int)list_empty(&vscsi->active_q));
+                               pr_warn("connection lost with outstanding work\n");
+                       } else {
+                               pr_debug("trans_event: SRP Processing, but no outstanding work\n");
+                       }
+
+                       ibmvscsis_post_disconnect(vscsi, WAIT_IDLE,
+                                                 (RESPONSE_Q_DOWN |
+                                                  TRANS_EVENT));
+                       break;
+
+               case ERR_DISCONNECT:
+               case ERR_DISCONNECT_RECONNECT:
+               case WAIT_IDLE:
+                       vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
+                       break;
+               }
+       }
+
+       rc =  vscsi->flags & SCHEDULE_DISCONNECT;
+
+       pr_debug("Leaving trans_event: flags 0x%x, state 0x%hx, rc %ld\n",
+                vscsi->flags, vscsi->state, rc);
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_poll_cmd_q() - Poll Command Queue
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Called to handle command elements that may have arrived while
+ * interrupts were disabled.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     intr_lock must be held
+ */
+static void ibmvscsis_poll_cmd_q(struct scsi_info *vscsi)
+{
+       struct viosrp_crq *crq;
+       long rc;
+       bool ack = true;
+       volatile u8 valid;
+
+       pr_debug("poll_cmd_q: flags 0x%x, state 0x%hx, q index %ud\n",
+                vscsi->flags, vscsi->state, vscsi->cmd_q.index);
+
+       rc = vscsi->flags & SCHEDULE_DISCONNECT;
+       crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+       valid = crq->valid;
+       dma_rmb();
+
+       while (valid) {
+poll_work:
+               vscsi->cmd_q.index =
+                       (vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
+
+               if (!rc) {
+                       rc = ibmvscsis_parse_command(vscsi, crq);
+               } else {
+                       if ((uint)crq->valid == VALID_TRANS_EVENT) {
+                               /*
+                                * must service the transport layer events even
+                                * in an error state, dont break out until all
+                                * the consecutive transport events have been
+                                * processed
+                                */
+                               rc = ibmvscsis_trans_event(vscsi, crq);
+                       } else if (vscsi->flags & TRANS_EVENT) {
+                               /*
+                                * if a tranport event has occurred leave
+                                * everything but transport events on the queue
+                                */
+                               pr_debug("poll_cmd_q, ignoring\n");
+
+                               /*
+                                * need to decrement the queue index so we can
+                                * look at the elment again
+                                */
+                               if (vscsi->cmd_q.index)
+                                       vscsi->cmd_q.index -= 1;
+                               else
+                                       /*
+                                        * index is at 0 it just wrapped.
+                                        * have it index last element in q
+                                        */
+                                       vscsi->cmd_q.index = vscsi->cmd_q.mask;
+                               break;
+                       }
+               }
+
+               crq->valid = INVALIDATE_CMD_RESP_EL;
+
+               crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+               valid = crq->valid;
+               dma_rmb();
+       }
+
+       if (!rc) {
+               if (ack) {
+                       vio_enable_interrupts(vscsi->dma_dev);
+                       ack = false;
+                       pr_debug("poll_cmd_q, reenabling interrupts\n");
+               }
+               valid = crq->valid;
+               dma_rmb();
+               if (valid)
+                       goto poll_work;
+       }
+
+       pr_debug("Leaving poll_cmd_q: rc %ld\n", rc);
+}
+
+/**
+ * ibmvscsis_free_cmd_qs() - Free elements in queue
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Free all of the elements on all queues that are waiting for
+ * whatever reason.
+ *
+ * PRECONDITION:
+ *     Called with interrupt lock held
+ */
+static void ibmvscsis_free_cmd_qs(struct scsi_info *vscsi)
+{
+       struct ibmvscsis_cmd *cmd, *nxt;
+
+       pr_debug("free_cmd_qs: waiting_rsp empty %d, timer starter %d\n",
+                (int)list_empty(&vscsi->waiting_rsp),
+                vscsi->rsp_q_timer.started);
+
+       list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
+               list_del(&cmd->list);
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+       }
+}
+
+/**
+ * ibmvscsis_get_free_cmd() - Get free command from list
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
+{
+       struct ibmvscsis_cmd *cmd = NULL;
+       struct iu_entry *iue;
+
+       iue = srp_iu_get(&vscsi->target);
+       if (iue) {
+               cmd = list_first_entry_or_null(&vscsi->free_cmd,
+                                              struct ibmvscsis_cmd, list);
+               if (cmd) {
+                       list_del(&cmd->list);
+                       cmd->iue = iue;
+                       cmd->type = UNSET_TYPE;
+                       memset(&cmd->se_cmd, 0, sizeof(cmd->se_cmd));
+               } else {
+                       srp_iu_put(iue);
+               }
+       }
+
+       return cmd;
+}
+
+/**
+ * ibmvscsis_adapter_idle() - Helper function to handle idle adapter
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * This function is called when the adapter is idle when the driver
+ * is attempting to clear an error condition.
+ * The adapter is considered busy if any of its cmd queues
+ * are non-empty. This function can be invoked
+ * from the off level disconnect function.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process environment called with interrupt lock held
+ */
+static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
+{
+       int free_qs = false;
+
+       pr_debug("adapter_idle: flags 0x%x, state 0x%hx\n", vscsi->flags,
+                vscsi->state);
+
+       /* Only need to free qs if we're disconnecting from client */
+       if (vscsi->state != WAIT_CONNECTION || vscsi->flags & TRANS_EVENT)
+               free_qs = true;
+
+       switch (vscsi->state) {
+       case ERR_DISCONNECT_RECONNECT:
+               ibmvscsis_reset_queue(vscsi, WAIT_CONNECTION);
+               pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags);
+               break;
+
+       case ERR_DISCONNECT:
+               ibmvscsis_free_command_q(vscsi);
+               vscsi->flags &= ~DISCONNECT_SCHEDULED;
+               vscsi->flags |= RESPONSE_Q_DOWN;
+               vscsi->state = ERR_DISCONNECTED;
+               pr_debug("adapter_idle, disc: flags 0x%x, state 0x%hx\n",
+                        vscsi->flags, vscsi->state);
+               break;
+
+       case WAIT_IDLE:
+               vscsi->rsp_q_timer.timer_pops = 0;
+               vscsi->debit = 0;
+               vscsi->credit = 0;
+               if (vscsi->flags & TRANS_EVENT) {
+                       vscsi->state = WAIT_CONNECTION;
+                       vscsi->flags &= PRESERVE_FLAG_FIELDS;
+               } else {
+                       vscsi->state = CONNECTED;
+                       vscsi->flags &= ~DISCONNECT_SCHEDULED;
+               }
+
+               pr_debug("adapter_idle, wait: flags 0x%x, state 0x%hx\n",
+                        vscsi->flags, vscsi->state);
+               ibmvscsis_poll_cmd_q(vscsi);
+               break;
+
+       case ERR_DISCONNECTED:
+               vscsi->flags &= ~DISCONNECT_SCHEDULED;
+               pr_debug("adapter_idle, disconnected: flags 0x%x, state 0x%hx\n",
+                        vscsi->flags, vscsi->state);
+               break;
+
+       default:
+               dev_err(&vscsi->dev, "adapter_idle: in invalid state %d\n",
+                       vscsi->state);
+               break;
+       }
+
+       if (free_qs)
+               ibmvscsis_free_cmd_qs(vscsi);
+
+       /*
+        * There is a timing window where we could lose a disconnect request.
+        * The known path to this window occurs during the DISCONNECT_RECONNECT
+        * case above: reset_queue calls free_command_q, which will release the
+        * interrupt lock.  During that time, a new post_disconnect call can be
+        * made with a "more severe" state (DISCONNECT or UNCONFIGURING).
+        * Because the DISCONNECT_SCHEDULED flag is already set, post_disconnect
+        * will only set the new_state.  Now free_command_q reacquires the intr
+        * lock and clears the DISCONNECT_SCHEDULED flag (using PRESERVE_FLAG_
+        * FIELDS), and the disconnect is lost.  This is particularly bad when
+        * the new disconnect was for UNCONFIGURING, since the unconfigure hangs
+        * forever.
+        * Fix is that free command queue sets acr state and acr flags if there
+        * is a change under the lock
+        * note free command queue writes to this state it clears it
+        * before releasing the lock, different drivers call the free command
+        * queue different times so dont initialize above
+        */
+       if (vscsi->phyp_acr_state != 0) {
+               /*
+                * set any bits in flags that may have been cleared by
+                * a call to free command queue in switch statement
+                * or reset queue
+                */
+               vscsi->flags |= vscsi->phyp_acr_flags;
+               ibmvscsis_post_disconnect(vscsi, vscsi->phyp_acr_state, 0);
+               vscsi->phyp_acr_state = 0;
+               vscsi->phyp_acr_flags = 0;
+
+               pr_debug("adapter_idle: flags 0x%x, state 0x%hx, acr_flags 0x%x, acr_state 0x%hx\n",
+                        vscsi->flags, vscsi->state, vscsi->phyp_acr_flags,
+                        vscsi->phyp_acr_state);
+       }
+
+       pr_debug("Leaving adapter_idle: flags 0x%x, state 0x%hx, new_state 0x%x\n",
+                vscsi->flags, vscsi->state, vscsi->new_state);
+}
+
+/**
+ * ibmvscsis_copy_crq_packet() - Copy CRQ Packet
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to command element to use to process the request
+ * @crq:       Pointer to CRQ entry containing the request
+ *
+ * Copy the srp information unit from the hosted
+ * partition using remote dma
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_copy_crq_packet(struct scsi_info *vscsi,
+                                     struct ibmvscsis_cmd *cmd,
+                                     struct viosrp_crq *crq)
+{
+       struct iu_entry *iue = cmd->iue;
+       long rc = 0;
+       u16 len;
+
+       len = be16_to_cpu(crq->IU_length);
+       if ((len > SRP_MAX_IU_LEN) || (len == 0)) {
+               dev_err(&vscsi->dev, "copy_crq: Invalid len %d passed", len);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               return SRP_VIOLATION;
+       }
+
+       rc = h_copy_rdma(len, vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(crq->IU_data_ptr),
+                        vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma);
+
+       switch (rc) {
+       case H_SUCCESS:
+               cmd->init_time = mftb();
+               iue->remote_token = crq->IU_data_ptr;
+               iue->iu_len = len;
+               pr_debug("copy_crq: ioba 0x%llx, init_time 0x%llx\n",
+                        be64_to_cpu(crq->IU_data_ptr), cmd->init_time);
+               break;
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT,
+                                                 (RESPONSE_Q_DOWN |
+                                                  CLIENT_FAILED));
+               else
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+
+               dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
+                       rc);
+               break;
+       case H_DEST_PARM:
+       case H_SOURCE_PARM:
+       default:
+               dev_err(&vscsi->dev, "copy_crq: h_copy_rdma failed, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_adapter_info - Service an Adapter Info MAnagement Data gram
+ * @vscsi:     Pointer to our adapter structure
+ * @iue:       Information Unit containing the Adapter Info MAD request
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt adpater lock is held
+ */
+static long ibmvscsis_adapter_info(struct scsi_info *vscsi,
+                                  struct iu_entry *iue)
+{
+       struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
+       struct mad_adapter_info_data *info;
+       uint flag_bits = 0;
+       dma_addr_t token;
+       long rc;
+
+       mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+
+       if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
+               mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+               return 0;
+       }
+
+       info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token,
+                                 GFP_KERNEL);
+       if (!info) {
+               dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
+                       iue->target);
+               mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+               return 0;
+       }
+
+       /* Get remote info */
+       rc = h_copy_rdma(be16_to_cpu(mad->common.length),
+                        vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(mad->buffer),
+                        vscsi->dds.window[LOCAL].liobn, token);
+
+       if (rc != H_SUCCESS) {
+               if (rc == H_PERMISSION) {
+                       if (connection_broken(vscsi))
+                               flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+               }
+               pr_warn("adapter_info: h_copy_rdma from client failed, rc %ld\n",
+                       rc);
+               pr_debug("adapter_info: ioba 0x%llx, flags 0x%x, flag_bits 0x%x\n",
+                        be64_to_cpu(mad->buffer), vscsi->flags, flag_bits);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+                                         flag_bits);
+               goto free_dma;
+       }
+
+       /*
+        * Copy client info, but ignore partition number, which we
+        * already got from phyp - unless we failed to get it from
+        * phyp (e.g. if we're running on a p5 system).
+        */
+       if (vscsi->client_data.partition_number == 0)
+               vscsi->client_data.partition_number =
+                       be32_to_cpu(info->partition_number);
+       strncpy(vscsi->client_data.srp_version, info->srp_version,
+               sizeof(vscsi->client_data.srp_version));
+       strncpy(vscsi->client_data.partition_name, info->partition_name,
+               sizeof(vscsi->client_data.partition_name));
+       vscsi->client_data.mad_version = be32_to_cpu(info->mad_version);
+       vscsi->client_data.os_type = be32_to_cpu(info->os_type);
+
+       /* Copy our info */
+       strncpy(info->srp_version, SRP_VERSION,
+               sizeof(info->srp_version));
+       strncpy(info->partition_name, vscsi->dds.partition_name,
+               sizeof(info->partition_name));
+       info->partition_number = cpu_to_be32(vscsi->dds.partition_num);
+       info->mad_version = cpu_to_be32(MAD_VERSION_1);
+       info->os_type = cpu_to_be32(LINUX);
+       memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
+       info->port_max_txu[0] = cpu_to_be32(128 * PAGE_SIZE);
+
+       dma_wmb();
+       rc = h_copy_rdma(sizeof(*info), vscsi->dds.window[LOCAL].liobn,
+                        token, vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(mad->buffer));
+       switch (rc) {
+       case H_SUCCESS:
+               break;
+
+       case H_SOURCE_PARM:
+       case H_DEST_PARM:
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+                       flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+       default:
+               dev_err(&vscsi->dev, "adapter_info: h_copy_rdma to client failed, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi,
+                                         ERR_DISCONNECT_RECONNECT,
+                                         flag_bits);
+               break;
+       }
+
+free_dma:
+       dma_free_coherent(&vscsi->dma_dev->dev, sizeof(*info), info, token);
+       pr_debug("Leaving adapter_info, rc %ld\n", rc);
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_cap_mad() - Service a Capabilities MAnagement Data gram
+ * @vscsi:     Pointer to our adapter structure
+ * @iue:       Information Unit containing the Capabilities MAD request
+ *
+ * NOTE: if you return an error from this routine you must be
+ * disconnecting or you will cause a hang
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt called with adapter lock held
+ */
+static int ibmvscsis_cap_mad(struct scsi_info *vscsi, struct iu_entry *iue)
+{
+       struct viosrp_capabilities *mad = &vio_iu(iue)->mad.capabilities;
+       struct capabilities *cap;
+       struct mad_capability_common *common;
+       dma_addr_t token;
+       u16 olen, len, status, min_len, cap_len;
+       u32 flag;
+       uint flag_bits = 0;
+       long rc = 0;
+
+       olen = be16_to_cpu(mad->common.length);
+       /*
+        * struct capabilities hardcodes a couple capabilities after the
+        * header, but the capabilities can actually be in any order.
+        */
+       min_len = offsetof(struct capabilities, migration);
+       if ((olen < min_len) || (olen > PAGE_SIZE)) {
+               pr_warn("cap_mad: invalid len %d\n", olen);
+               mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+               return 0;
+       }
+
+       cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token,
+                                GFP_KERNEL);
+       if (!cap) {
+               dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
+                       iue->target);
+               mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+               return 0;
+       }
+       rc = h_copy_rdma(olen, vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(mad->buffer),
+                        vscsi->dds.window[LOCAL].liobn, token);
+       if (rc == H_SUCCESS) {
+               strncpy(cap->name, dev_name(&vscsi->dma_dev->dev),
+                       SRP_MAX_LOC_LEN);
+
+               len = olen - min_len;
+               status = VIOSRP_MAD_SUCCESS;
+               common = (struct mad_capability_common *)&cap->migration;
+
+               while ((len > 0) && (status == VIOSRP_MAD_SUCCESS) && !rc) {
+                       pr_debug("cap_mad: len left %hd, cap type %d, cap len %hd\n",
+                                len, be32_to_cpu(common->cap_type),
+                                be16_to_cpu(common->length));
+
+                       cap_len = be16_to_cpu(common->length);
+                       if (cap_len > len) {
+                               dev_err(&vscsi->dev, "cap_mad: cap len mismatch with total len\n");
+                               status = VIOSRP_MAD_FAILED;
+                               break;
+                       }
+
+                       if (cap_len == 0) {
+                               dev_err(&vscsi->dev, "cap_mad: cap len is 0\n");
+                               status = VIOSRP_MAD_FAILED;
+                               break;
+                       }
+
+                       switch (common->cap_type) {
+                       default:
+                               pr_debug("cap_mad: unsupported capability\n");
+                               common->server_support = 0;
+                               flag = cpu_to_be32((u32)CAP_LIST_SUPPORTED);
+                               cap->flags &= ~flag;
+                               break;
+                       }
+
+                       len = len - cap_len;
+                       common = (struct mad_capability_common *)
+                               ((char *)common + cap_len);
+               }
+
+               mad->common.status = cpu_to_be16(status);
+
+               dma_wmb();
+               rc = h_copy_rdma(olen, vscsi->dds.window[LOCAL].liobn, token,
+                                vscsi->dds.window[REMOTE].liobn,
+                                be64_to_cpu(mad->buffer));
+
+               if (rc != H_SUCCESS) {
+                       pr_debug("cap_mad: failed to copy to client, rc %ld\n",
+                                rc);
+
+                       if (rc == H_PERMISSION) {
+                               if (connection_broken(vscsi))
+                                       flag_bits = (RESPONSE_Q_DOWN |
+                                                    CLIENT_FAILED);
+                       }
+
+                       pr_warn("cap_mad: error copying data to client, rc %ld\n",
+                               rc);
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT,
+                                                 flag_bits);
+               }
+       }
+
+       dma_free_coherent(&vscsi->dma_dev->dev, olen, cap, token);
+
+       pr_debug("Leaving cap_mad, rc %ld, client_cap 0x%x\n",
+                rc, vscsi->client_cap);
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_process_mad() - Service a MAnagement Data gram
+ * @vscsi:     Pointer to our adapter structure
+ * @iue:       Information Unit containing the MAD request
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_process_mad(struct scsi_info *vscsi, struct iu_entry *iue)
+{
+       struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
+       struct viosrp_empty_iu *empty;
+       long rc = ADAPT_SUCCESS;
+
+       switch (be32_to_cpu(mad->type)) {
+       case VIOSRP_EMPTY_IU_TYPE:
+               empty = &vio_iu(iue)->mad.empty_iu;
+               vscsi->empty_iu_id = be64_to_cpu(empty->buffer);
+               vscsi->empty_iu_tag = be64_to_cpu(empty->common.tag);
+               mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+               break;
+       case VIOSRP_ADAPTER_INFO_TYPE:
+               rc = ibmvscsis_adapter_info(vscsi, iue);
+               break;
+       case VIOSRP_CAPABILITIES_TYPE:
+               rc = ibmvscsis_cap_mad(vscsi, iue);
+               break;
+       case VIOSRP_ENABLE_FAST_FAIL:
+               if (vscsi->state == CONNECTED) {
+                       vscsi->fast_fail = true;
+                       mad->status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+               } else {
+                       pr_warn("fast fail mad sent after login\n");
+                       mad->status = cpu_to_be16(VIOSRP_MAD_FAILED);
+               }
+               break;
+       default:
+               mad->status = cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * srp_snd_msg_failed() - Handle an error when sending a response
+ * @vscsi:     Pointer to our adapter structure
+ * @rc:                The return code from the h_send_crq command
+ *
+ * Must be called with interrupt lock held.
+ */
+static void srp_snd_msg_failed(struct scsi_info *vscsi, long rc)
+{
+       ktime_t kt;
+
+       if (rc != H_DROPPED) {
+               ibmvscsis_free_cmd_qs(vscsi);
+
+               if (rc == H_CLOSED)
+                       vscsi->flags |= CLIENT_FAILED;
+
+               /* don't flag the same problem multiple times */
+               if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
+                       vscsi->flags |= RESPONSE_Q_DOWN;
+                       if (!(vscsi->state & (ERR_DISCONNECT |
+                                             ERR_DISCONNECT_RECONNECT |
+                                             ERR_DISCONNECTED | UNDEFINED))) {
+                               dev_err(&vscsi->dev, "snd_msg_failed: setting RESPONSE_Q_DOWN, state 0x%hx, flags 0x%x, rc %ld\n",
+                                       vscsi->state, vscsi->flags, rc);
+                       }
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+               }
+               return;
+       }
+
+       /*
+        * The response queue is full.
+        * If the server is processing SRP requests, i.e.
+        * the client has successfully done an
+        * SRP_LOGIN, then it will wait forever for room in
+        * the queue.  However if the system admin
+        * is attempting to unconfigure the server then one
+        * or more children will be in a state where
+        * they are being removed. So if there is even one
+        * child being removed then the driver assumes
+        * the system admin is attempting to break the
+        * connection with the client and MAX_TIMER_POPS
+        * is honored.
+        */
+       if ((vscsi->rsp_q_timer.timer_pops < MAX_TIMER_POPS) ||
+           (vscsi->state == SRP_PROCESSING)) {
+               pr_debug("snd_msg_failed: response queue full, flags 0x%x, timer started %d, pops %d\n",
+                        vscsi->flags, (int)vscsi->rsp_q_timer.started,
+                        vscsi->rsp_q_timer.timer_pops);
+
+               /*
+                * Check if the timer is running; if it
+                * is not then start it up.
+                */
+               if (!vscsi->rsp_q_timer.started) {
+                       if (vscsi->rsp_q_timer.timer_pops <
+                           MAX_TIMER_POPS) {
+                               kt = ktime_set(0, WAIT_NANO_SECONDS);
+                       } else {
+                               /*
+                                * slide the timeslice if the maximum
+                                * timer pops have already happened
+                                */
+                               kt = ktime_set(WAIT_SECONDS, 0);
+                       }
+
+                       vscsi->rsp_q_timer.started = true;
+                       hrtimer_start(&vscsi->rsp_q_timer.timer, kt,
+                                     HRTIMER_MODE_REL);
+               }
+       } else {
+               /*
+                * TBD: Do we need to worry about this? Need to get
+                *      remove working.
+                */
+               /*
+                * waited a long time and it appears the system admin
+                * is bring this driver down
+                */
+               vscsi->flags |= RESPONSE_Q_DOWN;
+               ibmvscsis_free_cmd_qs(vscsi);
+               /*
+                * if the driver is already attempting to disconnect
+                * from the client and has already logged an error
+                * trace this event but don't put it in the error log
+                */
+               if (!(vscsi->state & (ERR_DISCONNECT |
+                                     ERR_DISCONNECT_RECONNECT |
+                                     ERR_DISCONNECTED | UNDEFINED))) {
+                       dev_err(&vscsi->dev, "client crq full too long\n");
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT,
+                                                 0);
+               }
+       }
+}
+
+/**
+ * ibmvscsis_send_messages() - Send a Response
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Send a response, first checking the waiting queue. Responses are
+ * sent in order they are received. If the response cannot be sent,
+ * because the client queue is full, it stays on the waiting queue.
+ *
+ * PRECONDITION:
+ *     Called with interrupt lock held
+ */
+static void ibmvscsis_send_messages(struct scsi_info *vscsi)
+{
+       u64 msg_hi = 0;
+       /* note do not attmempt to access the IU_data_ptr with this pointer
+        * it is not valid
+        */
+       struct viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
+       struct ibmvscsis_cmd *cmd, *nxt;
+       struct iu_entry *iue;
+       long rc = ADAPT_SUCCESS;
+
+       if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
+               list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
+                       pr_debug("send_messages cmd %p\n", cmd);
+
+                       iue = cmd->iue;
+
+                       crq->valid = VALID_CMD_RESP_EL;
+                       crq->format = cmd->rsp.format;
+
+                       if (cmd->flags & CMD_FAST_FAIL)
+                               crq->status = VIOSRP_ADAPTER_FAIL;
+
+                       crq->IU_length = cpu_to_be16(cmd->rsp.len);
+
+                       rc = h_send_crq(vscsi->dma_dev->unit_address,
+                                       be64_to_cpu(msg_hi),
+                                       be64_to_cpu(cmd->rsp.tag));
+
+                       pr_debug("send_messages: tag 0x%llx, rc %ld\n",
+                                be64_to_cpu(cmd->rsp.tag), rc);
+
+                       /* if all ok free up the command element resources */
+                       if (rc == H_SUCCESS) {
+                               /* some movement has occurred */
+                               vscsi->rsp_q_timer.timer_pops = 0;
+                               list_del(&cmd->list);
+
+                               ibmvscsis_free_cmd_resources(vscsi, cmd);
+                       } else {
+                               srp_snd_msg_failed(vscsi, rc);
+                               break;
+                       }
+               }
+
+               if (!rc) {
+                       /*
+                        * The timer could pop with the queue empty.  If
+                        * this happens, rc will always indicate a
+                        * success; clear the pop count.
+                        */
+                       vscsi->rsp_q_timer.timer_pops = 0;
+               }
+       } else {
+               ibmvscsis_free_cmd_qs(vscsi);
+       }
+}
+
+/* Called with intr lock held */
+static void ibmvscsis_send_mad_resp(struct scsi_info *vscsi,
+                                   struct ibmvscsis_cmd *cmd,
+                                   struct viosrp_crq *crq)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct mad_common *mad = (struct mad_common *)&vio_iu(iue)->mad;
+       uint flag_bits = 0;
+       long rc;
+
+       dma_wmb();
+       rc = h_copy_rdma(sizeof(struct mad_common),
+                        vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
+                        vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(crq->IU_data_ptr));
+       if (!rc) {
+               cmd->rsp.format = VIOSRP_MAD_FORMAT;
+               cmd->rsp.len = sizeof(struct mad_common);
+               cmd->rsp.tag = mad->tag;
+               list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+               ibmvscsis_send_messages(vscsi);
+       } else {
+               pr_debug("Error sending mad response, rc %ld\n", rc);
+               if (rc == H_PERMISSION) {
+                       if (connection_broken(vscsi))
+                               flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED);
+               }
+               dev_err(&vscsi->dev, "mad: failed to copy to client, rc %ld\n",
+                       rc);
+
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+                                         flag_bits);
+       }
+}
+
+/**
+ * ibmvscsis_mad() - Service a MAnagement Data gram.
+ * @vscsi:     Pointer to our adapter structure
+ * @crq:       Pointer to the CRQ entry containing the MAD request
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt  called with adapter lock held
+ */
+static long ibmvscsis_mad(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+       struct iu_entry *iue;
+       struct ibmvscsis_cmd *cmd;
+       struct mad_common *mad;
+       long rc = ADAPT_SUCCESS;
+
+       switch (vscsi->state) {
+               /*
+                * We have not exchanged Init Msgs yet, so this MAD was sent
+                * before the last Transport Event; client will not be
+                * expecting a response.
+                */
+       case WAIT_CONNECTION:
+               pr_debug("mad: in Wait Connection state, ignoring MAD, flags %d\n",
+                        vscsi->flags);
+               return ADAPT_SUCCESS;
+
+       case SRP_PROCESSING:
+       case CONNECTED:
+               break;
+
+               /*
+                * We should never get here while we're in these states.
+                * Just log an error and get out.
+                */
+       case UNCONFIGURING:
+       case WAIT_IDLE:
+       case ERR_DISCONNECT:
+       case ERR_DISCONNECT_RECONNECT:
+       default:
+               dev_err(&vscsi->dev, "mad: invalid adapter state %d for mad\n",
+                       vscsi->state);
+               return ADAPT_SUCCESS;
+       }
+
+       cmd = ibmvscsis_get_free_cmd(vscsi);
+       if (!cmd) {
+               dev_err(&vscsi->dev, "mad: failed to get cmd, debit %d\n",
+                       vscsi->debit);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               return ERROR;
+       }
+       iue = cmd->iue;
+       cmd->type = ADAPTER_MAD;
+
+       rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
+       if (!rc) {
+               mad = (struct mad_common *)&vio_iu(iue)->mad;
+
+               pr_debug("mad: type %d\n", be32_to_cpu(mad->type));
+
+               if (be16_to_cpu(mad->length) < 0) {
+                       dev_err(&vscsi->dev, "mad: length is < 0\n");
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+                       rc = SRP_VIOLATION;
+               } else {
+                       rc = ibmvscsis_process_mad(vscsi, iue);
+               }
+
+               pr_debug("mad: status %hd, rc %ld\n", be16_to_cpu(mad->status),
+                        rc);
+
+               if (!rc)
+                       ibmvscsis_send_mad_resp(vscsi, cmd, crq);
+       } else {
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+       }
+
+       pr_debug("Leaving mad, rc %ld\n", rc);
+       return rc;
+}
+
+/**
+ * ibmvscsis_login_rsp() - Create/copy a login response notice to the client
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to the command for the SRP Login request
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_login_rsp(struct scsi_info *vscsi,
+                               struct ibmvscsis_cmd *cmd)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_login_rsp *rsp = &vio_iu(iue)->srp.login_rsp;
+       struct format_code *fmt;
+       uint flag_bits = 0;
+       long rc = ADAPT_SUCCESS;
+
+       memset(rsp, 0, sizeof(struct srp_login_rsp));
+
+       rsp->opcode = SRP_LOGIN_RSP;
+       rsp->req_lim_delta = cpu_to_be32(vscsi->request_limit);
+       rsp->tag = cmd->rsp.tag;
+       rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+       rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+       fmt = (struct format_code *)&rsp->buf_fmt;
+       fmt->buffers = SUPPORTED_FORMATS;
+       vscsi->credit = 0;
+
+       cmd->rsp.len = sizeof(struct srp_login_rsp);
+
+       dma_wmb();
+       rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
+                        iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(iue->remote_token));
+
+       switch (rc) {
+       case H_SUCCESS:
+               break;
+
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+                       flag_bits = RESPONSE_Q_DOWN | CLIENT_FAILED;
+               dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+                                         flag_bits);
+               break;
+       case H_SOURCE_PARM:
+       case H_DEST_PARM:
+       default:
+               dev_err(&vscsi->dev, "login_rsp: error copying to client, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_srp_login_rej() - Create/copy a login rejection notice to client
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to the command for the SRP Login request
+ * @reason:    The reason the SRP Login is being rejected, per SRP protocol
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_srp_login_rej(struct scsi_info *vscsi,
+                                   struct ibmvscsis_cmd *cmd, u32 reason)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_login_rej *rej = &vio_iu(iue)->srp.login_rej;
+       struct format_code *fmt;
+       uint flag_bits = 0;
+       long rc = ADAPT_SUCCESS;
+
+       memset(rej, 0, sizeof(*rej));
+
+       rej->opcode = SRP_LOGIN_REJ;
+       rej->reason = cpu_to_be32(reason);
+       rej->tag = cmd->rsp.tag;
+       fmt = (struct format_code *)&rej->buf_fmt;
+       fmt->buffers = SUPPORTED_FORMATS;
+
+       cmd->rsp.len = sizeof(*rej);
+
+       dma_wmb();
+       rc = h_copy_rdma(cmd->rsp.len, vscsi->dds.window[LOCAL].liobn,
+                        iue->sbuf->dma, vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(iue->remote_token));
+
+       switch (rc) {
+       case H_SUCCESS:
+               break;
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+                       flag_bits =  RESPONSE_Q_DOWN | CLIENT_FAILED;
+               dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT,
+                                         flag_bits);
+               break;
+       case H_SOURCE_PARM:
+       case H_DEST_PARM:
+       default:
+               dev_err(&vscsi->dev, "login_rej: error copying to client, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+static int ibmvscsis_make_nexus(struct ibmvscsis_tport *tport)
+{
+       char *name = tport->tport_name;
+       struct ibmvscsis_nexus *nexus;
+       int rc;
+
+       if (tport->ibmv_nexus) {
+               pr_debug("tport->ibmv_nexus already exists\n");
+               return 0;
+       }
+
+       nexus = kzalloc(sizeof(*nexus), GFP_KERNEL);
+       if (!nexus) {
+               pr_err("Unable to allocate struct ibmvscsis_nexus\n");
+               return -ENOMEM;
+       }
+
+       nexus->se_sess = target_alloc_session(&tport->se_tpg, 0, 0,
+                                             TARGET_PROT_NORMAL, name, nexus,
+                                             NULL);
+       if (IS_ERR(nexus->se_sess)) {
+               rc = PTR_ERR(nexus->se_sess);
+               goto transport_init_fail;
+       }
+
+       tport->ibmv_nexus = nexus;
+
+       return 0;
+
+transport_init_fail:
+       kfree(nexus);
+       return rc;
+}
+
+static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
+{
+       struct se_session *se_sess;
+       struct ibmvscsis_nexus *nexus;
+
+       nexus = tport->ibmv_nexus;
+       if (!nexus)
+               return -ENODEV;
+
+       se_sess = nexus->se_sess;
+       if (!se_sess)
+               return -ENODEV;
+
+       /*
+        * Release the SCSI I_T Nexus to the emulated ibmvscsis Target Port
+        */
+       transport_deregister_session(se_sess);
+       tport->ibmv_nexus = NULL;
+       kfree(nexus);
+
+       return 0;
+}
+
+/**
+ * ibmvscsis_srp_login() - Process an SRP Login Request
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Command element to use to process the SRP Login request
+ * @crq:       Pointer to CRQ entry containing the SRP Login request
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, called with interrupt lock held
+ */
+static long ibmvscsis_srp_login(struct scsi_info *vscsi,
+                               struct ibmvscsis_cmd *cmd,
+                               struct viosrp_crq *crq)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_login_req *req = &vio_iu(iue)->srp.login_req;
+       struct port_id {
+               __be64 id_extension;
+               __be64 io_guid;
+       } *iport, *tport;
+       struct format_code *fmt;
+       u32 reason = 0x0;
+       long rc = ADAPT_SUCCESS;
+
+       iport = (struct port_id *)req->initiator_port_id;
+       tport = (struct port_id *)req->target_port_id;
+       fmt = (struct format_code *)&req->req_buf_fmt;
+       if (be32_to_cpu(req->req_it_iu_len) > SRP_MAX_IU_LEN)
+               reason = SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE;
+       else if (be32_to_cpu(req->req_it_iu_len) < 64)
+               reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
+       else if ((be64_to_cpu(iport->id_extension) > (MAX_NUM_PORTS - 1)) ||
+                (be64_to_cpu(tport->id_extension) > (MAX_NUM_PORTS - 1)))
+               reason = SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL;
+       else if (req->req_flags & SRP_MULTICHAN_MULTI)
+               reason = SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED;
+       else if (fmt->buffers & (~SUPPORTED_FORMATS))
+               reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
+       else if ((fmt->buffers | SUPPORTED_FORMATS) == 0)
+               reason = SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT;
+
+       if (vscsi->state == SRP_PROCESSING)
+               reason = SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED;
+
+       rc = ibmvscsis_make_nexus(&vscsi->tport);
+       if (rc)
+               reason = SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL;
+
+       cmd->rsp.format = VIOSRP_SRP_FORMAT;
+       cmd->rsp.tag = req->tag;
+
+       pr_debug("srp_login: reason 0x%x\n", reason);
+
+       if (reason)
+               rc = ibmvscsis_srp_login_rej(vscsi, cmd, reason);
+       else
+               rc = ibmvscsis_login_rsp(vscsi, cmd);
+
+       if (!rc) {
+               if (!reason)
+                       vscsi->state = SRP_PROCESSING;
+
+               list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+               ibmvscsis_send_messages(vscsi);
+       } else {
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+       }
+
+       pr_debug("Leaving srp_login, rc %ld\n", rc);
+       return rc;
+}
+
+/**
+ * ibmvscsis_srp_i_logout() - Helper Function to close I_T Nexus
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Command element to use to process the Implicit Logout request
+ * @crq:       Pointer to CRQ entry containing the Implicit Logout request
+ *
+ * Do the logic to close the I_T nexus.  This function may not
+ * behave to specification.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_srp_i_logout(struct scsi_info *vscsi,
+                                  struct ibmvscsis_cmd *cmd,
+                                  struct viosrp_crq *crq)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
+       long rc = ADAPT_SUCCESS;
+
+       if ((vscsi->debit > 0) || !list_empty(&vscsi->schedule_q) ||
+           !list_empty(&vscsi->waiting_rsp)) {
+               dev_err(&vscsi->dev, "i_logout: outstanding work\n");
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+       } else {
+               cmd->rsp.format = SRP_FORMAT;
+               cmd->rsp.tag = log_out->tag;
+               cmd->rsp.len = sizeof(struct mad_common);
+               list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+               ibmvscsis_send_messages(vscsi);
+
+               ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
+       }
+
+       return rc;
+}
+
+/* Called with intr lock held */
+static void ibmvscsis_srp_cmd(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+       struct ibmvscsis_cmd *cmd;
+       struct iu_entry *iue;
+       struct srp_cmd *srp;
+       struct srp_tsk_mgmt *tsk;
+       long rc;
+
+       if (vscsi->request_limit - vscsi->debit <= 0) {
+               /* Client has exceeded request limit */
+               dev_err(&vscsi->dev, "Client exceeded the request limit (%d), debit %d\n",
+                       vscsi->request_limit, vscsi->debit);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               return;
+       }
+
+       cmd = ibmvscsis_get_free_cmd(vscsi);
+       if (!cmd) {
+               dev_err(&vscsi->dev, "srp_cmd failed to get cmd, debit %d\n",
+                       vscsi->debit);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               return;
+       }
+       iue = cmd->iue;
+       srp = &vio_iu(iue)->srp.cmd;
+
+       rc = ibmvscsis_copy_crq_packet(vscsi, cmd, crq);
+       if (rc) {
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+               return;
+       }
+
+       if (vscsi->state == SRP_PROCESSING) {
+               switch (srp->opcode) {
+               case SRP_LOGIN_REQ:
+                       rc = ibmvscsis_srp_login(vscsi, cmd, crq);
+                       break;
+
+               case SRP_TSK_MGMT:
+                       tsk = &vio_iu(iue)->srp.tsk_mgmt;
+                       pr_debug("tsk_mgmt tag: %llu (0x%llx)\n", tsk->tag,
+                                tsk->tag);
+                       cmd->rsp.tag = tsk->tag;
+                       vscsi->debit += 1;
+                       cmd->type = TASK_MANAGEMENT;
+                       list_add_tail(&cmd->list, &vscsi->schedule_q);
+                       queue_work(vscsi->work_q, &cmd->work);
+                       break;
+
+               case SRP_CMD:
+                       pr_debug("srp_cmd tag: %llu (0x%llx)\n", srp->tag,
+                                srp->tag);
+                       cmd->rsp.tag = srp->tag;
+                       vscsi->debit += 1;
+                       cmd->type = SCSI_CDB;
+                       /*
+                        * We want to keep track of work waiting for
+                        * the workqueue.
+                        */
+                       list_add_tail(&cmd->list, &vscsi->schedule_q);
+                       queue_work(vscsi->work_q, &cmd->work);
+                       break;
+
+               case SRP_I_LOGOUT:
+                       rc = ibmvscsis_srp_i_logout(vscsi, cmd, crq);
+                       break;
+
+               case SRP_CRED_RSP:
+               case SRP_AER_RSP:
+               default:
+                       ibmvscsis_free_cmd_resources(vscsi, cmd);
+                       dev_err(&vscsi->dev, "invalid srp cmd, opcode %d\n",
+                               (uint)srp->opcode);
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+                       break;
+               }
+       } else if (srp->opcode == SRP_LOGIN_REQ && vscsi->state == CONNECTED) {
+               rc = ibmvscsis_srp_login(vscsi, cmd, crq);
+       } else {
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+               dev_err(&vscsi->dev, "Invalid state %d to handle srp cmd\n",
+                       vscsi->state);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+       }
+}
+
+/**
+ * ibmvscsis_ping_response() - Respond to a ping request
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Let the client know that the server is alive and waiting on
+ * its native I/O stack.
+ * If any type of error occurs from the call to queue a ping
+ * response then the client is either not accepting or receiving
+ * interrupts.  Disconnect with an error.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_ping_response(struct scsi_info *vscsi)
+{
+       struct viosrp_crq *crq;
+       u64 buffer[2] = { 0, 0 };
+       long rc;
+
+       crq = (struct viosrp_crq *)&buffer;
+       crq->valid = VALID_CMD_RESP_EL;
+       crq->format = (u8)MESSAGE_IN_CRQ;
+       crq->status = PING_RESPONSE;
+
+       rc = h_send_crq(vscsi->dds.unit_id, cpu_to_be64(buffer[MSG_HI]),
+                       cpu_to_be64(buffer[MSG_LOW]));
+
+       switch (rc) {
+       case H_SUCCESS:
+               break;
+       case H_CLOSED:
+               vscsi->flags |= CLIENT_FAILED;
+       case H_DROPPED:
+               vscsi->flags |= RESPONSE_Q_DOWN;
+       case H_REMOTE_PARM:
+               dev_err(&vscsi->dev, "ping_response: h_send_crq failed, rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       default:
+               dev_err(&vscsi->dev, "ping_response: h_send_crq returned unknown rc %ld\n",
+                       rc);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_handle_init_compl_msg() - Respond to an Init Complete Message
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_handle_init_compl_msg(struct scsi_info *vscsi)
+{
+       long rc = ADAPT_SUCCESS;
+
+       switch (vscsi->state) {
+       case NO_QUEUE:
+       case ERR_DISCONNECT:
+       case ERR_DISCONNECT_RECONNECT:
+       case ERR_DISCONNECTED:
+       case UNCONFIGURING:
+       case UNDEFINED:
+               rc = ERROR;
+               break;
+
+       case WAIT_CONNECTION:
+               vscsi->state = CONNECTED;
+               break;
+
+       case WAIT_IDLE:
+       case SRP_PROCESSING:
+       case CONNECTED:
+       case WAIT_ENABLED:
+       case PART_UP_WAIT_ENAB:
+       default:
+               rc = ERROR;
+               dev_err(&vscsi->dev, "init_msg: invalid state %d to get init compl msg\n",
+                       vscsi->state);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_handle_init_msg() - Respond to an Init Message
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_handle_init_msg(struct scsi_info *vscsi)
+{
+       long rc = ADAPT_SUCCESS;
+
+       switch (vscsi->state) {
+       case WAIT_ENABLED:
+               vscsi->state = PART_UP_WAIT_ENAB;
+               break;
+
+       case WAIT_CONNECTION:
+               rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+               switch (rc) {
+               case H_SUCCESS:
+                       vscsi->state = CONNECTED;
+                       break;
+
+               case H_PARAMETER:
+                       dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+                               rc);
+                       ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT, 0);
+                       break;
+
+               case H_DROPPED:
+                       dev_err(&vscsi->dev, "init_msg: failed to send, rc %ld\n",
+                               rc);
+                       rc = ERROR;
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+                       break;
+
+               case H_CLOSED:
+                       pr_warn("init_msg: failed to send, rc %ld\n", rc);
+                       rc = 0;
+                       break;
+               }
+               break;
+
+       case UNDEFINED:
+               rc = ERROR;
+               break;
+
+       case UNCONFIGURING:
+               break;
+
+       case PART_UP_WAIT_ENAB:
+       case CONNECTED:
+       case SRP_PROCESSING:
+       case WAIT_IDLE:
+       case NO_QUEUE:
+       case ERR_DISCONNECT:
+       case ERR_DISCONNECT_RECONNECT:
+       case ERR_DISCONNECTED:
+       default:
+               rc = ERROR;
+               dev_err(&vscsi->dev, "init_msg: invalid state %d to get init msg\n",
+                       vscsi->state);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_init_msg() - Respond to an init message
+ * @vscsi:     Pointer to our adapter structure
+ * @crq:       Pointer to CRQ element containing the Init Message
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, interrupt lock held
+ */
+static long ibmvscsis_init_msg(struct scsi_info *vscsi, struct viosrp_crq *crq)
+{
+       long rc = ADAPT_SUCCESS;
+
+       pr_debug("init_msg: state 0x%hx\n", vscsi->state);
+
+       rc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
+                     (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
+                     0);
+       if (rc == H_SUCCESS) {
+               vscsi->client_data.partition_number =
+                       be64_to_cpu(*(u64 *)vscsi->map_buf);
+               pr_debug("init_msg, part num %d\n",
+                        vscsi->client_data.partition_number);
+       } else {
+               pr_debug("init_msg h_vioctl rc %ld\n", rc);
+               rc = ADAPT_SUCCESS;
+       }
+
+       if (crq->format == INIT_MSG) {
+               rc = ibmvscsis_handle_init_msg(vscsi);
+       } else if (crq->format == INIT_COMPLETE_MSG) {
+               rc = ibmvscsis_handle_init_compl_msg(vscsi);
+       } else {
+               rc = ERROR;
+               dev_err(&vscsi->dev, "init_msg: invalid format %d\n",
+                       (uint)crq->format);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_parse_command() - Parse an element taken from the cmd rsp queue.
+ * @vscsi:     Pointer to our adapter structure
+ * @crq:       Pointer to CRQ element containing the SRP request
+ *
+ * This function will return success if the command queue element is valid
+ * and the srp iu or MAD request it pointed to was also valid.  That does
+ * not mean that an error was not returned to the client.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Interrupt, intr lock held
+ */
+static long ibmvscsis_parse_command(struct scsi_info *vscsi,
+                                   struct viosrp_crq *crq)
+{
+       long rc = ADAPT_SUCCESS;
+
+       switch (crq->valid) {
+       case VALID_CMD_RESP_EL:
+               switch (crq->format) {
+               case OS400_FORMAT:
+               case AIX_FORMAT:
+               case LINUX_FORMAT:
+               case MAD_FORMAT:
+                       if (vscsi->flags & PROCESSING_MAD) {
+                               rc = ERROR;
+                               dev_err(&vscsi->dev, "parse_command: already processing mad\n");
+                               ibmvscsis_post_disconnect(vscsi,
+                                                      ERR_DISCONNECT_RECONNECT,
+                                                      0);
+                       } else {
+                               vscsi->flags |= PROCESSING_MAD;
+                               rc = ibmvscsis_mad(vscsi, crq);
+                       }
+                       break;
+
+               case SRP_FORMAT:
+                       ibmvscsis_srp_cmd(vscsi, crq);
+                       break;
+
+               case MESSAGE_IN_CRQ:
+                       if (crq->status == PING)
+                               ibmvscsis_ping_response(vscsi);
+                       break;
+
+               default:
+                       dev_err(&vscsi->dev, "parse_command: invalid format %d\n",
+                               (uint)crq->format);
+                       ibmvscsis_post_disconnect(vscsi,
+                                                 ERR_DISCONNECT_RECONNECT, 0);
+                       break;
+               }
+               break;
+
+       case VALID_TRANS_EVENT:
+               rc =  ibmvscsis_trans_event(vscsi, crq);
+               break;
+
+       case VALID_INIT_MSG:
+               rc = ibmvscsis_init_msg(vscsi, crq);
+               break;
+
+       default:
+               dev_err(&vscsi->dev, "parse_command: invalid valid field %d\n",
+                       (uint)crq->valid);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               break;
+       }
+
+       /*
+        * Return only what the interrupt handler cares
+        * about. Most errors we keep right on trucking.
+        */
+       rc = vscsi->flags & SCHEDULE_DISCONNECT;
+
+       return rc;
+}
+
+static int read_dma_window(struct scsi_info *vscsi)
+{
+       struct vio_dev *vdev = vscsi->dma_dev;
+       const __be32 *dma_window;
+       const __be32 *prop;
+
+       /* TODO Using of_parse_dma_window would be better, but it doesn't give
+        * a way to read multiple windows without already knowing the size of
+        * a window or the number of windows.
+        */
+       dma_window = (const __be32 *)vio_get_attribute(vdev,
+                                                      "ibm,my-dma-window",
+                                                      NULL);
+       if (!dma_window) {
+               pr_err("Couldn't find ibm,my-dma-window property\n");
+               return -1;
+       }
+
+       vscsi->dds.window[LOCAL].liobn = be32_to_cpu(*dma_window);
+       dma_window++;
+
+       prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
+                                                NULL);
+       if (!prop) {
+               pr_warn("Couldn't find ibm,#dma-address-cells property\n");
+               dma_window++;
+       } else {
+               dma_window += be32_to_cpu(*prop);
+       }
+
+       prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
+                                                NULL);
+       if (!prop) {
+               pr_warn("Couldn't find ibm,#dma-size-cells property\n");
+               dma_window++;
+       } else {
+               dma_window += be32_to_cpu(*prop);
+       }
+
+       /* dma_window should point to the second window now */
+       vscsi->dds.window[REMOTE].liobn = be32_to_cpu(*dma_window);
+
+       return 0;
+}
+
+static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
+{
+       struct ibmvscsis_tport *tport = NULL;
+       struct vio_dev *vdev;
+       struct scsi_info *vscsi;
+
+       spin_lock_bh(&ibmvscsis_dev_lock);
+       list_for_each_entry(vscsi, &ibmvscsis_dev_list, list) {
+               vdev = vscsi->dma_dev;
+               if (!strcmp(dev_name(&vdev->dev), name)) {
+                       tport = &vscsi->tport;
+                       break;
+               }
+       }
+       spin_unlock_bh(&ibmvscsis_dev_lock);
+
+       return tport;
+}
+
+/**
+ * ibmvscsis_parse_cmd() - Parse SRP Command
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to command element with SRP command
+ *
+ * Parse the srp command; if it is valid then submit it to tcm.
+ * Note: The return code does not reflect the status of the SCSI CDB.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level
+ */
+static void ibmvscsis_parse_cmd(struct scsi_info *vscsi,
+                               struct ibmvscsis_cmd *cmd)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+       struct ibmvscsis_nexus *nexus;
+       u64 data_len = 0;
+       enum dma_data_direction dir;
+       int attr = 0;
+       int rc = 0;
+
+       nexus = vscsi->tport.ibmv_nexus;
+       /*
+        * additional length in bytes.  Note that the SRP spec says that
+        * additional length is in 4-byte words, but technically the
+        * additional length field is only the upper 6 bits of the byte.
+        * The lower 2 bits are reserved.  If the lower 2 bits are 0 (as
+        * all reserved fields should be), then interpreting the byte as
+        * an int will yield the length in bytes.
+        */
+       if (srp->add_cdb_len & 0x03) {
+               dev_err(&vscsi->dev, "parse_cmd: reserved bits set in IU\n");
+               spin_lock_bh(&vscsi->intr_lock);
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+               spin_unlock_bh(&vscsi->intr_lock);
+               return;
+       }
+
+       if (srp_get_desc_table(srp, &dir, &data_len)) {
+               dev_err(&vscsi->dev, "0x%llx: parsing SRP descriptor table failed.\n",
+                       srp->tag);
+               goto fail;
+               return;
+       }
+
+       cmd->rsp.sol_not = srp->sol_not;
+
+       switch (srp->task_attr) {
+       case SRP_SIMPLE_TASK:
+               attr = TCM_SIMPLE_TAG;
+               break;
+       case SRP_ORDERED_TASK:
+               attr = TCM_ORDERED_TAG;
+               break;
+       case SRP_HEAD_TASK:
+               attr = TCM_HEAD_TAG;
+               break;
+       case SRP_ACA_TASK:
+               attr = TCM_ACA_TAG;
+               break;
+       default:
+               dev_err(&vscsi->dev, "Invalid task attribute %d\n",
+                       srp->task_attr);
+               goto fail;
+       }
+
+       cmd->se_cmd.tag = be64_to_cpu(srp->tag);
+
+       spin_lock_bh(&vscsi->intr_lock);
+       list_add_tail(&cmd->list, &vscsi->active_q);
+       spin_unlock_bh(&vscsi->intr_lock);
+
+       srp->lun.scsi_lun[0] &= 0x3f;
+
+       pr_debug("calling submit_cmd, se_cmd %p, lun 0x%llx, cdb 0x%x, attr:%d\n",
+                &cmd->se_cmd, scsilun_to_int(&srp->lun), (int)srp->cdb[0],
+                attr);
+
+       rc = target_submit_cmd(&cmd->se_cmd, nexus->se_sess, srp->cdb,
+                              cmd->sense_buf, scsilun_to_int(&srp->lun),
+                              data_len, attr, dir, 0);
+       if (rc) {
+               dev_err(&vscsi->dev, "target_submit_cmd failed, rc %d\n", rc);
+               goto fail;
+       }
+       return;
+
+fail:
+       spin_lock_bh(&vscsi->intr_lock);
+       ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+       spin_unlock_bh(&vscsi->intr_lock);
+}
+
+/**
+ * ibmvscsis_parse_task() - Parse SRP Task Management Request
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to command element with SRP task management request
+ *
+ * Parse the srp task management request; if it is valid then submit it to tcm.
+ * Note: The return code does not reflect the status of the task management
+ * request.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Processor level
+ */
+static void ibmvscsis_parse_task(struct scsi_info *vscsi,
+                                struct ibmvscsis_cmd *cmd)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
+       int tcm_type;
+       u64 tag_to_abort = 0;
+       int rc = 0;
+       struct ibmvscsis_nexus *nexus;
+
+       nexus = vscsi->tport.ibmv_nexus;
+
+       cmd->rsp.sol_not = srp_tsk->sol_not;
+
+       switch (srp_tsk->tsk_mgmt_func) {
+       case SRP_TSK_ABORT_TASK:
+               tcm_type = TMR_ABORT_TASK;
+               tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
+               break;
+       case SRP_TSK_ABORT_TASK_SET:
+               tcm_type = TMR_ABORT_TASK_SET;
+               break;
+       case SRP_TSK_CLEAR_TASK_SET:
+               tcm_type = TMR_CLEAR_TASK_SET;
+               break;
+       case SRP_TSK_LUN_RESET:
+               tcm_type = TMR_LUN_RESET;
+               break;
+       case SRP_TSK_CLEAR_ACA:
+               tcm_type = TMR_CLEAR_ACA;
+               break;
+       default:
+               dev_err(&vscsi->dev, "unknown task mgmt func %d\n",
+                       srp_tsk->tsk_mgmt_func);
+               cmd->se_cmd.se_tmr_req->response =
+                       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+               rc = -1;
+               break;
+       }
+
+       if (!rc) {
+               cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
+
+               spin_lock_bh(&vscsi->intr_lock);
+               list_add_tail(&cmd->list, &vscsi->active_q);
+               spin_unlock_bh(&vscsi->intr_lock);
+
+               srp_tsk->lun.scsi_lun[0] &= 0x3f;
+
+               pr_debug("calling submit_tmr, func %d\n",
+                        srp_tsk->tsk_mgmt_func);
+               rc = target_submit_tmr(&cmd->se_cmd, nexus->se_sess, NULL,
+                                      scsilun_to_int(&srp_tsk->lun), srp_tsk,
+                                      tcm_type, GFP_KERNEL, tag_to_abort, 0);
+               if (rc) {
+                       dev_err(&vscsi->dev, "target_submit_tmr failed, rc %d\n",
+                               rc);
+                       cmd->se_cmd.se_tmr_req->response =
+                               TMR_FUNCTION_REJECTED;
+               }
+       }
+
+       if (rc)
+               transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
+}
+
+static void ibmvscsis_scheduler(struct work_struct *work)
+{
+       struct ibmvscsis_cmd *cmd = container_of(work, struct ibmvscsis_cmd,
+                                                work);
+       struct scsi_info *vscsi = cmd->adapter;
+
+       spin_lock_bh(&vscsi->intr_lock);
+
+       /* Remove from schedule_q */
+       list_del(&cmd->list);
+
+       /* Don't submit cmd if we're disconnecting */
+       if (vscsi->flags & (SCHEDULE_DISCONNECT | DISCONNECT_SCHEDULED)) {
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+
+               /* ibmvscsis_disconnect might be waiting for us */
+               if (list_empty(&vscsi->active_q) &&
+                   list_empty(&vscsi->schedule_q) &&
+                   (vscsi->flags & WAIT_FOR_IDLE)) {
+                       vscsi->flags &= ~WAIT_FOR_IDLE;
+                       complete(&vscsi->wait_idle);
+               }
+
+               spin_unlock_bh(&vscsi->intr_lock);
+               return;
+       }
+
+       spin_unlock_bh(&vscsi->intr_lock);
+
+       switch (cmd->type) {
+       case SCSI_CDB:
+               ibmvscsis_parse_cmd(vscsi, cmd);
+               break;
+       case TASK_MANAGEMENT:
+               ibmvscsis_parse_task(vscsi, cmd);
+               break;
+       default:
+               dev_err(&vscsi->dev, "scheduler, invalid cmd type %d\n",
+                       cmd->type);
+               spin_lock_bh(&vscsi->intr_lock);
+               ibmvscsis_free_cmd_resources(vscsi, cmd);
+               spin_unlock_bh(&vscsi->intr_lock);
+               break;
+       }
+}
+
+static int ibmvscsis_alloc_cmds(struct scsi_info *vscsi, int num)
+{
+       struct ibmvscsis_cmd *cmd;
+       int i;
+
+       INIT_LIST_HEAD(&vscsi->free_cmd);
+       vscsi->cmd_pool = kcalloc(num, sizeof(struct ibmvscsis_cmd),
+                                 GFP_KERNEL);
+       if (!vscsi->cmd_pool)
+               return -ENOMEM;
+
+       for (i = 0, cmd = (struct ibmvscsis_cmd *)vscsi->cmd_pool; i < num;
+            i++, cmd++) {
+               cmd->adapter = vscsi;
+               INIT_WORK(&cmd->work, ibmvscsis_scheduler);
+               list_add_tail(&cmd->list, &vscsi->free_cmd);
+       }
+
+       return 0;
+}
+
+static void ibmvscsis_free_cmds(struct scsi_info *vscsi)
+{
+       kfree(vscsi->cmd_pool);
+       vscsi->cmd_pool = NULL;
+       INIT_LIST_HEAD(&vscsi->free_cmd);
+}
+
+/**
+ * ibmvscsis_service_wait_q() - Service Waiting Queue
+ * @timer:     Pointer to timer which has expired
+ *
+ * This routine is called when the timer pops to service the waiting
+ * queue. Elements on the queue have completed, their responses have been
+ * copied to the client, but the client's response queue was full so
+ * the queue message could not be sent. The routine grabs the proper locks
+ * and calls send messages.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     called at interrupt level
+ */
+static enum hrtimer_restart ibmvscsis_service_wait_q(struct hrtimer *timer)
+{
+       struct timer_cb *p_timer = container_of(timer, struct timer_cb, timer);
+       struct scsi_info *vscsi = container_of(p_timer, struct scsi_info,
+                                              rsp_q_timer);
+
+       spin_lock_bh(&vscsi->intr_lock);
+       p_timer->timer_pops += 1;
+       p_timer->started = false;
+       ibmvscsis_send_messages(vscsi);
+       spin_unlock_bh(&vscsi->intr_lock);
+
+       return HRTIMER_NORESTART;
+}
+
+static long ibmvscsis_alloctimer(struct scsi_info *vscsi)
+{
+       struct timer_cb *p_timer;
+
+       p_timer = &vscsi->rsp_q_timer;
+       hrtimer_init(&p_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+       p_timer->timer.function = ibmvscsis_service_wait_q;
+       p_timer->started = false;
+       p_timer->timer_pops = 0;
+
+       return ADAPT_SUCCESS;
+}
+
+static void ibmvscsis_freetimer(struct scsi_info *vscsi)
+{
+       struct timer_cb *p_timer;
+
+       p_timer = &vscsi->rsp_q_timer;
+
+       (void)hrtimer_cancel(&p_timer->timer);
+
+       p_timer->started = false;
+       p_timer->timer_pops = 0;
+}
+
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+       struct scsi_info *vscsi = data;
+
+       vio_disable_interrupts(vscsi->dma_dev);
+       tasklet_schedule(&vscsi->work_task);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ibmvscsis_check_q() - Helper function to Check Init Message Valid
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Checks if a initialize message was queued by the initiatior
+ * while the timing window was open.  This function is called from
+ * probe after the CRQ is created and interrupts are enabled.
+ * It would only be used by adapters who wait for some event before
+ * completing the init handshake with the client.  For ibmvscsi, this
+ * event is waiting for the port to be enabled.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level only, interrupt lock held
+ */
+static long ibmvscsis_check_q(struct scsi_info *vscsi)
+{
+       uint format;
+       long rc;
+
+       rc = ibmvscsis_check_init_msg(vscsi, &format);
+       if (rc)
+               ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT_RECONNECT, 0);
+       else if (format == UNUSED_FORMAT)
+               vscsi->state = WAIT_ENABLED;
+       else
+               vscsi->state = PART_UP_WAIT_ENAB;
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_enable_change_state() - Set new state based on enabled status
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * This function determines our new state now that we are enabled.  This
+ * may involve sending an Init Complete message to the client.
+ *
+ * Must be called with interrupt lock held.
+ */
+static long ibmvscsis_enable_change_state(struct scsi_info *vscsi)
+{
+       long rc = ADAPT_SUCCESS;
+
+handle_state_change:
+       switch (vscsi->state) {
+       case WAIT_ENABLED:
+               rc = ibmvscsis_send_init_message(vscsi, INIT_MSG);
+               switch (rc) {
+               case H_SUCCESS:
+               case H_DROPPED:
+               case H_CLOSED:
+                       vscsi->state =  WAIT_CONNECTION;
+                       rc = ADAPT_SUCCESS;
+                       break;
+
+               case H_PARAMETER:
+                       break;
+
+               case H_HARDWARE:
+                       break;
+
+               default:
+                       vscsi->state = UNDEFINED;
+                       rc = H_HARDWARE;
+                       break;
+               }
+               break;
+       case PART_UP_WAIT_ENAB:
+               rc = ibmvscsis_send_init_message(vscsi, INIT_COMPLETE_MSG);
+               switch (rc) {
+               case H_SUCCESS:
+                       vscsi->state = CONNECTED;
+                       rc = ADAPT_SUCCESS;
+                       break;
+
+               case H_DROPPED:
+               case H_CLOSED:
+                       vscsi->state = WAIT_ENABLED;
+                       goto handle_state_change;
+
+               case H_PARAMETER:
+                       break;
+
+               case H_HARDWARE:
+                       break;
+
+               default:
+                       rc = H_HARDWARE;
+                       break;
+               }
+               break;
+
+       case WAIT_CONNECTION:
+       case WAIT_IDLE:
+       case SRP_PROCESSING:
+       case CONNECTED:
+               rc = ADAPT_SUCCESS;
+               break;
+               /* should not be able to get here */
+       case UNCONFIGURING:
+               rc = ERROR;
+               vscsi->state = UNDEFINED;
+               break;
+
+               /* driver should never allow this to happen */
+       case ERR_DISCONNECT:
+       case ERR_DISCONNECT_RECONNECT:
+       default:
+               dev_err(&vscsi->dev, "in invalid state %d during enable_change_state\n",
+                       vscsi->state);
+               rc = ADAPT_SUCCESS;
+               break;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_create_command_q() - Create Command Queue
+ * @vscsi:     Pointer to our adapter structure
+ * @num_cmds:  Currently unused.  In the future, may be used to determine
+ *             the size of the CRQ.
+ *
+ * Allocates memory for command queue maps remote memory into an ioba
+ * initializes the command response queue
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level only
+ */
+static long ibmvscsis_create_command_q(struct scsi_info *vscsi, int num_cmds)
+{
+       long rc = 0;
+       int pages;
+       struct vio_dev *vdev = vscsi->dma_dev;
+
+       /* We might support multiple pages in the future, but just 1 for now */
+       pages = 1;
+
+       vscsi->cmd_q.size = pages;
+
+       vscsi->cmd_q.base_addr =
+               (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+       if (!vscsi->cmd_q.base_addr)
+               return -ENOMEM;
+
+       vscsi->cmd_q.mask = ((uint)pages * CRQ_PER_PAGE) - 1;
+
+       vscsi->cmd_q.crq_token = dma_map_single(&vdev->dev,
+                                               vscsi->cmd_q.base_addr,
+                                               PAGE_SIZE, DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(&vdev->dev, vscsi->cmd_q.crq_token)) {
+               free_page((unsigned long)vscsi->cmd_q.base_addr);
+               return -ENOMEM;
+       }
+
+       rc =  h_reg_crq(vscsi->dds.unit_id, vscsi->cmd_q.crq_token, PAGE_SIZE);
+       if (rc) {
+               if (rc == H_CLOSED) {
+                       vscsi->state = WAIT_ENABLED;
+                       rc = 0;
+               } else {
+                       dma_unmap_single(&vdev->dev, vscsi->cmd_q.crq_token,
+                                        PAGE_SIZE, DMA_BIDIRECTIONAL);
+                       free_page((unsigned long)vscsi->cmd_q.base_addr);
+                       rc = -ENODEV;
+               }
+       } else {
+               vscsi->state = WAIT_ENABLED;
+       }
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_destroy_command_q - Destroy Command Queue
+ * @vscsi:     Pointer to our adapter structure
+ *
+ * Releases memory for command queue and unmaps mapped remote memory.
+ *
+ * EXECUTION ENVIRONMENT:
+ *     Process level only
+ */
+static void ibmvscsis_destroy_command_q(struct scsi_info *vscsi)
+{
+       dma_unmap_single(&vscsi->dma_dev->dev, vscsi->cmd_q.crq_token,
+                        PAGE_SIZE, DMA_BIDIRECTIONAL);
+       free_page((unsigned long)vscsi->cmd_q.base_addr);
+       vscsi->cmd_q.base_addr = NULL;
+       vscsi->state = NO_QUEUE;
+}
+
+static u8 ibmvscsis_fast_fail(struct scsi_info *vscsi,
+                             struct ibmvscsis_cmd *cmd)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+       struct scsi_sense_hdr sshdr;
+       u8 rc = se_cmd->scsi_status;
+
+       if (vscsi->fast_fail && (READ_CMD(srp->cdb) || WRITE_CMD(srp->cdb)))
+               if (scsi_normalize_sense(se_cmd->sense_buffer,
+                                        se_cmd->scsi_sense_length, &sshdr))
+                       if (sshdr.sense_key == HARDWARE_ERROR &&
+                           (se_cmd->residual_count == 0 ||
+                            se_cmd->residual_count == se_cmd->data_length)) {
+                               rc = NO_SENSE;
+                               cmd->flags |= CMD_FAST_FAIL;
+                       }
+
+       return rc;
+}
+
+/**
+ * srp_build_response() - Build an SRP response buffer
+ * @vscsi:     Pointer to our adapter structure
+ * @cmd:       Pointer to command for which to send the response
+ * @len_p:     Where to return the length of the IU response sent.  This
+ *             is needed to construct the CRQ response.
+ *
+ * Build the SRP response buffer and copy it to the client's memory space.
+ */
+static long srp_build_response(struct scsi_info *vscsi,
+                              struct ibmvscsis_cmd *cmd, uint *len_p)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct srp_rsp *rsp;
+       uint len;
+       u32 rsp_code;
+       char *data;
+       u32 *tsk_status;
+       long rc = ADAPT_SUCCESS;
+
+       spin_lock_bh(&vscsi->intr_lock);
+
+       rsp = &vio_iu(iue)->srp.rsp;
+       len = sizeof(*rsp);
+       memset(rsp, 0, len);
+       data = rsp->data;
+
+       rsp->opcode = SRP_RSP;
+
+       if (vscsi->credit > 0 && vscsi->state == SRP_PROCESSING)
+               rsp->req_lim_delta = cpu_to_be32(vscsi->credit);
+       else
+               rsp->req_lim_delta = cpu_to_be32(1 + vscsi->credit);
+       rsp->tag = cmd->rsp.tag;
+       rsp->flags = 0;
+
+       if (cmd->type == SCSI_CDB) {
+               rsp->status = ibmvscsis_fast_fail(vscsi, cmd);
+               if (rsp->status) {
+                       pr_debug("build_resp: cmd %p, scsi status %d\n", cmd,
+                                (int)rsp->status);
+                       ibmvscsis_determine_resid(se_cmd, rsp);
+                       if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+                               rsp->sense_data_len =
+                                       cpu_to_be32(se_cmd->scsi_sense_length);
+                               rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+                               len += se_cmd->scsi_sense_length;
+                               memcpy(data, se_cmd->sense_buffer,
+                                      se_cmd->scsi_sense_length);
+                       }
+                       rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+                               UCSOLNT_RESP_SHIFT;
+               } else if (cmd->flags & CMD_FAST_FAIL) {
+                       pr_debug("build_resp: cmd %p, fast fail\n", cmd);
+                       rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+                               UCSOLNT_RESP_SHIFT;
+               } else {
+                       rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
+                               SCSOLNT_RESP_SHIFT;
+               }
+       } else {
+               /* this is task management */
+               rsp->status = 0;
+               rsp->resp_data_len = cpu_to_be32(4);
+               rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+
+               switch (se_cmd->se_tmr_req->response) {
+               case TMR_FUNCTION_COMPLETE:
+               case TMR_TASK_DOES_NOT_EXIST:
+                       rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
+                       rsp->sol_not = (cmd->rsp.sol_not & SCSOLNT) >>
+                               SCSOLNT_RESP_SHIFT;
+                       break;
+               case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+               case TMR_LUN_DOES_NOT_EXIST:
+                       rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
+                       rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+                               UCSOLNT_RESP_SHIFT;
+                       break;
+               case TMR_FUNCTION_FAILED:
+               case TMR_FUNCTION_REJECTED:
+               default:
+                       rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
+                       rsp->sol_not = (cmd->rsp.sol_not & UCSOLNT) >>
+                               UCSOLNT_RESP_SHIFT;
+                       break;
+               }
+
+               tsk_status = (u32 *)data;
+               *tsk_status = cpu_to_be32(rsp_code);
+               data = (char *)(tsk_status + 1);
+               len += 4;
+       }
+
+       dma_wmb();
+       rc = h_copy_rdma(len, vscsi->dds.window[LOCAL].liobn, iue->sbuf->dma,
+                        vscsi->dds.window[REMOTE].liobn,
+                        be64_to_cpu(iue->remote_token));
+
+       switch (rc) {
+       case H_SUCCESS:
+               vscsi->credit = 0;
+               *len_p = len;
+               break;
+       case H_PERMISSION:
+               if (connection_broken(vscsi))
+                       vscsi->flags |= RESPONSE_Q_DOWN | CLIENT_FAILED;
+
+               dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld, flags 0x%x, state 0x%hx\n",
+                       rc, vscsi->flags, vscsi->state);
+               break;
+       case H_SOURCE_PARM:
+       case H_DEST_PARM:
+       default:
+               dev_err(&vscsi->dev, "build_response: error copying to client, rc %ld\n",
+                       rc);
+               break;
+       }
+
+       spin_unlock_bh(&vscsi->intr_lock);
+
+       return rc;
+}
+
+static int ibmvscsis_rdma(struct ibmvscsis_cmd *cmd, struct scatterlist *sg,
+                         int nsg, struct srp_direct_buf *md, int nmd,
+                         enum dma_data_direction dir, unsigned int bytes)
+{
+       struct iu_entry *iue = cmd->iue;
+       struct srp_target *target = iue->target;
+       struct scsi_info *vscsi = target->ldata;
+       struct scatterlist *sgp;
+       dma_addr_t client_ioba, server_ioba;
+       ulong buf_len;
+       ulong client_len, server_len;
+       int md_idx;
+       long tx_len;
+       long rc = 0;
+
+       pr_debug("rdma: dir %d, bytes 0x%x\n", dir, bytes);
+
+       if (bytes == 0)
+               return 0;
+
+       sgp = sg;
+       client_len = 0;
+       server_len = 0;
+       md_idx = 0;
+       tx_len = bytes;
+
+       do {
+               if (client_len == 0) {
+                       if (md_idx >= nmd) {
+                               dev_err(&vscsi->dev, "rdma: ran out of client memory descriptors\n");
+                               rc = -EIO;
+                               break;
+                       }
+                       client_ioba = be64_to_cpu(md[md_idx].va);
+                       client_len = be32_to_cpu(md[md_idx].len);
+               }
+               if (server_len == 0) {
+                       if (!sgp) {
+                               dev_err(&vscsi->dev, "rdma: ran out of scatter/gather list\n");
+                               rc = -EIO;
+                               break;
+                       }
+                       server_ioba = sg_dma_address(sgp);
+                       server_len = sg_dma_len(sgp);
+               }
+
+               buf_len = tx_len;
+
+               if (buf_len > client_len)
+                       buf_len = client_len;
+
+               if (buf_len > server_len)
+                       buf_len = server_len;
+
+               if (buf_len > max_vdma_size)
+                       buf_len = max_vdma_size;
+
+               if (dir == DMA_TO_DEVICE) {
+                       /* read from client */
+                       rc = h_copy_rdma(buf_len,
+                                        vscsi->dds.window[REMOTE].liobn,
+                                        client_ioba,
+                                        vscsi->dds.window[LOCAL].liobn,
+                                        server_ioba);
+               } else {
+                       /* write to client */
+                       struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+
+                       if (!READ_CMD(srp->cdb))
+                               print_hex_dump_bytes(" data:", DUMP_PREFIX_NONE,
+                                                    sg_virt(sgp), buf_len);
+                       /* The h_copy_rdma will cause phyp, running in another
+                        * partition, to read memory, so we need to make sure
+                        * the data has been written out, hence these syncs.
+                        */
+                       /* ensure that everything is in memory */
+                       isync();
+                       /* ensure that memory has been made visible */
+                       dma_wmb();
+                       rc = h_copy_rdma(buf_len,
+                                        vscsi->dds.window[LOCAL].liobn,
+                                        server_ioba,
+                                        vscsi->dds.window[REMOTE].liobn,
+                                        client_ioba);
+               }
+               switch (rc) {
+               case H_SUCCESS:
+                       break;
+               case H_PERMISSION:
+               case H_SOURCE_PARM:
+               case H_DEST_PARM:
+                       if (connection_broken(vscsi)) {
+                               spin_lock_bh(&vscsi->intr_lock);
+                               vscsi->flags |=
+                                       (RESPONSE_Q_DOWN | CLIENT_FAILED);
+                               spin_unlock_bh(&vscsi->intr_lock);
+                       }
+                       dev_err(&vscsi->dev, "rdma: h_copy_rdma failed, rc %ld\n",
+                               rc);
+                       break;
+
+               default:
+                       dev_err(&vscsi->dev, "rdma: unknown error %ld from h_copy_rdma\n",
+                               rc);
+                       break;
+               }
+
+               if (!rc) {
+                       tx_len -= buf_len;
+                       if (tx_len) {
+                               client_len -= buf_len;
+                               if (client_len == 0)
+                                       md_idx++;
+                               else
+                                       client_ioba += buf_len;
+
+                               server_len -= buf_len;
+                               if (server_len == 0)
+                                       sgp = sg_next(sgp);
+                               else
+                                       server_ioba += buf_len;
+                       } else {
+                               break;
+                       }
+               }
+       } while (!rc);
+
+       return rc;
+}
+
+/**
+ * ibmvscsis_handle_crq() - Handle CRQ
+ * @data:      Pointer to our adapter structure
+ *
+ * Read the command elements from the command queue and copy the payloads
+ * associated with the command elements to local memory and execute the
+ * SRP requests.
+ *
+ * Note: this is an edge triggered interrupt. It can not be shared.
+ */
+static void ibmvscsis_handle_crq(unsigned long data)
+{
+       struct scsi_info *vscsi = (struct scsi_info *)data;
+       struct viosrp_crq *crq;
+       long rc;
+       bool ack = true;
+       volatile u8 valid;
+
+       spin_lock_bh(&vscsi->intr_lock);
+
+       pr_debug("got interrupt\n");
+
+       /*
+        * if we are in a path where we are waiting for all pending commands
+        * to complete because we received a transport event and anything in
+        * the command queue is for a new connection,  do nothing
+        */
+       if (TARGET_STOP(vscsi)) {
+               vio_enable_interrupts(vscsi->dma_dev);
+
+               pr_debug("handle_crq, don't process: flags 0x%x, state 0x%hx\n",
+                        vscsi->flags, vscsi->state);
+               spin_unlock_bh(&vscsi->intr_lock);
+               return;
+       }
+
+       rc = vscsi->flags & SCHEDULE_DISCONNECT;
+       crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+       valid = crq->valid;
+       dma_rmb();
+
+       while (valid) {
+               /*
+                * These are edege triggered interrupts. After dropping out of
+                * the while loop, the code must check for work since an
+                * interrupt could be lost, and an elment be left on the queue,
+                * hence the label.
+                */
+cmd_work:
+               vscsi->cmd_q.index =
+                       (vscsi->cmd_q.index + 1) & vscsi->cmd_q.mask;
+
+               if (!rc) {
+                       rc = ibmvscsis_parse_command(vscsi, crq);
+               } else {
+                       if ((uint)crq->valid == VALID_TRANS_EVENT) {
+                               /*
+                                * must service the transport layer events even
+                                * in an error state, dont break out until all
+                                * the consecutive transport events have been
+                                * processed
+                                */
+                               rc = ibmvscsis_trans_event(vscsi, crq);
+                       } else if (vscsi->flags & TRANS_EVENT) {
+                               /*
+                                * if a tranport event has occurred leave
+                                * everything but transport events on the queue
+                                */
+                               pr_debug("handle_crq, ignoring\n");
+
+                               /*
+                                * need to decrement the queue index so we can
+                                * look at the elment again
+                                */
+                               if (vscsi->cmd_q.index)
+                                       vscsi->cmd_q.index -= 1;
+                               else
+                                       /*
+                                        * index is at 0 it just wrapped.
+                                        * have it index last element in q
+                                        */
+                                       vscsi->cmd_q.index = vscsi->cmd_q.mask;
+                               break;
+                       }
+               }
+
+               crq->valid = INVALIDATE_CMD_RESP_EL;
+
+               crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
+               valid = crq->valid;
+               dma_rmb();
+       }
+
+       if (!rc) {
+               if (ack) {
+                       vio_enable_interrupts(vscsi->dma_dev);
+                       ack = false;
+                       pr_debug("handle_crq, reenabling interrupts\n");
+               }
+               valid = crq->valid;
+               dma_rmb();
+               if (valid)
+                       goto cmd_work;
+       } else {
+               pr_debug("handle_crq, error: flags 0x%x, state 0x%hx, crq index 0x%x\n",
+                        vscsi->flags, vscsi->state, vscsi->cmd_q.index);
+       }
+
+       pr_debug("Leaving handle_crq: schedule_q empty %d, flags 0x%x, state 0x%hx\n",
+                (int)list_empty(&vscsi->schedule_q), vscsi->flags,
+                vscsi->state);
+
+       spin_unlock_bh(&vscsi->intr_lock);
+}
+
+static int ibmvscsis_probe(struct vio_dev *vdev,
+                          const struct vio_device_id *id)
+{
+       struct scsi_info *vscsi;
+       int rc = 0;
+       long hrc = 0;
+       char wq_name[24];
+
+       vscsi = kzalloc(sizeof(*vscsi), GFP_KERNEL);
+       if (!vscsi) {
+               rc = -ENOMEM;
+               pr_err("probe: allocation of adapter failed\n");
+               return rc;
+       }
+
+       vscsi->dma_dev = vdev;
+       vscsi->dev = vdev->dev;
+       INIT_LIST_HEAD(&vscsi->schedule_q);
+       INIT_LIST_HEAD(&vscsi->waiting_rsp);
+       INIT_LIST_HEAD(&vscsi->active_q);
+
+       snprintf(vscsi->tport.tport_name, 256, "%s", dev_name(&vdev->dev));
+
+       pr_debug("probe tport_name: %s\n", vscsi->tport.tport_name);
+
+       rc = read_dma_window(vscsi);
+       if (rc)
+               goto free_adapter;
+       pr_debug("Probe: liobn 0x%x, riobn 0x%x\n",
+                vscsi->dds.window[LOCAL].liobn,
+                vscsi->dds.window[REMOTE].liobn);
+
+       strcpy(vscsi->eye, "VSCSI ");
+       strncat(vscsi->eye, vdev->name, MAX_EYE);
+
+       vscsi->dds.unit_id = vdev->unit_address;
+
+       spin_lock_bh(&ibmvscsis_dev_lock);
+       list_add_tail(&vscsi->list, &ibmvscsis_dev_list);
+       spin_unlock_bh(&ibmvscsis_dev_lock);
+
+       /*
+        * TBD: How do we determine # of cmds to request?  Do we know how
+        * many "children" we have?
+        */
+       vscsi->request_limit = INITIAL_SRP_LIMIT;
+       rc = srp_target_alloc(&vscsi->target, &vdev->dev, vscsi->request_limit,
+                             SRP_MAX_IU_LEN);
+       if (rc)
+               goto rem_list;
+
+       vscsi->target.ldata = vscsi;
+
+       rc = ibmvscsis_alloc_cmds(vscsi, vscsi->request_limit);
+       if (rc) {
+               dev_err(&vscsi->dev, "alloc_cmds failed, rc %d, num %d\n",
+                       rc, vscsi->request_limit);
+               goto free_target;
+       }
+
+       /*
+        * Note: the lock is used in freeing timers, so must initialize
+        * first so that ordering in case of error is correct.
+        */
+       spin_lock_init(&vscsi->intr_lock);
+
+       rc = ibmvscsis_alloctimer(vscsi);
+       if (rc) {
+               dev_err(&vscsi->dev, "probe: alloctimer failed, rc %d\n", rc);
+               goto free_cmds;
+       }
+
+       rc = ibmvscsis_create_command_q(vscsi, 256);
+       if (rc) {
+               dev_err(&vscsi->dev, "probe: create_command_q failed, rc %d\n",
+                       rc);
+               goto free_timer;
+       }
+
+       vscsi->map_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!vscsi->map_buf) {
+               rc = -ENOMEM;
+               dev_err(&vscsi->dev, "probe: allocating cmd buffer failed\n");
+               goto destroy_queue;
+       }
+
+       vscsi->map_ioba = dma_map_single(&vdev->dev, vscsi->map_buf, PAGE_SIZE,
+                                        DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(&vdev->dev, vscsi->map_ioba)) {
+               dev_err(&vscsi->dev, "probe: error mapping command buffer\n");
+               goto free_buf;
+       }
+
+       hrc = h_vioctl(vscsi->dds.unit_id, H_GET_PARTNER_INFO,
+                      (u64)vscsi->map_ioba | ((u64)PAGE_SIZE << 32), 0, 0, 0,
+                      0);
+       if (hrc == H_SUCCESS)
+               vscsi->client_data.partition_number =
+                       be64_to_cpu(*(u64 *)vscsi->map_buf);
+       /*
+        * We expect the VIOCTL to fail if we're configured as "any
+        * client can connect" and the client isn't activated yet.
+        * We'll make the call again when he sends an init msg.
+        */
+       pr_debug("probe hrc %ld, client partition num %d\n",
+                hrc, vscsi->client_data.partition_number);
+
+       tasklet_init(&vscsi->work_task, ibmvscsis_handle_crq,
+                    (unsigned long)vscsi);
+
+       init_completion(&vscsi->wait_idle);
+
+       snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev));
+       vscsi->work_q = create_workqueue(wq_name);
+       if (!vscsi->work_q) {
+               rc = -ENOMEM;
+               dev_err(&vscsi->dev, "create_workqueue failed\n");
+               goto unmap_buf;
+       }
+
+       rc = request_irq(vdev->irq, ibmvscsis_interrupt, 0, "ibmvscsis", vscsi);
+       if (rc) {
+               rc = -EPERM;
+               dev_err(&vscsi->dev, "probe: request_irq failed, rc %d\n", rc);
+               goto destroy_WQ;
+       }
+
+       spin_lock_bh(&vscsi->intr_lock);
+       vio_enable_interrupts(vdev);
+       if (rc) {
+               dev_err(&vscsi->dev, "enabling interrupts failed, rc %d\n", rc);
+               rc = -ENODEV;
+               spin_unlock_bh(&vscsi->intr_lock);
+               goto free_irq;
+       }
+
+       if (ibmvscsis_check_q(vscsi)) {
+               rc = ERROR;
+               dev_err(&vscsi->dev, "probe: check_q failed, rc %d\n", rc);
+               spin_unlock_bh(&vscsi->intr_lock);
+               goto disable_interrupt;
+       }
+       spin_unlock_bh(&vscsi->intr_lock);
+
+       dev_set_drvdata(&vdev->dev, vscsi);
+
+       return 0;
+
+disable_interrupt:
+       vio_disable_interrupts(vdev);
+free_irq:
+       free_irq(vdev->irq, vscsi);
+destroy_WQ:
+       destroy_workqueue(vscsi->work_q);
+unmap_buf:
+       dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
+                        DMA_BIDIRECTIONAL);
+free_buf:
+       kfree(vscsi->map_buf);
+destroy_queue:
+       tasklet_kill(&vscsi->work_task);
+       ibmvscsis_unregister_command_q(vscsi);
+       ibmvscsis_destroy_command_q(vscsi);
+free_timer:
+       ibmvscsis_freetimer(vscsi);
+free_cmds:
+       ibmvscsis_free_cmds(vscsi);
+free_target:
+       srp_target_free(&vscsi->target);
+rem_list:
+       spin_lock_bh(&ibmvscsis_dev_lock);
+       list_del(&vscsi->list);
+       spin_unlock_bh(&ibmvscsis_dev_lock);
+free_adapter:
+       kfree(vscsi);
+
+       return rc;
+}
+
+static int ibmvscsis_remove(struct vio_dev *vdev)
+{
+       struct scsi_info *vscsi = dev_get_drvdata(&vdev->dev);
+
+       pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev));
+
+       /*
+        * TBD: Need to handle if there are commands on the waiting_rsp q
+        *      Actually, can there still be cmds outstanding to tcm?
+        */
+
+       vio_disable_interrupts(vdev);
+       free_irq(vdev->irq, vscsi);
+       destroy_workqueue(vscsi->work_q);
+       dma_unmap_single(&vdev->dev, vscsi->map_ioba, PAGE_SIZE,
+                        DMA_BIDIRECTIONAL);
+       kfree(vscsi->map_buf);
+       tasklet_kill(&vscsi->work_task);
+       ibmvscsis_unregister_command_q(vscsi);
+       ibmvscsis_destroy_command_q(vscsi);
+       ibmvscsis_freetimer(vscsi);
+       ibmvscsis_free_cmds(vscsi);
+       srp_target_free(&vscsi->target);
+       spin_lock_bh(&ibmvscsis_dev_lock);
+       list_del(&vscsi->list);
+       spin_unlock_bh(&ibmvscsis_dev_lock);
+       kfree(vscsi);
+
+       return 0;
+}
+
+static ssize_t system_id_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
+
+static ssize_t partition_number_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
+}
+
+static ssize_t unit_address_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct scsi_info *vscsi = container_of(dev, struct scsi_info, dev);
+
+       return snprintf(buf, PAGE_SIZE, "%x\n", vscsi->dma_dev->unit_address);
+}
+
+static int ibmvscsis_get_system_info(void)
+{
+       struct device_node *rootdn, *vdevdn;
+       const char *id, *model, *name;
+       const uint *num;
+
+       rootdn = of_find_node_by_path("/");
+       if (!rootdn)
+               return -ENOENT;
+
+       model = of_get_property(rootdn, "model", NULL);
+       id = of_get_property(rootdn, "system-id", NULL);
+       if (model && id)
+               snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+       name = of_get_property(rootdn, "ibm,partition-name", NULL);
+       if (name)
+               strncpy(partition_name, name, sizeof(partition_name));
+
+       num = of_get_property(rootdn, "ibm,partition-no", NULL);
+       if (num)
+               partition_number = *num;
+
+       of_node_put(rootdn);
+
+       vdevdn = of_find_node_by_path("/vdevice");
+       if (vdevdn) {
+               const uint *mvds;
+
+               mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
+                                      NULL);
+               if (mvds)
+                       max_vdma_size = *mvds;
+               of_node_put(vdevdn);
+       }
+
+       return 0;
+}
+
+static char *ibmvscsis_get_fabric_name(void)
+{
+       return "ibmvscsis";
+}
+
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+       struct ibmvscsis_tport *tport =
+               container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+       return tport->tport_name;
+}
+
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+       struct ibmvscsis_tport *tport =
+               container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+       return tport->tport_tpgt;
+}
+
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+       return target_put_sess_cmd(se_cmd);
+}
+
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
+{
+       struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+                                                se_cmd);
+       struct scsi_info *vscsi = cmd->adapter;
+
+       pr_debug("release_cmd %p, flags %d\n", se_cmd, cmd->flags);
+
+       spin_lock_bh(&vscsi->intr_lock);
+       /* Remove from active_q */
+       list_del(&cmd->list);
+       list_add_tail(&cmd->list, &vscsi->waiting_rsp);
+       ibmvscsis_send_messages(vscsi);
+       spin_unlock_bh(&vscsi->intr_lock);
+}
+
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+       struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+                                                se_cmd);
+       struct iu_entry *iue = cmd->iue;
+       int rc;
+
+       pr_debug("write_pending, se_cmd %p, length 0x%x\n",
+                se_cmd, se_cmd->data_length);
+
+       rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma,
+                              1, 1);
+       if (rc) {
+               pr_err("srp_transfer_data() failed: %d\n", rc);
+               return -EAGAIN;
+       }
+       /*
+        * We now tell TCM to add this WRITE CDB directly into the TCM storage
+        * object execution queue.
+        */
+       target_execute_cmd(se_cmd);
+       return 0;
+}
+
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+{
+       struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+                                                se_cmd);
+       struct iu_entry *iue = cmd->iue;
+       struct scsi_info *vscsi = cmd->adapter;
+       char *sd;
+       uint len = 0;
+       int rc;
+
+       pr_debug("queue_data_in, se_cmd %p, length 0x%x\n",
+                se_cmd, se_cmd->data_length);
+
+       rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma, 1,
+                              1);
+       if (rc) {
+               pr_err("srp_transfer_data failed: %d\n", rc);
+               sd = se_cmd->sense_buffer;
+               se_cmd->scsi_sense_length = 18;
+               memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
+               /* Logical Unit Communication Time-out asc/ascq = 0x0801 */
+               scsi_build_sense_buffer(0, se_cmd->sense_buffer, MEDIUM_ERROR,
+                                       0x08, 0x01);
+       }
+
+       srp_build_response(vscsi, cmd, &len);
+       cmd->rsp.format = SRP_FORMAT;
+       cmd->rsp.len = len;
+
+       return 0;
+}
+
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+{
+       struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+                                                se_cmd);
+       struct scsi_info *vscsi = cmd->adapter;
+       uint len;
+
+       pr_debug("queue_status %p\n", se_cmd);
+
+       srp_build_response(vscsi, cmd, &len);
+       cmd->rsp.format = SRP_FORMAT;
+       cmd->rsp.len = len;
+
+       return 0;
+}
+
+static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+       struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
+                                                se_cmd);
+       struct scsi_info *vscsi = cmd->adapter;
+       uint len;
+
+       pr_debug("queue_tm_rsp %p, status %d\n",
+                se_cmd, (int)se_cmd->se_tmr_req->response);
+
+       srp_build_response(vscsi, cmd, &len);
+       cmd->rsp.format = SRP_FORMAT;
+       cmd->rsp.len = len;
+}
+
+static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
+{
+       /* TBD: What (if anything) should we do here? */
+       pr_debug("ibmvscsis_aborted_task %p\n", se_cmd);
+}
+
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+                                          struct config_group *group,
+                                          const char *name)
+{
+       struct ibmvscsis_tport *tport;
+
+       tport = ibmvscsis_lookup_port(name);
+       if (tport) {
+               tport->tport_proto_id = SCSI_PROTOCOL_SRP;
+               pr_debug("make_tport(%s), pointer:%p, tport_id:%x\n",
+                        name, tport, tport->tport_proto_id);
+               return &tport->tport_wwn;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+       struct ibmvscsis_tport *tport = container_of(wwn,
+                                                    struct ibmvscsis_tport,
+                                                    tport_wwn);
+
+       pr_debug("drop_tport(%s)\n",
+                config_item_name(&tport->tport_wwn.wwn_group.cg_item));
+}
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+                                                 struct config_group *group,
+                                                 const char *name)
+{
+       struct ibmvscsis_tport *tport =
+               container_of(wwn, struct ibmvscsis_tport, tport_wwn);
+       int rc;
+
+       tport->releasing = false;
+
+       rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg,
+                              tport->tport_proto_id);
+       if (rc)
+               return ERR_PTR(rc);
+
+       return &tport->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+       struct ibmvscsis_tport *tport = container_of(se_tpg,
+                                                    struct ibmvscsis_tport,
+                                                    se_tpg);
+
+       tport->releasing = true;
+       tport->enabled = false;
+
+       /*
+        * Release the virtual I_T Nexus for this ibmvscsis TPG
+        */
+       ibmvscsis_drop_nexus(tport);
+       /*
+        * Deregister the se_tpg from TCM..
+        */
+       core_tpg_deregister(se_tpg);
+}
+
+static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
+                                         char *page)
+{
+       return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
+}
+CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+       &ibmvscsis_wwn_attr_version,
+       NULL,
+};
+
+static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
+                                        char *page)
+{
+       struct se_portal_group *se_tpg = to_tpg(item);
+       struct ibmvscsis_tport *tport = container_of(se_tpg,
+                                                    struct ibmvscsis_tport,
+                                                    se_tpg);
+
+       return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+}
+
+static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
+                                         const char *page, size_t count)
+{
+       struct se_portal_group *se_tpg = to_tpg(item);
+       struct ibmvscsis_tport *tport = container_of(se_tpg,
+                                                    struct ibmvscsis_tport,
+                                                    se_tpg);
+       struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport);
+       unsigned long tmp;
+       int rc;
+       long lrc;
+
+       rc = kstrtoul(page, 0, &tmp);
+       if (rc < 0) {
+               pr_err("Unable to extract srpt_tpg_store_enable\n");
+               return -EINVAL;
+       }
+
+       if ((tmp != 0) && (tmp != 1)) {
+               pr_err("Illegal value for srpt_tpg_store_enable\n");
+               return -EINVAL;
+       }
+
+       if (tmp) {
+               tport->enabled = true;
+               spin_lock_bh(&vscsi->intr_lock);
+               lrc = ibmvscsis_enable_change_state(vscsi);
+               if (lrc)
+                       pr_err("enable_change_state failed, rc %ld state %d\n",
+                              lrc, vscsi->state);
+               spin_unlock_bh(&vscsi->intr_lock);
+       } else {
+               tport->enabled = false;
+       }
+
+       pr_debug("tpg_enable_store, state %d\n", vscsi->state);
+
+       return count;
+}
+CONFIGFS_ATTR(ibmvscsis_tpg_, enable);
+
+static struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
+       &ibmvscsis_tpg_attr_enable,
+       NULL,
+};
+
+static const struct target_core_fabric_ops ibmvscsis_ops = {
+       .module                         = THIS_MODULE,
+       .name                           = "ibmvscsis",
+       .get_fabric_name                = ibmvscsis_get_fabric_name,
+       .tpg_get_wwn                    = ibmvscsis_get_fabric_wwn,
+       .tpg_get_tag                    = ibmvscsis_get_tag,
+       .tpg_get_default_depth          = ibmvscsis_get_default_depth,
+       .tpg_check_demo_mode            = ibmvscsis_check_true,
+       .tpg_check_demo_mode_cache      = ibmvscsis_check_true,
+       .tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+       .tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+       .tpg_get_inst_index             = ibmvscsis_tpg_get_inst_index,
+       .check_stop_free                = ibmvscsis_check_stop_free,
+       .release_cmd                    = ibmvscsis_release_cmd,
+       .sess_get_index                 = ibmvscsis_sess_get_index,
+       .write_pending                  = ibmvscsis_write_pending,
+       .write_pending_status           = ibmvscsis_write_pending_status,
+       .set_default_node_attributes    = ibmvscsis_set_default_node_attrs,
+       .get_cmd_state                  = ibmvscsis_get_cmd_state,
+       .queue_data_in                  = ibmvscsis_queue_data_in,
+       .queue_status                   = ibmvscsis_queue_status,
+       .queue_tm_rsp                   = ibmvscsis_queue_tm_rsp,
+       .aborted_task                   = ibmvscsis_aborted_task,
+       /*
+        * Setup function pointers for logic in target_core_fabric_configfs.c
+        */
+       .fabric_make_wwn                = ibmvscsis_make_tport,
+       .fabric_drop_wwn                = ibmvscsis_drop_tport,
+       .fabric_make_tpg                = ibmvscsis_make_tpg,
+       .fabric_drop_tpg                = ibmvscsis_drop_tpg,
+
+       .tfc_wwn_attrs                  = ibmvscsis_wwn_attrs,
+       .tfc_tpg_base_attrs             = ibmvscsis_tpg_attrs,
+};
+
+static void ibmvscsis_dev_release(struct device *dev) {};
+
+static struct class_attribute ibmvscsis_class_attrs[] = {
+       __ATTR_NULL,
+};
+
+static struct device_attribute dev_attr_system_id =
+       __ATTR(system_id, S_IRUGO, system_id_show, NULL);
+
+static struct device_attribute dev_attr_partition_number =
+       __ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+
+static struct device_attribute dev_attr_unit_address =
+       __ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct attribute *ibmvscsis_dev_attrs[] = {
+       &dev_attr_system_id.attr,
+       &dev_attr_partition_number.attr,
+       &dev_attr_unit_address.attr,
+};
+ATTRIBUTE_GROUPS(ibmvscsis_dev);
+
+static struct class ibmvscsis_class = {
+       .name           = "ibmvscsis",
+       .dev_release    = ibmvscsis_dev_release,
+       .class_attrs    = ibmvscsis_class_attrs,
+       .dev_groups     = ibmvscsis_dev_groups,
+};
+
+static struct vio_device_id ibmvscsis_device_table[] = {
+       { "v-scsi-host", "IBM,v-scsi-host" },
+       { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+       .name = "ibmvscsis",
+       .id_table = ibmvscsis_device_table,
+       .probe = ibmvscsis_probe,
+       .remove = ibmvscsis_remove,
+};
+
+/*
+ * ibmvscsis_init() - Kernel Module initialization
+ *
+ * Note: vio_register_driver() registers callback functions, and at least one
+ * of those callback functions calls TCM - Linux IO Target Subsystem, thus
+ * the SCSI Target template must be registered before vio_register_driver()
+ * is called.
+ */
+static int __init ibmvscsis_init(void)
+{
+       int rc = 0;
+
+       rc = ibmvscsis_get_system_info();
+       if (rc) {
+               pr_err("rc %d from get_system_info\n", rc);
+               goto out;
+       }
+
+       rc = class_register(&ibmvscsis_class);
+       if (rc) {
+               pr_err("failed class register\n");
+               goto out;
+       }
+
+       rc = target_register_template(&ibmvscsis_ops);
+       if (rc) {
+               pr_err("rc %d from target_register_template\n", rc);
+               goto unregister_class;
+       }
+
+       rc = vio_register_driver(&ibmvscsis_driver);
+       if (rc) {
+               pr_err("rc %d from vio_register_driver\n", rc);
+               goto unregister_target;
+       }
+
+       return 0;
+
+unregister_target:
+       target_unregister_template(&ibmvscsis_ops);
+unregister_class:
+       class_unregister(&ibmvscsis_class);
+out:
+       return rc;
+}
+
+static void __exit ibmvscsis_exit(void)
+{
+       pr_info("Unregister IBM virtual SCSI host driver\n");
+       vio_unregister_driver(&ibmvscsis_driver);
+       target_unregister_template(&ibmvscsis_ops);
+       class_unregister(&ibmvscsis_class);
+}
+
+MODULE_DESCRIPTION("IBMVSCSIS fabric driver");
+MODULE_AUTHOR("Bryant G. Ly and Michael Cyr");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVSCSIS_VERSION);
+module_init(ibmvscsis_init);
+module_exit(ibmvscsis_exit);
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
new file mode 100644 (file)
index 0000000..981a0c9
--- /dev/null
@@ -0,0 +1,346 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *                        Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *                        Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp.
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ * Authors: Michael Cyr <mikecyr@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.
+ *
+ ****************************************************************************/
+
+#ifndef __H_IBMVSCSI_TGT
+#define __H_IBMVSCSI_TGT
+
+#include "libsrp.h"
+
+#define SYS_ID_NAME_LEN                64
+#define PARTITION_NAMELEN      96
+#define IBMVSCSIS_NAMELEN       32
+
+#define MSG_HI  0
+#define MSG_LOW 1
+
+#define MAX_CMD_Q_PAGES       4
+#define CRQ_PER_PAGE          (PAGE_SIZE / sizeof(struct viosrp_crq))
+/* in terms of number of elements */
+#define DEFAULT_CMD_Q_SIZE    CRQ_PER_PAGE
+#define MAX_CMD_Q_SIZE        (DEFAULT_CMD_Q_SIZE * MAX_CMD_Q_PAGES)
+
+#define SRP_VIOLATION           0x102  /* general error code */
+
+/*
+ * SRP buffer formats defined as of 16.a supported by this driver.
+ */
+#define SUPPORTED_FORMATS  ((SRP_DATA_DESC_DIRECT << 1) | \
+                           (SRP_DATA_DESC_INDIRECT << 1))
+
+#define SCSI_LUN_ADDR_METHOD_FLAT      1
+
+struct dma_window {
+       u32 liobn;      /* Unique per vdevice */
+       u64 tce_base;   /* Physical location of the TCE table */
+       u64 tce_size;   /* Size of the TCE table in bytes */
+};
+
+struct target_dds {
+       u64 unit_id;                /* 64 bit will force alignment */
+#define NUM_DMA_WINDOWS 2
+#define LOCAL  0
+#define REMOTE 1
+       struct dma_window  window[NUM_DMA_WINDOWS];
+
+       /* root node property "ibm,partition-no" */
+       uint partition_num;
+       char partition_name[PARTITION_NAMELEN];
+};
+
+#define MAX_NUM_PORTS        1
+#define MAX_H_COPY_RDMA      (128 * 1024)
+
+#define MAX_EYE   64
+
+/* Return codes */
+#define ADAPT_SUCCESS            0L
+/* choose error codes that do not conflict with PHYP */
+#define ERROR                   -40L
+
+struct format_code {
+       u8 reserved;
+       u8 buffers;
+};
+
+struct client_info {
+#define SRP_VERSION "16.a"
+       char srp_version[8];
+       /* root node property ibm,partition-name */
+       char partition_name[PARTITION_NAMELEN];
+       /* root node property ibm,partition-no */
+       u32 partition_number;
+       /* initially 1 */
+       u32 mad_version;
+       u32 os_type;
+};
+
+/*
+ * Changing this constant changes the number of seconds to wait before
+ * considering the client will never service its queue again.
+ */
+#define SECONDS_TO_CONSIDER_FAILED 30
+/*
+ * These constants set the polling period used to determine if the client
+ * has freed at least one element in the response queue.
+ */
+#define WAIT_SECONDS 1
+#define WAIT_NANO_SECONDS 5000
+#define MAX_TIMER_POPS ((1000000 / WAIT_NANO_SECONDS) * \
+                       SECONDS_TO_CONSIDER_FAILED)
+/*
+ * general purpose timer control block
+ * which can be used for multiple functions
+ */
+struct timer_cb {
+       struct hrtimer timer;
+       /*
+        * how long has it been since the client
+        * serviced the queue. The variable is incrmented
+        * in the service_wait_q routine and cleared
+        * in send messages
+        */
+       int timer_pops;
+       /* the timer is started */
+       bool started;
+};
+
+struct cmd_queue {
+       /* kva */
+       struct viosrp_crq *base_addr;
+       dma_addr_t crq_token;
+       /* used to maintain index */
+       uint mask;
+       /* current element */
+       uint index;
+       int size;
+};
+
+#define SCSOLNT_RESP_SHIFT     1
+#define UCSOLNT_RESP_SHIFT     2
+
+#define SCSOLNT         BIT(SCSOLNT_RESP_SHIFT)
+#define UCSOLNT         BIT(UCSOLNT_RESP_SHIFT)
+
+enum cmd_type {
+       SCSI_CDB        = 0x01,
+       TASK_MANAGEMENT = 0x02,
+       /* MAD or addressed to port 0 */
+       ADAPTER_MAD     = 0x04,
+       UNSET_TYPE      = 0x08,
+};
+
+struct iu_rsp {
+       u8 format;
+       u8 sol_not;
+       u16 len;
+       /* tag is just to help client identify cmd, so don't translate be/le */
+       u64 tag;
+};
+
+struct ibmvscsis_cmd {
+       struct list_head list;
+       /* Used for TCM Core operations */
+       struct se_cmd se_cmd;
+       struct iu_entry *iue;
+       struct iu_rsp rsp;
+       struct work_struct work;
+       struct scsi_info *adapter;
+       /* Sense buffer that will be mapped into outgoing status */
+       unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+       u64 init_time;
+#define CMD_FAST_FAIL  BIT(0)
+       u32 flags;
+       char type;
+};
+
+struct ibmvscsis_nexus {
+       struct se_session *se_sess;
+};
+
+struct ibmvscsis_tport {
+       /* SCSI protocol the tport is providing */
+       u8 tport_proto_id;
+       /* ASCII formatted WWPN for SRP Target port */
+       char tport_name[IBMVSCSIS_NAMELEN];
+       /* Returned by ibmvscsis_make_tport() */
+       struct se_wwn tport_wwn;
+       /* Returned by ibmvscsis_make_tpg() */
+       struct se_portal_group se_tpg;
+       /* ibmvscsis port target portal group tag for TCM */
+       u16 tport_tpgt;
+       /* Pointer to TCM session for I_T Nexus */
+       struct ibmvscsis_nexus *ibmv_nexus;
+       bool enabled;
+       bool releasing;
+};
+
+struct scsi_info {
+       struct list_head list;
+       char eye[MAX_EYE];
+
+       /* commands waiting for space on repsonse queue */
+       struct list_head waiting_rsp;
+#define NO_QUEUE                    0x00
+#define WAIT_ENABLED                0X01
+       /* driver has received an initialize command */
+#define PART_UP_WAIT_ENAB           0x02
+#define WAIT_CONNECTION             0x04
+       /* have established a connection */
+#define CONNECTED                   0x08
+       /* at least one port is processing SRP IU */
+#define SRP_PROCESSING              0x10
+       /* remove request received */
+#define UNCONFIGURING               0x20
+       /* disconnect by letting adapter go idle, no error */
+#define WAIT_IDLE                   0x40
+       /* disconnecting to clear an error */
+#define ERR_DISCONNECT              0x80
+       /* disconnect to clear error state, then come back up */
+#define ERR_DISCONNECT_RECONNECT    0x100
+       /* disconnected after clearing an error */
+#define ERR_DISCONNECTED            0x200
+       /* A series of errors caused unexpected errors */
+#define UNDEFINED                   0x400
+       u16  state;
+       int fast_fail;
+       struct target_dds dds;
+       char *cmd_pool;
+       /* list of free commands */
+       struct list_head free_cmd;
+       /* command elements ready for scheduler */
+       struct list_head schedule_q;
+       /* commands sent to TCM */
+       struct list_head active_q;
+       caddr_t *map_buf;
+       /* ioba of map buffer */
+       dma_addr_t map_ioba;
+       /* allowable number of outstanding SRP requests */
+       int request_limit;
+       /* extra credit */
+       int credit;
+       /* outstanding transactions against credit limit */
+       int debit;
+
+       /* allow only one outstanding mad request */
+#define PROCESSING_MAD                0x00002
+       /* Waiting to go idle */
+#define WAIT_FOR_IDLE                0x00004
+       /* H_REG_CRQ called */
+#define CRQ_CLOSED                    0x00010
+       /* detected that client has failed */
+#define CLIENT_FAILED                 0x00040
+       /* detected that transport event occurred */
+#define TRANS_EVENT                   0x00080
+       /* don't attempt to send anything to the client */
+#define RESPONSE_Q_DOWN               0x00100
+       /* request made to schedule disconnect handler */
+#define SCHEDULE_DISCONNECT           0x00400
+       /* disconnect handler is scheduled */
+#define DISCONNECT_SCHEDULED          0x00800
+       u32 flags;
+       /* adapter lock */
+       spinlock_t intr_lock;
+       /* information needed to manage command queue */
+       struct cmd_queue cmd_q;
+       /* used in hcall to copy response back into srp buffer */
+       u64  empty_iu_id;
+       /* used in crq, to tag what iu the response is for */
+       u64  empty_iu_tag;
+       uint new_state;
+       /* control block for the response queue timer */
+       struct timer_cb rsp_q_timer;
+       /* keep last client to enable proper accounting */
+       struct client_info client_data;
+       /* what can this client do */
+       u32 client_cap;
+       /*
+        * The following two fields capture state and flag changes that
+        * can occur when the lock is given up.  In the orginal design,
+        * the lock was held during calls into phyp;
+        * however, phyp did not meet PAPR architecture.  This is
+        * a work around.
+        */
+       u16  phyp_acr_state;
+       u32 phyp_acr_flags;
+
+       struct workqueue_struct *work_q;
+       struct completion wait_idle;
+       struct device dev;
+       struct vio_dev *dma_dev;
+       struct srp_target target;
+       struct ibmvscsis_tport tport;
+       struct tasklet_struct work_task;
+       struct work_struct proc_work;
+};
+
+/*
+ * Provide a constant that allows software to detect the adapter is
+ * disconnecting from the client from one of several states.
+ */
+#define IS_DISCONNECTING (UNCONFIGURING | ERR_DISCONNECT_RECONNECT | \
+                         ERR_DISCONNECT)
+
+/*
+ * Provide a constant that can be used with interrupt handling that
+ * essentially lets the interrupt handler know that all requests should
+ * be thrown out,
+ */
+#define DONT_PROCESS_STATE (IS_DISCONNECTING | UNDEFINED | \
+                           ERR_DISCONNECTED  | WAIT_IDLE)
+
+/*
+ * If any of these flag bits are set then do not allow the interrupt
+ * handler to schedule the off level handler.
+ */
+#define BLOCK (DISCONNECT_SCHEDULED)
+
+/* State and transition events that stop the interrupt handler */
+#define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \
+                                 ((VSCSI)->flags & BLOCK))
+
+/* flag bit that are not reset during disconnect */
+#define PRESERVE_FLAG_FIELDS 0
+
+#define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))
+
+#define READ_CMD(cdb)  (((cdb)[0] & 0x1F) == 8)
+#define WRITE_CMD(cdb) (((cdb)[0] & 0x1F) == 0xA)
+
+#ifndef H_GET_PARTNER_INFO
+#define H_GET_PARTNER_INFO      0x0000000000000008LL
+#endif
+
+#define h_copy_rdma(l, sa, sb, da, db) \
+               plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_vioctl(u, o, a, u1, u2, u3, u4) \
+               plpar_hcall_norets(H_VIOCTL, u, o, a, u1, u2)
+#define h_reg_crq(ua, tok, sz) \
+               plpar_hcall_norets(H_REG_CRQ, ua, tok, sz)
+#define h_free_crq(ua) \
+               plpar_hcall_norets(H_FREE_CRQ, ua)
+#define h_send_crq(ua, d1, d2) \
+               plpar_hcall_norets(H_SEND_CRQ, ua, d1, d2)
+
+#endif
diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.c b/drivers/scsi/ibmvscsi_tgt/libsrp.c
new file mode 100644 (file)
index 0000000..5a4cc28
--- /dev/null
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * SCSI RDMA Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM 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.
+ *
+ * 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)    "libsrp: " fmt
+
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+#include "libsrp.h"
+#include "ibmvscsi_tgt.h"
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+                            struct srp_buf **ring)
+{
+       struct iu_entry *iue;
+       int i;
+
+       q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+       if (!q->pool)
+               return -ENOMEM;
+       q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+       if (!q->items)
+               goto free_pool;
+
+       spin_lock_init(&q->lock);
+       kfifo_init(&q->queue, (void *)q->pool, max * sizeof(void *));
+
+       for (i = 0, iue = q->items; i < max; i++) {
+               kfifo_in(&q->queue, (void *)&iue, sizeof(void *));
+               iue->sbuf = ring[i];
+               iue++;
+       }
+       return 0;
+
+free_pool:
+       kfree(q->pool);
+       return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+       kfree(q->items);
+       kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+                                      size_t max, size_t size)
+{
+       struct srp_buf **ring;
+       int i;
+
+       ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+       if (!ring)
+               return NULL;
+
+       for (i = 0; i < max; i++) {
+               ring[i] = kzalloc(sizeof(*ring[i]), GFP_KERNEL);
+               if (!ring[i])
+                       goto out;
+               ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+                                                 GFP_KERNEL);
+               if (!ring[i]->buf)
+                       goto out;
+       }
+       return ring;
+
+out:
+       for (i = 0; i < max && ring[i]; i++) {
+               if (ring[i]->buf) {
+                       dma_free_coherent(dev, size, ring[i]->buf,
+                                         ring[i]->dma);
+               }
+               kfree(ring[i]);
+       }
+       kfree(ring);
+
+       return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring,
+                         size_t max, size_t size)
+{
+       int i;
+
+       for (i = 0; i < max; i++) {
+               dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+               kfree(ring[i]);
+       }
+       kfree(ring);
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+                    size_t nr, size_t iu_size)
+{
+       int err;
+
+       spin_lock_init(&target->lock);
+
+       target->dev = dev;
+
+       target->srp_iu_size = iu_size;
+       target->rx_ring_size = nr;
+       target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+       if (!target->rx_ring)
+               return -ENOMEM;
+       err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+       if (err)
+               goto free_ring;
+
+       dev_set_drvdata(target->dev, target);
+       return 0;
+
+free_ring:
+       srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+       return -ENOMEM;
+}
+
+void srp_target_free(struct srp_target *target)
+{
+       dev_set_drvdata(target->dev, NULL);
+       srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+                     target->srp_iu_size);
+       srp_iu_pool_free(&target->iu_queue);
+}
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+       struct iu_entry *iue = NULL;
+
+       if (kfifo_out_locked(&target->iu_queue.queue, (void *)&iue,
+                            sizeof(void *),
+                            &target->iu_queue.lock) != sizeof(void *)) {
+               WARN_ONCE(1, "unexpected fifo state");
+               return NULL;
+       }
+       if (!iue)
+               return iue;
+       iue->target = target;
+       iue->flags = 0;
+       return iue;
+}
+
+void srp_iu_put(struct iu_entry *iue)
+{
+       kfifo_in_locked(&iue->target->iu_queue.queue, (void *)&iue,
+                       sizeof(void *), &iue->target->iu_queue.lock);
+}
+
+static int srp_direct_data(struct ibmvscsis_cmd *cmd, struct srp_direct_buf *md,
+                          enum dma_data_direction dir, srp_rdma_t rdma_io,
+                          int dma_map, int ext_desc)
+{
+       struct iu_entry *iue = NULL;
+       struct scatterlist *sg = NULL;
+       int err, nsg = 0, len;
+
+       if (dma_map) {
+               iue = cmd->iue;
+               sg = cmd->se_cmd.t_data_sg;
+               nsg = dma_map_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents,
+                                DMA_BIDIRECTIONAL);
+               if (!nsg) {
+                       pr_err("fail to map %p %d\n", iue,
+                              cmd->se_cmd.t_data_nents);
+                       return 0;
+               }
+               len = min(cmd->se_cmd.data_length, be32_to_cpu(md->len));
+       } else {
+               len = be32_to_cpu(md->len);
+       }
+
+       err = rdma_io(cmd, sg, nsg, md, 1, dir, len);
+
+       if (dma_map)
+               dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+       return err;
+}
+
+static int srp_indirect_data(struct ibmvscsis_cmd *cmd, struct srp_cmd *srp_cmd,
+                            struct srp_indirect_buf *id,
+                            enum dma_data_direction dir, srp_rdma_t rdma_io,
+                            int dma_map, int ext_desc)
+{
+       struct iu_entry *iue = NULL;
+       struct srp_direct_buf *md = NULL;
+       struct scatterlist dummy, *sg = NULL;
+       dma_addr_t token = 0;
+       int err = 0;
+       int nmd, nsg = 0, len;
+
+       if (dma_map || ext_desc) {
+               iue = cmd->iue;
+               sg = cmd->se_cmd.t_data_sg;
+       }
+
+       nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf);
+
+       if ((dir == DMA_FROM_DEVICE && nmd == srp_cmd->data_in_desc_cnt) ||
+           (dir == DMA_TO_DEVICE && nmd == srp_cmd->data_out_desc_cnt)) {
+               md = &id->desc_list[0];
+               goto rdma;
+       }
+
+       if (ext_desc && dma_map) {
+               md = dma_alloc_coherent(iue->target->dev,
+                                       be32_to_cpu(id->table_desc.len),
+                                       &token, GFP_KERNEL);
+               if (!md) {
+                       pr_err("Can't get dma memory %u\n",
+                              be32_to_cpu(id->table_desc.len));
+                       return -ENOMEM;
+               }
+
+               sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
+               sg_dma_address(&dummy) = token;
+               sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
+               err = rdma_io(cmd, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+                             be32_to_cpu(id->table_desc.len));
+               if (err) {
+                       pr_err("Error copying indirect table %d\n", err);
+                       goto free_mem;
+               }
+       } else {
+               pr_err("This command uses external indirect buffer\n");
+               return -EINVAL;
+       }
+
+rdma:
+       if (dma_map) {
+               nsg = dma_map_sg(iue->target->dev, sg, cmd->se_cmd.t_data_nents,
+                                DMA_BIDIRECTIONAL);
+               if (!nsg) {
+                       pr_err("fail to map %p %d\n", iue,
+                              cmd->se_cmd.t_data_nents);
+                       err = -EIO;
+                       goto free_mem;
+               }
+               len = min(cmd->se_cmd.data_length, be32_to_cpu(id->len));
+       } else {
+               len = be32_to_cpu(id->len);
+       }
+
+       err = rdma_io(cmd, sg, nsg, md, nmd, dir, len);
+
+       if (dma_map)
+               dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+       if (token && dma_map) {
+               dma_free_coherent(iue->target->dev,
+                                 be32_to_cpu(id->table_desc.len), md, token);
+       }
+       return err;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+       int size = 0;
+       u8 fmt = cmd->buf_fmt >> 4;
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               size = sizeof(struct srp_direct_buf);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               size = sizeof(struct srp_indirect_buf) +
+                       sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+               break;
+       default:
+               pr_err("client error. Invalid data_out_format %x\n", fmt);
+               break;
+       }
+       return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct ibmvscsis_cmd *cmd, struct srp_cmd *srp_cmd,
+                     srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+       struct srp_direct_buf *md;
+       struct srp_indirect_buf *id;
+       enum dma_data_direction dir;
+       int offset, err = 0;
+       u8 format;
+
+       if (!cmd->se_cmd.t_data_nents)
+               return 0;
+
+       offset = srp_cmd->add_cdb_len & ~3;
+
+       dir = srp_cmd_direction(srp_cmd);
+       if (dir == DMA_FROM_DEVICE)
+               offset += data_out_desc_size(srp_cmd);
+
+       if (dir == DMA_TO_DEVICE)
+               format = srp_cmd->buf_fmt >> 4;
+       else
+               format = srp_cmd->buf_fmt & ((1U << 4) - 1);
+
+       switch (format) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *)(srp_cmd->add_data + offset);
+               err = srp_direct_data(cmd, md, dir, rdma_io, dma_map, ext_desc);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *)(srp_cmd->add_data + offset);
+               err = srp_indirect_data(cmd, srp_cmd, id, dir, rdma_io, dma_map,
+                                       ext_desc);
+               break;
+       default:
+               pr_err("Unknown format %d %x\n", dir, format);
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+       struct srp_direct_buf *md;
+       struct srp_indirect_buf *id;
+       u64 len = 0;
+       uint offset = cmd->add_cdb_len & ~3;
+       u8 fmt;
+
+       if (dir == DMA_TO_DEVICE) {
+               fmt = cmd->buf_fmt >> 4;
+       } else {
+               fmt = cmd->buf_fmt & ((1U << 4) - 1);
+               offset += data_out_desc_size(cmd);
+       }
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *)(cmd->add_data + offset);
+               len = be32_to_cpu(md->len);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *)(cmd->add_data + offset);
+               len = be32_to_cpu(id->len);
+               break;
+       default:
+               pr_err("invalid data format %x\n", fmt);
+               break;
+       }
+       return len;
+}
+
+int srp_get_desc_table(struct srp_cmd *srp_cmd, enum dma_data_direction *dir,
+                      u64 *data_len)
+{
+       struct srp_indirect_buf *idb;
+       struct srp_direct_buf *db;
+       uint add_cdb_offset;
+       int rc;
+
+       /*
+        * The pointer computations below will only be compiled correctly
+        * if srp_cmd::add_data is declared as s8*, u8*, s8[] or u8[], so check
+        * whether srp_cmd::add_data has been declared as a byte pointer.
+        */
+       BUILD_BUG_ON(!__same_type(srp_cmd->add_data[0], (s8)0)
+                    && !__same_type(srp_cmd->add_data[0], (u8)0));
+
+       BUG_ON(!dir);
+       BUG_ON(!data_len);
+
+       rc = 0;
+       *data_len = 0;
+
+       *dir = DMA_NONE;
+
+       if (srp_cmd->buf_fmt & 0xf)
+               *dir = DMA_FROM_DEVICE;
+       else if (srp_cmd->buf_fmt >> 4)
+               *dir = DMA_TO_DEVICE;
+
+       add_cdb_offset = srp_cmd->add_cdb_len & ~3;
+       if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_DIRECT) ||
+           ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_DIRECT)) {
+               db = (struct srp_direct_buf *)(srp_cmd->add_data
+                                              + add_cdb_offset);
+               *data_len = be32_to_cpu(db->len);
+       } else if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_INDIRECT) ||
+                  ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_INDIRECT)) {
+               idb = (struct srp_indirect_buf *)(srp_cmd->add_data
+                                                 + add_cdb_offset);
+
+               *data_len = be32_to_cpu(idb->len);
+       }
+       return rc;
+}
+
+MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.h b/drivers/scsi/ibmvscsi_tgt/libsrp.h
new file mode 100644 (file)
index 0000000..4696f33
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <scsi/srp.h>
+
+enum srp_valid {
+       INVALIDATE_CMD_RESP_EL = 0,
+       VALID_CMD_RESP_EL = 0x80,
+       VALID_INIT_MSG = 0xC0,
+       VALID_TRANS_EVENT = 0xFF
+};
+
+enum srp_format {
+       SRP_FORMAT = 1,
+       MAD_FORMAT = 2,
+       OS400_FORMAT = 3,
+       AIX_FORMAT = 4,
+       LINUX_FORMAT = 5,
+       MESSAGE_IN_CRQ = 6
+};
+
+enum srp_init_msg {
+       INIT_MSG = 1,
+       INIT_COMPLETE_MSG = 2
+};
+
+enum srp_trans_event {
+       UNUSED_FORMAT = 0,
+       PARTNER_FAILED = 1,
+       PARTNER_DEREGISTER = 2,
+       MIGRATED = 6
+};
+
+enum srp_status {
+       HEADER_DESCRIPTOR = 0xF1,
+       PING = 0xF5,
+       PING_RESPONSE = 0xF6
+};
+
+enum srp_mad_version {
+       MAD_VERSION_1 = 1
+};
+
+enum srp_os_type {
+       OS400 = 1,
+       LINUX = 2,
+       AIX = 3,
+       OFW = 4
+};
+
+enum srp_task_attributes {
+       SRP_SIMPLE_TASK = 0,
+       SRP_HEAD_TASK = 1,
+       SRP_ORDERED_TASK = 2,
+       SRP_ACA_TASK = 4
+};
+
+enum {
+       SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE           = 0,
+       SRP_REQUEST_FIELDS_INVALID                      = 2,
+       SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED      = 4,
+       SRP_TASK_MANAGEMENT_FUNCTION_FAILED             = 5
+};
+
+struct srp_buf {
+       dma_addr_t dma;
+       void *buf;
+};
+
+struct srp_queue {
+       void *pool;
+       void *items;
+       struct kfifo queue;
+       spinlock_t lock;
+};
+
+struct srp_target {
+       struct device *dev;
+
+       spinlock_t lock;
+       struct list_head cmd_queue;
+
+       size_t srp_iu_size;
+       struct srp_queue iu_queue;
+       size_t rx_ring_size;
+       struct srp_buf **rx_ring;
+
+       void *ldata;
+};
+
+struct iu_entry {
+       struct srp_target *target;
+
+       struct list_head ilist;
+       dma_addr_t remote_token;
+       unsigned long flags;
+
+       struct srp_buf *sbuf;
+       u16 iu_len;
+};
+
+struct ibmvscsis_cmd;
+
+typedef int (srp_rdma_t)(struct ibmvscsis_cmd *, struct scatterlist *, int,
+                        struct srp_direct_buf *, int,
+                        enum dma_data_direction, unsigned int);
+int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
+void srp_target_free(struct srp_target *);
+struct iu_entry *srp_iu_get(struct srp_target *);
+void srp_iu_put(struct iu_entry *);
+int srp_transfer_data(struct ibmvscsis_cmd *, struct srp_cmd *,
+                     srp_rdma_t, int, int);
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir);
+int srp_get_desc_table(struct srp_cmd *srp_cmd, enum dma_data_direction *dir,
+                      u64 *data_len);
+static inline int srp_cmd_direction(struct srp_cmd *cmd)
+{
+       return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+#endif
index 1f539c2..17d04c7 100644 (file)
@@ -3288,6 +3288,11 @@ static void ipr_worker_thread(struct work_struct *work)
                return;
        }
 
+       if (!ioa_cfg->scan_enabled) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               return;
+       }
+
 restart:
        do {
                did_work = 0;
@@ -10214,6 +10219,7 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
 
                if (!ioa_cfg->reset_work_q) {
                        dev_err(&pdev->dev, "Couldn't register reset workqueue\n");
+                       rc = -ENOMEM;
                        goto out_free_irq;
                }
        } else
@@ -10362,6 +10368,7 @@ static void ipr_remove(struct pci_dev *pdev)
 static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
        struct ipr_ioa_cfg *ioa_cfg;
+       unsigned long flags;
        int rc, i;
 
        rc = ipr_probe_ioa(pdev, dev_id);
@@ -10403,8 +10410,11 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
                __ipr_remove(pdev);
                return rc;
        }
+       spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       ioa_cfg->scan_enabled = 1;
+       schedule_work(&ioa_cfg->work_q);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 
-       scsi_scan_host(ioa_cfg->host);
        ioa_cfg->iopoll_weight = ioa_cfg->chip_cfg->iopoll_weight;
 
        if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
@@ -10414,7 +10424,8 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
                }
        }
 
-       schedule_work(&ioa_cfg->work_q);
+       scsi_scan_host(ioa_cfg->host);
+
        return 0;
 }
 
index 1d42c74..cdb5196 100644 (file)
@@ -1478,6 +1478,7 @@ struct ipr_ioa_cfg {
        u8 in_ioa_bringdown:1;
        u8 ioa_unit_checked:1;
        u8 dump_taken:1;
+       u8 scan_enabled:1;
        u8 scan_done:1;
        u8 needs_hard_reset:1;
        u8 dual_raid:1;
index adf61b4..734a042 100644 (file)
@@ -4854,20 +4854,17 @@ static int
 lpfc_enable_pci_dev(struct lpfc_hba *phba)
 {
        struct pci_dev *pdev;
-       int bars = 0;
 
        /* Obtain PCI device reference */
        if (!phba->pcidev)
                goto out_error;
        else
                pdev = phba->pcidev;
-       /* Select PCI BARs */
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
        /* Enable PCI device */
        if (pci_enable_device_mem(pdev))
                goto out_error;
        /* Request PCI resource for the device */
-       if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
+       if (pci_request_mem_regions(pdev, LPFC_DRIVER_NAME))
                goto out_disable_device;
        /* Set up device as PCI master and save state for EEH */
        pci_set_master(pdev);
@@ -4884,7 +4881,7 @@ out_disable_device:
        pci_disable_device(pdev);
 out_error:
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "1401 Failed to enable pci device, bars:x%x\n", bars);
+                       "1401 Failed to enable pci device\n");
        return -ENODEV;
 }
 
@@ -4899,17 +4896,14 @@ static void
 lpfc_disable_pci_dev(struct lpfc_hba *phba)
 {
        struct pci_dev *pdev;
-       int bars;
 
        /* Obtain PCI device reference */
        if (!phba->pcidev)
                return;
        else
                pdev = phba->pcidev;
-       /* Select PCI BARs */
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
        /* Release PCI resource and disable PCI device */
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
        pci_disable_device(pdev);
 
        return;
@@ -9811,7 +9805,6 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
        struct lpfc_vport **vports;
        struct lpfc_hba   *phba = vport->phba;
        int i;
-       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
        spin_lock_irq(&phba->hbalock);
        vport->load_flag |= FC_UNLOADING;
@@ -9886,7 +9879,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 
        lpfc_hba_free(phba);
 
-       pci_release_selected_regions(pdev, bars);
+       pci_release_mem_regions(pdev);
        pci_disable_device(pdev);
 }
 
index a5655d5..d197aa1 100644 (file)
@@ -3877,7 +3877,7 @@ int lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba,
        uint32_t tag;
        uint16_t hwq;
 
-       if (shost_use_blk_mq(cmnd->device->host)) {
+       if (cmnd && shost_use_blk_mq(cmnd->device->host)) {
                tag = blk_mq_unique_tag(cmnd->request);
                hwq = blk_mq_unique_tag_to_hwq(tag);
 
index 351d08a..7080ce2 100644 (file)
@@ -1323,21 +1323,18 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 {
        lockdep_assert_held(&phba->hbalock);
 
+       BUG_ON(!piocb || !piocb->vport);
+
        list_add_tail(&piocb->list, &pring->txcmplq);
        piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
 
        if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
           (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
           (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN) &&
-        (!(piocb->vport->load_flag & FC_UNLOADING))) {
-               if (!piocb->vport)
-                       BUG();
-               else
-                       mod_timer(&piocb->vport->els_tmofunc,
-                               jiffies +
-                               msecs_to_jiffies(1000 * (phba->fc_ratov << 1)));
-       }
-
+           (!(piocb->vport->load_flag & FC_UNLOADING)))
+               mod_timer(&piocb->vport->els_tmofunc,
+                         jiffies +
+                         msecs_to_jiffies(1000 * (phba->fc_ratov << 1)));
 
        return 0;
 }
index 180e027..796e220 100644 (file)
@@ -23,7 +23,7 @@
  **************************************************/
 
 #if IS_ENABLED(CONFIG_SSB_EMBEDDED)
-static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -38,14 +38,14 @@ static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
  * ChipCommon
  **************************************************/
 
-static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
+static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
        return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
 }
 
-static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
+static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned int gpio,
                                      int value)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
@@ -54,7 +54,7 @@ static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
 }
 
 static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
-                                          unsigned gpio)
+                                          unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -63,7 +63,7 @@ static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
 }
 
 static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
-                                           unsigned gpio, int value)
+                                           unsigned int gpio, int value)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -72,7 +72,7 @@ static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
        return 0;
 }
 
-static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
+static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -85,7 +85,7 @@ static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
        return 0;
 }
 
-static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
+static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -256,14 +256,14 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
 
 #ifdef CONFIG_SSB_DRIVER_EXTIF
 
-static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
+static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
        return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
 }
 
-static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
+static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned int gpio,
                                     int value)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
@@ -272,7 +272,7 @@ static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
 }
 
 static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
-                                         unsigned gpio)
+                                         unsigned int gpio)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
@@ -281,7 +281,7 @@ static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
 }
 
 static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
-                                          unsigned gpio, int value)
+                                          unsigned int gpio, int value)
 {
        struct ssb_bus *bus = gpiochip_get_data(chip);
 
index cc34020..d757709 100644 (file)
@@ -1,5 +1,5 @@
 config USB_EMXX
-       bool "EMXX USB Function Device Controller"
+       tristate "EMXX USB Function Device Controller"
        depends on USB_GADGET && (ARCH_SHMOBILE || (ARM && COMPILE_TEST))
        help
           The Emma Mobile series of SoCs from Renesas Electronics and
index 3bd9175..3b56b28 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 
 #include "emxx_udc.h"
 
+#define        DRIVER_DESC     "EMXX UDC driver"
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
 static const char      driver_name[] = "emxx_udc";
+static const char      driver_desc[] = DRIVER_DESC;
 
 /*===========================================================================*/
 /* Prototype */
@@ -3295,6 +3297,28 @@ static void nbu2ss_drv_shutdown(struct platform_device *pdev)
        _nbu2ss_disable_controller(udc);
 }
 
+/*-------------------------------------------------------------------------*/
+static int nbu2ss_drv_remove(struct platform_device *pdev)
+{
+       struct nbu2ss_udc       *udc;
+       struct nbu2ss_ep        *ep;
+       int     i;
+
+       udc = &udc_controller;
+
+       for (i = 0; i < NUM_ENDPOINTS; i++) {
+               ep = &udc->ep[i];
+               if (ep->virt_buf)
+                       dma_free_coherent(NULL, PAGE_SIZE,
+                               (void *)ep->virt_buf, ep->phys_buf);
+       }
+
+       /* Interrupt Handler - Release */
+       free_irq(INT_VBUS, udc);
+
+       return 0;
+}
+
 /*-------------------------------------------------------------------------*/
 static int nbu2ss_drv_suspend(struct platform_device *pdev, pm_message_t state)
 {
@@ -3347,12 +3371,16 @@ static int nbu2ss_drv_resume(struct platform_device *pdev)
 static struct platform_driver udc_driver = {
        .probe          = nbu2ss_drv_probe,
        .shutdown       = nbu2ss_drv_shutdown,
+       .remove         = nbu2ss_drv_remove,
        .suspend        = nbu2ss_drv_suspend,
        .resume         = nbu2ss_drv_resume,
        .driver         = {
-               .name                   = driver_name,
-               .suppress_bind_attrs    = true,
+               .name   = driver_name,
        },
 };
 
-builtin_platform_driver(udc_driver);
+module_platform_driver(udc_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Renesas Electronics Corporation");
+MODULE_LICENSE("GPL");
index 581a63a..463b1a3 100644 (file)
@@ -78,7 +78,7 @@ static void ll_release(struct dentry *de)
  * INVALID) so d_lookup() matches it, but we have no lock on it (so
  * lock_match() fails) and we spin around real_lookup().
  */
-static int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
+static int ll_dcompare(const struct dentry *dentry,
                       unsigned int len, const char *str,
                       const struct qstr *name)
 {
index 8e52722..c1cb6b1 100644 (file)
@@ -781,7 +781,7 @@ static int sa_args_init(struct inode *dir, struct inode *child,
                        struct ll_sa_entry *entry, struct md_enqueue_info **pmi,
                        struct ldlm_enqueue_info **pei)
 {
-       struct qstr           *qstr = &entry->se_qstr;
+       const struct qstr      *qstr = &entry->se_qstr;
        struct ll_inode_info     *lli  = ll_i2info(dir);
        struct md_enqueue_info   *minfo;
        struct ldlm_enqueue_info *einfo;
@@ -1340,7 +1340,7 @@ enum {
 static int is_first_dirent(struct inode *dir, struct dentry *dentry)
 {
        struct ll_dir_chain   chain;
-       struct qstr       *target = &dentry->d_name;
+       const struct qstr  *target = &dentry->d_name;
        struct page       *page;
        __u64            pos    = 0;
        int                dot_de;
index cae42e5..7292f23 100644 (file)
@@ -16,7 +16,7 @@ menuconfig STAGING_MEDIA
           If in doubt, say N here.
 
 
-if STAGING_MEDIA
+if STAGING_MEDIA && MEDIA_SUPPORT
 
 # Please keep them in alphabetic order
 source "drivers/staging/media/bcm2048/Kconfig"
index 9fffddb..b2393bb 100644 (file)
@@ -1252,7 +1252,7 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
                        return -EINVAL;
                }
                /* Zero unused part of the feature array */
-               memset(features + i, 0, feature_sz - i);
+               memset(features + i + 1, 0, feature_sz - i - 1);
        }
 
        if (log_addrs->cec_version >= CEC_OP_CEC_VERSION_2_0) {
index 50f3d3a..39b928c 100644 (file)
@@ -492,7 +492,8 @@ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
        bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
 
        spin_lock_bh(&conn->cmd_lock);
-       if (!list_empty(&cmd->i_conn_node))
+       if (!list_empty(&cmd->i_conn_node) &&
+           !(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
                list_del_init(&cmd->i_conn_node);
        spin_unlock_bh(&conn->cmd_lock);
 
@@ -4034,6 +4035,7 @@ int iscsi_target_rx_thread(void *arg)
 
 static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
 {
+       LIST_HEAD(tmp_list);
        struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
        struct iscsi_session *sess = conn->sess;
        /*
@@ -4042,18 +4044,26 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
         * has been reset -> returned sleeping pre-handler state.
         */
        spin_lock_bh(&conn->cmd_lock);
-       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
+       list_splice_init(&conn->conn_cmd_list, &tmp_list);
 
+       list_for_each_entry(cmd, &tmp_list, i_conn_node) {
+               struct se_cmd *se_cmd = &cmd->se_cmd;
+
+               if (se_cmd->se_tfo != NULL) {
+                       spin_lock(&se_cmd->t_state_lock);
+                       se_cmd->transport_state |= CMD_T_FABRIC_STOP;
+                       spin_unlock(&se_cmd->t_state_lock);
+               }
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
                list_del_init(&cmd->i_conn_node);
-               spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_increment_maxcmdsn(cmd, sess);
-
                iscsit_free_cmd(cmd, true);
 
-               spin_lock_bh(&conn->cmd_lock);
        }
-       spin_unlock_bh(&conn->cmd_lock);
 }
 
 static void iscsit_stop_timers_for_cmds(
index b5212f0..adf419f 100644 (file)
@@ -1371,8 +1371,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
        login->zero_tsih = zero_tsih;
 
-       conn->sess->se_sess->sup_prot_ops =
-               conn->conn_transport->iscsit_get_sup_prot_ops(conn);
+       if (conn->sess)
+               conn->sess->se_sess->sup_prot_ops =
+                       conn->conn_transport->iscsit_get_sup_prot_ops(conn);
 
        tpg = conn->tpg;
        if (!tpg) {
index a4046ca..6b42348 100644 (file)
@@ -821,13 +821,15 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
  * in ATA and we need to set TPE=1
  */
 bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
-                                      struct request_queue *q, int block_size)
+                                      struct request_queue *q)
 {
+       int block_size = queue_logical_block_size(q);
+
        if (!blk_queue_discard(q))
                return false;
 
-       attrib->max_unmap_lba_count = (q->limits.max_discard_sectors << 9) /
-                                                               block_size;
+       attrib->max_unmap_lba_count =
+               q->limits.max_discard_sectors >> (ilog2(block_size) - 9);
        /*
         * Currently hardcoded to 1 in Linux/SCSI code..
         */
index 75f0f08..d545993 100644 (file)
@@ -161,8 +161,7 @@ static int fd_configure_device(struct se_device *dev)
                        dev_size, div_u64(dev_size, fd_dev->fd_block_size),
                        fd_dev->fd_block_size);
 
-               if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
-                                                     fd_dev->fd_block_size))
+               if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
                        pr_debug("IFILE: BLOCK Discard support available,"
                                 " disabled by default\n");
                /*
@@ -523,7 +522,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
         */
        if (cmd->data_length > FD_MAX_BYTES) {
                pr_err("FILEIO: Not able to process I/O of %u bytes due to"
-                      "FD_MAX_BYTES: %u iovec count limitiation\n",
+                      "FD_MAX_BYTES: %u iovec count limitation\n",
                        cmd->data_length, FD_MAX_BYTES);
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
index 22af12f..372d744 100644 (file)
@@ -121,8 +121,7 @@ static int iblock_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
        dev->dev_attrib.hw_queue_depth = q->nr_requests;
 
-       if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
-                                             dev->dev_attrib.hw_block_size))
+       if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
                pr_debug("IBLOCK: BLOCK Discard support available,"
                         " disabled by default\n");
 
@@ -389,7 +388,7 @@ iblock_execute_sync_cache(struct se_cmd *cmd)
        bio = bio_alloc(GFP_KERNEL, 0);
        bio->bi_end_io = iblock_end_io_flush;
        bio->bi_bdev = ib_dev->ibd_bd;
-       bio->bi_rw = WRITE_FLUSH;
+       bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH);
        if (!immed)
                bio->bi_private = cmd;
        submit_bio(bio);
index fc91e85..e2c970a 100644 (file)
@@ -146,6 +146,7 @@ sense_reason_t      target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
 void   target_qf_do_work(struct work_struct *work);
 bool   target_check_wce(struct se_device *dev);
 bool   target_check_fua(struct se_device *dev);
+void   __target_execute_cmd(struct se_cmd *, bool);
 
 /* target_core_stat.c */
 void   target_stat_setup_dev_default_groups(struct se_device *);
index a9057aa..04f616b 100644 (file)
@@ -602,7 +602,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
        cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
        spin_unlock_irq(&cmd->t_state_lock);
 
-       __target_execute_cmd(cmd);
+       __target_execute_cmd(cmd, false);
 
        kfree(buf);
        return ret;
index 5ab3967..6094a6b 100644 (file)
@@ -754,7 +754,15 @@ EXPORT_SYMBOL(target_complete_cmd);
 
 void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
 {
-       if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
+       if (scsi_status != SAM_STAT_GOOD) {
+               return;
+       }
+
+       /*
+        * Calculate new residual count based upon length of SCSI data
+        * transferred.
+        */
+       if (length < cmd->data_length) {
                if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
                        cmd->residual_count += cmd->data_length - length;
                } else {
@@ -763,6 +771,12 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
                }
 
                cmd->data_length = length;
+       } else if (length > cmd->data_length) {
+               cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
+               cmd->residual_count = length - cmd->data_length;
+       } else {
+               cmd->se_cmd_flags &= ~(SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT);
+               cmd->residual_count = 0;
        }
 
        target_complete_cmd(cmd, scsi_status);
@@ -1303,23 +1317,6 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 
        trace_target_sequencer_start(cmd);
 
-       /*
-        * Check for an existing UNIT ATTENTION condition
-        */
-       ret = target_scsi3_ua_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_alua_state_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_check_reservation(cmd);
-       if (ret) {
-               cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-               return ret;
-       }
-
        ret = dev->transport->parse_cdb(cmd);
        if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
                pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
@@ -1761,20 +1758,45 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-void __target_execute_cmd(struct se_cmd *cmd)
+void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
 {
        sense_reason_t ret;
 
-       if (cmd->execute_cmd) {
-               ret = cmd->execute_cmd(cmd);
-               if (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 = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               goto err;
+       }
+       if (do_checks) {
+               /*
+                * Check for an existing UNIT ATTENTION condition after
+                * target_handle_task_attr() has done SAM task attr
+                * checking, and possibly have already defered execution
+                * out to target_restart_delayed_cmds() context.
+                */
+               ret = target_scsi3_ua_check(cmd);
+               if (ret)
+                       goto err;
 
-                       transport_generic_request_failure(cmd, ret);
+               ret = target_alua_state_check(cmd);
+               if (ret)
+                       goto err;
+
+               ret = target_check_reservation(cmd);
+               if (ret) {
+                       cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+                       goto err;
                }
        }
+
+       ret = cmd->execute_cmd(cmd);
+       if (!ret)
+               return;
+err:
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       transport_generic_request_failure(cmd, ret);
 }
 
 static int target_write_prot_action(struct se_cmd *cmd)
@@ -1819,6 +1841,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return false;
 
+       cmd->se_cmd_flags |= SCF_TASK_ATTR_SET;
+
        /*
         * Check for the existence of HEAD_OF_QUEUE, and if true return 1
         * to allow the passed struct se_cmd list of tasks to the front of the list.
@@ -1899,7 +1923,7 @@ void target_execute_cmd(struct se_cmd *cmd)
                return;
        }
 
-       __target_execute_cmd(cmd);
+       __target_execute_cmd(cmd, true);
 }
 EXPORT_SYMBOL(target_execute_cmd);
 
@@ -1923,7 +1947,7 @@ static void target_restart_delayed_cmds(struct se_device *dev)
                list_del(&cmd->se_delayed_node);
                spin_unlock(&dev->delayed_cmd_lock);
 
-               __target_execute_cmd(cmd);
+               __target_execute_cmd(cmd, true);
 
                if (cmd->sam_task_attr == TCM_ORDERED_TAG)
                        break;
@@ -1941,6 +1965,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return;
 
+       if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET))
+               goto restart;
+
        if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
                atomic_dec_mb(&dev->simple_cmds);
                dev->dev_cur_ordered_id++;
@@ -1957,7 +1984,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
                pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
                         dev->dev_cur_ordered_id);
        }
-
+restart:
        target_restart_delayed_cmds(dev);
 }
 
@@ -2557,15 +2584,10 @@ static void target_release_cmd_kref(struct kref *kref)
        bool fabric_stop;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       if (list_empty(&se_cmd->se_cmd_list)) {
-               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-               target_free_cmd_mem(se_cmd);
-               se_cmd->se_tfo->release_cmd(se_cmd);
-               return;
-       }
 
        spin_lock(&se_cmd->t_state_lock);
-       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
+       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) &&
+                     (se_cmd->transport_state & CMD_T_ABORTED);
        spin_unlock(&se_cmd->t_state_lock);
 
        if (se_cmd->cmd_wait_set || fabric_stop) {
index f5186a7..6ffbb60 100644 (file)
@@ -91,6 +91,7 @@ static void ft_tport_delete(struct ft_tport *tport)
 
        ft_sess_delete_all(tport);
        lport = tport->lport;
+       lport->service_params &= ~FCP_SPPF_TARG_FCN;
        BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
        RCU_INIT_POINTER(lport->prov[FC_TYPE_FCP], NULL);
 
@@ -110,6 +111,7 @@ void ft_lport_add(struct fc_lport *lport, void *arg)
 {
        mutex_lock(&ft_lport_lock);
        ft_tport_get(lport);
+       lport->service_params |= FCP_SPPF_TARG_FCN;
        mutex_unlock(&ft_lport_lock);
 }
 
index 1519d2c..73137f4 100644 (file)
@@ -54,7 +54,7 @@ struct ar933x_uart_port {
 
 static inline bool ar933x_uart_console_enabled(void)
 {
-       return config_enabled(CONFIG_SERIAL_AR933X_CONSOLE);
+       return IS_ENABLED(CONFIG_SERIAL_AR933X_CONSOLE);
 }
 
 static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
@@ -636,7 +636,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
        int ret;
 
        np = pdev->dev.of_node;
-       if (config_enabled(CONFIG_OF) && np) {
+       if (IS_ENABLED(CONFIG_OF) && np) {
                id = of_alias_get_id(np, "serial");
                if (id < 0) {
                        dev_err(&pdev->dev, "unable to get alias id, err=%d\n",
index c10972f..4fd041b 100644 (file)
@@ -387,7 +387,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
         * need to have the registers polled during D3, so avoid D3cold.
         */
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
-               pdev->no_d3cold = true;
+               pci_d3cold_disable(pdev);
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
                xhci_pme_quirk(hcd);
index 96a7078..4d6a5c6 100644 (file)
@@ -496,12 +496,10 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
        void *dmabuf;
        int result;
 
-       dmabuf = kmalloc(bufsize, GFP_KERNEL);
+       dmabuf = kmemdup(buf, bufsize, GFP_KERNEL);
        if (!dmabuf)
                return -ENOMEM;
 
-       memcpy(dmabuf, buf, bufsize);
-
        result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                        req, REQTYPE_HOST_TO_INTERFACE, 0,
                        port_priv->bInterfaceNumber, dmabuf, bufsize,
index ae8c036..944de65 100644 (file)
@@ -350,6 +350,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
+       int status = urb->status;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
@@ -360,22 +361,22 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
 
        dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
                                                        urb->actual_length);
-       switch (urb->status) {
+       switch (status) {
        case 0:
                break;
        case -ENOENT:
        case -ECONNRESET:
        case -ESHUTDOWN:
                dev_dbg(&port->dev, "%s - urb stopped: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                return;
        case -EPIPE:
                dev_err(&port->dev, "%s - urb stopped: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                return;
        default:
                dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                goto resubmit;
        }
 
@@ -399,6 +400,7 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
 {
        unsigned long flags;
        struct usb_serial_port *port = urb->context;
+       int status = urb->status;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
@@ -410,22 +412,22 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
        set_bit(i, &port->write_urbs_free);
        spin_unlock_irqrestore(&port->lock, flags);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                break;
        case -ENOENT:
        case -ECONNRESET:
        case -ESHUTDOWN:
                dev_dbg(&port->dev, "%s - urb stopped: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                return;
        case -EPIPE:
                dev_err_console(port, "%s - urb stopped: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                return;
        default:
                dev_err_console(port, "%s - nonzero urb status: %d\n",
-                                                       __func__, urb->status);
+                                                       __func__, status);
                goto resubmit;
        }
 
index d96d423..8e07536 100644 (file)
@@ -273,6 +273,7 @@ static void option_instat_callback(struct urb *urb);
 #define TELIT_PRODUCT_LE922_USBCFG5            0x1045
 #define TELIT_PRODUCT_LE920                    0x1200
 #define TELIT_PRODUCT_LE910                    0x1201
+#define TELIT_PRODUCT_LE910_USBCFG4            0x1206
 
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID                          0x19d2
@@ -1198,6 +1199,8 @@ static const struct usb_device_id option_ids[] = {
                .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
                .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
+               .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
                .driver_info = (kernel_ulong_t)&telit_le920_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
index e7dbbef..07b4bf0 100644 (file)
@@ -1,5 +1,4 @@
-/* vi: ts=8 sw=8
- *
+/*
  * TI 3410/5052 USB Serial Driver
  *
  * Copyright (C) 2004 Texas Instruments
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-#include "ti_usb_3410_5052.h"
-
-/* Defines */
+/* Configuration ids */
+#define TI_BOOT_CONFIG                 1
+#define TI_ACTIVE_CONFIG               2
+
+/* Vendor and product ids */
+#define TI_VENDOR_ID                   0x0451
+#define IBM_VENDOR_ID                  0x04b3
+#define TI_3410_PRODUCT_ID             0x3410
+#define IBM_4543_PRODUCT_ID            0x4543
+#define IBM_454B_PRODUCT_ID            0x454b
+#define IBM_454C_PRODUCT_ID            0x454c
+#define TI_3410_EZ430_ID               0xF430  /* TI ez430 development tool */
+#define TI_5052_BOOT_PRODUCT_ID                0x5052  /* no EEPROM, no firmware */
+#define TI_5152_BOOT_PRODUCT_ID                0x5152  /* no EEPROM, no firmware */
+#define TI_5052_EEPROM_PRODUCT_ID      0x505A  /* EEPROM, no firmware */
+#define TI_5052_FIRMWARE_PRODUCT_ID    0x505F  /* firmware is running */
+#define FRI2_PRODUCT_ID                        0x5053  /* Fish River Island II */
+
+/* Multi-Tech vendor and product ids */
+#define MTS_VENDOR_ID                  0x06E0
+#define MTS_GSM_NO_FW_PRODUCT_ID       0xF108
+#define MTS_CDMA_NO_FW_PRODUCT_ID      0xF109
+#define MTS_CDMA_PRODUCT_ID            0xF110
+#define MTS_GSM_PRODUCT_ID             0xF111
+#define MTS_EDGE_PRODUCT_ID            0xF112
+#define MTS_MT9234MU_PRODUCT_ID                0xF114
+#define MTS_MT9234ZBA_PRODUCT_ID       0xF115
+#define MTS_MT9234ZBAOLD_PRODUCT_ID    0x0319
+
+/* Abbott Diabetics vendor and product ids */
+#define ABBOTT_VENDOR_ID               0x1a61
+#define ABBOTT_STEREO_PLUG_ID          0x3410
+#define ABBOTT_PRODUCT_ID              ABBOTT_STEREO_PLUG_ID
+#define ABBOTT_STRIP_PORT_ID           0x3420
+
+/* Honeywell vendor and product IDs */
+#define HONEYWELL_VENDOR_ID            0x10ac
+#define HONEYWELL_HGI80_PRODUCT_ID     0x0102  /* Honeywell HGI80 */
+
+/* Moxa UPORT 11x0 vendor and product IDs */
+#define MXU1_VENDOR_ID                         0x110a
+#define MXU1_1110_PRODUCT_ID                   0x1110
+#define MXU1_1130_PRODUCT_ID                   0x1130
+#define MXU1_1150_PRODUCT_ID                   0x1150
+#define MXU1_1151_PRODUCT_ID                   0x1151
+#define MXU1_1131_PRODUCT_ID                   0x1131
+
+/* Commands */
+#define TI_GET_VERSION                 0x01
+#define TI_GET_PORT_STATUS             0x02
+#define TI_GET_PORT_DEV_INFO           0x03
+#define TI_GET_CONFIG                  0x04
+#define TI_SET_CONFIG                  0x05
+#define TI_OPEN_PORT                   0x06
+#define TI_CLOSE_PORT                  0x07
+#define TI_START_PORT                  0x08
+#define TI_STOP_PORT                   0x09
+#define TI_TEST_PORT                   0x0A
+#define TI_PURGE_PORT                  0x0B
+#define TI_RESET_EXT_DEVICE            0x0C
+#define TI_WRITE_DATA                  0x80
+#define TI_READ_DATA                   0x81
+#define TI_REQ_TYPE_CLASS              0x82
+
+/* Module identifiers */
+#define TI_I2C_PORT                    0x01
+#define TI_IEEE1284_PORT               0x02
+#define TI_UART1_PORT                  0x03
+#define TI_UART2_PORT                  0x04
+#define TI_RAM_PORT                    0x05
+
+/* Modem status */
+#define TI_MSR_DELTA_CTS               0x01
+#define TI_MSR_DELTA_DSR               0x02
+#define TI_MSR_DELTA_RI                        0x04
+#define TI_MSR_DELTA_CD                        0x08
+#define TI_MSR_CTS                     0x10
+#define TI_MSR_DSR                     0x20
+#define TI_MSR_RI                      0x40
+#define TI_MSR_CD                      0x80
+#define TI_MSR_DELTA_MASK              0x0F
+#define TI_MSR_MASK                    0xF0
+
+/* Line status */
+#define TI_LSR_OVERRUN_ERROR           0x01
+#define TI_LSR_PARITY_ERROR            0x02
+#define TI_LSR_FRAMING_ERROR           0x04
+#define TI_LSR_BREAK                   0x08
+#define TI_LSR_ERROR                   0x0F
+#define TI_LSR_RX_FULL                 0x10
+#define TI_LSR_TX_EMPTY                        0x20
+
+/* Line control */
+#define TI_LCR_BREAK                   0x40
+
+/* Modem control */
+#define TI_MCR_LOOP                    0x04
+#define TI_MCR_DTR                     0x10
+#define TI_MCR_RTS                     0x20
+
+/* Mask settings */
+#define TI_UART_ENABLE_RTS_IN          0x0001
+#define TI_UART_DISABLE_RTS            0x0002
+#define TI_UART_ENABLE_PARITY_CHECKING 0x0008
+#define TI_UART_ENABLE_DSR_OUT         0x0010
+#define TI_UART_ENABLE_CTS_OUT         0x0020
+#define TI_UART_ENABLE_X_OUT           0x0040
+#define TI_UART_ENABLE_XA_OUT          0x0080
+#define TI_UART_ENABLE_X_IN            0x0100
+#define TI_UART_ENABLE_DTR_IN          0x0800
+#define TI_UART_DISABLE_DTR            0x1000
+#define TI_UART_ENABLE_MS_INTS         0x2000
+#define TI_UART_ENABLE_AUTO_START_DMA  0x4000
+
+/* Parity */
+#define TI_UART_NO_PARITY              0x00
+#define TI_UART_ODD_PARITY             0x01
+#define TI_UART_EVEN_PARITY            0x02
+#define TI_UART_MARK_PARITY            0x03
+#define TI_UART_SPACE_PARITY           0x04
+
+/* Stop bits */
+#define TI_UART_1_STOP_BITS            0x00
+#define TI_UART_1_5_STOP_BITS          0x01
+#define TI_UART_2_STOP_BITS            0x02
+
+/* Bits per character */
+#define TI_UART_5_DATA_BITS            0x00
+#define TI_UART_6_DATA_BITS            0x01
+#define TI_UART_7_DATA_BITS            0x02
+#define TI_UART_8_DATA_BITS            0x03
+
+/* 232/485 modes */
+#define TI_UART_232                    0x00
+#define TI_UART_485_RECEIVER_DISABLED  0x01
+#define TI_UART_485_RECEIVER_ENABLED   0x02
+
+/* Pipe transfer mode and timeout */
+#define TI_PIPE_MODE_CONTINUOUS                0x01
+#define TI_PIPE_MODE_MASK              0x03
+#define TI_PIPE_TIMEOUT_MASK           0x7C
+#define TI_PIPE_TIMEOUT_ENABLE         0x80
+
+/* Config struct */
+struct ti_uart_config {
+       __u16   wBaudRate;
+       __u16   wFlags;
+       __u8    bDataBits;
+       __u8    bParity;
+       __u8    bStopBits;
+       char    cXon;
+       char    cXoff;
+       __u8    bUartMode;
+} __packed;
+
+/* Get port status */
+struct ti_port_status {
+       __u8    bCmdCode;
+       __u8    bModuleId;
+       __u8    bErrorCode;
+       __u8    bMSR;
+       __u8    bLSR;
+} __packed;
+
+/* Purge modes */
+#define TI_PURGE_OUTPUT                        0x00
+#define TI_PURGE_INPUT                 0x80
+
+/* Read/Write data */
+#define TI_RW_DATA_ADDR_SFR            0x10
+#define TI_RW_DATA_ADDR_IDATA          0x20
+#define TI_RW_DATA_ADDR_XDATA          0x30
+#define TI_RW_DATA_ADDR_CODE           0x40
+#define TI_RW_DATA_ADDR_GPIO           0x50
+#define TI_RW_DATA_ADDR_I2C            0x60
+#define TI_RW_DATA_ADDR_FLASH          0x70
+#define TI_RW_DATA_ADDR_DSP            0x80
+
+#define TI_RW_DATA_UNSPECIFIED         0x00
+#define TI_RW_DATA_BYTE                        0x01
+#define TI_RW_DATA_WORD                        0x02
+#define TI_RW_DATA_DOUBLE_WORD         0x04
+
+struct ti_write_data_bytes {
+       __u8    bAddrType;
+       __u8    bDataType;
+       __u8    bDataCounter;
+       __be16  wBaseAddrHi;
+       __be16  wBaseAddrLo;
+       __u8    bData[0];
+} __packed;
+
+struct ti_read_data_request {
+       __u8    bAddrType;
+       __u8    bDataType;
+       __u8    bDataCounter;
+       __be16  wBaseAddrHi;
+       __be16  wBaseAddrLo;
+} __packed;
+
+struct ti_read_data_bytes {
+       __u8    bCmdCode;
+       __u8    bModuleId;
+       __u8    bErrorCode;
+       __u8    bData[0];
+} __packed;
+
+/* Interrupt struct */
+struct ti_interrupt {
+       __u8    bICode;
+       __u8    bIInfo;
+} __packed;
+
+/* Interrupt codes */
+#define TI_CODE_HARDWARE_ERROR         0xFF
+#define TI_CODE_DATA_ERROR             0x03
+#define TI_CODE_MODEM_STATUS           0x04
+
+/* Download firmware max packet size */
+#define TI_DOWNLOAD_MAX_PACKET_SIZE    64
+
+/* Firmware image header */
+struct ti_firmware_header {
+       __le16  wLength;
+       __u8    bCheckSum;
+} __packed;
+
+/* UART addresses */
+#define TI_UART1_BASE_ADDR             0xFFA0  /* UART 1 base address */
+#define TI_UART2_BASE_ADDR             0xFFB0  /* UART 2 base address */
+#define TI_UART_OFFSET_LCR             0x0002  /* UART MCR register offset */
+#define TI_UART_OFFSET_MCR             0x0004  /* UART MCR register offset */
 
 #define TI_DRIVER_AUTHOR       "Al Borchers <alborchers@steinerpoint.com>"
 #define TI_DRIVER_DESC         "TI USB 3410/5052 Serial Driver"
 
 #define TI_EXTRA_VID_PID_COUNT 5
 
-
-/* Structures */
-
 struct ti_port {
        int                     tp_is_open;
        __u8                    tp_msr;
@@ -84,9 +309,6 @@ struct ti_device {
        int                     td_urb_error;
 };
 
-
-/* Function Declarations */
-
 static int ti_startup(struct usb_serial *serial);
 static void ti_release(struct usb_serial *serial);
 static int ti_port_probe(struct usb_serial_port *port);
@@ -136,13 +358,8 @@ static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev,
 
 static int ti_download_firmware(struct ti_device *tdev);
 
-
-/* Data */
-
-/* module parameters */
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
 
-/* supported devices */
 static const struct usb_device_id ti_id_table_3410[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
@@ -174,7 +391,7 @@ static const struct usb_device_id ti_id_table_5052[] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
-       { }     /* terminator */
+       { }
 };
 
 static const struct usb_device_id ti_id_table_combined[] = {
@@ -275,8 +492,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
        &ti_1port_device, &ti_2port_device, NULL
 };
 
-/* Module */
-
 MODULE_AUTHOR(TI_DRIVER_AUTHOR);
 MODULE_DESCRIPTION(TI_DRIVER_DESC);
 MODULE_LICENSE("GPL");
@@ -302,8 +517,6 @@ MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
 
 module_usb_serial_driver(serial_drivers, ti_id_table_combined);
 
-/* Functions */
-
 static int ti_startup(struct usb_serial *serial)
 {
        struct ti_device *tdev;
@@ -319,7 +532,6 @@ static int ti_startup(struct usb_serial *serial)
                dev->descriptor.bNumConfigurations,
                dev->actconfig->desc.bConfigurationValue);
 
-       /* create device structure */
        tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
        if (!tdev)
                return -ENOMEM;
@@ -435,7 +647,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct urb *urb;
        int port_number;
        int status;
-       __u16 open_settings = (__u8)(TI_PIPE_MODE_CONTINOUS |
+       __u16 open_settings = (__u8)(TI_PIPE_MODE_CONTINUOUS |
                             TI_PIPE_TIMEOUT_ENABLE |
                             (TI_TRANSFER_TIMEOUT << 2));
 
@@ -954,6 +1166,15 @@ static void ti_break(struct tty_struct *tty, int break_state)
                dev_dbg(&port->dev, "%s - error setting break, %d\n", __func__, status);
 }
 
+static int ti_get_port_from_code(unsigned char code)
+{
+       return (code >> 4) - 3;
+}
+
+static int ti_get_func_from_code(unsigned char code)
+{
+       return code & 0x0f;
+}
 
 static void ti_interrupt_callback(struct urb *urb)
 {
@@ -995,8 +1216,8 @@ static void ti_interrupt_callback(struct urb *urb)
                goto exit;
        }
 
-       port_number = TI_GET_PORT_FROM_CODE(data[0]);
-       function = TI_GET_FUNC_FROM_CODE(data[0]);
+       port_number = ti_get_port_from_code(data[0]);
+       function = ti_get_func_from_code(data[0]);
 
        dev_dbg(dev, "%s - port_number %d, function %d, data 0x%02X\n",
                __func__, port_number, function, data[1]);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
deleted file mode 100644 (file)
index bbfd3a1..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/* vi: ts=8 sw=8
- *
- * TI 3410/5052 USB Serial Driver Header
- *
- * Copyright (C) 2004 Texas Instruments
- *
- * This driver is based on the Linux io_ti driver, which is
- *   Copyright (C) 2000-2002 Inside Out Networks
- *   Copyright (C) 2001-2002 Greg Kroah-Hartman
- *
- * 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.
- *
- * For questions or problems with this driver, contact Texas Instruments
- * technical support, or Al Borchers <alborchers@steinerpoint.com>, or
- * Peter Berger <pberger@brimson.com>.
- */
-
-#ifndef _TI_3410_5052_H_
-#define _TI_3410_5052_H_
-
-/* Configuration ids */
-#define TI_BOOT_CONFIG                 1
-#define TI_ACTIVE_CONFIG               2
-
-/* Vendor and product ids */
-#define TI_VENDOR_ID                   0x0451
-#define IBM_VENDOR_ID                  0x04b3
-#define TI_3410_PRODUCT_ID             0x3410
-#define IBM_4543_PRODUCT_ID            0x4543
-#define IBM_454B_PRODUCT_ID            0x454b
-#define IBM_454C_PRODUCT_ID            0x454c
-#define TI_3410_EZ430_ID               0xF430  /* TI ez430 development tool */
-#define TI_5052_BOOT_PRODUCT_ID                0x5052  /* no EEPROM, no firmware */
-#define TI_5152_BOOT_PRODUCT_ID                0x5152  /* no EEPROM, no firmware */
-#define TI_5052_EEPROM_PRODUCT_ID      0x505A  /* EEPROM, no firmware */
-#define TI_5052_FIRMWARE_PRODUCT_ID    0x505F  /* firmware is running */
-#define FRI2_PRODUCT_ID                        0x5053  /* Fish River Island II */
-
-/* Multi-Tech vendor and product ids */
-#define MTS_VENDOR_ID                  0x06E0
-#define MTS_GSM_NO_FW_PRODUCT_ID       0xF108
-#define MTS_CDMA_NO_FW_PRODUCT_ID      0xF109
-#define MTS_CDMA_PRODUCT_ID            0xF110
-#define MTS_GSM_PRODUCT_ID             0xF111
-#define MTS_EDGE_PRODUCT_ID            0xF112
-#define MTS_MT9234MU_PRODUCT_ID                0xF114
-#define MTS_MT9234ZBA_PRODUCT_ID       0xF115
-#define MTS_MT9234ZBAOLD_PRODUCT_ID    0x0319
-
-/* Abbott Diabetics vendor and product ids */
-#define ABBOTT_VENDOR_ID               0x1a61
-#define ABBOTT_STEREO_PLUG_ID          0x3410
-#define ABBOTT_PRODUCT_ID              ABBOTT_STEREO_PLUG_ID
-#define ABBOTT_STRIP_PORT_ID           0x3420
-
-/* Honeywell vendor and product IDs */
-#define HONEYWELL_VENDOR_ID            0x10ac
-#define HONEYWELL_HGI80_PRODUCT_ID     0x0102  /* Honeywell HGI80 */
-
-/* Moxa UPORT 11x0 vendor and product IDs */
-#define MXU1_VENDOR_ID                         0x110a
-#define MXU1_1110_PRODUCT_ID                   0x1110
-#define MXU1_1130_PRODUCT_ID                   0x1130
-#define MXU1_1131_PRODUCT_ID                   0x1131
-#define MXU1_1150_PRODUCT_ID                   0x1150
-#define MXU1_1151_PRODUCT_ID                   0x1151
-
-/* Commands */
-#define TI_GET_VERSION                 0x01
-#define TI_GET_PORT_STATUS             0x02
-#define TI_GET_PORT_DEV_INFO           0x03
-#define TI_GET_CONFIG                  0x04
-#define TI_SET_CONFIG                  0x05
-#define TI_OPEN_PORT                   0x06
-#define TI_CLOSE_PORT                  0x07
-#define TI_START_PORT                  0x08
-#define TI_STOP_PORT                   0x09
-#define TI_TEST_PORT                   0x0A
-#define TI_PURGE_PORT                  0x0B
-#define TI_RESET_EXT_DEVICE            0x0C
-#define TI_WRITE_DATA                  0x80
-#define TI_READ_DATA                   0x81
-#define TI_REQ_TYPE_CLASS              0x82
-
-/* Module identifiers */
-#define TI_I2C_PORT                    0x01
-#define TI_IEEE1284_PORT               0x02
-#define TI_UART1_PORT                  0x03
-#define TI_UART2_PORT                  0x04
-#define TI_RAM_PORT                    0x05
-
-/* Modem status */
-#define TI_MSR_DELTA_CTS               0x01
-#define TI_MSR_DELTA_DSR               0x02
-#define TI_MSR_DELTA_RI                        0x04
-#define TI_MSR_DELTA_CD                        0x08
-#define TI_MSR_CTS                     0x10
-#define TI_MSR_DSR                     0x20
-#define TI_MSR_RI                      0x40
-#define TI_MSR_CD                      0x80
-#define TI_MSR_DELTA_MASK              0x0F
-#define TI_MSR_MASK                    0xF0
-
-/* Line status */
-#define TI_LSR_OVERRUN_ERROR           0x01
-#define TI_LSR_PARITY_ERROR            0x02
-#define TI_LSR_FRAMING_ERROR           0x04
-#define TI_LSR_BREAK                   0x08
-#define TI_LSR_ERROR                   0x0F
-#define TI_LSR_RX_FULL                 0x10
-#define TI_LSR_TX_EMPTY                        0x20
-
-/* Line control */
-#define TI_LCR_BREAK                   0x40
-
-/* Modem control */
-#define TI_MCR_LOOP                    0x04
-#define TI_MCR_DTR                     0x10
-#define TI_MCR_RTS                     0x20
-
-/* Mask settings */
-#define TI_UART_ENABLE_RTS_IN          0x0001
-#define TI_UART_DISABLE_RTS            0x0002
-#define TI_UART_ENABLE_PARITY_CHECKING 0x0008
-#define TI_UART_ENABLE_DSR_OUT         0x0010
-#define TI_UART_ENABLE_CTS_OUT         0x0020
-#define TI_UART_ENABLE_X_OUT           0x0040
-#define TI_UART_ENABLE_XA_OUT          0x0080
-#define TI_UART_ENABLE_X_IN            0x0100
-#define TI_UART_ENABLE_DTR_IN          0x0800
-#define TI_UART_DISABLE_DTR            0x1000
-#define TI_UART_ENABLE_MS_INTS         0x2000
-#define TI_UART_ENABLE_AUTO_START_DMA  0x4000
-
-/* Parity */
-#define TI_UART_NO_PARITY              0x00
-#define TI_UART_ODD_PARITY             0x01
-#define TI_UART_EVEN_PARITY            0x02
-#define TI_UART_MARK_PARITY            0x03
-#define TI_UART_SPACE_PARITY           0x04
-
-/* Stop bits */
-#define TI_UART_1_STOP_BITS            0x00
-#define TI_UART_1_5_STOP_BITS          0x01
-#define TI_UART_2_STOP_BITS            0x02
-
-/* Bits per character */
-#define TI_UART_5_DATA_BITS            0x00
-#define TI_UART_6_DATA_BITS            0x01
-#define TI_UART_7_DATA_BITS            0x02
-#define TI_UART_8_DATA_BITS            0x03
-
-/* 232/485 modes */
-#define TI_UART_232                    0x00
-#define TI_UART_485_RECEIVER_DISABLED  0x01
-#define TI_UART_485_RECEIVER_ENABLED   0x02
-
-/* Pipe transfer mode and timeout */
-#define TI_PIPE_MODE_CONTINOUS         0x01
-#define TI_PIPE_MODE_MASK              0x03
-#define TI_PIPE_TIMEOUT_MASK           0x7C
-#define TI_PIPE_TIMEOUT_ENABLE         0x80
-
-/* Config struct */
-struct ti_uart_config {
-       __u16   wBaudRate;
-       __u16   wFlags;
-       __u8    bDataBits;
-       __u8    bParity;
-       __u8    bStopBits;
-       char    cXon;
-       char    cXoff;
-       __u8    bUartMode;
-} __attribute__((packed));
-
-/* Get port status */
-struct ti_port_status {
-       __u8    bCmdCode;
-       __u8    bModuleId;
-       __u8    bErrorCode;
-       __u8    bMSR;
-       __u8    bLSR;
-} __attribute__((packed));
-
-/* Purge modes */
-#define TI_PURGE_OUTPUT                        0x00
-#define TI_PURGE_INPUT                 0x80
-
-/* Read/Write data */
-#define TI_RW_DATA_ADDR_SFR            0x10
-#define TI_RW_DATA_ADDR_IDATA          0x20
-#define TI_RW_DATA_ADDR_XDATA          0x30
-#define TI_RW_DATA_ADDR_CODE           0x40
-#define TI_RW_DATA_ADDR_GPIO           0x50
-#define TI_RW_DATA_ADDR_I2C            0x60
-#define TI_RW_DATA_ADDR_FLASH          0x70
-#define TI_RW_DATA_ADDR_DSP            0x80
-
-#define TI_RW_DATA_UNSPECIFIED         0x00
-#define TI_RW_DATA_BYTE                        0x01
-#define TI_RW_DATA_WORD                        0x02
-#define TI_RW_DATA_DOUBLE_WORD         0x04
-
-struct ti_write_data_bytes {
-       __u8    bAddrType;
-       __u8    bDataType;
-       __u8    bDataCounter;
-       __be16  wBaseAddrHi;
-       __be16  wBaseAddrLo;
-       __u8    bData[0];
-} __attribute__((packed));
-
-struct ti_read_data_request {
-       __u8    bAddrType;
-       __u8    bDataType;
-       __u8    bDataCounter;
-       __be16  wBaseAddrHi;
-       __be16  wBaseAddrLo;
-} __attribute__((packed));
-
-struct ti_read_data_bytes {
-       __u8    bCmdCode;
-       __u8    bModuleId;
-       __u8    bErrorCode;
-       __u8    bData[0];
-} __attribute__((packed));
-
-/* Interrupt struct */
-struct ti_interrupt {
-       __u8    bICode;
-       __u8    bIInfo;
-} __attribute__((packed));
-
-/* Interrupt codes */
-#define TI_GET_PORT_FROM_CODE(c)       (((c) >> 4) - 3)
-#define TI_GET_FUNC_FROM_CODE(c)       ((c) & 0x0f)
-#define TI_CODE_HARDWARE_ERROR         0xFF
-#define TI_CODE_DATA_ERROR             0x03
-#define TI_CODE_MODEM_STATUS           0x04
-
-/* Download firmware max packet size */
-#define TI_DOWNLOAD_MAX_PACKET_SIZE    64
-
-/* Firmware image header */
-struct ti_firmware_header {
-       __le16  wLength;
-       __u8    bCheckSum;
-} __attribute__((packed));
-
-/* UART addresses */
-#define TI_UART1_BASE_ADDR             0xFFA0  /* UART 1 base address */
-#define TI_UART2_BASE_ADDR             0xFFB0  /* UART 2 base address */
-#define TI_UART_OFFSET_LCR             0x0002  /* UART MCR register offset */
-#define TI_UART_OFFSET_MCR             0x0004  /* UART MCR register offset */
-
-#endif /* _TI_3410_5052_H_ */
index 533eaf0..40764ec 100644 (file)
@@ -2,7 +2,6 @@ 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
          guest networking with virtio_net. Not to be confused with virtio_net
@@ -15,17 +14,24 @@ config VHOST_SCSI
        tristate "VHOST_SCSI TCM fabric driver"
        depends on TARGET_CORE && EVENTFD && m
        select VHOST
-       select VHOST_RING
        default n
        ---help---
        Say M here to enable the vhost_scsi TCM fabric module
        for use with virtio-scsi guests
 
-config VHOST_RING
-       tristate
+config VHOST_VSOCK
+       tristate "vhost virtio-vsock driver"
+       depends on VSOCKETS && EVENTFD
+       select VIRTIO_VSOCKETS_COMMON
+       select VHOST
+       default n
        ---help---
-         This option is selected by any driver which needs to access
-         the host side of a virtio ring.
+       This kernel module can be loaded in the host kernel to provide AF_VSOCK
+       sockets for communicating with guests.  The guests must have the
+       virtio_transport.ko driver loaded to use the virtio-vsock device.
+
+       To compile this driver as a module, choose M here: the module will be called
+       vhost_vsock.
 
 config VHOST
        tristate
diff --git a/drivers/vhost/Kconfig.vringh b/drivers/vhost/Kconfig.vringh
new file mode 100644 (file)
index 0000000..6a4490c
--- /dev/null
@@ -0,0 +1,5 @@
+config VHOST_RING
+       tristate
+       ---help---
+         This option is selected by any driver which needs to access
+         the host side of a virtio ring.
index e0441c3..6b012b9 100644 (file)
@@ -4,5 +4,9 @@ vhost_net-y := net.o
 obj-$(CONFIG_VHOST_SCSI) += vhost_scsi.o
 vhost_scsi-y := scsi.o
 
+obj-$(CONFIG_VHOST_VSOCK) += vhost_vsock.o
+vhost_vsock-y := vsock.o
+
 obj-$(CONFIG_VHOST_RING) += vringh.o
+
 obj-$(CONFIG_VHOST)    += vhost.o
index e032ca3..5dc128a 100644 (file)
@@ -61,7 +61,8 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
 enum {
        VHOST_NET_FEATURES = VHOST_FEATURES |
                         (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
-                        (1ULL << VIRTIO_NET_F_MRG_RXBUF)
+                        (1ULL << VIRTIO_NET_F_MRG_RXBUF) |
+                        (1ULL << VIRTIO_F_IOMMU_PLATFORM)
 };
 
 enum {
@@ -334,7 +335,7 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
 {
        unsigned long uninitialized_var(endtime);
        int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
-                                   out_num, in_num, NULL, NULL);
+                                 out_num, in_num, NULL, NULL);
 
        if (r == vq->num && vq->busyloop_timeout) {
                preempt_disable();
@@ -344,7 +345,7 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
                        cpu_relax_lowlatency();
                preempt_enable();
                r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
-                                       out_num, in_num, NULL, NULL);
+                                     out_num, in_num, NULL, NULL);
        }
 
        return r;
@@ -377,6 +378,9 @@ static void handle_tx(struct vhost_net *net)
        if (!sock)
                goto out;
 
+       if (!vq_iotlb_prefetch(vq))
+               goto out;
+
        vhost_disable_notify(&net->dev, vq);
 
        hdr_size = nvq->vhost_hlen;
@@ -652,6 +656,10 @@ static void handle_rx(struct vhost_net *net)
        sock = vq->private_data;
        if (!sock)
                goto out;
+
+       if (!vq_iotlb_prefetch(vq))
+               goto out;
+
        vhost_disable_notify(&net->dev, vq);
        vhost_net_disable_vq(net, vq);
 
@@ -1052,20 +1060,20 @@ static long vhost_net_reset_owner(struct vhost_net *n)
        struct socket *tx_sock = NULL;
        struct socket *rx_sock = NULL;
        long err;
-       struct vhost_memory *memory;
+       struct vhost_umem *umem;
 
        mutex_lock(&n->dev.mutex);
        err = vhost_dev_check_owner(&n->dev);
        if (err)
                goto done;
-       memory = vhost_dev_reset_owner_prepare();
-       if (!memory) {
+       umem = vhost_dev_reset_owner_prepare();
+       if (!umem) {
                err = -ENOMEM;
                goto done;
        }
        vhost_net_stop(n, &tx_sock, &rx_sock);
        vhost_net_flush(n);
-       vhost_dev_reset_owner(&n->dev, memory);
+       vhost_dev_reset_owner(&n->dev, umem);
        vhost_net_vq_reset(n);
 done:
        mutex_unlock(&n->dev.mutex);
@@ -1096,10 +1104,14 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
        }
        mutex_lock(&n->dev.mutex);
        if ((features & (1 << VHOST_F_LOG_ALL)) &&
-           !vhost_log_access_ok(&n->dev)) {
-               mutex_unlock(&n->dev.mutex);
-               return -EFAULT;
+           !vhost_log_access_ok(&n->dev))
+               goto out_unlock;
+
+       if ((features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) {
+               if (vhost_init_device_iotlb(&n->dev, true))
+                       goto out_unlock;
        }
+
        for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
                mutex_lock(&n->vqs[i].vq.mutex);
                n->vqs[i].vq.acked_features = features;
@@ -1109,6 +1121,10 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
        }
        mutex_unlock(&n->dev.mutex);
        return 0;
+
+out_unlock:
+       mutex_unlock(&n->dev.mutex);
+       return -EFAULT;
 }
 
 static long vhost_net_set_owner(struct vhost_net *n)
@@ -1182,9 +1198,40 @@ static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
 }
 #endif
 
+static ssize_t vhost_net_chr_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+       struct file *file = iocb->ki_filp;
+       struct vhost_net *n = file->private_data;
+       struct vhost_dev *dev = &n->dev;
+       int noblock = file->f_flags & O_NONBLOCK;
+
+       return vhost_chr_read_iter(dev, to, noblock);
+}
+
+static ssize_t vhost_net_chr_write_iter(struct kiocb *iocb,
+                                       struct iov_iter *from)
+{
+       struct file *file = iocb->ki_filp;
+       struct vhost_net *n = file->private_data;
+       struct vhost_dev *dev = &n->dev;
+
+       return vhost_chr_write_iter(dev, from);
+}
+
+static unsigned int vhost_net_chr_poll(struct file *file, poll_table *wait)
+{
+       struct vhost_net *n = file->private_data;
+       struct vhost_dev *dev = &n->dev;
+
+       return vhost_chr_poll(file, dev, wait);
+}
+
 static const struct file_operations vhost_net_fops = {
        .owner          = THIS_MODULE,
        .release        = vhost_net_release,
+       .read_iter      = vhost_net_chr_read_iter,
+       .write_iter     = vhost_net_chr_write_iter,
+       .poll           = vhost_net_chr_poll,
        .unlocked_ioctl = vhost_net_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = vhost_net_compat_ioctl,
index 669fef1..c6f2d89 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/cgroup.h>
 #include <linux/module.h>
 #include <linux/sort.h>
+#include <linux/interval_tree_generic.h>
 
 #include "vhost.h"
 
@@ -34,6 +35,10 @@ static ushort max_mem_regions = 64;
 module_param(max_mem_regions, ushort, 0444);
 MODULE_PARM_DESC(max_mem_regions,
        "Maximum number of memory regions in memory map. (default: 64)");
+static int max_iotlb_entries = 2048;
+module_param(max_iotlb_entries, int, 0444);
+MODULE_PARM_DESC(max_iotlb_entries,
+       "Maximum number of iotlb entries. (default: 2048)");
 
 enum {
        VHOST_MEMORY_F_LOG = 0x1,
@@ -42,6 +47,10 @@ enum {
 #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num])
 #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num])
 
+INTERVAL_TREE_DEFINE(struct vhost_umem_node,
+                    rb, __u64, __subtree_last,
+                    START, LAST, , vhost_umem_interval_tree);
+
 #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY
 static void vhost_disable_cross_endian(struct vhost_virtqueue *vq)
 {
@@ -131,6 +140,19 @@ static void vhost_reset_is_le(struct vhost_virtqueue *vq)
        vq->is_le = virtio_legacy_is_little_endian();
 }
 
+struct vhost_flush_struct {
+       struct vhost_work work;
+       struct completion wait_event;
+};
+
+static void vhost_flush_work(struct vhost_work *work)
+{
+       struct vhost_flush_struct *s;
+
+       s = container_of(work, struct vhost_flush_struct, work);
+       complete(&s->wait_event);
+}
+
 static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
                            poll_table *pt)
 {
@@ -155,11 +177,9 @@ static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
 
 void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn)
 {
-       INIT_LIST_HEAD(&work->node);
+       clear_bit(VHOST_WORK_QUEUED, &work->flags);
        work->fn = fn;
        init_waitqueue_head(&work->done);
-       work->flushing = 0;
-       work->queue_seq = work->done_seq = 0;
 }
 EXPORT_SYMBOL_GPL(vhost_work_init);
 
@@ -211,31 +231,17 @@ void vhost_poll_stop(struct vhost_poll *poll)
 }
 EXPORT_SYMBOL_GPL(vhost_poll_stop);
 
-static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
-                               unsigned seq)
-{
-       int left;
-
-       spin_lock_irq(&dev->work_lock);
-       left = seq - work->done_seq;
-       spin_unlock_irq(&dev->work_lock);
-       return left <= 0;
-}
-
 void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
 {
-       unsigned seq;
-       int flushing;
+       struct vhost_flush_struct flush;
 
-       spin_lock_irq(&dev->work_lock);
-       seq = work->queue_seq;
-       work->flushing++;
-       spin_unlock_irq(&dev->work_lock);
-       wait_event(work->done, vhost_work_seq_done(dev, work, seq));
-       spin_lock_irq(&dev->work_lock);
-       flushing = --work->flushing;
-       spin_unlock_irq(&dev->work_lock);
-       BUG_ON(flushing < 0);
+       if (dev->worker) {
+               init_completion(&flush.wait_event);
+               vhost_work_init(&flush.work, vhost_flush_work);
+
+               vhost_work_queue(dev, &flush.work);
+               wait_for_completion(&flush.wait_event);
+       }
 }
 EXPORT_SYMBOL_GPL(vhost_work_flush);
 
@@ -249,16 +255,16 @@ EXPORT_SYMBOL_GPL(vhost_poll_flush);
 
 void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 {
-       unsigned long flags;
+       if (!dev->worker)
+               return;
 
-       spin_lock_irqsave(&dev->work_lock, flags);
-       if (list_empty(&work->node)) {
-               list_add_tail(&work->node, &dev->work_list);
-               work->queue_seq++;
-               spin_unlock_irqrestore(&dev->work_lock, flags);
+       if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) {
+               /* We can only add the work to the list after we're
+                * sure it was not in the list.
+                */
+               smp_mb();
+               llist_add(&work->node, &dev->work_list);
                wake_up_process(dev->worker);
-       } else {
-               spin_unlock_irqrestore(&dev->work_lock, flags);
        }
 }
 EXPORT_SYMBOL_GPL(vhost_work_queue);
@@ -266,7 +272,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue);
 /* A lockless hint for busy polling code to exit the loop */
 bool vhost_has_work(struct vhost_dev *dev)
 {
-       return !list_empty(&dev->work_list);
+       return !llist_empty(&dev->work_list);
 }
 EXPORT_SYMBOL_GPL(vhost_has_work);
 
@@ -300,17 +306,18 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->call_ctx = NULL;
        vq->call = NULL;
        vq->log_ctx = NULL;
-       vq->memory = NULL;
        vhost_reset_is_le(vq);
        vhost_disable_cross_endian(vq);
        vq->busyloop_timeout = 0;
+       vq->umem = NULL;
+       vq->iotlb = NULL;
 }
 
 static int vhost_worker(void *data)
 {
        struct vhost_dev *dev = data;
-       struct vhost_work *work = NULL;
-       unsigned uninitialized_var(seq);
+       struct vhost_work *work, *work_next;
+       struct llist_node *node;
        mm_segment_t oldfs = get_fs();
 
        set_fs(USER_DS);
@@ -320,35 +327,25 @@ static int vhost_worker(void *data)
                /* mb paired w/ kthread_stop */
                set_current_state(TASK_INTERRUPTIBLE);
 
-               spin_lock_irq(&dev->work_lock);
-               if (work) {
-                       work->done_seq = seq;
-                       if (work->flushing)
-                               wake_up_all(&work->done);
-               }
-
                if (kthread_should_stop()) {
-                       spin_unlock_irq(&dev->work_lock);
                        __set_current_state(TASK_RUNNING);
                        break;
                }
-               if (!list_empty(&dev->work_list)) {
-                       work = list_first_entry(&dev->work_list,
-                                               struct vhost_work, node);
-                       list_del_init(&work->node);
-                       seq = work->queue_seq;
-               } else
-                       work = NULL;
-               spin_unlock_irq(&dev->work_lock);
 
-               if (work) {
+               node = llist_del_all(&dev->work_list);
+               if (!node)
+                       schedule();
+
+               node = llist_reverse_order(node);
+               /* make sure flag is seen after deletion */
+               smp_wmb();
+               llist_for_each_entry_safe(work, work_next, node, node) {
+                       clear_bit(VHOST_WORK_QUEUED, &work->flags);
                        __set_current_state(TASK_RUNNING);
                        work->fn(work);
                        if (need_resched())
                                schedule();
-               } else
-                       schedule();
-
+               }
        }
        unuse_mm(dev->mm);
        set_fs(oldfs);
@@ -407,11 +404,16 @@ void vhost_dev_init(struct vhost_dev *dev,
        mutex_init(&dev->mutex);
        dev->log_ctx = NULL;
        dev->log_file = NULL;
-       dev->memory = NULL;
+       dev->umem = NULL;
+       dev->iotlb = NULL;
        dev->mm = NULL;
-       spin_lock_init(&dev->work_lock);
-       INIT_LIST_HEAD(&dev->work_list);
        dev->worker = NULL;
+       init_llist_head(&dev->work_list);
+       init_waitqueue_head(&dev->wait);
+       INIT_LIST_HEAD(&dev->read_list);
+       INIT_LIST_HEAD(&dev->pending_list);
+       spin_lock_init(&dev->iotlb_lock);
+
 
        for (i = 0; i < dev->nvqs; ++i) {
                vq = dev->vqs[i];
@@ -512,27 +514,36 @@ err_mm:
 }
 EXPORT_SYMBOL_GPL(vhost_dev_set_owner);
 
-struct vhost_memory *vhost_dev_reset_owner_prepare(void)
+static void *vhost_kvzalloc(unsigned long size)
 {
-       return kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL);
+       void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+
+       if (!n)
+               n = vzalloc(size);
+       return n;
+}
+
+struct vhost_umem *vhost_dev_reset_owner_prepare(void)
+{
+       return vhost_kvzalloc(sizeof(struct vhost_umem));
 }
 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)
+void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_umem *umem)
 {
        int i;
 
        vhost_dev_cleanup(dev, true);
 
        /* Restore memory to default empty mapping. */
-       memory->nregions = 0;
-       dev->memory = memory;
+       INIT_LIST_HEAD(&umem->umem_list);
+       dev->umem = umem;
        /* We don't need VQ locks below since vhost_dev_cleanup makes sure
         * VQs aren't running.
         */
        for (i = 0; i < dev->nvqs; ++i)
-               dev->vqs[i]->memory = memory;
+               dev->vqs[i]->umem = umem;
 }
 EXPORT_SYMBOL_GPL(vhost_dev_reset_owner);
 
@@ -549,6 +560,47 @@ void vhost_dev_stop(struct vhost_dev *dev)
 }
 EXPORT_SYMBOL_GPL(vhost_dev_stop);
 
+static void vhost_umem_free(struct vhost_umem *umem,
+                           struct vhost_umem_node *node)
+{
+       vhost_umem_interval_tree_remove(node, &umem->umem_tree);
+       list_del(&node->link);
+       kfree(node);
+       umem->numem--;
+}
+
+static void vhost_umem_clean(struct vhost_umem *umem)
+{
+       struct vhost_umem_node *node, *tmp;
+
+       if (!umem)
+               return;
+
+       list_for_each_entry_safe(node, tmp, &umem->umem_list, link)
+               vhost_umem_free(umem, node);
+
+       kvfree(umem);
+}
+
+static void vhost_clear_msg(struct vhost_dev *dev)
+{
+       struct vhost_msg_node *node, *n;
+
+       spin_lock(&dev->iotlb_lock);
+
+       list_for_each_entry_safe(node, n, &dev->read_list, node) {
+               list_del(&node->node);
+               kfree(node);
+       }
+
+       list_for_each_entry_safe(node, n, &dev->pending_list, node) {
+               list_del(&node->node);
+               kfree(node);
+       }
+
+       spin_unlock(&dev->iotlb_lock);
+}
+
 /* Caller should have device mutex if and only if locked is set */
 void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
 {
@@ -575,9 +627,13 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
                fput(dev->log_file);
        dev->log_file = NULL;
        /* No one will access memory at this point */
-       kvfree(dev->memory);
-       dev->memory = NULL;
-       WARN_ON(!list_empty(&dev->work_list));
+       vhost_umem_clean(dev->umem);
+       dev->umem = NULL;
+       vhost_umem_clean(dev->iotlb);
+       dev->iotlb = NULL;
+       vhost_clear_msg(dev);
+       wake_up_interruptible_poll(&dev->wait, POLLIN | POLLRDNORM);
+       WARN_ON(!llist_empty(&dev->work_list));
        if (dev->worker) {
                kthread_stop(dev->worker);
                dev->worker = NULL;
@@ -601,26 +657,34 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
                         (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
 }
 
+static bool vhost_overflow(u64 uaddr, u64 size)
+{
+       /* Make sure 64 bit math will not overflow. */
+       return uaddr > ULONG_MAX || size > ULONG_MAX || uaddr > ULONG_MAX - size;
+}
+
 /* Caller should have vq mutex and device mutex. */
-static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
+static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem,
                               int log_all)
 {
-       int i;
+       struct vhost_umem_node *node;
 
-       if (!mem)
+       if (!umem)
                return 0;
 
-       for (i = 0; i < mem->nregions; ++i) {
-               struct vhost_memory_region *m = mem->regions + i;
-               unsigned long a = m->userspace_addr;
-               if (m->memory_size > ULONG_MAX)
+       list_for_each_entry(node, &umem->umem_list, link) {
+               unsigned long a = node->userspace_addr;
+
+               if (vhost_overflow(node->userspace_addr, node->size))
                        return 0;
-               else if (!access_ok(VERIFY_WRITE, (void __user *)a,
-                                   m->memory_size))
+
+
+               if (!access_ok(VERIFY_WRITE, (void __user *)a,
+                                   node->size))
                        return 0;
                else if (log_all && !log_access_ok(log_base,
-                                                  m->guest_phys_addr,
-                                                  m->memory_size))
+                                                  node->start,
+                                                  node->size))
                        return 0;
        }
        return 1;
@@ -628,7 +692,7 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
 
 /* Can we switch to this memory table? */
 /* Caller should have device mutex but not vq mutex */
-static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
+static int memory_access_ok(struct vhost_dev *d, struct vhost_umem *umem,
                            int log_all)
 {
        int i;
@@ -641,7 +705,8 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
                log = log_all || vhost_has_feature(d->vqs[i], VHOST_F_LOG_ALL);
                /* If ring is inactive, will check when it's enabled. */
                if (d->vqs[i]->private_data)
-                       ok = vq_memory_access_ok(d->vqs[i]->log_base, mem, log);
+                       ok = vq_memory_access_ok(d->vqs[i]->log_base,
+                                                umem, log);
                else
                        ok = 1;
                mutex_unlock(&d->vqs[i]->mutex);
@@ -651,12 +716,385 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
        return 1;
 }
 
+static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,
+                         struct iovec iov[], int iov_size, int access);
+
+static int vhost_copy_to_user(struct vhost_virtqueue *vq, void *to,
+                             const void *from, unsigned size)
+{
+       int ret;
+
+       if (!vq->iotlb)
+               return __copy_to_user(to, from, size);
+       else {
+               /* This function should be called after iotlb
+                * prefetch, which means we're sure that all vq
+                * could be access through iotlb. So -EAGAIN should
+                * not happen in this case.
+                */
+               /* TODO: more fast path */
+               struct iov_iter t;
+               ret = translate_desc(vq, (u64)(uintptr_t)to, size, vq->iotlb_iov,
+                                    ARRAY_SIZE(vq->iotlb_iov),
+                                    VHOST_ACCESS_WO);
+               if (ret < 0)
+                       goto out;
+               iov_iter_init(&t, WRITE, vq->iotlb_iov, ret, size);
+               ret = copy_to_iter(from, size, &t);
+               if (ret == size)
+                       ret = 0;
+       }
+out:
+       return ret;
+}
+
+static int vhost_copy_from_user(struct vhost_virtqueue *vq, void *to,
+                               void *from, unsigned size)
+{
+       int ret;
+
+       if (!vq->iotlb)
+               return __copy_from_user(to, from, size);
+       else {
+               /* This function should be called after iotlb
+                * prefetch, which means we're sure that vq
+                * could be access through iotlb. So -EAGAIN should
+                * not happen in this case.
+                */
+               /* TODO: more fast path */
+               struct iov_iter f;
+               ret = translate_desc(vq, (u64)(uintptr_t)from, size, vq->iotlb_iov,
+                                    ARRAY_SIZE(vq->iotlb_iov),
+                                    VHOST_ACCESS_RO);
+               if (ret < 0) {
+                       vq_err(vq, "IOTLB translation failure: uaddr "
+                              "%p size 0x%llx\n", from,
+                              (unsigned long long) size);
+                       goto out;
+               }
+               iov_iter_init(&f, READ, vq->iotlb_iov, ret, size);
+               ret = copy_from_iter(to, size, &f);
+               if (ret == size)
+                       ret = 0;
+       }
+
+out:
+       return ret;
+}
+
+static void __user *__vhost_get_user(struct vhost_virtqueue *vq,
+                                    void *addr, unsigned size)
+{
+       int ret;
+
+       /* This function should be called after iotlb
+        * prefetch, which means we're sure that vq
+        * could be access through iotlb. So -EAGAIN should
+        * not happen in this case.
+        */
+       /* TODO: more fast path */
+       ret = translate_desc(vq, (u64)(uintptr_t)addr, size, vq->iotlb_iov,
+                            ARRAY_SIZE(vq->iotlb_iov),
+                            VHOST_ACCESS_RO);
+       if (ret < 0) {
+               vq_err(vq, "IOTLB translation failure: uaddr "
+                       "%p size 0x%llx\n", addr,
+                       (unsigned long long) size);
+               return NULL;
+       }
+
+       if (ret != 1 || vq->iotlb_iov[0].iov_len != size) {
+               vq_err(vq, "Non atomic userspace memory access: uaddr "
+                       "%p size 0x%llx\n", addr,
+                       (unsigned long long) size);
+               return NULL;
+       }
+
+       return vq->iotlb_iov[0].iov_base;
+}
+
+#define vhost_put_user(vq, x, ptr) \
+({ \
+       int ret = -EFAULT; \
+       if (!vq->iotlb) { \
+               ret = __put_user(x, ptr); \
+       } else { \
+               __typeof__(ptr) to = \
+                       (__typeof__(ptr)) __vhost_get_user(vq, ptr, sizeof(*ptr)); \
+               if (to != NULL) \
+                       ret = __put_user(x, to); \
+               else \
+                       ret = -EFAULT;  \
+       } \
+       ret; \
+})
+
+#define vhost_get_user(vq, x, ptr) \
+({ \
+       int ret; \
+       if (!vq->iotlb) { \
+               ret = __get_user(x, ptr); \
+       } else { \
+               __typeof__(ptr) from = \
+                       (__typeof__(ptr)) __vhost_get_user(vq, ptr, sizeof(*ptr)); \
+               if (from != NULL) \
+                       ret = __get_user(x, from); \
+               else \
+                       ret = -EFAULT; \
+       } \
+       ret; \
+})
+
+static void vhost_dev_lock_vqs(struct vhost_dev *d)
+{
+       int i = 0;
+       for (i = 0; i < d->nvqs; ++i)
+               mutex_lock(&d->vqs[i]->mutex);
+}
+
+static void vhost_dev_unlock_vqs(struct vhost_dev *d)
+{
+       int i = 0;
+       for (i = 0; i < d->nvqs; ++i)
+               mutex_unlock(&d->vqs[i]->mutex);
+}
+
+static int vhost_new_umem_range(struct vhost_umem *umem,
+                               u64 start, u64 size, u64 end,
+                               u64 userspace_addr, int perm)
+{
+       struct vhost_umem_node *tmp, *node = kmalloc(sizeof(*node), GFP_ATOMIC);
+
+       if (!node)
+               return -ENOMEM;
+
+       if (umem->numem == max_iotlb_entries) {
+               tmp = list_first_entry(&umem->umem_list, typeof(*tmp), link);
+               vhost_umem_free(umem, tmp);
+       }
+
+       node->start = start;
+       node->size = size;
+       node->last = end;
+       node->userspace_addr = userspace_addr;
+       node->perm = perm;
+       INIT_LIST_HEAD(&node->link);
+       list_add_tail(&node->link, &umem->umem_list);
+       vhost_umem_interval_tree_insert(node, &umem->umem_tree);
+       umem->numem++;
+
+       return 0;
+}
+
+static void vhost_del_umem_range(struct vhost_umem *umem,
+                                u64 start, u64 end)
+{
+       struct vhost_umem_node *node;
+
+       while ((node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
+                                                          start, end)))
+               vhost_umem_free(umem, node);
+}
+
+static void vhost_iotlb_notify_vq(struct vhost_dev *d,
+                                 struct vhost_iotlb_msg *msg)
+{
+       struct vhost_msg_node *node, *n;
+
+       spin_lock(&d->iotlb_lock);
+
+       list_for_each_entry_safe(node, n, &d->pending_list, node) {
+               struct vhost_iotlb_msg *vq_msg = &node->msg.iotlb;
+               if (msg->iova <= vq_msg->iova &&
+                   msg->iova + msg->size - 1 > vq_msg->iova &&
+                   vq_msg->type == VHOST_IOTLB_MISS) {
+                       vhost_poll_queue(&node->vq->poll);
+                       list_del(&node->node);
+                       kfree(node);
+               }
+       }
+
+       spin_unlock(&d->iotlb_lock);
+}
+
+static int umem_access_ok(u64 uaddr, u64 size, int access)
+{
+       unsigned long a = uaddr;
+
+       /* Make sure 64 bit math will not overflow. */
+       if (vhost_overflow(uaddr, size))
+               return -EFAULT;
+
+       if ((access & VHOST_ACCESS_RO) &&
+           !access_ok(VERIFY_READ, (void __user *)a, size))
+               return -EFAULT;
+       if ((access & VHOST_ACCESS_WO) &&
+           !access_ok(VERIFY_WRITE, (void __user *)a, size))
+               return -EFAULT;
+       return 0;
+}
+
+int vhost_process_iotlb_msg(struct vhost_dev *dev,
+                           struct vhost_iotlb_msg *msg)
+{
+       int ret = 0;
+
+       vhost_dev_lock_vqs(dev);
+       switch (msg->type) {
+       case VHOST_IOTLB_UPDATE:
+               if (!dev->iotlb) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (umem_access_ok(msg->uaddr, msg->size, msg->perm)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (vhost_new_umem_range(dev->iotlb, msg->iova, msg->size,
+                                        msg->iova + msg->size - 1,
+                                        msg->uaddr, msg->perm)) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               vhost_iotlb_notify_vq(dev, msg);
+               break;
+       case VHOST_IOTLB_INVALIDATE:
+               vhost_del_umem_range(dev->iotlb, msg->iova,
+                                    msg->iova + msg->size - 1);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       vhost_dev_unlock_vqs(dev);
+       return ret;
+}
+ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
+                            struct iov_iter *from)
+{
+       struct vhost_msg_node node;
+       unsigned size = sizeof(struct vhost_msg);
+       size_t ret;
+       int err;
+
+       if (iov_iter_count(from) < size)
+               return 0;
+       ret = copy_from_iter(&node.msg, size, from);
+       if (ret != size)
+               goto done;
+
+       switch (node.msg.type) {
+       case VHOST_IOTLB_MSG:
+               err = vhost_process_iotlb_msg(dev, &node.msg.iotlb);
+               if (err)
+                       ret = err;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+done:
+       return ret;
+}
+EXPORT_SYMBOL(vhost_chr_write_iter);
+
+unsigned int vhost_chr_poll(struct file *file, struct vhost_dev *dev,
+                           poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &dev->wait, wait);
+
+       if (!list_empty(&dev->read_list))
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+EXPORT_SYMBOL(vhost_chr_poll);
+
+ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
+                           int noblock)
+{
+       DEFINE_WAIT(wait);
+       struct vhost_msg_node *node;
+       ssize_t ret = 0;
+       unsigned size = sizeof(struct vhost_msg);
+
+       if (iov_iter_count(to) < size)
+               return 0;
+
+       while (1) {
+               if (!noblock)
+                       prepare_to_wait(&dev->wait, &wait,
+                                       TASK_INTERRUPTIBLE);
+
+               node = vhost_dequeue_msg(dev, &dev->read_list);
+               if (node)
+                       break;
+               if (noblock) {
+                       ret = -EAGAIN;
+                       break;
+               }
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               if (!dev->iotlb) {
+                       ret = -EBADFD;
+                       break;
+               }
+
+               schedule();
+       }
+
+       if (!noblock)
+               finish_wait(&dev->wait, &wait);
+
+       if (node) {
+               ret = copy_to_iter(&node->msg, size, to);
+
+               if (ret != size || node->msg.type != VHOST_IOTLB_MISS) {
+                       kfree(node);
+                       return ret;
+               }
+
+               vhost_enqueue_msg(dev, &dev->pending_list, node);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(vhost_chr_read_iter);
+
+static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access)
+{
+       struct vhost_dev *dev = vq->dev;
+       struct vhost_msg_node *node;
+       struct vhost_iotlb_msg *msg;
+
+       node = vhost_new_msg(vq, VHOST_IOTLB_MISS);
+       if (!node)
+               return -ENOMEM;
+
+       msg = &node->msg.iotlb;
+       msg->type = VHOST_IOTLB_MISS;
+       msg->iova = iova;
+       msg->perm = access;
+
+       vhost_enqueue_msg(dev, &dev->read_list, node);
+
+       return 0;
+}
+
 static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
                        struct vring_desc __user *desc,
                        struct vring_avail __user *avail,
                        struct vring_used __user *used)
+
 {
        size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+
        return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
               access_ok(VERIFY_READ, avail,
                         sizeof *avail + num * sizeof *avail->ring + s) &&
@@ -664,11 +1102,59 @@ static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
                        sizeof *used + num * sizeof *used->ring + s);
 }
 
+static int iotlb_access_ok(struct vhost_virtqueue *vq,
+                          int access, u64 addr, u64 len)
+{
+       const struct vhost_umem_node *node;
+       struct vhost_umem *umem = vq->iotlb;
+       u64 s = 0, size;
+
+       while (len > s) {
+               node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
+                                                          addr,
+                                                          addr + len - 1);
+               if (node == NULL || node->start > addr) {
+                       vhost_iotlb_miss(vq, addr, access);
+                       return false;
+               } else if (!(node->perm & access)) {
+                       /* Report the possible access violation by
+                        * request another translation from userspace.
+                        */
+                       return false;
+               }
+
+               size = node->size - addr + node->start;
+               s += size;
+               addr += size;
+       }
+
+       return true;
+}
+
+int vq_iotlb_prefetch(struct vhost_virtqueue *vq)
+{
+       size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+       unsigned int num = vq->num;
+
+       if (!vq->iotlb)
+               return 1;
+
+       return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
+                              num * sizeof *vq->desc) &&
+              iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
+                              sizeof *vq->avail +
+                              num * sizeof *vq->avail->ring + s) &&
+              iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
+                              sizeof *vq->used +
+                              num * sizeof *vq->used->ring + s);
+}
+EXPORT_SYMBOL_GPL(vq_iotlb_prefetch);
+
 /* Can we log writes? */
 /* Caller should have device mutex but not vq mutex */
 int vhost_log_access_ok(struct vhost_dev *dev)
 {
-       return memory_access_ok(dev, dev->memory, 1);
+       return memory_access_ok(dev, dev->umem, 1);
 }
 EXPORT_SYMBOL_GPL(vhost_log_access_ok);
 
@@ -679,7 +1165,7 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq,
 {
        size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
 
-       return vq_memory_access_ok(log_base, vq->memory,
+       return vq_memory_access_ok(log_base, vq->umem,
                                   vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
                                        sizeof *vq->used +
@@ -690,33 +1176,36 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq,
 /* Caller should have vq mutex and device mutex */
 int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 {
+       if (vq->iotlb) {
+               /* When device IOTLB was used, the access validation
+                * will be validated during prefetching.
+                */
+               return 1;
+       }
        return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) &&
                vq_log_access_ok(vq, vq->log_base);
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
-static int vhost_memory_reg_sort_cmp(const void *p1, const void *p2)
+static struct vhost_umem *vhost_umem_alloc(void)
 {
-       const struct vhost_memory_region *r1 = p1, *r2 = p2;
-       if (r1->guest_phys_addr < r2->guest_phys_addr)
-               return 1;
-       if (r1->guest_phys_addr > r2->guest_phys_addr)
-               return -1;
-       return 0;
-}
+       struct vhost_umem *umem = vhost_kvzalloc(sizeof(*umem));
 
-static void *vhost_kvzalloc(unsigned long size)
-{
-       void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       if (!umem)
+               return NULL;
 
-       if (!n)
-               n = vzalloc(size);
-       return n;
+       umem->umem_tree = RB_ROOT;
+       umem->numem = 0;
+       INIT_LIST_HEAD(&umem->umem_list);
+
+       return umem;
 }
 
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
-       struct vhost_memory mem, *newmem, *oldmem;
+       struct vhost_memory mem, *newmem;
+       struct vhost_memory_region *region;
+       struct vhost_umem *newumem, *oldumem;
        unsigned long size = offsetof(struct vhost_memory, regions);
        int i;
 
@@ -736,24 +1225,47 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                kvfree(newmem);
                return -EFAULT;
        }
-       sort(newmem->regions, newmem->nregions, sizeof(*newmem->regions),
-               vhost_memory_reg_sort_cmp, NULL);
 
-       if (!memory_access_ok(d, newmem, 0)) {
+       newumem = vhost_umem_alloc();
+       if (!newumem) {
                kvfree(newmem);
-               return -EFAULT;
+               return -ENOMEM;
        }
-       oldmem = d->memory;
-       d->memory = newmem;
+
+       for (region = newmem->regions;
+            region < newmem->regions + mem.nregions;
+            region++) {
+               if (vhost_new_umem_range(newumem,
+                                        region->guest_phys_addr,
+                                        region->memory_size,
+                                        region->guest_phys_addr +
+                                        region->memory_size - 1,
+                                        region->userspace_addr,
+                                        VHOST_ACCESS_RW))
+                       goto err;
+       }
+
+       if (!memory_access_ok(d, newumem, 0))
+               goto err;
+
+       oldumem = d->umem;
+       d->umem = newumem;
 
        /* All memory accesses are done under some VQ mutex. */
        for (i = 0; i < d->nvqs; ++i) {
                mutex_lock(&d->vqs[i]->mutex);
-               d->vqs[i]->memory = newmem;
+               d->vqs[i]->umem = newumem;
                mutex_unlock(&d->vqs[i]->mutex);
        }
-       kvfree(oldmem);
+
+       kvfree(newmem);
+       vhost_umem_clean(oldumem);
        return 0;
+
+err:
+       vhost_umem_clean(newumem);
+       kvfree(newmem);
+       return -EFAULT;
 }
 
 long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
@@ -974,6 +1486,30 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
 }
 EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
 
+int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled)
+{
+       struct vhost_umem *niotlb, *oiotlb;
+       int i;
+
+       niotlb = vhost_umem_alloc();
+       if (!niotlb)
+               return -ENOMEM;
+
+       oiotlb = d->iotlb;
+       d->iotlb = niotlb;
+
+       for (i = 0; i < d->nvqs; ++i) {
+               mutex_lock(&d->vqs[i]->mutex);
+               d->vqs[i]->iotlb = niotlb;
+               mutex_unlock(&d->vqs[i]->mutex);
+       }
+
+       vhost_umem_clean(oiotlb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vhost_init_device_iotlb);
+
 /* Caller must have device mutex */
 long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
 {
@@ -1056,28 +1592,6 @@ done:
 }
 EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
 
-static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
-                                                    __u64 addr, __u32 len)
-{
-       const struct vhost_memory_region *reg;
-       int start = 0, end = mem->nregions;
-
-       while (start < end) {
-               int slot = start + (end - start) / 2;
-               reg = mem->regions + slot;
-               if (addr >= reg->guest_phys_addr)
-                       end = slot;
-               else
-                       start = slot + 1;
-       }
-
-       reg = mem->regions + start;
-       if (addr >= reg->guest_phys_addr &&
-               reg->guest_phys_addr + reg->memory_size > addr)
-               return reg;
-       return NULL;
-}
-
 /* TODO: This is really inefficient.  We need something like get_user()
  * (instruction directly accesses the data, with an exception table entry
  * returning -EFAULT). See Documentation/x86/exception-tables.txt.
@@ -1156,7 +1670,8 @@ EXPORT_SYMBOL_GPL(vhost_log_write);
 static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 {
        void __user *used;
-       if (__put_user(cpu_to_vhost16(vq, vq->used_flags), &vq->used->flags) < 0)
+       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
+                          &vq->used->flags) < 0)
                return -EFAULT;
        if (unlikely(vq->log_used)) {
                /* Make sure the flag is seen before log. */
@@ -1174,7 +1689,8 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
 
 static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
 {
-       if (__put_user(cpu_to_vhost16(vq, vq->avail_idx), vhost_avail_event(vq)))
+       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
+                          vhost_avail_event(vq)))
                return -EFAULT;
        if (unlikely(vq->log_used)) {
                void __user *used;
@@ -1208,15 +1724,20 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
        if (r)
                goto err;
        vq->signalled_used_valid = false;
-       if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) {
+       if (!vq->iotlb &&
+           !access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) {
                r = -EFAULT;
                goto err;
        }
-       r = __get_user(last_used_idx, &vq->used->idx);
-       if (r)
+       r = vhost_get_user(vq, last_used_idx, &vq->used->idx);
+       if (r) {
+               vq_err(vq, "Can't access used idx at %p\n",
+                      &vq->used->idx);
                goto err;
+       }
        vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx);
        return 0;
+
 err:
        vq->is_le = is_le;
        return r;
@@ -1224,36 +1745,48 @@ err:
 EXPORT_SYMBOL_GPL(vhost_vq_init_access);
 
 static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,
-                         struct iovec iov[], int iov_size)
+                         struct iovec iov[], int iov_size, int access)
 {
-       const struct vhost_memory_region *reg;
-       struct vhost_memory *mem;
+       const struct vhost_umem_node *node;
+       struct vhost_dev *dev = vq->dev;
+       struct vhost_umem *umem = dev->iotlb ? dev->iotlb : dev->umem;
        struct iovec *_iov;
        u64 s = 0;
        int ret = 0;
 
-       mem = vq->memory;
        while ((u64)len > s) {
                u64 size;
                if (unlikely(ret >= iov_size)) {
                        ret = -ENOBUFS;
                        break;
                }
-               reg = find_region(mem, addr, len);
-               if (unlikely(!reg)) {
-                       ret = -EFAULT;
+
+               node = vhost_umem_interval_tree_iter_first(&umem->umem_tree,
+                                                       addr, addr + len - 1);
+               if (node == NULL || node->start > addr) {
+                       if (umem != dev->iotlb) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       ret = -EAGAIN;
+                       break;
+               } else if (!(node->perm & access)) {
+                       ret = -EPERM;
                        break;
                }
+
                _iov = iov + ret;
-               size = reg->memory_size - addr + reg->guest_phys_addr;
+               size = node->size - addr + node->start;
                _iov->iov_len = min((u64)len - s, size);
                _iov->iov_base = (void __user *)(unsigned long)
-                       (reg->userspace_addr + addr - reg->guest_phys_addr);
+                       (node->userspace_addr + addr - node->start);
                s += size;
                addr += size;
                ++ret;
        }
 
+       if (ret == -EAGAIN)
+               vhost_iotlb_miss(vq, addr, access);
        return ret;
 }
 
@@ -1288,7 +1821,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
        unsigned int i = 0, count, found = 0;
        u32 len = vhost32_to_cpu(vq, indirect->len);
        struct iov_iter from;
-       int ret;
+       int ret, access;
 
        /* Sanity check */
        if (unlikely(len % sizeof desc)) {
@@ -1300,9 +1833,10 @@ static int get_indirect(struct vhost_virtqueue *vq,
        }
 
        ret = translate_desc(vq, vhost64_to_cpu(vq, indirect->addr), len, vq->indirect,
-                            UIO_MAXIOV);
+                            UIO_MAXIOV, VHOST_ACCESS_RO);
        if (unlikely(ret < 0)) {
-               vq_err(vq, "Translation failure %d in indirect.\n", ret);
+               if (ret != -EAGAIN)
+                       vq_err(vq, "Translation failure %d in indirect.\n", ret);
                return ret;
        }
        iov_iter_init(&from, READ, vq->indirect, ret, len);
@@ -1340,16 +1874,22 @@ static int get_indirect(struct vhost_virtqueue *vq,
                        return -EINVAL;
                }
 
+               if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE))
+                       access = VHOST_ACCESS_WO;
+               else
+                       access = VHOST_ACCESS_RO;
+
                ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr),
                                     vhost32_to_cpu(vq, desc.len), iov + iov_count,
-                                    iov_size - iov_count);
+                                    iov_size - iov_count, access);
                if (unlikely(ret < 0)) {
-                       vq_err(vq, "Translation failure %d indirect idx %d\n",
-                              ret, i);
+                       if (ret != -EAGAIN)
+                               vq_err(vq, "Translation failure %d indirect idx %d\n",
+                                       ret, i);
                        return ret;
                }
                /* If this is an input descriptor, increment that count. */
-               if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) {
+               if (access == VHOST_ACCESS_WO) {
                        *in_num += ret;
                        if (unlikely(log)) {
                                log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
@@ -1388,11 +1928,11 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
        u16 last_avail_idx;
        __virtio16 avail_idx;
        __virtio16 ring_head;
-       int ret;
+       int ret, access;
 
        /* Check it isn't doing very strange things with descriptor numbers. */
        last_avail_idx = vq->last_avail_idx;
-       if (unlikely(__get_user(avail_idx, &vq->avail->idx))) {
+       if (unlikely(vhost_get_user(vq, avail_idx, &vq->avail->idx))) {
                vq_err(vq, "Failed to access avail idx at %p\n",
                       &vq->avail->idx);
                return -EFAULT;
@@ -1414,8 +1954,8 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
 
        /* Grab the next descriptor number they're advertising, and increment
         * the index we've seen. */
-       if (unlikely(__get_user(ring_head,
-                               &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
+       if (unlikely(vhost_get_user(vq, ring_head,
+                    &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
                vq_err(vq, "Failed to read head: idx %d address %p\n",
                       last_avail_idx,
                       &vq->avail->ring[last_avail_idx % vq->num]);
@@ -1450,7 +1990,8 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                               i, vq->num, head);
                        return -EINVAL;
                }
-               ret = __copy_from_user(&desc, vq->desc + i, sizeof desc);
+               ret = vhost_copy_from_user(vq, &desc, vq->desc + i,
+                                          sizeof desc);
                if (unlikely(ret)) {
                        vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
                               i, vq->desc + i);
@@ -1461,22 +2002,28 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                                           out_num, in_num,
                                           log, log_num, &desc);
                        if (unlikely(ret < 0)) {
-                               vq_err(vq, "Failure detected "
-                                      "in indirect descriptor at idx %d\n", i);
+                               if (ret != -EAGAIN)
+                                       vq_err(vq, "Failure detected "
+                                               "in indirect descriptor at idx %d\n", i);
                                return ret;
                        }
                        continue;
                }
 
+               if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE))
+                       access = VHOST_ACCESS_WO;
+               else
+                       access = VHOST_ACCESS_RO;
                ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr),
                                     vhost32_to_cpu(vq, desc.len), iov + iov_count,
-                                    iov_size - iov_count);
+                                    iov_size - iov_count, access);
                if (unlikely(ret < 0)) {
-                       vq_err(vq, "Translation failure %d descriptor idx %d\n",
-                              ret, i);
+                       if (ret != -EAGAIN)
+                               vq_err(vq, "Translation failure %d descriptor idx %d\n",
+                                       ret, i);
                        return ret;
                }
-               if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) {
+               if (access == VHOST_ACCESS_WO) {
                        /* If this is an input descriptor,
                         * increment that count. */
                        *in_num += ret;
@@ -1538,15 +2085,15 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
        start = vq->last_used_idx & (vq->num - 1);
        used = vq->used->ring + start;
        if (count == 1) {
-               if (__put_user(heads[0].id, &used->id)) {
+               if (vhost_put_user(vq, heads[0].id, &used->id)) {
                        vq_err(vq, "Failed to write used id");
                        return -EFAULT;
                }
-               if (__put_user(heads[0].len, &used->len)) {
+               if (vhost_put_user(vq, heads[0].len, &used->len)) {
                        vq_err(vq, "Failed to write used len");
                        return -EFAULT;
                }
-       } else if (__copy_to_user(used, heads, count * sizeof *used)) {
+       } else if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) {
                vq_err(vq, "Failed to write used");
                return -EFAULT;
        }
@@ -1590,7 +2137,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
 
        /* Make sure buffer is written before we update index. */
        smp_wmb();
-       if (__put_user(cpu_to_vhost16(vq, vq->last_used_idx), &vq->used->idx)) {
+       if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
+                          &vq->used->idx)) {
                vq_err(vq, "Failed to increment used idx");
                return -EFAULT;
        }
@@ -1622,7 +2170,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 
        if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
                __virtio16 flags;
-               if (__get_user(flags, &vq->avail->flags)) {
+               if (vhost_get_user(vq, flags, &vq->avail->flags)) {
                        vq_err(vq, "Failed to get flags");
                        return true;
                }
@@ -1636,7 +2184,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        if (unlikely(!v))
                return true;
 
-       if (__get_user(event, vhost_used_event(vq))) {
+       if (vhost_get_user(vq, event, vhost_used_event(vq))) {
                vq_err(vq, "Failed to get used event idx");
                return true;
        }
@@ -1678,7 +2226,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        __virtio16 avail_idx;
        int r;
 
-       r = __get_user(avail_idx, &vq->avail->idx);
+       r = vhost_get_user(vq, avail_idx, &vq->avail->idx);
        if (r)
                return false;
 
@@ -1713,7 +2261,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
        /* They could have slipped one in as we were doing that: make
         * sure it's written, then check again. */
        smp_mb();
-       r = __get_user(avail_idx, &vq->avail->idx);
+       r = vhost_get_user(vq, avail_idx, &vq->avail->idx);
        if (r) {
                vq_err(vq, "Failed to check avail idx at %p: %d\n",
                       &vq->avail->idx, r);
@@ -1741,6 +2289,47 @@ void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 }
 EXPORT_SYMBOL_GPL(vhost_disable_notify);
 
+/* Create a new message. */
+struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type)
+{
+       struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL);
+       if (!node)
+               return NULL;
+       node->vq = vq;
+       node->msg.type = type;
+       return node;
+}
+EXPORT_SYMBOL_GPL(vhost_new_msg);
+
+void vhost_enqueue_msg(struct vhost_dev *dev, struct list_head *head,
+                      struct vhost_msg_node *node)
+{
+       spin_lock(&dev->iotlb_lock);
+       list_add_tail(&node->node, head);
+       spin_unlock(&dev->iotlb_lock);
+
+       wake_up_interruptible_poll(&dev->wait, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(vhost_enqueue_msg);
+
+struct vhost_msg_node *vhost_dequeue_msg(struct vhost_dev *dev,
+                                        struct list_head *head)
+{
+       struct vhost_msg_node *node = NULL;
+
+       spin_lock(&dev->iotlb_lock);
+       if (!list_empty(head)) {
+               node = list_first_entry(head, struct vhost_msg_node,
+                                       node);
+               list_del(&node->node);
+       }
+       spin_unlock(&dev->iotlb_lock);
+
+       return node;
+}
+EXPORT_SYMBOL_GPL(vhost_dequeue_msg);
+
+
 static int __init vhost_init(void)
 {
        return 0;
index d36d8be..78f3c5f 100644 (file)
 struct vhost_work;
 typedef void (*vhost_work_fn_t)(struct vhost_work *work);
 
+#define VHOST_WORK_QUEUED 1
 struct vhost_work {
-       struct list_head          node;
+       struct llist_node         node;
        vhost_work_fn_t           fn;
        wait_queue_head_t         done;
        int                       flushing;
        unsigned                  queue_seq;
        unsigned                  done_seq;
+       unsigned long             flags;
 };
 
 /* Poll a file (eventfd or socket) */
@@ -53,6 +55,27 @@ struct vhost_log {
        u64 len;
 };
 
+#define START(node) ((node)->start)
+#define LAST(node) ((node)->last)
+
+struct vhost_umem_node {
+       struct rb_node rb;
+       struct list_head link;
+       __u64 start;
+       __u64 last;
+       __u64 size;
+       __u64 userspace_addr;
+       __u32 perm;
+       __u32 flags_padding;
+       __u64 __subtree_last;
+};
+
+struct vhost_umem {
+       struct rb_root umem_tree;
+       struct list_head umem_list;
+       int numem;
+};
+
 /* The virtqueue structure describes a queue attached to a device. */
 struct vhost_virtqueue {
        struct vhost_dev *dev;
@@ -98,10 +121,12 @@ struct vhost_virtqueue {
        u64 log_addr;
 
        struct iovec iov[UIO_MAXIOV];
+       struct iovec iotlb_iov[64];
        struct iovec *indirect;
        struct vring_used_elem *heads;
        /* Protected by virtqueue mutex. */
-       struct vhost_memory *memory;
+       struct vhost_umem *umem;
+       struct vhost_umem *iotlb;
        void *private_data;
        u64 acked_features;
        /* Log write descriptors */
@@ -118,25 +143,35 @@ struct vhost_virtqueue {
        u32 busyloop_timeout;
 };
 
+struct vhost_msg_node {
+  struct vhost_msg msg;
+  struct vhost_virtqueue *vq;
+  struct list_head node;
+};
+
 struct vhost_dev {
-       struct vhost_memory *memory;
        struct mm_struct *mm;
        struct mutex mutex;
        struct vhost_virtqueue **vqs;
        int nvqs;
        struct file *log_file;
        struct eventfd_ctx *log_ctx;
-       spinlock_t work_lock;
-       struct list_head work_list;
+       struct llist_head work_list;
        struct task_struct *worker;
+       struct vhost_umem *umem;
+       struct vhost_umem *iotlb;
+       spinlock_t iotlb_lock;
+       struct list_head read_list;
+       struct list_head pending_list;
+       wait_queue_head_t wait;
 };
 
 void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs);
 long vhost_dev_set_owner(struct vhost_dev *dev);
 bool vhost_dev_has_owner(struct vhost_dev *dev);
 long vhost_dev_check_owner(struct vhost_dev *);
-struct vhost_memory *vhost_dev_reset_owner_prepare(void);
-void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *);
+struct vhost_umem *vhost_dev_reset_owner_prepare(void);
+void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_umem *);
 void vhost_dev_cleanup(struct vhost_dev *, bool locked);
 void vhost_dev_stop(struct vhost_dev *);
 long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp);
@@ -165,6 +200,21 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
 
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
                    unsigned int log_num, u64 len);
+int vq_iotlb_prefetch(struct vhost_virtqueue *vq);
+
+struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type);
+void vhost_enqueue_msg(struct vhost_dev *dev,
+                      struct list_head *head,
+                      struct vhost_msg_node *node);
+struct vhost_msg_node *vhost_dequeue_msg(struct vhost_dev *dev,
+                                        struct list_head *head);
+unsigned int vhost_chr_poll(struct file *file, struct vhost_dev *dev,
+                           poll_table *wait);
+ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
+                           int noblock);
+ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
+                            struct iov_iter *from);
+int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled);
 
 #define vq_err(vq, fmt, ...) do {                                  \
                pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
new file mode 100644 (file)
index 0000000..e3b30ea
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * vhost transport for vsock
+ *
+ * Copyright (C) 2013-2015 Red Hat, Inc.
+ * Author: Asias He <asias@redhat.com>
+ *         Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+#include <linux/miscdevice.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <net/sock.h>
+#include <linux/virtio_vsock.h>
+#include <linux/vhost.h>
+
+#include <net/af_vsock.h>
+#include "vhost.h"
+
+#define VHOST_VSOCK_DEFAULT_HOST_CID   2
+
+enum {
+       VHOST_VSOCK_FEATURES = VHOST_FEATURES,
+};
+
+/* Used to track all the vhost_vsock instances on the system. */
+static DEFINE_SPINLOCK(vhost_vsock_lock);
+static LIST_HEAD(vhost_vsock_list);
+
+struct vhost_vsock {
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[2];
+
+       /* Link to global vhost_vsock_list, protected by vhost_vsock_lock */
+       struct list_head list;
+
+       struct vhost_work send_pkt_work;
+       spinlock_t send_pkt_list_lock;
+       struct list_head send_pkt_list; /* host->guest pending packets */
+
+       atomic_t queued_replies;
+
+       u32 guest_cid;
+};
+
+static u32 vhost_transport_get_local_cid(void)
+{
+       return VHOST_VSOCK_DEFAULT_HOST_CID;
+}
+
+static struct vhost_vsock *vhost_vsock_get(u32 guest_cid)
+{
+       struct vhost_vsock *vsock;
+
+       spin_lock_bh(&vhost_vsock_lock);
+       list_for_each_entry(vsock, &vhost_vsock_list, list) {
+               u32 other_cid = vsock->guest_cid;
+
+               /* Skip instances that have no CID yet */
+               if (other_cid == 0)
+                       continue;
+
+               if (other_cid == guest_cid) {
+                       spin_unlock_bh(&vhost_vsock_lock);
+                       return vsock;
+               }
+       }
+       spin_unlock_bh(&vhost_vsock_lock);
+
+       return NULL;
+}
+
+static void
+vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
+                           struct vhost_virtqueue *vq)
+{
+       struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX];
+       bool added = false;
+       bool restart_tx = false;
+
+       mutex_lock(&vq->mutex);
+
+       if (!vq->private_data)
+               goto out;
+
+       /* Avoid further vmexits, we're already processing the virtqueue */
+       vhost_disable_notify(&vsock->dev, vq);
+
+       for (;;) {
+               struct virtio_vsock_pkt *pkt;
+               struct iov_iter iov_iter;
+               unsigned out, in;
+               size_t nbytes;
+               size_t len;
+               int head;
+
+               spin_lock_bh(&vsock->send_pkt_list_lock);
+               if (list_empty(&vsock->send_pkt_list)) {
+                       spin_unlock_bh(&vsock->send_pkt_list_lock);
+                       vhost_enable_notify(&vsock->dev, vq);
+                       break;
+               }
+
+               pkt = list_first_entry(&vsock->send_pkt_list,
+                                      struct virtio_vsock_pkt, list);
+               list_del_init(&pkt->list);
+               spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+               head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
+                                        &out, &in, NULL, NULL);
+               if (head < 0) {
+                       spin_lock_bh(&vsock->send_pkt_list_lock);
+                       list_add(&pkt->list, &vsock->send_pkt_list);
+                       spin_unlock_bh(&vsock->send_pkt_list_lock);
+                       break;
+               }
+
+               if (head == vq->num) {
+                       spin_lock_bh(&vsock->send_pkt_list_lock);
+                       list_add(&pkt->list, &vsock->send_pkt_list);
+                       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+                       /* We cannot finish yet if more buffers snuck in while
+                        * re-enabling notify.
+                        */
+                       if (unlikely(vhost_enable_notify(&vsock->dev, vq))) {
+                               vhost_disable_notify(&vsock->dev, vq);
+                               continue;
+                       }
+                       break;
+               }
+
+               if (out) {
+                       virtio_transport_free_pkt(pkt);
+                       vq_err(vq, "Expected 0 output buffers, got %u\n", out);
+                       break;
+               }
+
+               len = iov_length(&vq->iov[out], in);
+               iov_iter_init(&iov_iter, READ, &vq->iov[out], in, len);
+
+               nbytes = copy_to_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter);
+               if (nbytes != sizeof(pkt->hdr)) {
+                       virtio_transport_free_pkt(pkt);
+                       vq_err(vq, "Faulted on copying pkt hdr\n");
+                       break;
+               }
+
+               nbytes = copy_to_iter(pkt->buf, pkt->len, &iov_iter);
+               if (nbytes != pkt->len) {
+                       virtio_transport_free_pkt(pkt);
+                       vq_err(vq, "Faulted on copying pkt buf\n");
+                       break;
+               }
+
+               vhost_add_used(vq, head, sizeof(pkt->hdr) + pkt->len);
+               added = true;
+
+               if (pkt->reply) {
+                       int val;
+
+                       val = atomic_dec_return(&vsock->queued_replies);
+
+                       /* Do we have resources to resume tx processing? */
+                       if (val + 1 == tx_vq->num)
+                               restart_tx = true;
+               }
+
+               virtio_transport_free_pkt(pkt);
+       }
+       if (added)
+               vhost_signal(&vsock->dev, vq);
+
+out:
+       mutex_unlock(&vq->mutex);
+
+       if (restart_tx)
+               vhost_poll_queue(&tx_vq->poll);
+}
+
+static void vhost_transport_send_pkt_work(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_vsock *vsock;
+
+       vsock = container_of(work, struct vhost_vsock, send_pkt_work);
+       vq = &vsock->vqs[VSOCK_VQ_RX];
+
+       vhost_transport_do_send_pkt(vsock, vq);
+}
+
+static int
+vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt)
+{
+       struct vhost_vsock *vsock;
+       struct vhost_virtqueue *vq;
+       int len = pkt->len;
+
+       /* Find the vhost_vsock according to guest context id  */
+       vsock = vhost_vsock_get(le64_to_cpu(pkt->hdr.dst_cid));
+       if (!vsock) {
+               virtio_transport_free_pkt(pkt);
+               return -ENODEV;
+       }
+
+       vq = &vsock->vqs[VSOCK_VQ_RX];
+
+       if (pkt->reply)
+               atomic_inc(&vsock->queued_replies);
+
+       spin_lock_bh(&vsock->send_pkt_list_lock);
+       list_add_tail(&pkt->list, &vsock->send_pkt_list);
+       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+       vhost_work_queue(&vsock->dev, &vsock->send_pkt_work);
+       return len;
+}
+
+static struct virtio_vsock_pkt *
+vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq,
+                     unsigned int out, unsigned int in)
+{
+       struct virtio_vsock_pkt *pkt;
+       struct iov_iter iov_iter;
+       size_t nbytes;
+       size_t len;
+
+       if (in != 0) {
+               vq_err(vq, "Expected 0 input buffers, got %u\n", in);
+               return NULL;
+       }
+
+       pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
+       if (!pkt)
+               return NULL;
+
+       len = iov_length(vq->iov, out);
+       iov_iter_init(&iov_iter, WRITE, vq->iov, out, len);
+
+       nbytes = copy_from_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter);
+       if (nbytes != sizeof(pkt->hdr)) {
+               vq_err(vq, "Expected %zu bytes for pkt->hdr, got %zu bytes\n",
+                      sizeof(pkt->hdr), nbytes);
+               kfree(pkt);
+               return NULL;
+       }
+
+       if (le16_to_cpu(pkt->hdr.type) == VIRTIO_VSOCK_TYPE_STREAM)
+               pkt->len = le32_to_cpu(pkt->hdr.len);
+
+       /* No payload */
+       if (!pkt->len)
+               return pkt;
+
+       /* The pkt is too big */
+       if (pkt->len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE) {
+               kfree(pkt);
+               return NULL;
+       }
+
+       pkt->buf = kmalloc(pkt->len, GFP_KERNEL);
+       if (!pkt->buf) {
+               kfree(pkt);
+               return NULL;
+       }
+
+       nbytes = copy_from_iter(pkt->buf, pkt->len, &iov_iter);
+       if (nbytes != pkt->len) {
+               vq_err(vq, "Expected %u byte payload, got %zu bytes\n",
+                      pkt->len, nbytes);
+               virtio_transport_free_pkt(pkt);
+               return NULL;
+       }
+
+       return pkt;
+}
+
+/* Is there space left for replies to rx packets? */
+static bool vhost_vsock_more_replies(struct vhost_vsock *vsock)
+{
+       struct vhost_virtqueue *vq = &vsock->vqs[VSOCK_VQ_TX];
+       int val;
+
+       smp_rmb(); /* paired with atomic_inc() and atomic_dec_return() */
+       val = atomic_read(&vsock->queued_replies);
+
+       return val < vq->num;
+}
+
+static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+                                                 poll.work);
+       struct vhost_vsock *vsock = container_of(vq->dev, struct vhost_vsock,
+                                                dev);
+       struct virtio_vsock_pkt *pkt;
+       int head;
+       unsigned int out, in;
+       bool added = false;
+
+       mutex_lock(&vq->mutex);
+
+       if (!vq->private_data)
+               goto out;
+
+       vhost_disable_notify(&vsock->dev, vq);
+       for (;;) {
+               u32 len;
+
+               if (!vhost_vsock_more_replies(vsock)) {
+                       /* Stop tx until the device processes already
+                        * pending replies.  Leave tx virtqueue
+                        * callbacks disabled.
+                        */
+                       goto no_more_replies;
+               }
+
+               head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
+                                        &out, &in, NULL, NULL);
+               if (head < 0)
+                       break;
+
+               if (head == vq->num) {
+                       if (unlikely(vhost_enable_notify(&vsock->dev, vq))) {
+                               vhost_disable_notify(&vsock->dev, vq);
+                               continue;
+                       }
+                       break;
+               }
+
+               pkt = vhost_vsock_alloc_pkt(vq, out, in);
+               if (!pkt) {
+                       vq_err(vq, "Faulted on pkt\n");
+                       continue;
+               }
+
+               len = pkt->len;
+
+               /* Only accept correctly addressed packets */
+               if (le64_to_cpu(pkt->hdr.src_cid) == vsock->guest_cid)
+                       virtio_transport_recv_pkt(pkt);
+               else
+                       virtio_transport_free_pkt(pkt);
+
+               vhost_add_used(vq, head, sizeof(pkt->hdr) + len);
+               added = true;
+       }
+
+no_more_replies:
+       if (added)
+               vhost_signal(&vsock->dev, vq);
+
+out:
+       mutex_unlock(&vq->mutex);
+}
+
+static void vhost_vsock_handle_rx_kick(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+                                               poll.work);
+       struct vhost_vsock *vsock = container_of(vq->dev, struct vhost_vsock,
+                                                dev);
+
+       vhost_transport_do_send_pkt(vsock, vq);
+}
+
+static int vhost_vsock_start(struct vhost_vsock *vsock)
+{
+       size_t i;
+       int ret;
+
+       mutex_lock(&vsock->dev.mutex);
+
+       ret = vhost_dev_check_owner(&vsock->dev);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
+               struct vhost_virtqueue *vq = &vsock->vqs[i];
+
+               mutex_lock(&vq->mutex);
+
+               if (!vhost_vq_access_ok(vq)) {
+                       ret = -EFAULT;
+                       mutex_unlock(&vq->mutex);
+                       goto err_vq;
+               }
+
+               if (!vq->private_data) {
+                       vq->private_data = vsock;
+                       vhost_vq_init_access(vq);
+               }
+
+               mutex_unlock(&vq->mutex);
+       }
+
+       mutex_unlock(&vsock->dev.mutex);
+       return 0;
+
+err_vq:
+       for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
+               struct vhost_virtqueue *vq = &vsock->vqs[i];
+
+               mutex_lock(&vq->mutex);
+               vq->private_data = NULL;
+               mutex_unlock(&vq->mutex);
+       }
+err:
+       mutex_unlock(&vsock->dev.mutex);
+       return ret;
+}
+
+static int vhost_vsock_stop(struct vhost_vsock *vsock)
+{
+       size_t i;
+       int ret;
+
+       mutex_lock(&vsock->dev.mutex);
+
+       ret = vhost_dev_check_owner(&vsock->dev);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
+               struct vhost_virtqueue *vq = &vsock->vqs[i];
+
+               mutex_lock(&vq->mutex);
+               vq->private_data = NULL;
+               mutex_unlock(&vq->mutex);
+       }
+
+err:
+       mutex_unlock(&vsock->dev.mutex);
+       return ret;
+}
+
+static void vhost_vsock_free(struct vhost_vsock *vsock)
+{
+       kvfree(vsock);
+}
+
+static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
+{
+       struct vhost_virtqueue **vqs;
+       struct vhost_vsock *vsock;
+       int ret;
+
+       /* This struct is large and allocation could fail, fall back to vmalloc
+        * if there is no other way.
+        */
+       vsock = kzalloc(sizeof(*vsock), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       if (!vsock) {
+               vsock = vmalloc(sizeof(*vsock));
+               if (!vsock)
+                       return -ENOMEM;
+       }
+
+       vqs = kmalloc_array(ARRAY_SIZE(vsock->vqs), sizeof(*vqs), GFP_KERNEL);
+       if (!vqs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       atomic_set(&vsock->queued_replies, 0);
+
+       vqs[VSOCK_VQ_TX] = &vsock->vqs[VSOCK_VQ_TX];
+       vqs[VSOCK_VQ_RX] = &vsock->vqs[VSOCK_VQ_RX];
+       vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick;
+       vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick;
+
+       vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs));
+
+       file->private_data = vsock;
+       spin_lock_init(&vsock->send_pkt_list_lock);
+       INIT_LIST_HEAD(&vsock->send_pkt_list);
+       vhost_work_init(&vsock->send_pkt_work, vhost_transport_send_pkt_work);
+
+       spin_lock_bh(&vhost_vsock_lock);
+       list_add_tail(&vsock->list, &vhost_vsock_list);
+       spin_unlock_bh(&vhost_vsock_lock);
+       return 0;
+
+out:
+       vhost_vsock_free(vsock);
+       return ret;
+}
+
+static void vhost_vsock_flush(struct vhost_vsock *vsock)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++)
+               if (vsock->vqs[i].handle_kick)
+                       vhost_poll_flush(&vsock->vqs[i].poll);
+       vhost_work_flush(&vsock->dev, &vsock->send_pkt_work);
+}
+
+static void vhost_vsock_reset_orphans(struct sock *sk)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+
+       /* vmci_transport.c doesn't take sk_lock here either.  At least we're
+        * under vsock_table_lock so the sock cannot disappear while we're
+        * executing.
+        */
+
+       if (!vhost_vsock_get(vsk->local_addr.svm_cid)) {
+               sock_set_flag(sk, SOCK_DONE);
+               vsk->peer_shutdown = SHUTDOWN_MASK;
+               sk->sk_state = SS_UNCONNECTED;
+               sk->sk_err = ECONNRESET;
+               sk->sk_error_report(sk);
+       }
+}
+
+static int vhost_vsock_dev_release(struct inode *inode, struct file *file)
+{
+       struct vhost_vsock *vsock = file->private_data;
+
+       spin_lock_bh(&vhost_vsock_lock);
+       list_del(&vsock->list);
+       spin_unlock_bh(&vhost_vsock_lock);
+
+       /* Iterating over all connections for all CIDs to find orphans is
+        * inefficient.  Room for improvement here. */
+       vsock_for_each_connected_socket(vhost_vsock_reset_orphans);
+
+       vhost_vsock_stop(vsock);
+       vhost_vsock_flush(vsock);
+       vhost_dev_stop(&vsock->dev);
+
+       spin_lock_bh(&vsock->send_pkt_list_lock);
+       while (!list_empty(&vsock->send_pkt_list)) {
+               struct virtio_vsock_pkt *pkt;
+
+               pkt = list_first_entry(&vsock->send_pkt_list,
+                               struct virtio_vsock_pkt, list);
+               list_del_init(&pkt->list);
+               virtio_transport_free_pkt(pkt);
+       }
+       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+       vhost_dev_cleanup(&vsock->dev, false);
+       kfree(vsock->dev.vqs);
+       vhost_vsock_free(vsock);
+       return 0;
+}
+
+static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid)
+{
+       struct vhost_vsock *other;
+
+       /* Refuse reserved CIDs */
+       if (guest_cid <= VMADDR_CID_HOST ||
+           guest_cid == U32_MAX)
+               return -EINVAL;
+
+       /* 64-bit CIDs are not yet supported */
+       if (guest_cid > U32_MAX)
+               return -EINVAL;
+
+       /* Refuse if CID is already in use */
+       other = vhost_vsock_get(guest_cid);
+       if (other && other != vsock)
+               return -EADDRINUSE;
+
+       spin_lock_bh(&vhost_vsock_lock);
+       vsock->guest_cid = guest_cid;
+       spin_unlock_bh(&vhost_vsock_lock);
+
+       return 0;
+}
+
+static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
+{
+       struct vhost_virtqueue *vq;
+       int i;
+
+       if (features & ~VHOST_VSOCK_FEATURES)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&vsock->dev.mutex);
+       if ((features & (1 << VHOST_F_LOG_ALL)) &&
+           !vhost_log_access_ok(&vsock->dev)) {
+               mutex_unlock(&vsock->dev.mutex);
+               return -EFAULT;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
+               vq = &vsock->vqs[i];
+               mutex_lock(&vq->mutex);
+               vq->acked_features = features;
+               mutex_unlock(&vq->mutex);
+       }
+       mutex_unlock(&vsock->dev.mutex);
+       return 0;
+}
+
+static long vhost_vsock_dev_ioctl(struct file *f, unsigned int ioctl,
+                                 unsigned long arg)
+{
+       struct vhost_vsock *vsock = f->private_data;
+       void __user *argp = (void __user *)arg;
+       u64 guest_cid;
+       u64 features;
+       int start;
+       int r;
+
+       switch (ioctl) {
+       case VHOST_VSOCK_SET_GUEST_CID:
+               if (copy_from_user(&guest_cid, argp, sizeof(guest_cid)))
+                       return -EFAULT;
+               return vhost_vsock_set_cid(vsock, guest_cid);
+       case VHOST_VSOCK_SET_RUNNING:
+               if (copy_from_user(&start, argp, sizeof(start)))
+                       return -EFAULT;
+               if (start)
+                       return vhost_vsock_start(vsock);
+               else
+                       return vhost_vsock_stop(vsock);
+       case VHOST_GET_FEATURES:
+               features = VHOST_VSOCK_FEATURES;
+               if (copy_to_user(argp, &features, sizeof(features)))
+                       return -EFAULT;
+               return 0;
+       case VHOST_SET_FEATURES:
+               if (copy_from_user(&features, argp, sizeof(features)))
+                       return -EFAULT;
+               return vhost_vsock_set_features(vsock, features);
+       default:
+               mutex_lock(&vsock->dev.mutex);
+               r = vhost_dev_ioctl(&vsock->dev, ioctl, argp);
+               if (r == -ENOIOCTLCMD)
+                       r = vhost_vring_ioctl(&vsock->dev, ioctl, argp);
+               else
+                       vhost_vsock_flush(vsock);
+               mutex_unlock(&vsock->dev.mutex);
+               return r;
+       }
+}
+
+static const struct file_operations vhost_vsock_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vhost_vsock_dev_open,
+       .release        = vhost_vsock_dev_release,
+       .llseek         = noop_llseek,
+       .unlocked_ioctl = vhost_vsock_dev_ioctl,
+};
+
+static struct miscdevice vhost_vsock_misc = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "vhost-vsock",
+       .fops = &vhost_vsock_fops,
+};
+
+static struct virtio_transport vhost_transport = {
+       .transport = {
+               .get_local_cid            = vhost_transport_get_local_cid,
+
+               .init                     = virtio_transport_do_socket_init,
+               .destruct                 = virtio_transport_destruct,
+               .release                  = virtio_transport_release,
+               .connect                  = virtio_transport_connect,
+               .shutdown                 = virtio_transport_shutdown,
+
+               .dgram_enqueue            = virtio_transport_dgram_enqueue,
+               .dgram_dequeue            = virtio_transport_dgram_dequeue,
+               .dgram_bind               = virtio_transport_dgram_bind,
+               .dgram_allow              = virtio_transport_dgram_allow,
+
+               .stream_enqueue           = virtio_transport_stream_enqueue,
+               .stream_dequeue           = virtio_transport_stream_dequeue,
+               .stream_has_data          = virtio_transport_stream_has_data,
+               .stream_has_space         = virtio_transport_stream_has_space,
+               .stream_rcvhiwat          = virtio_transport_stream_rcvhiwat,
+               .stream_is_active         = virtio_transport_stream_is_active,
+               .stream_allow             = virtio_transport_stream_allow,
+
+               .notify_poll_in           = virtio_transport_notify_poll_in,
+               .notify_poll_out          = virtio_transport_notify_poll_out,
+               .notify_recv_init         = virtio_transport_notify_recv_init,
+               .notify_recv_pre_block    = virtio_transport_notify_recv_pre_block,
+               .notify_recv_pre_dequeue  = virtio_transport_notify_recv_pre_dequeue,
+               .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue,
+               .notify_send_init         = virtio_transport_notify_send_init,
+               .notify_send_pre_block    = virtio_transport_notify_send_pre_block,
+               .notify_send_pre_enqueue  = virtio_transport_notify_send_pre_enqueue,
+               .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue,
+
+               .set_buffer_size          = virtio_transport_set_buffer_size,
+               .set_min_buffer_size      = virtio_transport_set_min_buffer_size,
+               .set_max_buffer_size      = virtio_transport_set_max_buffer_size,
+               .get_buffer_size          = virtio_transport_get_buffer_size,
+               .get_min_buffer_size      = virtio_transport_get_min_buffer_size,
+               .get_max_buffer_size      = virtio_transport_get_max_buffer_size,
+       },
+
+       .send_pkt = vhost_transport_send_pkt,
+};
+
+static int __init vhost_vsock_init(void)
+{
+       int ret;
+
+       ret = vsock_core_init(&vhost_transport.transport);
+       if (ret < 0)
+               return ret;
+       return misc_register(&vhost_vsock_misc);
+};
+
+static void __exit vhost_vsock_exit(void)
+{
+       misc_deregister(&vhost_vsock_misc);
+       vsock_core_exit();
+};
+
+module_init(vhost_vsock_init);
+module_exit(vhost_vsock_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Asias He");
+MODULE_DESCRIPTION("vhost transport for vsock ");
index 8fe41ca..e2d7d03 100644 (file)
@@ -10,6 +10,8 @@
  * TODO: Code Cleanup
  */
 
+#define DRIVER_NAME "bfin-adv7393"
+
 #define pr_fmt(fmt) DRIVER_NAME ": " fmt
 
 #include <linux/module.h>
index cd591b5..afd0380 100644 (file)
@@ -59,8 +59,6 @@ enum {
        BLANK_OFF,
 };
 
-#define DRIVER_NAME "bfin-adv7393"
-
 struct adv7393fb_modes {
        const s8 name[25];      /* Full name */
        u16 xres;               /* Active Horizonzal Pixels  */
index 2fb90cb..1d7c012 100644 (file)
@@ -1332,7 +1332,7 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
        }
 
        dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
-                       &rg->attrs);
+                       rg->attrs);
 
        rg->token = NULL;
        rg->vaddr = NULL;
@@ -1370,7 +1370,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
        struct omapfb2_device *fbdev = ofbi->fbdev;
        struct omapfb2_mem_region *rg;
        void *token;
-       DEFINE_DMA_ATTRS(attrs);
+       unsigned long attrs;
        dma_addr_t dma_handle;
        int r;
 
@@ -1386,15 +1386,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
 
        size = PAGE_ALIGN(size);
 
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+       attrs = DMA_ATTR_WRITE_COMBINE;
 
        if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
-               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+               attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
 
        DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
 
        token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
-                       GFP_KERNEL, &attrs);
+                       GFP_KERNEL, attrs);
 
        if (token == NULL) {
                dev_err(fbdev->dev, "failed to allocate framebuffer\n");
@@ -1408,7 +1408,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
                r = omap_vrfb_request_ctx(&rg->vrfb);
                if (r) {
                        dma_free_attrs(fbdev->dev, size, token, dma_handle,
-                                       &attrs);
+                                       attrs);
                        dev_err(fbdev->dev, "vrfb create ctx failed\n");
                        return r;
                }
index bcb9ff4..555487d 100644 (file)
@@ -28,7 +28,6 @@
 #endif
 
 #include <linux/rwsem.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-mapping.h>
 
 #include <video/omapfb_dss.h>
@@ -51,7 +50,7 @@ extern bool omapfb_debug;
 
 struct omapfb2_mem_region {
        int             id;
-       struct dma_attrs attrs;
+       unsigned long   attrs;
        void            *token;
        dma_addr_t      dma_handle;
        u32             paddr;
index 10fbfd8..b6bc4a0 100644 (file)
@@ -36,11 +36,11 @@ static int __init fb_logo_late_init(void)
 
 late_initcall(fb_logo_late_init);
 
-/* logo's are marked __initdata. Use __init_refok to tell
+/* logo's are marked __initdata. Use __ref to tell
  * modpost that it is intended that this function uses data
  * marked __initdata.
  */
-const struct linux_logo * __init_refok fb_find_logo(int depth)
+const struct linux_logo * __ref fb_find_logo(int depth)
 {
        const struct linux_logo *logo = NULL;
 
index 888d5f8..4e7003d 100644 (file)
@@ -207,6 +207,8 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
        num = min(num, ARRAY_SIZE(vb->pfns));
 
        mutex_lock(&vb->balloon_lock);
+       /* We can't release more pages than taken */
+       num = min(num, (size_t)vb->num_pages);
        for (vb->num_pfns = 0; vb->num_pfns < num;
             vb->num_pfns += VIRTIO_BALLOON_PAGES_PER_PAGE) {
                page = balloon_page_dequeue(vb_dev_info);
index ca6bfdd..e383ecd 100644 (file)
@@ -117,7 +117,10 @@ struct vring_virtqueue {
 #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
 
 /*
- * The interaction between virtio and a possible IOMMU is a mess.
+ * Modern virtio devices have feature bits to specify whether they need a
+ * quirk and bypass the IOMMU. If not there, just use the DMA API.
+ *
+ * If there, the interaction between virtio and DMA API is messy.
  *
  * On most systems with virtio, physical addresses match bus addresses,
  * and it doesn't particularly matter whether we use the DMA API.
@@ -133,10 +136,18 @@ struct vring_virtqueue {
  *
  * For the time being, we preserve historic behavior and bypass the DMA
  * API.
+ *
+ * TODO: install a per-device DMA ops structure that does the right thing
+ * taking into account all the above quirks, and use the DMA API
+ * unconditionally on data path.
  */
 
 static bool vring_use_dma_api(struct virtio_device *vdev)
 {
+       if (!virtio_has_iommu_quirk(vdev))
+               return true;
+
+       /* Otherwise, we are left to guess. */
        /*
         * In theory, it's possible to have a buggy QEMU-supposed
         * emulated Q35 IOMMU and Xen enabled at the same time.  On
@@ -316,6 +327,8 @@ static inline int virtqueue_add(struct virtqueue *_vq,
                 * host should service the ring ASAP. */
                if (out_sgs)
                        vq->notify(&vq->vq);
+               if (indirect)
+                       kfree(desc);
                END_USE(vq);
                return -ENOSPC;
        }
@@ -415,6 +428,7 @@ unmap_release:
        if (indirect)
                kfree(desc);
 
+       END_USE(vq);
        return -EIO;
 }
 
@@ -1099,6 +1113,8 @@ void vring_transport_features(struct virtio_device *vdev)
                        break;
                case VIRTIO_F_VERSION_1:
                        break;
+               case VIRTIO_F_IOMMU_PLATFORM:
+                       break;
                default:
                        /* We don't understand this bit. */
                        __virtio_clear_bit(vdev, i);
index a2eec97..bb09de6 100644 (file)
@@ -390,8 +390,6 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
                goto out;
        }
 
-       hdq_data->hdq_irqstatus = 0;
-
        if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
                hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
                        OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
index d488961..51f2f66 100644 (file)
@@ -153,16 +153,4 @@ static struct w1_family w1_family_12 = {
        .fid = W1_FAMILY_DS2406,
        .fops = &w1_f12_fops,
 };
-
-static int __init w1_f12_init(void)
-{
-       return w1_register_family(&w1_family_12);
-}
-
-static void __exit w1_f12_exit(void)
-{
-       w1_unregister_family(&w1_family_12);
-}
-
-module_init(w1_f12_init);
-module_exit(w1_f12_exit);
+module_w1_family(w1_family_12);
index 7dfa0e1..aec5958 100644 (file)
@@ -351,16 +351,4 @@ static struct w1_family w1_family_29 = {
        .fid = W1_FAMILY_DS2408,
        .fops = &w1_f29_fops,
 };
-
-static int __init w1_f29_init(void)
-{
-       return w1_register_family(&w1_family_29);
-}
-
-static void __exit w1_f29_exit(void)
-{
-       w1_unregister_family(&w1_family_29);
-}
-
-module_init(w1_f29_init);
-module_exit(w1_f29_exit);
+module_w1_family(w1_family_29);
index ee28fc1..f2e1c51 100644 (file)
@@ -135,16 +135,4 @@ static struct w1_family w1_family_3a = {
        .fid = W1_FAMILY_DS2413,
        .fops = &w1_f3a_fops,
 };
-
-static int __init w1_f3a_init(void)
-{
-       return w1_register_family(&w1_family_3a);
-}
-
-static void __exit w1_f3a_exit(void)
-{
-       w1_unregister_family(&w1_family_3a);
-}
-
-module_init(w1_f3a_init);
-module_exit(w1_f3a_exit);
+module_w1_family(w1_family_3a);
index 7e41b7d..4ab54fd 100644 (file)
@@ -138,19 +138,7 @@ static struct w1_family w1_family_1d = {
        .fid = W1_COUNTER_DS2423,
        .fops = &w1_f1d_fops,
 };
-
-static int __init w1_f1d_init(void)
-{
-       return w1_register_family(&w1_family_1d);
-}
-
-static void __exit w1_f1d_exit(void)
-{
-       w1_unregister_family(&w1_family_1d);
-}
-
-module_init(w1_f1d_init);
-module_exit(w1_f1d_exit);
+module_w1_family(w1_family_1d);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>");
index 9c4ff9d..80572cb 100644 (file)
@@ -288,19 +288,7 @@ static struct w1_family w1_family_2d = {
        .fid = W1_EEPROM_DS2431,
        .fops = &w1_f2d_fops,
 };
-
-static int __init w1_f2d_init(void)
-{
-       return w1_register_family(&w1_family_2d);
-}
-
-static void __exit w1_f2d_fini(void)
-{
-       w1_unregister_family(&w1_family_2d);
-}
-
-module_init(w1_f2d_init);
-module_exit(w1_f2d_fini);
+module_w1_family(w1_family_2d);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>");
index 72319a9..6cf378c 100644 (file)
@@ -305,16 +305,4 @@ static struct w1_family w1_family_23 = {
        .fid = W1_EEPROM_DS2433,
        .fops = &w1_f23_fops,
 };
-
-static int __init w1_f23_init(void)
-{
-       return w1_register_family(&w1_family_23);
-}
-
-static void __exit w1_f23_fini(void)
-{
-       w1_unregister_family(&w1_family_23);
-}
-
-module_init(w1_f23_init);
-module_exit(w1_f23_fini);
+module_w1_family(w1_family_23);
index d9079d4..ffa37f7 100644 (file)
@@ -121,25 +121,14 @@ static const struct attribute_group *w1_ds2760_groups[] = {
        NULL,
 };
 
-static DEFINE_IDA(bat_ida);
-
 static int w1_ds2760_add_slave(struct w1_slave *sl)
 {
        int ret;
-       int id;
        struct platform_device *pdev;
 
-       id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
-       if (id < 0) {
-               ret = id;
-               goto noid;
-       }
-
-       pdev = platform_device_alloc("ds2760-battery", id);
-       if (!pdev) {
-               ret = -ENOMEM;
-               goto pdev_alloc_failed;
-       }
+       pdev = platform_device_alloc("ds2760-battery", PLATFORM_DEVID_AUTO);
+       if (!pdev)
+               return -ENOMEM;
        pdev->dev.parent = &sl->dev;
 
        ret = platform_device_add(pdev);
@@ -148,24 +137,19 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
 
        dev_set_drvdata(&sl->dev, pdev);
 
-       goto success;
+       return 0;
 
 pdev_add_failed:
        platform_device_put(pdev);
-pdev_alloc_failed:
-       ida_simple_remove(&bat_ida, id);
-noid:
-success:
+
        return ret;
 }
 
 static void w1_ds2760_remove_slave(struct w1_slave *sl)
 {
        struct platform_device *pdev = dev_get_drvdata(&sl->dev);
-       int id = pdev->id;
 
        platform_device_unregister(pdev);
-       ida_simple_remove(&bat_ida, id);
 }
 
 static struct w1_family_ops w1_ds2760_fops = {
@@ -178,28 +162,13 @@ static struct w1_family w1_ds2760_family = {
        .fid = W1_FAMILY_DS2760,
        .fops = &w1_ds2760_fops,
 };
-
-static int __init w1_ds2760_init(void)
-{
-       pr_info("1-Wire driver for the DS2760 battery monitor chip - (c) 2004-2005, Szabolcs Gyurko\n");
-       ida_init(&bat_ida);
-       return w1_register_family(&w1_ds2760_family);
-}
-
-static void __exit w1_ds2760_exit(void)
-{
-       w1_unregister_family(&w1_ds2760_family);
-       ida_destroy(&bat_ida);
-}
+module_w1_family(w1_ds2760_family);
 
 EXPORT_SYMBOL(w1_ds2760_read);
 EXPORT_SYMBOL(w1_ds2760_write);
 EXPORT_SYMBOL(w1_ds2760_store_eeprom);
 EXPORT_SYMBOL(w1_ds2760_recall_eeprom);
 
-module_init(w1_ds2760_init);
-module_exit(w1_ds2760_exit);
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>");
 MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip");
index 50e85f7..f5c2aa4 100644 (file)
@@ -113,25 +113,14 @@ static const struct attribute_group *w1_ds2780_groups[] = {
        NULL,
 };
 
-static DEFINE_IDA(bat_ida);
-
 static int w1_ds2780_add_slave(struct w1_slave *sl)
 {
        int ret;
-       int id;
        struct platform_device *pdev;
 
-       id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
-       if (id < 0) {
-               ret = id;
-               goto noid;
-       }
-
-       pdev = platform_device_alloc("ds2780-battery", id);
-       if (!pdev) {
-               ret = -ENOMEM;
-               goto pdev_alloc_failed;
-       }
+       pdev = platform_device_alloc("ds2780-battery", PLATFORM_DEVID_AUTO);
+       if (!pdev)
+               return -ENOMEM;
        pdev->dev.parent = &sl->dev;
 
        ret = platform_device_add(pdev);
@@ -144,19 +133,15 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
 
 pdev_add_failed:
        platform_device_put(pdev);
-pdev_alloc_failed:
-       ida_simple_remove(&bat_ida, id);
-noid:
+
        return ret;
 }
 
 static void w1_ds2780_remove_slave(struct w1_slave *sl)
 {
        struct platform_device *pdev = dev_get_drvdata(&sl->dev);
-       int id = pdev->id;
 
        platform_device_unregister(pdev);
-       ida_simple_remove(&bat_ida, id);
 }
 
 static struct w1_family_ops w1_ds2780_fops = {
@@ -169,21 +154,7 @@ static struct w1_family w1_ds2780_family = {
        .fid = W1_FAMILY_DS2780,
        .fops = &w1_ds2780_fops,
 };
-
-static int __init w1_ds2780_init(void)
-{
-       ida_init(&bat_ida);
-       return w1_register_family(&w1_ds2780_family);
-}
-
-static void __exit w1_ds2780_exit(void)
-{
-       w1_unregister_family(&w1_ds2780_family);
-       ida_destroy(&bat_ida);
-}
-
-module_init(w1_ds2780_init);
-module_exit(w1_ds2780_exit);
+module_w1_family(w1_ds2780_family);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
index 1eb98fb..9c03e01 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
-#include <linux/idr.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
@@ -111,25 +110,14 @@ static const struct attribute_group *w1_ds2781_groups[] = {
        NULL,
 };
 
-static DEFINE_IDA(bat_ida);
-
 static int w1_ds2781_add_slave(struct w1_slave *sl)
 {
        int ret;
-       int id;
        struct platform_device *pdev;
 
-       id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
-       if (id < 0) {
-               ret = id;
-               goto noid;
-       }
-
-       pdev = platform_device_alloc("ds2781-battery", id);
-       if (!pdev) {
-               ret = -ENOMEM;
-               goto pdev_alloc_failed;
-       }
+       pdev = platform_device_alloc("ds2781-battery", PLATFORM_DEVID_AUTO);
+       if (!pdev)
+               return -ENOMEM;
        pdev->dev.parent = &sl->dev;
 
        ret = platform_device_add(pdev);
@@ -142,19 +130,15 @@ static int w1_ds2781_add_slave(struct w1_slave *sl)
 
 pdev_add_failed:
        platform_device_put(pdev);
-pdev_alloc_failed:
-       ida_simple_remove(&bat_ida, id);
-noid:
+
        return ret;
 }
 
 static void w1_ds2781_remove_slave(struct w1_slave *sl)
 {
        struct platform_device *pdev = dev_get_drvdata(&sl->dev);
-       int id = pdev->id;
 
        platform_device_unregister(pdev);
-       ida_simple_remove(&bat_ida, id);
 }
 
 static struct w1_family_ops w1_ds2781_fops = {
@@ -167,21 +151,7 @@ static struct w1_family w1_ds2781_family = {
        .fid = W1_FAMILY_DS2781,
        .fops = &w1_ds2781_fops,
 };
-
-static int __init w1_ds2781_init(void)
-{
-       ida_init(&bat_ida);
-       return w1_register_family(&w1_ds2781_family);
-}
-
-static void __exit w1_ds2781_exit(void)
-{
-       w1_unregister_family(&w1_ds2781_family);
-       ida_destroy(&bat_ida);
-}
-
-module_init(w1_ds2781_init);
-module_exit(w1_ds2781_exit);
+module_w1_family(w1_ds2781_family);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Renata Sayakhova <renata@oktetlabs.ru>");
index 365d6df..5e348d3 100644 (file)
@@ -427,16 +427,4 @@ static struct w1_family w1_family_1C = {
        .fid = W1_FAMILY_DS28E04,
        .fops = &w1_f1C_fops,
 };
-
-static int __init w1_f1C_init(void)
-{
-       return w1_register_family(&w1_family_1C);
-}
-
-static void __exit w1_f1C_fini(void)
-{
-       w1_unregister_family(&w1_family_1C);
-}
-
-module_init(w1_f1C_init);
-module_exit(w1_f1C_fini);
+module_w1_family(w1_family_1C);
index ed5dcb8..10a7a07 100644 (file)
@@ -88,4 +88,16 @@ struct w1_family * w1_family_registered(u8);
 void w1_unregister_family(struct w1_family *);
 int w1_register_family(struct w1_family *);
 
+/**
+ * module_w1_driver() - Helper macro for registering a 1-Wire families
+ * @__w1_family: w1_family struct
+ *
+ * Helper macro for 1-Wire families which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_w1_family(__w1_family) \
+       module_driver(__w1_family, w1_register_family, \
+                       w1_unregister_family)
+
 #endif /* __W1_FAMILY_H */
index 7399782..87e6035 100644 (file)
@@ -294,7 +294,7 @@ error:
 void *
 xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flags,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        void *ret;
        int order = get_order(size);
@@ -346,7 +346,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent);
 
 void
 xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
-                         dma_addr_t dev_addr, struct dma_attrs *attrs)
+                         dma_addr_t dev_addr, unsigned long attrs)
 {
        int order = get_order(size);
        phys_addr_t phys;
@@ -378,7 +378,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_free_coherent);
 dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
                                unsigned long offset, size_t size,
                                enum dma_data_direction dir,
-                               struct dma_attrs *attrs)
+                               unsigned long attrs)
 {
        phys_addr_t map, phys = page_to_phys(page) + offset;
        dma_addr_t dev_addr = xen_phys_to_bus(phys);
@@ -434,7 +434,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_map_page);
  */
 static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
                             size_t size, enum dma_data_direction dir,
-                                struct dma_attrs *attrs)
+                            unsigned long attrs)
 {
        phys_addr_t paddr = xen_bus_to_phys(dev_addr);
 
@@ -462,7 +462,7 @@ static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 
 void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                            size_t size, enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        xen_unmap_single(hwdev, dev_addr, size, dir, attrs);
 }
@@ -538,7 +538,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_sync_single_for_device);
 int
 xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                         int nelems, enum dma_data_direction dir,
-                        struct dma_attrs *attrs)
+                        unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -599,7 +599,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_map_sg_attrs);
 void
 xen_swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                           int nelems, enum dma_data_direction dir,
-                          struct dma_attrs *attrs)
+                          unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
index 47db55a..60fb474 100644 (file)
@@ -257,36 +257,12 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        return v9fs_fid_lookup_with_uid(dentry, uid, any);
 }
 
-struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
-{
-       struct p9_fid *fid, *ret;
-
-       fid = v9fs_fid_lookup(dentry);
-       if (IS_ERR(fid))
-               return fid;
-
-       ret = p9_client_walk(fid, 0, NULL, 1);
-       return ret;
-}
-
-static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, kuid_t uid)
-{
-       struct p9_fid *fid, *ret;
-
-       fid = v9fs_fid_lookup_with_uid(dentry, uid, 0);
-       if (IS_ERR(fid))
-               return fid;
-
-       ret = p9_client_walk(fid, 0, NULL, 1);
-       return ret;
-}
-
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
 {
        int err;
        struct p9_fid *fid;
 
-       fid = v9fs_fid_clone_with_uid(dentry, GLOBAL_ROOT_UID);
+       fid = clone_fid(v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0));
        if (IS_ERR(fid))
                goto error_out;
        /*
index 12700df..4491bca 100644 (file)
@@ -28,7 +28,14 @@ static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
 {
        return v9fs_fid_lookup(dentry->d_parent);
 }
-struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
 void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
+static inline struct p9_fid *clone_fid(struct p9_fid *fid)
+{
+       return IS_ERR(fid) ? fid :  p9_client_walk(fid, 0, NULL, 1);
+}
+static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
+{
+       return clone_fid(v9fs_fid_lookup(dentry));
+}
 #endif
index 7da9a83..8b1999b 100644 (file)
@@ -661,7 +661,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        }
 
        /* clone a fid to use for creation */
-       ofid = p9_client_walk(dfid, 0, NULL, 1);
+       ofid = clone_fid(dfid);
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
                p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
@@ -975,13 +975,13 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (IS_ERR(oldfid))
                return PTR_ERR(oldfid);
 
-       olddirfid = v9fs_parent_fid(old_dentry);
+       olddirfid = clone_fid(v9fs_parent_fid(old_dentry));
        if (IS_ERR(olddirfid)) {
                retval = PTR_ERR(olddirfid);
                goto done;
        }
 
-       newdirfid = v9fs_parent_fid(new_dentry);
+       newdirfid = clone_fid(v9fs_parent_fid(new_dentry));
        if (IS_ERR(newdirfid)) {
                retval = PTR_ERR(newdirfid);
                goto clunk_olddir;
index 2ed04c2..eeabcb0 100644 (file)
@@ -281,7 +281,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
        }
 
        /* clone a fid to use for creation */
-       ofid = p9_client_walk(dfid, 0, NULL, 1);
+       ofid = clone_fid(dfid);
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
                p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
index a6bd349..f329eee 100644 (file)
@@ -97,8 +97,6 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
                   const void *value, size_t value_len, int flags)
 {
        struct p9_fid *fid = v9fs_fid_lookup(dentry);
-       if (IS_ERR(fid))
-               return PTR_ERR(fid);
        return v9fs_fid_xattr_set(fid, name, value, value_len, flags);
 }
 
@@ -115,7 +113,7 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
                 name, value_len, flags);
 
        /* Clone it */
-       fid = p9_client_walk(fid, 0, NULL, 1);
+       fid = clone_fid(fid);
        if (IS_ERR(fid))
                return PTR_ERR(fid);
 
index 4524916..2bc7ad7 100644 (file)
@@ -70,6 +70,12 @@ config FS_POSIX_ACL
 config EXPORTFS
        tristate
 
+config EXPORTFS_BLOCK_OPS
+       bool "Enable filesystem export operations for block IO"
+       help
+         This option enables the export operations for a filesystem to support
+         external block IO.
+
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EXPERT
        default y
index 72c0335..c7efddf 100644 (file)
@@ -89,7 +89,8 @@ config BINFMT_SCRIPT
 
 config BINFMT_FLAT
        bool "Kernel support for flat binaries"
-       depends on !MMU && (!FRV || BROKEN)
+       depends on !MMU || M68K
+       depends on !FRV || BROKEN
        help
          Support uClinux FLAT format binaries.
 
index bec25f7..29444c8 100644 (file)
@@ -101,7 +101,7 @@ out:
 }
 
 static int
-adfs_match(struct qstr *name, struct object_info *obj)
+adfs_match(const struct qstr *name, struct object_info *obj)
 {
        int i;
 
@@ -126,7 +126,7 @@ adfs_match(struct qstr *name, struct object_info *obj)
 }
 
 static int
-adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
+adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct object_info *obj)
 {
        struct super_block *sb = inode->i_sb;
        const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
@@ -227,7 +227,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
  * requirements of the underlying filesystem.
  */
 static int
-adfs_compare(const struct dentry *parent, const struct dentry *dentry,
+adfs_compare(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i;
index d6c7a51..d8f217c 100644 (file)
@@ -472,9 +472,7 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
 bool
 affs_nofilenametruncate(const struct dentry *dentry)
 {
-       struct inode *inode = d_inode(dentry);
-
-       return affs_test_opt(AFFS_SB(inode->i_sb)->s_flags, SF_NO_TRUNCATE);
+       return affs_test_opt(AFFS_SB(dentry->d_sb)->s_flags, SF_NO_TRUNCATE);
 }
 
 /* Check if the name is valid for a affs object. */
index eb32029..a2d68f8 100644 (file)
@@ -14,11 +14,11 @@ typedef int (*toupper_t)(int);
 
 static int      affs_toupper(int ch);
 static int      affs_hash_dentry(const struct dentry *, struct qstr *);
-static int       affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+static int       affs_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int      affs_intl_toupper(int ch);
 static int      affs_intl_hash_dentry(const struct dentry *, struct qstr *);
-static int       affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+static int       affs_intl_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 const struct dentry_operations affs_dentry_operations = {
@@ -131,20 +131,20 @@ static inline int __affs_compare_dentry(unsigned int len,
 }
 
 static int
-affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+affs_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
 
        return __affs_compare_dentry(len, str, name, affs_toupper,
-                                    affs_nofilenametruncate(parent));
+                                    affs_nofilenametruncate(dentry));
 }
 
 static int
-affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+affs_intl_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return __affs_compare_dentry(len, str, name, affs_intl_toupper,
-                                    affs_nofilenametruncate(parent));
+                                    affs_nofilenametruncate(dentry));
 
 }
 
index 3767f66..fa84bb8 100644 (file)
@@ -159,7 +159,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct dentry *parent = dentry->d_parent;
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        unsigned int len = name->len;
        unsigned int hash = name->hash;
        const unsigned char *str = name->name;
@@ -172,7 +172,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
        list_for_each(p, head) {
                struct autofs_info *ino;
                struct dentry *active;
-               struct qstr *qstr;
+               const struct qstr *qstr;
 
                ino = list_entry(p, struct autofs_info, active);
                active = ino->dentry;
@@ -214,7 +214,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct dentry *parent = dentry->d_parent;
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        unsigned int len = name->len;
        unsigned int hash = name->hash;
        const unsigned char *str = name->name;
@@ -227,7 +227,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
        list_for_each(p, head) {
                struct autofs_info *ino;
                struct dentry *expiring;
-               struct qstr *qstr;
+               const struct qstr *qstr;
 
                if (rcu_walk) {
                        spin_unlock(&sbi->lookup_lock);
index 7082144..431fd7e 100644 (file)
@@ -225,7 +225,7 @@ rename_retry:
 }
 
 static struct autofs_wait_queue *
-autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr)
+autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
 {
        struct autofs_wait_queue *wq;
 
@@ -249,7 +249,7 @@ autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr)
  */
 static int validate_request(struct autofs_wait_queue **wait,
                            struct autofs_sb_info *sbi,
-                           struct qstr *qstr,
+                           const struct qstr *qstr,
                            struct dentry *dentry, enum autofs_notify notify)
 {
        struct autofs_wait_queue *wq;
index a7a2811..7f6aff3 100644 (file)
@@ -605,28 +605,30 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
                         * Do the same thing for the memory mapping - between
                         * elf_bss and last_bss is the bss section.
                         */
-                       k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+                       k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
                        if (k > last_bss)
                                last_bss = k;
                }
        }
 
+       /*
+        * Now fill out the bss section: first pad the last page from
+        * the file up to the page boundary, and zero it from elf_bss
+        * up to the end of the page.
+        */
+       if (padzero(elf_bss)) {
+               error = -EFAULT;
+               goto out;
+       }
+       /*
+        * Next, align both the file and mem bss up to the page size,
+        * since this is where elf_bss was just zeroed up to, and where
+        * last_bss will end after the vm_brk() below.
+        */
+       elf_bss = ELF_PAGEALIGN(elf_bss);
+       last_bss = ELF_PAGEALIGN(last_bss);
+       /* Finally, if there is still more bss to allocate, do it. */
        if (last_bss > elf_bss) {
-               /*
-                * Now fill out the bss section.  First pad the last page up
-                * to the page boundary, and then perform a mmap to make sure
-                * that there are zero-mapped pages up to and including the
-                * last bss page.
-                */
-               if (padzero(elf_bss)) {
-                       error = -EFAULT;
-                       goto out;
-               }
-
-               /* What we have mapped so far */
-               elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
-
-               /* Map the last of the bss segment */
                error = vm_brk(elf_bss, last_bss - elf_bss);
                if (error)
                        goto out;
index 2035893..464a972 100644 (file)
@@ -67,8 +67,6 @@ static int create_elf_fdpic_tables(struct linux_binprm *, struct mm_struct *,
                                   struct elf_fdpic_params *);
 
 #ifndef CONFIG_MMU
-static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *,
-                                           unsigned long *);
 static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *,
                                                   struct file *,
                                                   struct mm_struct *);
@@ -515,8 +513,9 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        sp = mm->start_stack;
 
        /* stack the program arguments and environment */
-       if (elf_fdpic_transfer_args_to_stack(bprm, &sp) < 0)
+       if (transfer_args_to_stack(bprm, &sp) < 0)
                return -EFAULT;
+       sp &= ~15;
 #endif
 
        /*
@@ -709,39 +708,6 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
        return 0;
 }
 
-/*****************************************************************************/
-/*
- * transfer the program arguments and environment from the holding pages onto
- * the stack
- */
-#ifndef CONFIG_MMU
-static int elf_fdpic_transfer_args_to_stack(struct linux_binprm *bprm,
-                                           unsigned long *_sp)
-{
-       unsigned long index, stop, sp;
-       char *src;
-       int ret = 0;
-
-       stop = bprm->p >> PAGE_SHIFT;
-       sp = *_sp;
-
-       for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
-               src = kmap(bprm->page[index]);
-               sp -= PAGE_SIZE;
-               if (copy_to_user((void *) sp, src, PAGE_SIZE) != 0)
-                       ret = -EFAULT;
-               kunmap(bprm->page[index]);
-               if (ret < 0)
-                       goto out;
-       }
-
-       *_sp = (*_sp - (MAX_ARG_PAGES * PAGE_SIZE - bprm->p)) & ~15;
-
-out:
-       return ret;
-}
-#endif
-
 /*****************************************************************************/
 /*
  * load the appropriate binary image (executable or interpreter) into memory
index 4905385..dd2d3f0 100644 (file)
@@ -24,7 +24,8 @@
 
 static int load_em86(struct linux_binprm *bprm)
 {
-       char *interp, *i_name, *i_arg;
+       const char *i_name, *i_arg;
+       char *interp;
        struct file * file;
        int retval;
        struct elfhdr   elf_ex;
index caf9e39..9b2917a 100644 (file)
@@ -15,7 +15,8 @@
  *     JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
-#include <linux/export.h>
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -25,8 +26,6 @@
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/slab.h>
 #include <linux/personality.h>
 #include <linux/init.h>
 #include <linux/flat.h>
-#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
 
 #include <asm/byteorder.h>
-#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 #include <asm/page.h>
 
 /****************************************************************************/
 
-#if 0
-#define DEBUG 1
-#endif
-
-#ifdef DEBUG
-#define        DBG_FLT(a...)   printk(a)
-#else
-#define        DBG_FLT(a...)
-#endif
-
 /*
  * User data (data section and bss) needs to be aligned.
  * We pick 0x20 here because it is the max value elf2flt has always
@@ -80,7 +69,7 @@ struct lib_info {
                unsigned long text_len;                 /* Length of text segment */
                unsigned long entry;                    /* Start address for this module */
                unsigned long build_date;               /* When this one was compiled */
-               short loaded;                           /* Has this library been loaded? */
+               bool loaded;                            /* Has this library been loaded? */
        } lib_list[MAX_SHARED_LIBS];
 };
 
@@ -106,59 +95,67 @@ static struct linux_binfmt flat_format = {
 
 static int flat_core_dump(struct coredump_params *cprm)
 {
-       printk("Process %s:%d received signr %d and should have core dumped\n",
-                       current->comm, current->pid, (int) cprm->siginfo->si_signo);
-       return(1);
+       pr_warn("Process %s:%d received signr %d and should have core dumped\n",
+               current->comm, current->pid, cprm->siginfo->si_signo);
+       return 1;
 }
 
 /****************************************************************************/
 /*
  * create_flat_tables() parses the env- and arg-strings in new user
  * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
+ * addresses on the "stack", recording the new stack pointer value.
  */
 
-static unsigned long create_flat_tables(
-       unsigned long pp,
-       struct linux_binprm * bprm)
+static int create_flat_tables(struct linux_binprm *bprm, unsigned long arg_start)
 {
-       unsigned long *argv,*envp;
-       unsigned long * sp;
-       char * p = (char*)pp;
-       int argc = bprm->argc;
-       int envc = bprm->envc;
-       char uninitialized_var(dummy);
-
-       sp = (unsigned long *)p;
-       sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-       sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
-       argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
-       envp = argv + (argc + 1);
+       char __user *p;
+       unsigned long __user *sp;
+       long i, len;
+
+       p = (char __user *)arg_start;
+       sp = (unsigned long __user *)current->mm->start_stack;
+
+       sp -= bprm->envc + 1;
+       sp -= bprm->argc + 1;
+       sp -= flat_argvp_envp_on_stack() ? 2 : 0;
+       sp -= 1;  /* &argc */
 
+       current->mm->start_stack = (unsigned long)sp & -FLAT_STACK_ALIGN;
+       sp = (unsigned long __user *)current->mm->start_stack;
+
+       __put_user(bprm->argc, sp++);
        if (flat_argvp_envp_on_stack()) {
-               put_user((unsigned long) envp, sp + 2);
-               put_user((unsigned long) argv, sp + 1);
-       }
-
-       put_user(argc, sp);
-       current->mm->arg_start = (unsigned long) p;
-       while (argc-->0) {
-               put_user((unsigned long) p, argv++);
-               do {
-                       get_user(dummy, p); p++;
-               } while (dummy);
-       }
-       put_user((unsigned long) NULL, argv);
-       current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-       while (envc-->0) {
-               put_user((unsigned long)p, envp); envp++;
-               do {
-                       get_user(dummy, p); p++;
-               } while (dummy);
-       }
-       put_user((unsigned long) NULL, envp);
-       current->mm->env_end = (unsigned long) p;
-       return (unsigned long)sp;
+               unsigned long argv, envp;
+               argv = (unsigned long)(sp + 2);
+               envp = (unsigned long)(sp + 2 + bprm->argc + 1);
+               __put_user(argv, sp++);
+               __put_user(envp, sp++);
+       }
+
+       current->mm->arg_start = (unsigned long)p;
+       for (i = bprm->argc; i > 0; i--) {
+               __put_user((unsigned long)p, sp++);
+               len = strnlen_user(p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
+                       return -EINVAL;
+               p += len;
+       }
+       __put_user(0, sp++);
+       current->mm->arg_end = (unsigned long)p;
+
+       current->mm->env_start = (unsigned long) p;
+       for (i = bprm->envc; i > 0; i--) {
+               __put_user((unsigned long)p, sp++);
+               len = strnlen_user(p, MAX_ARG_STRLEN);
+               if (!len || len > MAX_ARG_STRLEN)
+                       return -EINVAL;
+               p += len;
+       }
+       __put_user(0, sp++);
+       current->mm->env_end = (unsigned long)p;
+
+       return 0;
 }
 
 /****************************************************************************/
@@ -190,17 +187,17 @@ static int decompress_exec(
        loff_t fpos;
        int ret, retval;
 
-       DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
+       pr_debug("decompress_exec(offset=%lx,buf=%p,len=%lx)\n", offset, dst, len);
 
        memset(&strm, 0, sizeof(strm));
        strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
        if (strm.workspace == NULL) {
-               DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
+               pr_debug("no memory for decompress workspace\n");
                return -ENOMEM;
        }
        buf = kmalloc(LBUFSIZE, GFP_KERNEL);
        if (buf == NULL) {
-               DBG_FLT("binfmt_flat: no memory for read buffer\n");
+               pr_debug("no memory for read buffer\n");
                retval = -ENOMEM;
                goto out_free;
        }
@@ -218,49 +215,49 @@ static int decompress_exec(
 
        /* Check minimum size -- gzip header */
        if (ret < 10) {
-               DBG_FLT("binfmt_flat: file too small?\n");
+               pr_debug("file too small?\n");
                goto out_free_buf;
        }
 
        /* Check gzip magic number */
        if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
-               DBG_FLT("binfmt_flat: unknown compression magic?\n");
+               pr_debug("unknown compression magic?\n");
                goto out_free_buf;
        }
 
        /* Check gzip method */
        if (buf[2] != 8) {
-               DBG_FLT("binfmt_flat: unknown compression method?\n");
+               pr_debug("unknown compression method?\n");
                goto out_free_buf;
        }
        /* Check gzip flags */
        if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
            (buf[3] & RESERVED)) {
-               DBG_FLT("binfmt_flat: unknown flags?\n");
+               pr_debug("unknown flags?\n");
                goto out_free_buf;
        }
 
        ret = 10;
        if (buf[3] & EXTRA_FIELD) {
                ret += 2 + buf[10] + (buf[11] << 8);
-               if (unlikely(LBUFSIZE <= ret)) {
-                       DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
+               if (unlikely(ret >= LBUFSIZE)) {
+                       pr_debug("buffer overflow (EXTRA)?\n");
                        goto out_free_buf;
                }
        }
        if (buf[3] & ORIG_NAME) {
                while (ret < LBUFSIZE && buf[ret++] != 0)
                        ;
-               if (unlikely(LBUFSIZE == ret)) {
-                       DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
+               if (unlikely(ret == LBUFSIZE)) {
+                       pr_debug("buffer overflow (ORIG_NAME)?\n");
                        goto out_free_buf;
                }
        }
        if (buf[3] & COMMENT) {
                while (ret < LBUFSIZE && buf[ret++] != 0)
                        ;
-               if (unlikely(LBUFSIZE == ret)) {
-                       DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
+               if (unlikely(ret == LBUFSIZE)) {
+                       pr_debug("buffer overflow (COMMENT)?\n");
                        goto out_free_buf;
                }
        }
@@ -273,7 +270,7 @@ static int decompress_exec(
        strm.total_out = 0;
 
        if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
-               DBG_FLT("binfmt_flat: zlib init failed?\n");
+               pr_debug("zlib init failed?\n");
                goto out_free_buf;
        }
 
@@ -290,7 +287,7 @@ static int decompress_exec(
        }
 
        if (ret < 0) {
-               DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
+               pr_debug("decompression failed (%d), %s\n",
                        ret, strm.msg);
                goto out_zlib;
        }
@@ -327,24 +324,23 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
                r &= 0x00ffffff;        /* Trim ID off here */
        }
        if (id >= MAX_SHARED_LIBS) {
-               printk("BINFMT_FLAT: reference 0x%x to shared library %d",
-                               (unsigned) r, id);
+               pr_err("reference 0x%lx to shared library %d", r, id);
                goto failed;
        }
        if (curid != id) {
                if (internalp) {
-                       printk("BINFMT_FLAT: reloc address 0x%x not in same module "
-                                       "(%d != %d)", (unsigned) r, curid, id);
+                       pr_err("reloc address 0x%lx not in same module "
+                              "(%d != %d)", r, curid, id);
                        goto failed;
-               } else if ( ! p->lib_list[id].loaded &&
-                               load_flat_shared_library(id, p) < 0) {
-                       printk("BINFMT_FLAT: failed to load library %d", id);
+               } else if (!p->lib_list[id].loaded &&
+                          load_flat_shared_library(id, p) < 0) {
+                       pr_err("failed to load library %d", id);
                        goto failed;
                }
                /* Check versioning information (i.e. time stamps) */
                if (p->lib_list[id].build_date && p->lib_list[curid].build_date &&
                                p->lib_list[curid].build_date < p->lib_list[id].build_date) {
-                       printk("BINFMT_FLAT: library %d is younger than %d", id, curid);
+                       pr_err("library %d is younger than %d", id, curid);
                        goto failed;
                }
        }
@@ -358,8 +354,8 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
        text_len = p->lib_list[id].text_len;
 
        if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
-               printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)",
-                      (int) r,(int)(start_brk-start_data+text_len),(int)text_len);
+               pr_err("reloc outside program 0x%lx (0 - 0x%lx/0x%lx)",
+                      r, start_brk-start_data+text_len, text_len);
                goto failed;
        }
 
@@ -369,10 +365,10 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp)
                addr = r - text_len + start_data;
 
        /* Range checked already above so doing the range tests is redundant...*/
-       return(addr);
+       return addr;
 
 failed:
-       printk(", killing %s!\n", current->comm);
+       pr_cont(", killing %s!\n", current->comm);
        send_sig(SIGSEGV, current, 0);
 
        return RELOC_FAILED;
@@ -382,62 +378,57 @@ failed:
 
 static void old_reloc(unsigned long rl)
 {
-#ifdef DEBUG
-       char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
-#endif
+       static const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
        flat_v2_reloc_t r;
-       unsigned long *ptr;
-       
+       unsigned long __user *ptr;
+       unsigned long val;
+
        r.value = rl;
 #if defined(CONFIG_COLDFIRE)
-       ptr = (unsigned long *) (current->mm->start_code + r.reloc.offset);
+       ptr = (unsigned long __user *)(current->mm->start_code + r.reloc.offset);
 #else
-       ptr = (unsigned long *) (current->mm->start_data + r.reloc.offset);
+       ptr = (unsigned long __user *)(current->mm->start_data + r.reloc.offset);
 #endif
+       get_user(val, ptr);
+
+       pr_debug("Relocation of variable at DATASEG+%x "
+                "(address %p, currently %lx) into segment %s\n",
+                r.reloc.offset, ptr, val, segment[r.reloc.type]);
 
-#ifdef DEBUG
-       printk("Relocation of variable at DATASEG+%x "
-               "(address %p, currently %x) into segment %s\n",
-               r.reloc.offset, ptr, (int)*ptr, segment[r.reloc.type]);
-#endif
-       
        switch (r.reloc.type) {
        case OLD_FLAT_RELOC_TYPE_TEXT:
-               *ptr += current->mm->start_code;
+               val += current->mm->start_code;
                break;
        case OLD_FLAT_RELOC_TYPE_DATA:
-               *ptr += current->mm->start_data;
+               val += current->mm->start_data;
                break;
        case OLD_FLAT_RELOC_TYPE_BSS:
-               *ptr += current->mm->end_data;
+               val += current->mm->end_data;
                break;
        default:
-               printk("BINFMT_FLAT: Unknown relocation type=%x\n", r.reloc.type);
+               pr_err("Unknown relocation type=%x\n", r.reloc.type);
                break;
        }
+       put_user(val, ptr);
 
-#ifdef DEBUG
-       printk("Relocation became %x\n", (int)*ptr);
-#endif
-}              
+       pr_debug("Relocation became %lx\n", val);
+}
 
 /****************************************************************************/
 
-static int load_flat_file(struct linux_binprm * bprm,
+static int load_flat_file(struct linux_binprm *bprm,
                struct lib_info *libinfo, int id, unsigned long *extra_stack)
 {
-       struct flat_hdr * hdr;
-       unsigned long textpos = 0, datapos = 0, result;
-       unsigned long realdatastart = 0;
-       unsigned long text_len, data_len, bss_len, stack_len, flags;
-       unsigned long full_data;
-       unsigned long len, memp = 0;
-       unsigned long memp_size, extra, rlim;
-       unsigned long *reloc = 0, *rp;
+       struct flat_hdr *hdr;
+       unsigned long textpos, datapos, realdatastart;
+       unsigned long text_len, data_len, bss_len, stack_len, full_data, flags;
+       unsigned long len, memp, memp_size, extra, rlim;
+       unsigned long __user *reloc, *rp;
        struct inode *inode;
-       int i, rev, relocs = 0;
+       int i, rev, relocs;
        loff_t fpos;
        unsigned long start_code, end_code;
+       ssize_t result;
        int ret;
 
        hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
@@ -469,20 +460,30 @@ static int load_flat_file(struct linux_binprm * bprm,
        }
 
        if (flags & FLAT_FLAG_KTRACE)
-               printk("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
+               pr_info("Loading file: %s\n", bprm->filename);
 
        if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
-               printk("BINFMT_FLAT: bad flat file version 0x%x (supported "
-                       "0x%lx and 0x%lx)\n",
-                       rev, FLAT_VERSION, OLD_FLAT_VERSION);
+               pr_err("bad flat file version 0x%x (supported 0x%lx and 0x%lx)\n",
+                      rev, FLAT_VERSION, OLD_FLAT_VERSION);
                ret = -ENOEXEC;
                goto err;
        }
-       
+
        /* Don't allow old format executables to use shared libraries */
        if (rev == OLD_FLAT_VERSION && id != 0) {
-               printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x\n",
-                               (int) FLAT_VERSION);
+               pr_err("shared libraries are not available before rev 0x%lx\n",
+                      FLAT_VERSION);
+               ret = -ENOEXEC;
+               goto err;
+       }
+
+       /*
+        * Make sure the header params are sane.
+        * 28 bits (256 MB) is way more than reasonable in this case.
+        * If some top bits are set we have probable binary corruption.
+       */
+       if ((text_len | data_len | bss_len | stack_len | full_data) >> 28) {
+               pr_err("bad header\n");
                ret = -ENOEXEC;
                goto err;
        }
@@ -496,7 +497,7 @@ static int load_flat_file(struct linux_binprm * bprm,
 
 #ifndef CONFIG_BINFMT_ZFLAT
        if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
-               printk("Support for ZFLAT executables is not enabled.\n");
+               pr_err("Support for ZFLAT executables is not enabled.\n");
                ret = -ENOEXEC;
                goto err;
        }
@@ -517,11 +518,9 @@ static int load_flat_file(struct linux_binprm * bprm,
 
        /* Flush all traces of the currently running executable */
        if (id == 0) {
-               result = flush_old_exec(bprm);
-               if (result) {
-                       ret = result;
+               ret = flush_old_exec(bprm);
+               if (ret)
                        goto err;
-               }
 
                /* OK, This is the point of no return */
                set_personality(PER_LINUX_32BIT);
@@ -539,48 +538,48 @@ static int load_flat_file(struct linux_binprm * bprm,
         * case,  and then the fully copied to RAM case which lumps
         * it all together.
         */
-       if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
+       if (!IS_ENABLED(CONFIG_MMU) && !(flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP))) {
                /*
                 * this should give us a ROM ptr,  but if it doesn't we don't
                 * really care
                 */
-               DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
+               pr_debug("ROM mapping of file (we hope)\n");
 
                textpos = vm_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
                                  MAP_PRIVATE|MAP_EXECUTABLE, 0);
                if (!textpos || IS_ERR_VALUE(textpos)) {
-                       if (!textpos)
-                               textpos = (unsigned long) -ENOMEM;
-                       printk("Unable to mmap process text, errno %d\n", (int)-textpos);
                        ret = textpos;
+                       if (!textpos)
+                               ret = -ENOMEM;
+                       pr_err("Unable to mmap process text, errno %d\n", ret);
                        goto err;
                }
 
                len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
                len = PAGE_ALIGN(len);
-               realdatastart = vm_mmap(0, 0, len,
+               realdatastart = vm_mmap(NULL, 0, len,
                        PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0);
 
                if (realdatastart == 0 || IS_ERR_VALUE(realdatastart)) {
+                       ret = realdatastart;
                        if (!realdatastart)
-                               realdatastart = (unsigned long) -ENOMEM;
-                       printk("Unable to allocate RAM for process data, errno %d\n",
-                                       (int)-realdatastart);
+                               ret = -ENOMEM;
+                       pr_err("Unable to allocate RAM for process data, "
+                              "errno %d\n", ret);
                        vm_munmap(textpos, text_len);
-                       ret = realdatastart;
                        goto err;
                }
                datapos = ALIGN(realdatastart +
                                MAX_SHARED_LIBS * sizeof(unsigned long),
                                FLAT_DATA_ALIGN);
 
-               DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
-                               (int)(data_len + bss_len + stack_len), (int)datapos);
+               pr_debug("Allocated data+bss+stack (%ld bytes): %lx\n",
+                        data_len + bss_len + stack_len, datapos);
 
                fpos = ntohl(hdr->data_start);
 #ifdef CONFIG_BINFMT_ZFLAT
                if (flags & FLAT_FLAG_GZDATA) {
-                       result = decompress_exec(bprm, fpos, (char *) datapos, 
+                       result = decompress_exec(bprm, fpos, (char *)datapos,
                                                 full_data, 0);
                } else
 #endif
@@ -589,29 +588,30 @@ static int load_flat_file(struct linux_binprm * bprm,
                                        full_data);
                }
                if (IS_ERR_VALUE(result)) {
-                       printk("Unable to read data+bss, errno %d\n", (int)-result);
+                       ret = result;
+                       pr_err("Unable to read data+bss, errno %d\n", ret);
                        vm_munmap(textpos, text_len);
                        vm_munmap(realdatastart, len);
-                       ret = result;
                        goto err;
                }
 
-               reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len));
+               reloc = (unsigned long __user *)
+                       (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = realdatastart;
                memp_size = len;
        } else {
 
                len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
                len = PAGE_ALIGN(len);
-               textpos = vm_mmap(0, 0, len,
+               textpos = vm_mmap(NULL, 0, len,
                        PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0);
 
                if (!textpos || IS_ERR_VALUE(textpos)) {
-                       if (!textpos)
-                               textpos = (unsigned long) -ENOMEM;
-                       printk("Unable to allocate RAM for process text/data, errno %d\n",
-                                       (int)-textpos);
                        ret = textpos;
+                       if (!textpos)
+                               ret = -ENOMEM;
+                       pr_err("Unable to allocate RAM for process text/data, "
+                              "errno %d\n", ret);
                        goto err;
                }
 
@@ -620,7 +620,7 @@ static int load_flat_file(struct linux_binprm * bprm,
                                MAX_SHARED_LIBS * sizeof(unsigned long),
                                FLAT_DATA_ALIGN);
 
-               reloc = (unsigned long *)
+               reloc = (unsigned long __user *)
                        (datapos + (ntohl(hdr->reloc_start) - text_len));
                memp = textpos;
                memp_size = len;
@@ -629,21 +629,59 @@ static int load_flat_file(struct linux_binprm * bprm,
                 * load it all in and treat it like a RAM load from now on
                 */
                if (flags & FLAT_FLAG_GZIP) {
-                       result = decompress_exec(bprm, sizeof (struct flat_hdr),
-                                        (((char *) textpos) + sizeof (struct flat_hdr)),
+#ifndef CONFIG_MMU
+                       result = decompress_exec(bprm, sizeof(struct flat_hdr),
+                                        (((char *)textpos) + sizeof(struct flat_hdr)),
                                         (text_len + full_data
-                                                 - sizeof (struct flat_hdr)),
+                                                 - sizeof(struct flat_hdr)),
                                         0);
                        memmove((void *) datapos, (void *) realdatastart,
                                        full_data);
+#else
+                       /*
+                        * This is used on MMU systems mainly for testing.
+                        * Let's use a kernel buffer to simplify things.
+                        */
+                       long unz_text_len = text_len - sizeof(struct flat_hdr);
+                       long unz_len = unz_text_len + full_data;
+                       char *unz_data = vmalloc(unz_len);
+                       if (!unz_data) {
+                               result = -ENOMEM;
+                       } else {
+                               result = decompress_exec(bprm, sizeof(struct flat_hdr),
+                                                        unz_data, unz_len, 0);
+                               if (result == 0 &&
+                                   (copy_to_user((void __user *)textpos + sizeof(struct flat_hdr),
+                                                 unz_data, unz_text_len) ||
+                                    copy_to_user((void __user *)datapos,
+                                                 unz_data + unz_text_len, full_data)))
+                                       result = -EFAULT;
+                               vfree(unz_data);
+                       }
+#endif
                } else if (flags & FLAT_FLAG_GZDATA) {
                        result = read_code(bprm->file, textpos, 0, text_len);
-                       if (!IS_ERR_VALUE(result))
+                       if (!IS_ERR_VALUE(result)) {
+#ifndef CONFIG_MMU
                                result = decompress_exec(bprm, text_len, (char *) datapos,
                                                 full_data, 0);
-               }
-               else
+#else
+                               char *unz_data = vmalloc(full_data);
+                               if (!unz_data) {
+                                       result = -ENOMEM;
+                               } else {
+                                       result = decompress_exec(bprm, text_len,
+                                                      unz_data, full_data, 0);
+                                       if (result == 0 &&
+                                           copy_to_user((void __user *)datapos,
+                                                        unz_data, full_data))
+                                               result = -EFAULT;
+                                       vfree(unz_data);
+                               }
 #endif
+                       }
+               } else
+#endif /* CONFIG_BINFMT_ZFLAT */
                {
                        result = read_code(bprm->file, textpos, 0, text_len);
                        if (!IS_ERR_VALUE(result))
@@ -652,21 +690,19 @@ static int load_flat_file(struct linux_binprm * bprm,
                                                   full_data);
                }
                if (IS_ERR_VALUE(result)) {
-                       printk("Unable to read code+data+bss, errno %d\n",(int)-result);
+                       ret = result;
+                       pr_err("Unable to read code+data+bss, errno %d\n", ret);
                        vm_munmap(textpos, text_len + data_len + extra +
                                MAX_SHARED_LIBS * sizeof(unsigned long));
-                       ret = result;
                        goto err;
                }
        }
 
-       if (flags & FLAT_FLAG_KTRACE)
-               printk("Mapping is %x, Entry point is %x, data_start is %x\n",
-                       (int)textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
+       start_code = textpos + sizeof(struct flat_hdr);
+       end_code = textpos + text_len;
+       text_len -= sizeof(struct flat_hdr); /* the real code len */
 
        /* The main program needs a little extra setup in the task structure */
-       start_code = textpos + sizeof (struct flat_hdr);
-       end_code = textpos + text_len;
        if (id == 0) {
                current->mm->start_code = start_code;
                current->mm->end_code = end_code;
@@ -681,19 +717,19 @@ static int load_flat_file(struct linux_binprm * bprm,
                 */
                current->mm->start_brk = datapos + data_len + bss_len;
                current->mm->brk = (current->mm->start_brk + 3) & ~3;
+#ifndef CONFIG_MMU
                current->mm->context.end_brk = memp + memp_size - stack_len;
+#endif
        }
 
-       if (flags & FLAT_FLAG_KTRACE)
-               printk("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
+       if (flags & FLAT_FLAG_KTRACE) {
+               pr_info("Mapping is %lx, Entry point is %x, data_start is %x\n",
+                       textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start));
+               pr_info("%s %s: TEXT=%lx-%lx DATA=%lx-%lx BSS=%lx-%lx\n",
                        id ? "Lib" : "Load", bprm->filename,
-                       (int) start_code, (int) end_code,
-                       (int) datapos,
-                       (int) (datapos + data_len),
-                       (int) (datapos + data_len),
-                       (int) (((datapos + data_len + bss_len) + 3) & ~3));
-
-       text_len -= sizeof(struct flat_hdr); /* the real code len */
+                       start_code, end_code, datapos, datapos + data_len,
+                       datapos + data_len, (datapos + data_len + bss_len + 3) & ~3);
+       }
 
        /* Store the current module values into the global library structure */
        libinfo->lib_list[id].start_code = start_code;
@@ -703,7 +739,7 @@ static int load_flat_file(struct linux_binprm * bprm,
        libinfo->lib_list[id].loaded = 1;
        libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
        libinfo->lib_list[id].build_date = ntohl(hdr->build_date);
-       
+
        /*
         * We just load the allocations into some temporary memory to
         * help simplify all this mumbo jumbo
@@ -717,15 +753,20 @@ static int load_flat_file(struct linux_binprm * bprm,
         * image.
         */
        if (flags & FLAT_FLAG_GOTPIC) {
-               for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) {
-                       unsigned long addr;
-                       if (*rp) {
-                               addr = calc_reloc(*rp, libinfo, id, 0);
+               for (rp = (unsigned long __user *)datapos; ; rp++) {
+                       unsigned long addr, rp_val;
+                       if (get_user(rp_val, rp))
+                               return -EFAULT;
+                       if (rp_val == 0xffffffff)
+                               break;
+                       if (rp_val) {
+                               addr = calc_reloc(rp_val, libinfo, id, 0);
                                if (addr == RELOC_FAILED) {
                                        ret = -ENOEXEC;
                                        goto err;
                                }
-                               *rp = addr;
+                               if (put_user(addr, rp))
+                                       return -EFAULT;
                        }
                }
        }
@@ -742,19 +783,23 @@ static int load_flat_file(struct linux_binprm * bprm,
         * __start to address 4 so that is okay).
         */
        if (rev > OLD_FLAT_VERSION) {
-               unsigned long persistent = 0;
-               for (i=0; i < relocs; i++) {
+               unsigned long __maybe_unused persistent = 0;
+               for (i = 0; i < relocs; i++) {
                        unsigned long addr, relval;
 
-                       /* Get the address of the pointer to be
-                          relocated (of course, the address has to be
-                          relocated first).  */
-                       relval = ntohl(reloc[i]);
-                       if (flat_set_persistent (relval, &persistent))
+                       /*
+                        * Get the address of the pointer to be
+                        * relocated (of course, the address has to be
+                        * relocated first).
+                        */
+                       if (get_user(relval, reloc + i))
+                               return -EFAULT;
+                       relval = ntohl(relval);
+                       if (flat_set_persistent(relval, &persistent))
                                continue;
                        addr = flat_get_relocate_addr(relval);
-                       rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1);
-                       if (rp == (unsigned long *)RELOC_FAILED) {
+                       rp = (unsigned long __user *)calc_reloc(addr, libinfo, id, 1);
+                       if (rp == (unsigned long __user *)RELOC_FAILED) {
                                ret = -ENOEXEC;
                                goto err;
                        }
@@ -780,17 +825,23 @@ static int load_flat_file(struct linux_binprm * bprm,
                        }
                }
        } else {
-               for (i=0; i < relocs; i++)
-                       old_reloc(ntohl(reloc[i]));
+               for (i = 0; i < relocs; i++) {
+                       unsigned long relval;
+                       if (get_user(relval, reloc + i))
+                               return -EFAULT;
+                       relval = ntohl(relval);
+                       old_reloc(relval);
+               }
        }
-       
+
        flush_icache_range(start_code, end_code);
 
        /* zero the BSS,  BRK and stack areas */
-       memset((void*)(datapos + data_len), 0, bss_len + 
-                       (memp + memp_size - stack_len -         /* end brk */
-                       libinfo->lib_list[id].start_brk) +      /* start brk */
-                       stack_len);
+       if (clear_user((void __user *)(datapos + data_len), bss_len +
+                      (memp + memp_size - stack_len -          /* end brk */
+                      libinfo->lib_list[id].start_brk) +       /* start brk */
+                      stack_len))
+               return -EFAULT;
 
        return 0;
 err:
@@ -846,7 +897,7 @@ out:
        allow_write_access(bprm.file);
        fput(bprm.file);
 
-       return(res);
+       return res;
 }
 
 #endif /* CONFIG_BINFMT_SHARED_FLAT */
@@ -857,18 +908,17 @@ out:
  * libraries.  There is no binary dependent code anywhere else.
  */
 
-static int load_flat_binary(struct linux_binprm * bprm)
+static int load_flat_binary(struct linux_binprm *bprm)
 {
        struct lib_info libinfo;
        struct pt_regs *regs = current_pt_regs();
-       unsigned long p = bprm->p;
-       unsigned long stack_len;
+       unsigned long stack_len = 0;
        unsigned long start_addr;
-       unsigned long *sp;
        int res;
        int i, j;
 
        memset(&libinfo, 0, sizeof(libinfo));
+
        /*
         * We have to add the size of our arguments to our stack size
         * otherwise it's too easy for users to create stack overflows
@@ -876,38 +926,54 @@ static int load_flat_binary(struct linux_binprm * bprm)
         * pedantic and include space for the argv/envp array as it may have
         * a lot of entries.
         */
-#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
-       stack_len = TOP_OF_ARGS - bprm->p;             /* the strings */
-       stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
-       stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
-       stack_len += FLAT_STACK_ALIGN - 1;  /* reserve for upcoming alignment */
-       
+#ifndef CONFIG_MMU
+       stack_len += PAGE_SIZE * MAX_ARG_PAGES - bprm->p; /* the strings */
+#endif
+       stack_len += (bprm->argc + 1) * sizeof(char *);   /* the argv array */
+       stack_len += (bprm->envc + 1) * sizeof(char *);   /* the envp array */
+       stack_len = ALIGN(stack_len, FLAT_STACK_ALIGN);
+
        res = load_flat_file(bprm, &libinfo, 0, &stack_len);
        if (res < 0)
                return res;
-       
+
        /* Update data segment pointers for all libraries */
-       for (i=0; i<MAX_SHARED_LIBS; i++)
-               if (libinfo.lib_list[i].loaded)
-                       for (j=0; j<MAX_SHARED_LIBS; j++)
-                               (-(j+1))[(unsigned long *)(libinfo.lib_list[i].start_data)] =
-                                       (libinfo.lib_list[j].loaded)?
-                                               libinfo.lib_list[j].start_data:UNLOADED_LIB;
+       for (i = 0; i < MAX_SHARED_LIBS; i++) {
+               if (!libinfo.lib_list[i].loaded)
+                       continue;
+               for (j = 0; j < MAX_SHARED_LIBS; j++) {
+                       unsigned long val = libinfo.lib_list[j].loaded ?
+                               libinfo.lib_list[j].start_data : UNLOADED_LIB;
+                       unsigned long __user *p = (unsigned long __user *)
+                               libinfo.lib_list[i].start_data;
+                       p -= j + 1;
+                       if (put_user(val, p))
+                               return -EFAULT;
+               }
+       }
 
        install_exec_creds(bprm);
 
        set_binfmt(&flat_format);
 
-       p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
-       DBG_FLT("p=%x\n", (int)p);
+#ifdef CONFIG_MMU
+       res = setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
+       if (!res)
+               res = create_flat_tables(bprm, bprm->p);
+#else
+       /* Stash our initial stack pointer into the mm structure */
+       current->mm->start_stack =
+               ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4;
+       pr_debug("sp=%lx\n", current->mm->start_stack);
 
-       /* copy the arg pages onto the stack, this could be more efficient :-) */
-       for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--)
-               * (char *) --p =
-                       ((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE];
+       /* copy the arg pages onto the stack */
+       res = transfer_args_to_stack(bprm, &current->mm->start_stack);
+       if (!res)
+               res = create_flat_tables(bprm, current->mm->start_stack);
+#endif
+       if (res)
+               return res;
 
-       sp = (unsigned long *) create_flat_tables(p, bprm);
-       
        /* Fake some return addresses to ensure the call chain will
         * initialise library in order for us.  We are required to call
         * lib 1 first, then 2, ... and finally the main program (id 0).
@@ -915,24 +981,24 @@ static int load_flat_binary(struct linux_binprm * bprm)
        start_addr = libinfo.lib_list[0].entry;
 
 #ifdef CONFIG_BINFMT_SHARED_FLAT
-       for (i = MAX_SHARED_LIBS-1; i>0; i--) {
+       for (i = MAX_SHARED_LIBS-1; i > 0; i--) {
                if (libinfo.lib_list[i].loaded) {
                        /* Push previos first to call address */
-                       --sp;   put_user(start_addr, sp);
+                       unsigned long __user *sp;
+                       current->mm->start_stack -= sizeof(unsigned long);
+                       sp = (unsigned long __user *)current->mm->start_stack;
+                       __put_user(start_addr, sp);
                        start_addr = libinfo.lib_list[i].entry;
                }
        }
 #endif
-       
-       /* Stash our initial stack pointer into the mm structure */
-       current->mm->start_stack = (unsigned long )sp;
 
 #ifdef FLAT_PLAT_INIT
        FLAT_PLAT_INIT(regs);
 #endif
-       DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n",
-               (int)regs, (int)start_addr, (int)current->mm->start_stack);
-       
+
+       pr_debug("start_thread(regs=0x%p, entry=0x%lx, start_stack=0x%lx)\n",
+                regs, start_addr, current->mm->start_stack);
        start_thread(regs, start_addr, current->mm->start_stack);
 
        return 0;
@@ -945,9 +1011,6 @@ static int __init init_flat_binfmt(void)
        register_binfmt(&flat_format);
        return 0;
 }
-
-/****************************************************************************/
-
 core_initcall(init_flat_binfmt);
 
 /****************************************************************************/
index 5417516..6103a63 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/fs.h>
 #include <linux/uaccess.h>
 
+#include "internal.h"
+
 #ifdef DEBUG
 # define USE_DEBUG 1
 #else
@@ -43,6 +45,7 @@ enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
 #define MISC_FMT_OPEN_BINARY (1 << 30)
 #define MISC_FMT_CREDENTIALS (1 << 29)
+#define MISC_FMT_OPEN_FILE (1 << 28)
 
 typedef struct {
        struct list_head list;
@@ -54,6 +57,7 @@ typedef struct {
        char *interpreter;              /* filename of interpreter */
        char *name;
        struct dentry *dentry;
+       struct file *interp_file;
 } Node;
 
 static DEFINE_RWLOCK(entries_lock);
@@ -201,7 +205,13 @@ static int load_misc_binary(struct linux_binprm *bprm)
        if (retval < 0)
                goto error;
 
-       interp_file = open_exec(iname);
+       if (fmt->flags & MISC_FMT_OPEN_FILE && fmt->interp_file) {
+               interp_file = filp_clone_open(fmt->interp_file);
+               if (!IS_ERR(interp_file))
+                       deny_write_access(interp_file);
+       } else {
+               interp_file = open_exec(iname);
+       }
        retval = PTR_ERR(interp_file);
        if (IS_ERR(interp_file))
                goto error;
@@ -285,6 +295,11 @@ static char *check_special_flags(char *sfs, Node *e)
                        e->flags |= (MISC_FMT_CREDENTIALS |
                                        MISC_FMT_OPEN_BINARY);
                        break;
+               case 'F':
+                       pr_debug("register: flag: F: open interpreter file now\n");
+                       p++;
+                       e->flags |= MISC_FMT_OPEN_FILE;
+                       break;
                default:
                        cont = 0;
                }
@@ -543,6 +558,8 @@ static void entry_status(Node *e, char *page)
                *dp++ = 'O';
        if (e->flags & MISC_FMT_CREDENTIALS)
                *dp++ = 'C';
+       if (e->flags & MISC_FMT_OPEN_FILE)
+               *dp++ = 'F';
        *dp++ = '\n';
 
        if (!test_bit(Magic, &e->flags)) {
@@ -590,6 +607,11 @@ static void kill_node(Node *e)
        }
        write_unlock(&entries_lock);
 
+       if ((e->flags & MISC_FMT_OPEN_FILE) && e->interp_file) {
+               filp_close(e->interp_file, NULL);
+               e->interp_file = NULL;
+       }
+
        if (dentry) {
                drop_nlink(d_inode(dentry));
                d_drop(dentry);
@@ -696,6 +718,21 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
                goto out2;
        }
 
+       if (e->flags & MISC_FMT_OPEN_FILE) {
+               struct file *f;
+
+               f = open_exec(e->interpreter);
+               if (IS_ERR(f)) {
+                       err = PTR_ERR(f);
+                       pr_notice("register: failed to install interpreter file %s\n", e->interpreter);
+                       simple_release_fs(&bm_mnt, &entry_count);
+                       iput(inode);
+                       inode = NULL;
+                       goto out2;
+               }
+               e->interp_file = f;
+       }
+
        e->dentry = dget(dentry);
        inode->i_private = e;
        inode->i_fop = &bm_entry_operations;
@@ -713,7 +750,7 @@ out:
 
        if (err) {
                kfree(e);
-               return -EINVAL;
+               return err;
        }
        return count;
 }
index ada42cf..c3cdde8 100644 (file)
@@ -416,7 +416,7 @@ int bdev_read_page(struct block_device *bdev, sector_t sector,
        result = blk_queue_enter(bdev->bd_queue, false);
        if (result)
                return result;
-       result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
+       result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, false);
        blk_queue_exit(bdev->bd_queue);
        return result;
 }
@@ -445,7 +445,6 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
                        struct page *page, struct writeback_control *wbc)
 {
        int result;
-       int rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE;
        const struct block_device_operations *ops = bdev->bd_disk->fops;
 
        if (!ops->rw_page || bdev_get_integrity(bdev))
@@ -455,7 +454,7 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
                return result;
 
        set_page_writeback(page);
-       result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, rw);
+       result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, true);
        if (result)
                end_page_writeback(page);
        else
@@ -1275,11 +1274,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                bdev->bd_disk = disk;
                bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
-               if (IS_ENABLED(CONFIG_BLK_DEV_DAX) &&
-                   blk_queue_dax(disk->queue))
-                       bdev->bd_inode->i_flags = S_DAX;
-               else
-                       bdev->bd_inode->i_flags = 0;
+               bdev->bd_inode->i_flags = 0;
 
                if (!partno) {
                        ret = -ENXIO;
index 67a6077..53bb7af 100644 (file)
@@ -55,8 +55,7 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
        }
        if (size > 0) {
                acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       } else if (size == -ENOENT || size == -ENODATA || size == 0) {
-               /* FIXME, who returns -ENOENT?  I think nobody */
+       } else if (size == -ERANGE || size == -ENODATA || size == 0) {
                acl = NULL;
        } else {
                acl = ERR_PTR(-EIO);
index 5fb60ea..e0f071f 100644 (file)
 
 struct __btrfs_workqueue {
        struct workqueue_struct *normal_wq;
+
+       /* File system this workqueue services */
+       struct btrfs_fs_info *fs_info;
+
        /* List head pointing to ordered work list */
        struct list_head ordered_list;
 
@@ -70,6 +74,18 @@ void btrfs_##name(struct work_struct *arg)                           \
        normal_work_helper(work);                                       \
 }
 
+struct btrfs_fs_info *
+btrfs_workqueue_owner(struct __btrfs_workqueue *wq)
+{
+       return wq->fs_info;
+}
+
+struct btrfs_fs_info *
+btrfs_work_owner(struct btrfs_work *work)
+{
+       return work->wq->fs_info;
+}
+
 BTRFS_WORK_HELPER(worker_helper);
 BTRFS_WORK_HELPER(delalloc_helper);
 BTRFS_WORK_HELPER(flush_delalloc_helper);
@@ -94,14 +110,15 @@ BTRFS_WORK_HELPER(scrubnc_helper);
 BTRFS_WORK_HELPER(scrubparity_helper);
 
 static struct __btrfs_workqueue *
-__btrfs_alloc_workqueue(const char *name, unsigned int flags, int limit_active,
-                        int thresh)
+__btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, const char *name,
+                       unsigned int flags, int limit_active, int thresh)
 {
        struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 
        if (!ret)
                return NULL;
 
+       ret->fs_info = fs_info;
        ret->limit_active = limit_active;
        atomic_set(&ret->pending, 0);
        if (thresh == 0)
@@ -143,7 +160,8 @@ __btrfs_alloc_workqueue(const char *name, unsigned int flags, int limit_active,
 static inline void
 __btrfs_destroy_workqueue(struct __btrfs_workqueue *wq);
 
-struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
+struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info,
+                                             const char *name,
                                              unsigned int flags,
                                              int limit_active,
                                              int thresh)
@@ -153,7 +171,8 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
        if (!ret)
                return NULL;
 
-       ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI,
+       ret->normal = __btrfs_alloc_workqueue(fs_info, name,
+                                             flags & ~WQ_HIGHPRI,
                                              limit_active, thresh);
        if (!ret->normal) {
                kfree(ret);
@@ -161,8 +180,8 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
        }
 
        if (flags & WQ_HIGHPRI) {
-               ret->high = __btrfs_alloc_workqueue(name, flags, limit_active,
-                                                   thresh);
+               ret->high = __btrfs_alloc_workqueue(fs_info, name, flags,
+                                                   limit_active, thresh);
                if (!ret->high) {
                        __btrfs_destroy_workqueue(ret->normal);
                        kfree(ret);
index ad4d064..8e52484 100644 (file)
@@ -21,6 +21,7 @@
 #define __BTRFS_ASYNC_THREAD_
 #include <linux/workqueue.h>
 
+struct btrfs_fs_info;
 struct btrfs_workqueue;
 /* Internal use only */
 struct __btrfs_workqueue;
@@ -67,7 +68,8 @@ BTRFS_WORK_HELPER_PROTO(scrubnc_helper);
 BTRFS_WORK_HELPER_PROTO(scrubparity_helper);
 
 
-struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
+struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info,
+                                             const char *name,
                                              unsigned int flags,
                                              int limit_active,
                                              int thresh);
@@ -80,4 +82,6 @@ void btrfs_queue_work(struct btrfs_workqueue *wq,
 void btrfs_destroy_workqueue(struct btrfs_workqueue *wq);
 void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max);
 void btrfs_set_work_high_priority(struct btrfs_work *work);
+struct btrfs_fs_info *btrfs_work_owner(struct btrfs_work *work);
+struct btrfs_fs_info *btrfs_workqueue_owner(struct __btrfs_workqueue *wq);
 #endif
index 8bb3509..2b88439 100644 (file)
@@ -139,7 +139,7 @@ int __init btrfs_prelim_ref_init(void)
        btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
                                        sizeof(struct __prelim_ref),
                                        0,
-                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       SLAB_MEM_SPREAD,
                                        NULL);
        if (!btrfs_prelim_ref_cache)
                return -ENOMEM;
@@ -361,7 +361,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
                goto out;
        }
 
-       if (btrfs_test_is_dummy_root(root)) {
+       if (btrfs_is_testing(fs_info)) {
                srcu_read_unlock(&fs_info->subvol_srcu, index);
                ret = -ENOENT;
                goto out;
index 5d5cae0..6678947 100644 (file)
@@ -2945,7 +2945,7 @@ static void __btrfsic_submit_bio(struct bio *bio)
                        printk(KERN_INFO
                               "submit_bio(rw=%d,0x%x, bi_vcnt=%u,"
                               " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n",
-                              bio_op(bio), bio->bi_rw, bio->bi_vcnt,
+                              bio_op(bio), bio->bi_opf, bio->bi_vcnt,
                               (unsigned long long)bio->bi_iter.bi_sector,
                               dev_bytenr, bio->bi_bdev);
 
@@ -2976,18 +2976,18 @@ static void __btrfsic_submit_bio(struct bio *bio)
                btrfsic_process_written_block(dev_state, dev_bytenr,
                                              mapped_datav, bio->bi_vcnt,
                                              bio, &bio_is_patched,
-                                             NULL, bio->bi_rw);
+                                             NULL, bio->bi_opf);
                while (i > 0) {
                        i--;
                        kunmap(bio->bi_io_vec[i].bv_page);
                }
                kfree(mapped_datav);
-       } else if (NULL != dev_state && (bio->bi_rw & REQ_PREFLUSH)) {
+       } else if (NULL != dev_state && (bio->bi_opf & REQ_PREFLUSH)) {
                if (dev_state->state->print_mask &
                    BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
                        printk(KERN_INFO
                               "submit_bio(rw=%d,0x%x FLUSH, bdev=%p)\n",
-                              bio_op(bio), bio->bi_rw, bio->bi_bdev);
+                              bio_op(bio), bio->bi_opf, bio->bi_bdev);
                if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) {
                        if ((dev_state->state->print_mask &
                             (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
@@ -3005,7 +3005,7 @@ static void __btrfsic_submit_bio(struct bio *bio)
                        block->never_written = 0;
                        block->iodone_w_error = 0;
                        block->flush_gen = dev_state->last_flush_gen + 1;
-                       block->submit_bio_bh_rw = bio->bi_rw;
+                       block->submit_bio_bh_rw = bio->bi_opf;
                        block->orig_bio_bh_private = bio->bi_private;
                        block->orig_bio_bh_end_io.bio = bio->bi_end_io;
                        block->next_in_same_bio = NULL;
index cefedab..029db6e 100644 (file)
@@ -403,7 +403,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                        }
 
                        ret = btrfs_map_bio(root, bio, 0, 1);
-                       BUG_ON(ret); /* -ENOMEM */
+                       if (ret) {
+                               bio->bi_error = ret;
+                               bio_endio(bio);
+                       }
 
                        bio_put(bio);
 
@@ -434,7 +437,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        }
 
        ret = btrfs_map_bio(root, bio, 0, 1);
-       BUG_ON(ret); /* -ENOMEM */
+       if (ret) {
+               bio->bi_error = ret;
+               bio_endio(bio);
+       }
 
        bio_put(bio);
        return 0;
index a85cf7d..d1c56c9 100644 (file)
@@ -1153,14 +1153,14 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 
        ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
 
        if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
                ret = btrfs_reloc_cow_block(trans, root, buf, cow);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        return ret;
                }
        }
@@ -1198,7 +1198,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                if (last_ref) {
                        ret = tree_mod_log_free_eb(root->fs_info, buf);
                        if (ret) {
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                return ret;
                        }
                }
@@ -1505,7 +1505,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   struct extent_buffer *buf)
 {
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(root->fs_info))
                return 0;
 
        /* ensure we can see the force_cow */
@@ -1771,6 +1771,14 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
        unsigned long map_len = 0;
        int err;
 
+       if (low > high) {
+               btrfs_err(eb->fs_info,
+                "%s: low (%d) > high (%d) eb %llu owner %llu level %d",
+                         __func__, low, high, eb->start,
+                         btrfs_header_owner(eb), btrfs_header_level(eb));
+               return -EINVAL;
+       }
+
        while (low < high) {
                mid = (low + high) / 2;
                offset = p + mid * item_size;
@@ -1858,7 +1866,6 @@ static void root_sub_used(struct btrfs_root *root, u32 size)
 
 /* given a node and slot number, this reads the blocks it points to.  The
  * extent buffer is returned with a reference taken (but unlocked).
- * NULL is returned on error.
  */
 static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
                                   struct extent_buffer *parent, int slot)
@@ -1866,19 +1873,16 @@ static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
        int level = btrfs_header_level(parent);
        struct extent_buffer *eb;
 
-       if (slot < 0)
-               return NULL;
-       if (slot >= btrfs_header_nritems(parent))
-               return NULL;
+       if (slot < 0 || slot >= btrfs_header_nritems(parent))
+               return ERR_PTR(-ENOENT);
 
        BUG_ON(level == 0);
 
        eb = read_tree_block(root, btrfs_node_blockptr(parent, slot),
                             btrfs_node_ptr_generation(parent, slot));
-       if (IS_ERR(eb) || !extent_buffer_uptodate(eb)) {
-               if (!IS_ERR(eb))
-                       free_extent_buffer(eb);
-               eb = NULL;
+       if (!IS_ERR(eb) && !extent_buffer_uptodate(eb)) {
+               free_extent_buffer(eb);
+               eb = ERR_PTR(-EIO);
        }
 
        return eb;
@@ -1931,8 +1935,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 
                /* promote the child to a root */
                child = read_node_slot(root, mid, 0);
-               if (!child) {
-                       ret = -EROFS;
+               if (IS_ERR(child)) {
+                       ret = PTR_ERR(child);
                        btrfs_handle_fs_error(root->fs_info, ret, NULL);
                        goto enospc;
                }
@@ -1970,6 +1974,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                return 0;
 
        left = read_node_slot(root, parent, pslot - 1);
+       if (IS_ERR(left))
+               left = NULL;
+
        if (left) {
                btrfs_tree_lock(left);
                btrfs_set_lock_blocking(left);
@@ -1980,7 +1987,11 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        goto enospc;
                }
        }
+
        right = read_node_slot(root, parent, pslot + 1);
+       if (IS_ERR(right))
+               right = NULL;
+
        if (right) {
                btrfs_tree_lock(right);
                btrfs_set_lock_blocking(right);
@@ -2135,6 +2146,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                return 1;
 
        left = read_node_slot(root, parent, pslot - 1);
+       if (IS_ERR(left))
+               left = NULL;
 
        /* first, try to make some room in the middle buffer */
        if (left) {
@@ -2185,6 +2198,8 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                free_extent_buffer(left);
        }
        right = read_node_slot(root, parent, pslot + 1);
+       if (IS_ERR(right))
+               right = NULL;
 
        /*
         * then try to empty the right most buffer into the middle
@@ -3240,7 +3255,7 @@ static int push_node_left(struct btrfs_trans_handle *trans,
        ret = tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
                                   push_items);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
        copy_extent_buffer(dst, src,
@@ -3315,7 +3330,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
        ret = tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
                                   src_nritems - push_items, push_items);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
        copy_extent_buffer(dst, src,
@@ -3519,7 +3534,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        ret = tree_mod_log_eb_copy(root->fs_info, split, c, 0,
                                   mid, c_nritems - mid);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
        copy_extent_buffer(split, c,
@@ -3773,7 +3788,11 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_assert_tree_locked(path->nodes[1]);
 
        right = read_node_slot(root, upper, slot + 1);
-       if (right == NULL)
+       /*
+        * slot + 1 is not valid or we fail to read the right node,
+        * no big deal, just return.
+        */
+       if (IS_ERR(right))
                return 1;
 
        btrfs_tree_lock(right);
@@ -4003,7 +4022,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_assert_tree_locked(path->nodes[1]);
 
        left = read_node_slot(root, path->nodes[1], slot - 1);
-       if (left == NULL)
+       /*
+        * slot - 1 is not valid or we fail to read the left node,
+        * no big deal, just return.
+        */
+       if (IS_ERR(left))
                return 1;
 
        btrfs_tree_lock(left);
@@ -5210,7 +5233,10 @@ find_next_key:
                }
                btrfs_set_path_blocking(path);
                cur = read_node_slot(root, cur, slot);
-               BUG_ON(!cur); /* -ENOMEM */
+               if (IS_ERR(cur)) {
+                       ret = PTR_ERR(cur);
+                       goto out;
+               }
 
                btrfs_tree_read_lock(cur);
 
@@ -5229,15 +5255,21 @@ out:
        return ret;
 }
 
-static void tree_move_down(struct btrfs_root *root,
+static int tree_move_down(struct btrfs_root *root,
                           struct btrfs_path *path,
                           int *level, int root_level)
 {
+       struct extent_buffer *eb;
+
        BUG_ON(*level == 0);
-       path->nodes[*level - 1] = read_node_slot(root, path->nodes[*level],
-                                       path->slots[*level]);
+       eb = read_node_slot(root, path->nodes[*level], path->slots[*level]);
+       if (IS_ERR(eb))
+               return PTR_ERR(eb);
+
+       path->nodes[*level - 1] = eb;
        path->slots[*level - 1] = 0;
        (*level)--;
+       return 0;
 }
 
 static int tree_move_next_or_upnext(struct btrfs_root *root,
@@ -5282,8 +5314,7 @@ static int tree_advance(struct btrfs_root *root,
        if (*level == 0 || !allow_down) {
                ret = tree_move_next_or_upnext(root, path, level, root_level);
        } else {
-               tree_move_down(root, path, level, root_level);
-               ret = 0;
+               ret = tree_move_down(root, path, level, root_level);
        }
        if (ret >= 0) {
                if (*level == 0)
@@ -5457,8 +5488,10 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                                        left_root_level,
                                        advance_left != ADVANCE_ONLY_NEXT,
                                        &left_key);
-                       if (ret < 0)
+                       if (ret == -1)
                                left_end_reached = ADVANCE;
+                       else if (ret < 0)
+                               goto out;
                        advance_left = 0;
                }
                if (advance_right && !right_end_reached) {
@@ -5466,8 +5499,10 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                                        right_root_level,
                                        advance_right != ADVANCE_ONLY_NEXT,
                                        &right_key);
-                       if (ret < 0)
+                       if (ret == -1)
                                right_end_reached = ADVANCE;
+                       else if (ret < 0)
+                               goto out;
                        advance_right = 0;
                }
 
index 443fcc4..2fe8f89 100644 (file)
@@ -117,6 +117,7 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
 #define BTRFS_FS_STATE_REMOUNTING      1
 #define BTRFS_FS_STATE_TRANS_ABORTED   2
 #define BTRFS_FS_STATE_DEV_REPLACING   3
+#define BTRFS_FS_STATE_DUMMY_FS_INFO   4
 
 #define BTRFS_BACKREF_REV_MAX          256
 #define BTRFS_BACKREF_REV_SHIFT                56
@@ -144,21 +145,6 @@ struct btrfs_header {
        u8 level;
 } __attribute__ ((__packed__));
 
-#define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \
-                                     sizeof(struct btrfs_header)) / \
-                                    sizeof(struct btrfs_key_ptr))
-#define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
-#define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->nodesize))
-#define BTRFS_FILE_EXTENT_INLINE_DATA_START            \
-               (offsetof(struct btrfs_file_extent_item, disk_bytenr))
-#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
-                                       sizeof(struct btrfs_item) - \
-                                       BTRFS_FILE_EXTENT_INLINE_DATA_START)
-#define BTRFS_MAX_XATTR_SIZE(r)        (BTRFS_LEAF_DATA_SIZE(r) - \
-                                sizeof(struct btrfs_item) -\
-                                sizeof(struct btrfs_dir_item))
-
-
 /*
  * this is a very generous portion of the super block, giving us
  * room to translate 14 chunks with 3 stripes each.
@@ -1114,12 +1100,11 @@ struct btrfs_subvolume_writers {
 #define BTRFS_ROOT_REF_COWS            1
 #define BTRFS_ROOT_TRACK_DIRTY         2
 #define BTRFS_ROOT_IN_RADIX            3
-#define BTRFS_ROOT_DUMMY_ROOT          4
-#define BTRFS_ROOT_ORPHAN_ITEM_INSERTED        5
-#define BTRFS_ROOT_DEFRAG_RUNNING      6
-#define BTRFS_ROOT_FORCE_COW           7
-#define BTRFS_ROOT_MULTI_LOG_TASKS     8
-#define BTRFS_ROOT_DIRTY               9
+#define BTRFS_ROOT_ORPHAN_ITEM_INSERTED        4
+#define BTRFS_ROOT_DEFRAG_RUNNING      5
+#define BTRFS_ROOT_FORCE_COW           6
+#define BTRFS_ROOT_MULTI_LOG_TASKS     7
+#define BTRFS_ROOT_DIRTY               8
 
 /*
  * in ram representation of the tree.  extent_root is used for all allocations
@@ -1181,8 +1166,10 @@ struct btrfs_root {
 
        u64 highest_objectid;
 
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
        /* only used with CONFIG_BTRFS_FS_RUN_SANITY_TESTS is enabled */
        u64 alloc_bytenr;
+#endif
 
        u64 defrag_trans_start;
        struct btrfs_key defrag_progress;
@@ -1259,6 +1246,39 @@ struct btrfs_root {
        atomic_t qgroup_meta_rsv;
 };
 
+static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 blocksize)
+{
+       return blocksize - sizeof(struct btrfs_header);
+}
+
+static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_root *root)
+{
+       return __BTRFS_LEAF_DATA_SIZE(root->nodesize);
+}
+
+static inline u32 BTRFS_MAX_ITEM_SIZE(const struct btrfs_root *root)
+{
+       return BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item);
+}
+
+static inline u32 BTRFS_NODEPTRS_PER_BLOCK(const struct btrfs_root *root)
+{
+       return BTRFS_LEAF_DATA_SIZE(root) / sizeof(struct btrfs_key_ptr);
+}
+
+#define BTRFS_FILE_EXTENT_INLINE_DATA_START            \
+               (offsetof(struct btrfs_file_extent_item, disk_bytenr))
+static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_root *root)
+{
+       return BTRFS_MAX_ITEM_SIZE(root) -
+              BTRFS_FILE_EXTENT_INLINE_DATA_START;
+}
+
+static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_root *root)
+{
+       return BTRFS_MAX_ITEM_SIZE(root) - sizeof(struct btrfs_dir_item);
+}
+
 /*
  * Flags for mount options.
  *
@@ -1299,21 +1319,21 @@ struct btrfs_root {
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
 #define btrfs_raw_test_opt(o, opt)     ((o) & BTRFS_MOUNT_##opt)
-#define btrfs_test_opt(root, opt)      ((root)->fs_info->mount_opt & \
+#define btrfs_test_opt(fs_info, opt)   ((fs_info)->mount_opt & \
                                         BTRFS_MOUNT_##opt)
 
-#define btrfs_set_and_info(root, opt, fmt, args...)                    \
+#define btrfs_set_and_info(fs_info, opt, fmt, args...)                 \
 {                                                                      \
-       if (!btrfs_test_opt(root, opt))                                 \
-               btrfs_info(root->fs_info, fmt, ##args);                 \
-       btrfs_set_opt(root->fs_info->mount_opt, opt);                   \
+       if (!btrfs_test_opt(fs_info, opt))                              \
+               btrfs_info(fs_info, fmt, ##args);                       \
+       btrfs_set_opt(fs_info->mount_opt, opt);                         \
 }
 
-#define btrfs_clear_and_info(root, opt, fmt, args...)                  \
+#define btrfs_clear_and_info(fs_info, opt, fmt, args...)               \
 {                                                                      \
-       if (btrfs_test_opt(root, opt))                                  \
-               btrfs_info(root->fs_info, fmt, ##args);                 \
-       btrfs_clear_opt(root->fs_info->mount_opt, opt);                 \
+       if (btrfs_test_opt(fs_info, opt))                               \
+               btrfs_info(fs_info, fmt, ##args);                       \
+       btrfs_clear_opt(fs_info->mount_opt, opt);                       \
 }
 
 #ifdef CONFIG_BTRFS_DEBUG
@@ -1321,9 +1341,9 @@ static inline int
 btrfs_should_fragment_free_space(struct btrfs_root *root,
                                 struct btrfs_block_group_cache *block_group)
 {
-       return (btrfs_test_opt(root, FRAGMENT_METADATA) &&
+       return (btrfs_test_opt(root->fs_info, FRAGMENT_METADATA) &&
                block_group->flags & BTRFS_BLOCK_GROUP_METADATA) ||
-              (btrfs_test_opt(root, FRAGMENT_DATA) &&
+              (btrfs_test_opt(root->fs_info, FRAGMENT_DATA) &&
                block_group->flags &  BTRFS_BLOCK_GROUP_DATA);
 }
 #endif
@@ -2886,9 +2906,6 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
 int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq);
 
 /* root-item.c */
-int btrfs_find_root_ref(struct btrfs_root *tree_root,
-                       struct btrfs_path *path,
-                       u64 root_id, u64 ref_id);
 int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
                       struct btrfs_root *tree_root,
                       u64 root_id, u64 ref_id, u64 dirid, u64 sequence,
@@ -3362,23 +3379,23 @@ const char *btrfs_decode_error(int errno);
 
 __cold
 void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root, const char *function,
+                              const char *function,
                               unsigned int line, int errno);
 
 /*
  * Call btrfs_abort_transaction as early as possible when an error condition is
  * detected, that way the exact line number is reported.
  */
-#define btrfs_abort_transaction(trans, root, errno)            \
+#define btrfs_abort_transaction(trans, errno)          \
 do {                                                           \
        /* Report first abort since mount */                    \
        if (!test_and_set_bit(BTRFS_FS_STATE_TRANS_ABORTED,     \
-                       &((root)->fs_info->fs_state))) {        \
+                       &((trans)->fs_info->fs_state))) {       \
                WARN(1, KERN_DEBUG                              \
                "BTRFS: Transaction aborted (error %d)\n",      \
                (errno));                                       \
        }                                                       \
-       __btrfs_abort_transaction((trans), (root), __func__,    \
+       __btrfs_abort_transaction((trans), __func__,            \
                                  __LINE__, (errno));           \
 } while (0)
 
@@ -3610,13 +3627,13 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
 void btrfs_test_destroy_inode(struct inode *inode);
 #endif
 
-static inline int btrfs_test_is_dummy_root(struct btrfs_root *root)
+static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info)
 {
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-       if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
+       if (unlikely(test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO,
+                             &fs_info->fs_state)))
                return 1;
 #endif
        return 0;
 }
-
 #endif
diff --git a/fs/btrfs/dedupe.h b/fs/btrfs/dedupe.h
new file mode 100644 (file)
index 0000000..83ebfe2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 Fujitsu.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_DEDUPE__
+#define __BTRFS_DEDUPE__
+
+/* later in-band dedupe will expand this struct */
+struct btrfs_dedupe_hash;
+#endif
index dd3c040..3eeb9cd 100644 (file)
@@ -34,7 +34,7 @@ int __init btrfs_delayed_inode_init(void)
        delayed_node_cache = kmem_cache_create("btrfs_delayed_node",
                                        sizeof(struct btrfs_delayed_node),
                                        0,
-                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       SLAB_MEM_SPREAD,
                                        NULL);
        if (!delayed_node_cache)
                return -ENOMEM;
@@ -1170,7 +1170,7 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
                if (ret) {
                        btrfs_release_delayed_node(curr_node);
                        curr_node = NULL;
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        break;
                }
 
index 430b368..d9ddcfc 100644 (file)
@@ -606,7 +606,8 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
                qrecord->num_bytes = num_bytes;
                qrecord->old_roots = NULL;
 
-               qexisting = btrfs_qgroup_insert_dirty_extent(delayed_refs,
+               qexisting = btrfs_qgroup_insert_dirty_extent(fs_info,
+                                                            delayed_refs,
                                                             qrecord);
                if (qexisting)
                        kfree(qrecord);
@@ -615,7 +616,7 @@ add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        spin_lock_init(&head_ref->lock);
        mutex_init(&head_ref->mutex);
 
-       trace_add_delayed_ref_head(ref, head_ref, action);
+       trace_add_delayed_ref_head(fs_info, ref, head_ref, action);
 
        existing = htree_insert(&delayed_refs->href_root,
                                &head_ref->href_node);
@@ -682,7 +683,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
                ref->type = BTRFS_TREE_BLOCK_REF_KEY;
        full_ref->level = level;
 
-       trace_add_delayed_tree_ref(ref, full_ref, action);
+       trace_add_delayed_tree_ref(fs_info, ref, full_ref, action);
 
        ret = add_delayed_ref_tail_merge(trans, delayed_refs, head_ref, ref);
 
@@ -739,7 +740,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
        full_ref->objectid = owner;
        full_ref->offset = offset;
 
-       trace_add_delayed_data_ref(ref, full_ref, action);
+       trace_add_delayed_data_ref(fs_info, ref, full_ref, action);
 
        ret = add_delayed_ref_tail_merge(trans, delayed_refs, head_ref, ref);
 
@@ -861,33 +862,6 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
        return 0;
 }
 
-int btrfs_add_delayed_qgroup_reserve(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_trans_handle *trans,
-                                    u64 ref_root, u64 bytenr, u64 num_bytes)
-{
-       struct btrfs_delayed_ref_root *delayed_refs;
-       struct btrfs_delayed_ref_head *ref_head;
-       int ret = 0;
-
-       if (!fs_info->quota_enabled || !is_fstree(ref_root))
-               return 0;
-
-       delayed_refs = &trans->transaction->delayed_refs;
-
-       spin_lock(&delayed_refs->lock);
-       ref_head = find_ref_head(&delayed_refs->href_root, bytenr, 0);
-       if (!ref_head) {
-               ret = -ENOENT;
-               goto out;
-       }
-       WARN_ON(ref_head->qgroup_reserved || ref_head->qgroup_ref_root);
-       ref_head->qgroup_ref_root = ref_root;
-       ref_head->qgroup_reserved = num_bytes;
-out:
-       spin_unlock(&delayed_refs->lock);
-       return ret;
-}
-
 int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
                                struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
@@ -940,28 +914,28 @@ int btrfs_delayed_ref_init(void)
        btrfs_delayed_ref_head_cachep = kmem_cache_create(
                                "btrfs_delayed_ref_head",
                                sizeof(struct btrfs_delayed_ref_head), 0,
-                               SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                               SLAB_MEM_SPREAD, NULL);
        if (!btrfs_delayed_ref_head_cachep)
                goto fail;
 
        btrfs_delayed_tree_ref_cachep = kmem_cache_create(
                                "btrfs_delayed_tree_ref",
                                sizeof(struct btrfs_delayed_tree_ref), 0,
-                               SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                               SLAB_MEM_SPREAD, NULL);
        if (!btrfs_delayed_tree_ref_cachep)
                goto fail;
 
        btrfs_delayed_data_ref_cachep = kmem_cache_create(
                                "btrfs_delayed_data_ref",
                                sizeof(struct btrfs_delayed_data_ref), 0,
-                               SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                               SLAB_MEM_SPREAD, NULL);
        if (!btrfs_delayed_data_ref_cachep)
                goto fail;
 
        btrfs_delayed_extent_op_cachep = kmem_cache_create(
                                "btrfs_delayed_extent_op",
                                sizeof(struct btrfs_delayed_extent_op), 0,
-                               SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                               SLAB_MEM_SPREAD, NULL);
        if (!btrfs_delayed_extent_op_cachep)
                goto fail;
 
index 5fca953..43f3629 100644 (file)
@@ -250,9 +250,6 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
                               u64 parent, u64 ref_root,
                               u64 owner, u64 offset, u64 reserved, int action,
                               struct btrfs_delayed_extent_op *extent_op);
-int btrfs_add_delayed_qgroup_reserve(struct btrfs_fs_info *fs_info,
-                                    struct btrfs_trans_handle *trans,
-                                    u64 ref_root, u64 bytenr, u64 num_bytes);
 int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
                                struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes,
index 63ef9cd..e9bbff3 100644 (file)
@@ -142,7 +142,7 @@ no_valid_dev_replace_entry_found:
                 * missing
                 */
                if (!dev_replace->srcdev &&
-                   !btrfs_test_opt(dev_root, DEGRADED)) {
+                   !btrfs_test_opt(dev_root->fs_info, DEGRADED)) {
                        ret = -EIO;
                        btrfs_warn(fs_info,
                           "cannot mount because device replace operation is ongoing and");
@@ -151,7 +151,7 @@ no_valid_dev_replace_entry_found:
                           src_devid);
                }
                if (!dev_replace->tgtdev &&
-                   !btrfs_test_opt(dev_root, DEGRADED)) {
+                   !btrfs_test_opt(dev_root->fs_info, DEGRADED)) {
                        ret = -EIO;
                        btrfs_warn(fs_info,
                           "cannot mount because device replace operation is ongoing and");
index 9a726de..59febfb 100644 (file)
@@ -101,7 +101,7 @@ int __init btrfs_end_io_wq_init(void)
        btrfs_end_io_wq_cache = kmem_cache_create("btrfs_end_io_wq",
                                        sizeof(struct btrfs_end_io_wq),
                                        0,
-                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       SLAB_MEM_SPREAD,
                                        NULL);
        if (!btrfs_end_io_wq_cache)
                return -ENOMEM;
@@ -870,7 +870,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
 
        atomic_inc(&fs_info->nr_async_submits);
 
-       if (bio->bi_rw & REQ_SYNC)
+       if (bio->bi_opf & REQ_SYNC)
                btrfs_set_work_high_priority(&async->work);
 
        btrfs_queue_work(fs_info->workers, &async->work);
@@ -1140,7 +1140,7 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info,
 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
                                                 u64 bytenr)
 {
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(root->fs_info))
                return alloc_test_extent_buffer(root->fs_info, bytenr,
                                root->nodesize);
        return alloc_extent_buffer(root->fs_info, bytenr);
@@ -1227,6 +1227,7 @@ static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize,
                         struct btrfs_root *root, struct btrfs_fs_info *fs_info,
                         u64 objectid)
 {
+       bool dummy = test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
        root->node = NULL;
        root->commit_root = NULL;
        root->sectorsize = sectorsize;
@@ -1281,14 +1282,14 @@ static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize,
        root->log_transid = 0;
        root->log_transid_committed = -1;
        root->last_log_commit = 0;
-       if (fs_info)
+       if (!dummy)
                extent_io_tree_init(&root->dirty_log_pages,
                                     fs_info->btree_inode->i_mapping);
 
        memset(&root->root_key, 0, sizeof(root->root_key));
        memset(&root->root_item, 0, sizeof(root->root_item));
        memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
-       if (fs_info)
+       if (!dummy)
                root->defrag_trans_start = fs_info->generation;
        else
                root->defrag_trans_start = 0;
@@ -1309,17 +1310,20 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info,
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 /* Should only be used by the testing infrastructure */
-struct btrfs_root *btrfs_alloc_dummy_root(u32 sectorsize, u32 nodesize)
+struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info,
+                                         u32 sectorsize, u32 nodesize)
 {
        struct btrfs_root *root;
 
-       root = btrfs_alloc_root(NULL, GFP_KERNEL);
+       if (!fs_info)
+               return ERR_PTR(-EINVAL);
+
+       root = btrfs_alloc_root(fs_info, GFP_KERNEL);
        if (!root)
                return ERR_PTR(-ENOMEM);
        /* We don't use the stripesize in selftest, set it as sectorsize */
-       __setup_root(nodesize, sectorsize, sectorsize, root, NULL,
+       __setup_root(nodesize, sectorsize, sectorsize, root, fs_info,
                        BTRFS_ROOT_TREE_OBJECTID);
-       set_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state);
        root->alloc_bytenr = 0;
 
        return root;
@@ -1594,14 +1598,14 @@ int btrfs_init_fs_root(struct btrfs_root *root)
 
        ret = get_anon_bdev(&root->anon_dev);
        if (ret)
-               goto free_writers;
+               goto fail;
 
        mutex_lock(&root->objectid_mutex);
        ret = btrfs_find_highest_objectid(root,
                                        &root->highest_objectid);
        if (ret) {
                mutex_unlock(&root->objectid_mutex);
-               goto free_root_dev;
+               goto fail;
        }
 
        ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
@@ -1609,14 +1613,8 @@ int btrfs_init_fs_root(struct btrfs_root *root)
        mutex_unlock(&root->objectid_mutex);
 
        return 0;
-
-free_root_dev:
-       free_anon_bdev(root->anon_dev);
-free_writers:
-       btrfs_free_subvolume_writers(root->subv_writers);
 fail:
-       kfree(root->free_ino_ctl);
-       kfree(root->free_ino_pinned);
+       /* the caller is responsible to call free_fs_root */
        return ret;
 }
 
@@ -2310,17 +2308,19 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
        unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND;
 
        fs_info->workers =
-               btrfs_alloc_workqueue("worker", flags | WQ_HIGHPRI,
-                                     max_active, 16);
+               btrfs_alloc_workqueue(fs_info, "worker",
+                                     flags | WQ_HIGHPRI, max_active, 16);
 
        fs_info->delalloc_workers =
-               btrfs_alloc_workqueue("delalloc", flags, max_active, 2);
+               btrfs_alloc_workqueue(fs_info, "delalloc",
+                                     flags, max_active, 2);
 
        fs_info->flush_workers =
-               btrfs_alloc_workqueue("flush_delalloc", flags, max_active, 0);
+               btrfs_alloc_workqueue(fs_info, "flush_delalloc",
+                                     flags, max_active, 0);
 
        fs_info->caching_workers =
-               btrfs_alloc_workqueue("cache", flags, max_active, 0);
+               btrfs_alloc_workqueue(fs_info, "cache", flags, max_active, 0);
 
        /*
         * a higher idle thresh on the submit workers makes it much more
@@ -2328,41 +2328,48 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info,
         * devices
         */
        fs_info->submit_workers =
-               btrfs_alloc_workqueue("submit", flags,
+               btrfs_alloc_workqueue(fs_info, "submit", flags,
                                      min_t(u64, fs_devices->num_devices,
                                            max_active), 64);
 
        fs_info->fixup_workers =
-               btrfs_alloc_workqueue("fixup", flags, 1, 0);
+               btrfs_alloc_workqueue(fs_info, "fixup", flags, 1, 0);
 
        /*
         * endios are largely parallel and should have a very
         * low idle thresh
         */
        fs_info->endio_workers =
-               btrfs_alloc_workqueue("endio", flags, max_active, 4);
+               btrfs_alloc_workqueue(fs_info, "endio", flags, max_active, 4);
        fs_info->endio_meta_workers =
-               btrfs_alloc_workqueue("endio-meta", flags, max_active, 4);
+               btrfs_alloc_workqueue(fs_info, "endio-meta", flags,
+                                     max_active, 4);
        fs_info->endio_meta_write_workers =
-               btrfs_alloc_workqueue("endio-meta-write", flags, max_active, 2);
+               btrfs_alloc_workqueue(fs_info, "endio-meta-write", flags,
+                                     max_active, 2);
        fs_info->endio_raid56_workers =
-               btrfs_alloc_workqueue("endio-raid56", flags, max_active, 4);
+               btrfs_alloc_workqueue(fs_info, "endio-raid56", flags,
+                                     max_active, 4);
        fs_info->endio_repair_workers =
-               btrfs_alloc_workqueue("endio-repair", flags, 1, 0);
+               btrfs_alloc_workqueue(fs_info, "endio-repair", flags, 1, 0);
        fs_info->rmw_workers =
-               btrfs_alloc_workqueue("rmw", flags, max_active, 2);
+               btrfs_alloc_workqueue(fs_info, "rmw", flags, max_active, 2);
        fs_info->endio_write_workers =
-               btrfs_alloc_workqueue("endio-write", flags, max_active, 2);
+               btrfs_alloc_workqueue(fs_info, "endio-write", flags,
+                                     max_active, 2);
        fs_info->endio_freespace_worker =
-               btrfs_alloc_workqueue("freespace-write", flags, max_active, 0);
+               btrfs_alloc_workqueue(fs_info, "freespace-write", flags,
+                                     max_active, 0);
        fs_info->delayed_workers =
-               btrfs_alloc_workqueue("delayed-meta", flags, max_active, 0);
+               btrfs_alloc_workqueue(fs_info, "delayed-meta", flags,
+                                     max_active, 0);
        fs_info->readahead_workers =
-               btrfs_alloc_workqueue("readahead", flags, max_active, 2);
+               btrfs_alloc_workqueue(fs_info, "readahead", flags,
+                                     max_active, 2);
        fs_info->qgroup_rescan_workers =
-               btrfs_alloc_workqueue("qgroup-rescan", flags, 1, 0);
+               btrfs_alloc_workqueue(fs_info, "qgroup-rescan", flags, 1, 0);
        fs_info->extent_workers =
-               btrfs_alloc_workqueue("extent-refs", flags,
+               btrfs_alloc_workqueue(fs_info, "extent-refs", flags,
                                      min_t(u64, fs_devices->num_devices,
                                            max_active), 8);
 
@@ -3010,8 +3017,8 @@ retry_root_backup:
        if (IS_ERR(fs_info->transaction_kthread))
                goto fail_cleaner;
 
-       if (!btrfs_test_opt(tree_root, SSD) &&
-           !btrfs_test_opt(tree_root, NOSSD) &&
+       if (!btrfs_test_opt(tree_root->fs_info, SSD) &&
+           !btrfs_test_opt(tree_root->fs_info, NOSSD) &&
            !fs_info->fs_devices->rotating) {
                btrfs_info(fs_info, "detected SSD devices, enabling SSD mode");
                btrfs_set_opt(fs_info->mount_opt, SSD);
@@ -3024,9 +3031,9 @@ retry_root_backup:
        btrfs_apply_pending_changes(fs_info);
 
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
+       if (btrfs_test_opt(tree_root->fs_info, CHECK_INTEGRITY)) {
                ret = btrfsic_mount(tree_root, fs_devices,
-                                   btrfs_test_opt(tree_root,
+                                   btrfs_test_opt(tree_root->fs_info,
                                        CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ?
                                    1 : 0,
                                    fs_info->check_integrity_print_mask);
@@ -3042,7 +3049,7 @@ retry_root_backup:
 
        /* do not make disk changes in broken FS or nologreplay is given */
        if (btrfs_super_log_root(disk_super) != 0 &&
-           !btrfs_test_opt(tree_root, NOLOGREPLAY)) {
+           !btrfs_test_opt(tree_root->fs_info, NOLOGREPLAY)) {
                ret = btrfs_replay_log(fs_info, fs_devices);
                if (ret) {
                        err = ret;
@@ -3083,7 +3090,7 @@ retry_root_backup:
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
-       if (btrfs_test_opt(tree_root, FREE_SPACE_TREE) &&
+       if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) &&
            !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
                btrfs_info(fs_info, "creating free space tree");
                ret = btrfs_create_free_space_tree(fs_info);
@@ -3120,7 +3127,7 @@ retry_root_backup:
 
        btrfs_qgroup_rescan_resume(fs_info);
 
-       if (btrfs_test_opt(tree_root, CLEAR_CACHE) &&
+       if (btrfs_test_opt(tree_root->fs_info, CLEAR_CACHE) &&
            btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
                btrfs_info(fs_info, "clearing free space tree");
                ret = btrfs_clear_free_space_tree(fs_info);
@@ -3141,7 +3148,7 @@ retry_root_backup:
                        close_ctree(tree_root);
                        return ret;
                }
-       } else if (btrfs_test_opt(tree_root, RESCAN_UUID_TREE) ||
+       } else if (btrfs_test_opt(tree_root->fs_info, RESCAN_UUID_TREE) ||
                   fs_info->generation !=
                                btrfs_super_uuid_tree_generation(disk_super)) {
                btrfs_info(fs_info, "checking UUID tree");
@@ -3218,7 +3225,7 @@ fail:
        return err;
 
 recovery_tree_root:
-       if (!btrfs_test_opt(tree_root, USEBACKUPROOT))
+       if (!btrfs_test_opt(tree_root->fs_info, USEBACKUPROOT))
                goto fail_tree_roots;
 
        free_root_pointers(fs_info, 0);
@@ -3634,7 +3641,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
        int total_errors = 0;
        u64 flags;
 
-       do_barriers = !btrfs_test_opt(root, NOBARRIER);
+       do_barriers = !btrfs_test_opt(root->fs_info, NOBARRIER);
        backup_super_roots(root->fs_info);
 
        sb = root->fs_info->super_for_commit;
@@ -3918,7 +3925,7 @@ void close_ctree(struct btrfs_root *root)
        iput(fs_info->btree_inode);
 
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(root, CHECK_INTEGRITY))
+       if (btrfs_test_opt(root->fs_info, CHECK_INTEGRITY))
                btrfsic_unmount(root, fs_info->fs_devices);
 #endif
 
index dbf3e1a..b3207a0 100644 (file)
@@ -90,7 +90,8 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 void btrfs_free_fs_root(struct btrfs_root *root);
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-struct btrfs_root *btrfs_alloc_dummy_root(u32 sectorsize, u32 nodesize);
+struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info,
+                                         u32 sectorsize, u32 nodesize);
 #endif
 
 /*
index e9376b1..61b494e 100644 (file)
@@ -2180,7 +2180,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                    path, bytenr, parent, root_objectid,
                                    owner, offset, refs_to_add);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 out:
        btrfs_free_path(path);
        return ret;
@@ -2204,7 +2204,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
        ins.type = BTRFS_EXTENT_ITEM_KEY;
 
        ref = btrfs_delayed_node_to_data_ref(node);
-       trace_run_delayed_data_ref(node, ref, node->action);
+       trace_run_delayed_data_ref(root->fs_info, node, ref, node->action);
 
        if (node->type == BTRFS_SHARED_DATA_REF_KEY)
                parent = ref->parent;
@@ -2359,7 +2359,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
                                                 SKINNY_METADATA);
 
        ref = btrfs_delayed_node_to_tree_ref(node);
-       trace_run_delayed_tree_ref(node, ref, node->action);
+       trace_run_delayed_tree_ref(root->fs_info, node, ref, node->action);
 
        if (node->type == BTRFS_SHARED_BLOCK_REF_KEY)
                parent = ref->parent;
@@ -2423,7 +2423,8 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                 */
                BUG_ON(extent_op);
                head = btrfs_delayed_node_to_head(node);
-               trace_run_delayed_ref_head(node, head, node->action);
+               trace_run_delayed_ref_head(root->fs_info, node, head,
+                                          node->action);
 
                if (insert_reserved) {
                        btrfs_pin_extent(root, node->bytenr,
@@ -2778,7 +2779,7 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes)
        u64 num_csums_per_leaf;
        u64 num_csums;
 
-       csum_size = BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item);
+       csum_size = BTRFS_MAX_ITEM_SIZE(root);
        num_csums_per_leaf = div64_u64(csum_size,
                        (u64)btrfs_super_csum_size(root->fs_info->super_copy));
        num_csums = div64_u64(csum_bytes, root->sectorsize);
@@ -2970,7 +2971,7 @@ again:
        trans->can_flush_pending_bgs = false;
        ret = __btrfs_run_delayed_refs(trans, root, count);
        if (ret < 0) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
 
@@ -3234,7 +3235,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                            u64, u64, u64, u64, u64, u64);
 
 
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(root->fs_info))
                return 0;
 
        ref_root = btrfs_header_owner(buf);
@@ -3429,7 +3430,7 @@ again:
                 * transaction, this only happens in really bad situations
                 * anyway.
                 */
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_put;
        }
        WARN_ON(ret);
@@ -3447,7 +3448,7 @@ again:
 
        spin_lock(&block_group->lock);
        if (block_group->cached != BTRFS_CACHE_FINISHED ||
-           !btrfs_test_opt(root, SPACE_CACHE)) {
+           !btrfs_test_opt(root->fs_info, SPACE_CACHE)) {
                /*
                 * don't bother trying to write stuff out _if_
                 * a) we're not cached,
@@ -3524,7 +3525,7 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans,
        struct btrfs_path *path;
 
        if (list_empty(&cur_trans->dirty_bgs) ||
-           !btrfs_test_opt(root, SPACE_CACHE))
+           !btrfs_test_opt(root->fs_info, SPACE_CACHE))
                return 0;
 
        path = btrfs_alloc_path();
@@ -3669,7 +3670,7 @@ again:
                                }
                                spin_unlock(&cur_trans->dirty_bgs_lock);
                        } else if (ret) {
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                        }
                }
 
@@ -3815,7 +3816,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                                            cache);
                        }
                        if (ret)
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                }
 
                /* if its not on the io list, we need to put the block group */
@@ -4443,7 +4444,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans,
        thresh = btrfs_calc_trunc_metadata_size(root, num_devs) +
                btrfs_calc_trans_metadata_size(root, 1);
 
-       if (left < thresh && btrfs_test_opt(root, ENOSPC_DEBUG)) {
+       if (left < thresh && btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) {
                btrfs_info(root->fs_info, "left=%llu, need=%llu, flags=%llu",
                        left, thresh, type);
                dump_space_info(info, 0, 0);
@@ -4588,7 +4589,7 @@ out:
         */
        if (trans->can_flush_pending_bgs &&
            trans->chunk_bytes_reserved >= (u64)SZ_2M) {
-               btrfs_create_pending_block_groups(trans, trans->root);
+               btrfs_create_pending_block_groups(trans, extent_root);
                btrfs_trans_release_chunk_metadata(trans);
        }
        return ret;
@@ -5729,7 +5730,7 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
  */
 void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans)
 {
-       struct btrfs_fs_info *fs_info = trans->root->fs_info;
+       struct btrfs_fs_info *fs_info = trans->fs_info;
 
        if (!trans->chunk_bytes_reserved)
                return;
@@ -6100,7 +6101,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
        if (dropped > 0)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(root->fs_info))
                return;
 
        trace_btrfs_space_reservation(root->fs_info, "delalloc",
@@ -6215,7 +6216,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                spin_lock(&cache->space_info->lock);
                spin_lock(&cache->lock);
 
-               if (btrfs_test_opt(root, SPACE_CACHE) &&
+               if (btrfs_test_opt(root->fs_info, SPACE_CACHE) &&
                    cache->disk_cache_state < BTRFS_DC_CLEAR)
                        cache->disk_cache_state = BTRFS_DC_CLEAR;
 
@@ -6597,7 +6598,7 @@ fetch_cluster_info(struct btrfs_root *root, struct btrfs_space_info *space_info,
                   u64 *empty_cluster)
 {
        struct btrfs_free_cluster *ret = NULL;
-       bool ssd = btrfs_test_opt(root, SSD);
+       bool ssd = btrfs_test_opt(root->fs_info, SSD);
 
        *empty_cluster = 0;
        if (btrfs_mixed_space_info(space_info))
@@ -6742,7 +6743,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
                        break;
                }
 
-               if (btrfs_test_opt(root, DISCARD))
+               if (btrfs_test_opt(root->fs_info, DISCARD))
                        ret = btrfs_discard_extent(root, start,
                                                   end + 1 - start, NULL);
 
@@ -6880,7 +6881,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                                    NULL, refs_to_drop,
                                                    is_data, &last_ref);
                        if (ret) {
-                               btrfs_abort_transaction(trans, extent_root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
                        btrfs_release_path(path);
@@ -6929,7 +6930,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                                         path->nodes[0]);
                        }
                        if (ret < 0) {
-                               btrfs_abort_transaction(trans, extent_root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
                        extent_slot = path->slots[0];
@@ -6940,10 +6941,10 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        "unable to find ref byte nr %llu parent %llu root %llu  owner %llu offset %llu",
                        bytenr, parent, root_objectid, owner_objectid,
                        owner_offset);
-               btrfs_abort_transaction(trans, extent_root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        } else {
-               btrfs_abort_transaction(trans, extent_root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -6955,7 +6956,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                ret = convert_extent_item_v0(trans, extent_root, path,
                                             owner_objectid, 0);
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
@@ -6974,7 +6975,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        btrfs_print_leaf(extent_root, path->nodes[0]);
                }
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
@@ -6999,7 +7000,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                btrfs_err(info, "trying to drop %d refs but we only have %Lu "
                          "for bytenr %Lu", refs_to_drop, refs, bytenr);
                ret = -EINVAL;
-               btrfs_abort_transaction(trans, extent_root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
        refs -= refs_to_drop;
@@ -7022,7 +7023,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                                    iref, refs_to_drop,
                                                    is_data, &last_ref);
                        if (ret) {
-                               btrfs_abort_transaction(trans, extent_root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
                }
@@ -7045,7 +7046,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                if (ret) {
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
                btrfs_release_path(path);
@@ -7053,7 +7054,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                if (is_data) {
                        ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
                        if (ret) {
-                               btrfs_abort_transaction(trans, extent_root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
                }
@@ -7061,13 +7062,13 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                ret = add_to_free_space_tree(trans, root->fs_info, bytenr,
                                             num_bytes);
                if (ret) {
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
                ret = update_block_group(trans, root, bytenr, num_bytes, 0);
                if (ret) {
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
        }
@@ -7216,7 +7217,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
 
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(fs_info))
                return 0;
 
        add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid);
@@ -7851,8 +7852,7 @@ loop:
                         * can do more things.
                         */
                        if (ret < 0 && ret != -ENOSPC)
-                               btrfs_abort_transaction(trans,
-                                                       root, ret);
+                               btrfs_abort_transaction(trans, ret);
                        else
                                ret = 0;
                        if (!exist)
@@ -7906,8 +7906,8 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
        printk(KERN_INFO "BTRFS: space_info %llu has %llu free, is %sfull\n",
               info->flags,
               info->total_bytes - info->bytes_used - info->bytes_pinned -
-              info->bytes_reserved - info->bytes_readonly,
-              (info->full) ? "" : "not ");
+              info->bytes_reserved - info->bytes_readonly -
+              info->bytes_may_use, (info->full) ? "" : "not ");
        printk(KERN_INFO "BTRFS: space_info total=%llu, used=%llu, pinned=%llu, "
               "reserved=%llu, may_use=%llu, readonly=%llu\n",
               info->total_bytes, info->bytes_used, info->bytes_pinned,
@@ -7961,7 +7961,7 @@ again:
                        if (num_bytes == min_alloc_size)
                                final_tried = true;
                        goto again;
-               } else if (btrfs_test_opt(root, ENOSPC_DEBUG)) {
+               } else if (btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) {
                        struct btrfs_space_info *sinfo;
 
                        sinfo = __find_space_info(root->fs_info, flags);
@@ -7992,7 +7992,7 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root,
        if (pin)
                pin_down_extent(root, cache, start, len, 1);
        else {
-               if (btrfs_test_opt(root, DISCARD))
+               if (btrfs_test_opt(root->fs_info, DISCARD))
                        ret = btrfs_discard_extent(root, start, len, NULL);
                btrfs_add_free_space(cache, start, len);
                btrfs_update_reserved_bytes(cache, len, RESERVE_FREE, delalloc);
@@ -8300,7 +8300,7 @@ again:
                goto again;
        }
 
-       if (btrfs_test_opt(root, ENOSPC_DEBUG)) {
+       if (btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) {
                static DEFINE_RATELIMIT_STATE(_rs,
                                DEFAULT_RATELIMIT_INTERVAL * 10,
                                /*DEFAULT_RATELIMIT_BURST*/ 1);
@@ -8354,13 +8354,15 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
        bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
                                                 SKINNY_METADATA);
 
-       if (btrfs_test_is_dummy_root(root)) {
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+       if (btrfs_is_testing(root->fs_info)) {
                buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr,
                                            level);
                if (!IS_ERR(buf))
                        root->alloc_bytenr += blocksize;
                return buf;
        }
+#endif
 
        block_rsv = use_block_rsv(trans, root, blocksize);
        if (IS_ERR(block_rsv))
@@ -8540,7 +8542,8 @@ static int record_one_subtree_extent(struct btrfs_trans_handle *trans,
 
        delayed_refs = &trans->transaction->delayed_refs;
        spin_lock(&delayed_refs->lock);
-       if (btrfs_qgroup_insert_dirty_extent(delayed_refs, qrecord))
+       if (btrfs_qgroup_insert_dirty_extent(trans->fs_info,
+                                            delayed_refs, qrecord))
                kfree(qrecord);
        spin_unlock(&delayed_refs->lock);
 
@@ -9325,7 +9328,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                                &root->root_key,
                                                root_item);
                        if (ret) {
-                               btrfs_abort_transaction(trans, tree_root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                err = ret;
                                goto out_end_trans;
                        }
@@ -9352,7 +9355,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
 
        ret = btrfs_del_root(trans, tree_root, &root->root_key);
        if (ret) {
-               btrfs_abort_transaction(trans, tree_root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_end_trans;
        }
 
@@ -9360,7 +9363,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                ret = btrfs_find_root(tree_root, &root->root_key, path,
                                      NULL, NULL);
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, tree_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        err = ret;
                        goto out_end_trans;
                } else if (ret > 0) {
@@ -9731,7 +9734,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
        int full = 0;
        int ret = 0;
 
-       debug = btrfs_test_opt(root, ENOSPC_DEBUG);
+       debug = btrfs_test_opt(root->fs_info, ENOSPC_DEBUG);
 
        block_group = btrfs_lookup_block_group(root->fs_info, bytenr);
 
@@ -9887,7 +9890,22 @@ static int find_first_block_group(struct btrfs_root *root,
 
                if (found_key.objectid >= key->objectid &&
                    found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) {
-                       ret = 0;
+                       struct extent_map_tree *em_tree;
+                       struct extent_map *em;
+
+                       em_tree = &root->fs_info->mapping_tree.map_tree;
+                       read_lock(&em_tree->lock);
+                       em = lookup_extent_mapping(em_tree, found_key.objectid,
+                                                  found_key.offset);
+                       read_unlock(&em_tree->lock);
+                       if (!em) {
+                               btrfs_err(root->fs_info,
+                       "logical %llu len %llu found bg but no related chunk",
+                                         found_key.objectid, found_key.offset);
+                               ret = -ENOENT;
+                       } else {
+                               ret = 0;
+                       }
                        goto out;
                }
                path->slots[0]++;
@@ -10129,10 +10147,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
        path->reada = READA_FORWARD;
 
        cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
-       if (btrfs_test_opt(root, SPACE_CACHE) &&
+       if (btrfs_test_opt(root->fs_info, SPACE_CACHE) &&
            btrfs_super_generation(root->fs_info->super_copy) != cache_gen)
                need_clear = 1;
-       if (btrfs_test_opt(root, CLEAR_CACHE))
+       if (btrfs_test_opt(root->fs_info, CLEAR_CACHE))
                need_clear = 1;
 
        while (1) {
@@ -10163,7 +10181,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                         * b) Setting 'dirty flag' makes sure that we flush
                         *    the new space cache info onto disk.
                         */
-                       if (btrfs_test_opt(root, SPACE_CACHE))
+                       if (btrfs_test_opt(root->fs_info, SPACE_CACHE))
                                cache->disk_cache_state = BTRFS_DC_CLEAR;
                }
 
@@ -10305,11 +10323,11 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
                ret = btrfs_insert_item(trans, extent_root, &key, &item,
                                        sizeof(item));
                if (ret)
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                ret = btrfs_finish_chunk_alloc(trans, extent_root,
                                               key.objectid, key.offset);
                if (ret)
-                       btrfs_abort_transaction(trans, extent_root, ret);
+                       btrfs_abort_transaction(trans, ret);
                add_block_group_free_space(trans, root->fs_info, block_group);
                /* already aborted the transaction if it failed. */
 next:
@@ -10622,7 +10640,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        spin_lock(&block_group->space_info->lock);
        list_del_init(&block_group->ro_list);
 
-       if (btrfs_test_opt(root, ENOSPC_DEBUG)) {
+       if (btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) {
                WARN_ON(block_group->space_info->total_bytes
                        < block_group->key.offset);
                WARN_ON(block_group->space_info->bytes_readonly
@@ -10890,7 +10908,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                spin_unlock(&space_info->lock);
 
                /* DISCARD can flip during remount */
-               trimming = btrfs_test_opt(root, DISCARD);
+               trimming = btrfs_test_opt(root->fs_info, DISCARD);
 
                /* Implicit trim during transaction commit. */
                if (trimming)
index cee4cb9..44fe66b 100644 (file)
@@ -163,13 +163,13 @@ int __init extent_io_init(void)
 {
        extent_state_cache = kmem_cache_create("btrfs_extent_state",
                        sizeof(struct extent_state), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!extent_state_cache)
                return -ENOMEM;
 
        extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer",
                        sizeof(struct extent_buffer), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!extent_buffer_cache)
                goto free_state_cache;
 
@@ -2049,7 +2049,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
                return -EIO;
        }
        bio->bi_bdev = dev->bdev;
-       bio->bi_rw = WRITE_SYNC;
+       bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC);
        bio_add_page(bio, page, length, pg_offset);
 
        if (btrfsic_submit_bio_wait(bio)) {
@@ -2697,12 +2697,6 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
                btrfs_bio->csum = NULL;
                btrfs_bio->csum_allocated = NULL;
                btrfs_bio->end_io = NULL;
-
-#ifdef CONFIG_BLK_CGROUP
-               /* FIXME, put this into bio_clone_bioset */
-               if (bio->bi_css)
-                       bio_associate_blkcg(new, bio->bi_css);
-#endif
        }
        return new;
 }
@@ -2756,7 +2750,6 @@ static int merge_bio(struct extent_io_tree *tree, struct page *page,
        if (tree->ops && tree->ops->merge_bio_hook)
                ret = tree->ops->merge_bio_hook(page, offset, size, bio,
                                                bio_flags);
-       BUG_ON(ret < 0);
        return ret;
 
 }
@@ -2879,6 +2872,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
  * into the tree that are removed when the IO is done (by the end_io
  * handlers)
  * XXX JDM: This needs looking at to ensure proper page locking
+ * return 0 on success, otherwise return error
  */
 static int __do_readpage(struct extent_io_tree *tree,
                         struct page *page,
@@ -2900,7 +2894,7 @@ static int __do_readpage(struct extent_io_tree *tree,
        sector_t sector;
        struct extent_map *em;
        struct block_device *bdev;
-       int ret;
+       int ret = 0;
        int nr = 0;
        size_t pg_offset = 0;
        size_t iosize;
@@ -3081,6 +3075,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                } else {
                        SetPageError(page);
                        unlock_extent(tree, cur, cur + iosize - 1);
+                       goto out;
                }
                cur = cur + iosize;
                pg_offset += iosize;
@@ -3091,7 +3086,7 @@ out:
                        SetPageUptodate(page);
                unlock_page(page);
        }
-       return 0;
+       return ret;
 }
 
 static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
@@ -5230,14 +5225,31 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
        atomic_set(&eb->io_pages, num_reads);
        for (i = start_i; i < num_pages; i++) {
                page = eb->pages[i];
+
                if (!PageUptodate(page)) {
+                       if (ret) {
+                               atomic_dec(&eb->io_pages);
+                               unlock_page(page);
+                               continue;
+                       }
+
                        ClearPageError(page);
                        err = __extent_read_full_page(tree, page,
                                                      get_extent, &bio,
                                                      mirror_num, &bio_flags,
                                                      REQ_META);
-                       if (err)
+                       if (err) {
                                ret = err;
+                               /*
+                                * We use &bio in above __extent_read_full_page,
+                                * so we ensure that if it returns error, the
+                                * current page fails to add itself to bio and
+                                * it's been unlocked.
+                                *
+                                * We must dec io_pages by ourselves.
+                                */
+                               atomic_dec(&eb->io_pages);
+                       }
                } else {
                        unlock_page(page);
                }
index e0715fc..26f9ac7 100644 (file)
@@ -13,7 +13,7 @@ int __init extent_map_init(void)
 {
        extent_map_cache = kmem_cache_create("btrfs_extent_map",
                        sizeof(struct extent_map), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!extent_map_cache)
                return -ENOMEM;
        return 0;
index 62a81ee..d0d571c 100644 (file)
@@ -250,7 +250,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                                offset + root->sectorsize - 1,
                                                EXTENT_NODATASUM);
                                } else {
-                                       btrfs_info(BTRFS_I(inode)->root->fs_info,
+                                       btrfs_info_rl(BTRFS_I(inode)->root->fs_info,
                                                   "no csum found for inode %llu start %llu",
                                               btrfs_ino(inode), offset);
                                }
@@ -699,7 +699,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                         */
                        ret = btrfs_split_item(trans, root, path, &key, offset);
                        if (ret && ret != -EAGAIN) {
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
 
index bcfb4a2..5842423 100644 (file)
@@ -132,7 +132,7 @@ static int __btrfs_add_inode_defrag(struct inode *inode,
 
 static inline int __need_auto_defrag(struct btrfs_root *root)
 {
-       if (!btrfs_test_opt(root, AUTO_DEFRAG))
+       if (!btrfs_test_opt(root->fs_info, AUTO_DEFRAG))
                return 0;
 
        if (btrfs_fs_closing(root->fs_info))
@@ -950,7 +950,7 @@ delete_extent_item:
                        ret = btrfs_del_items(trans, root, path, del_slot,
                                              del_nr);
                        if (ret) {
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                break;
                        }
 
@@ -974,7 +974,7 @@ delete_extent_item:
                path->slots[0] = del_slot;
                ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
                if (ret)
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
        }
 
        leaf = path->nodes[0];
@@ -1190,7 +1190,7 @@ again:
                        goto again;
                }
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
@@ -1278,7 +1278,7 @@ again:
 
                ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
        }
@@ -2033,6 +2033,14 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                 */
                clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                          &BTRFS_I(inode)->runtime_flags);
+               /*
+                * An ordered extent might have started before and completed
+                * already with io errors, in which case the inode was not
+                * updated and we end up here. So check the inode's mapping
+                * flags for any errors that might have happened while doing
+                * writeback of file data.
+                */
+               ret = btrfs_inode_check_errors(inode);
                inode_unlock(inode);
                goto out;
        }
@@ -2975,7 +2983,7 @@ int btrfs_auto_defrag_init(void)
 {
        btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
                                        sizeof(struct inode_defrag), 0,
-                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       SLAB_MEM_SPREAD,
                                        NULL);
        if (!btrfs_inode_defrag_cachep)
                return -ENOMEM;
index 69d270f..d571bd2 100644 (file)
@@ -280,7 +280,7 @@ fail:
        if (locked)
                mutex_unlock(&trans->transaction->cache_write_mutex);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 
        return ret;
 }
@@ -3026,7 +3026,7 @@ int btrfs_find_space_cluster(struct btrfs_root *root,
         * For metadata, allow allocates with smaller extents.  For
         * data, keep it dense.
         */
-       if (btrfs_test_opt(root, SSD_SPREAD)) {
+       if (btrfs_test_opt(root->fs_info, SSD_SPREAD)) {
                cont1_bytes = min_bytes = bytes + empty_size;
        } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) {
                cont1_bytes = bytes;
@@ -3470,7 +3470,7 @@ int load_free_ino_cache(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
        int ret = 0;
        u64 root_gen = btrfs_root_generation(&root->root_item);
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return 0;
 
        /*
@@ -3514,7 +3514,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
        struct btrfs_io_ctl io_ctl;
        bool release_metadata = true;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return 0;
 
        memset(&io_ctl, 0, sizeof(io_ctl));
index 53dbeaf..87e7e3d 100644 (file)
@@ -305,7 +305,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
 out:
        kvfree(bitmap);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
@@ -454,7 +454,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans,
 out:
        kvfree(bitmap);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
@@ -851,7 +851,7 @@ int remove_from_free_space_tree(struct btrfs_trans_handle *trans,
 out:
        btrfs_free_path(path);
        if (ret)
-               btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
@@ -1047,7 +1047,7 @@ int add_to_free_space_tree(struct btrfs_trans_handle *trans,
 out:
        btrfs_free_path(path);
        if (ret)
-               btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
@@ -1193,7 +1193,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
 
 abort:
        fs_info->creating_free_space_tree = 0;
-       btrfs_abort_transaction(trans, tree_root, ret);
+       btrfs_abort_transaction(trans, ret);
        btrfs_end_transaction(trans, tree_root);
        return ret;
 }
@@ -1280,7 +1280,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
        return 0;
 
 abort:
-       btrfs_abort_transaction(trans, tree_root, ret);
+       btrfs_abort_transaction(trans, ret);
        btrfs_end_transaction(trans, tree_root);
        return ret;
 }
@@ -1333,7 +1333,7 @@ out:
        btrfs_free_path(path);
        mutex_unlock(&block_group->free_space_lock);
        if (ret)
-               btrfs_abort_transaction(trans, fs_info->free_space_root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
@@ -1410,7 +1410,7 @@ int remove_block_group_free_space(struct btrfs_trans_handle *trans,
 out:
        btrfs_free_path(path);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 }
 
index 70107f7..aa6faba 100644 (file)
@@ -38,7 +38,7 @@ static int caching_kthread(void *data)
        int slot;
        int ret;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return 0;
 
        path = btrfs_alloc_path();
@@ -141,7 +141,7 @@ static void start_caching(struct btrfs_root *root)
        int ret;
        u64 objectid;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return;
 
        spin_lock(&root->ino_cache_lock);
@@ -185,7 +185,7 @@ static void start_caching(struct btrfs_root *root)
 
 int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
 {
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return btrfs_find_free_objectid(root, objectid);
 
 again:
@@ -211,7 +211,7 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
 {
        struct btrfs_free_space_ctl *pinned = root->free_ino_pinned;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return;
 again:
        if (root->ino_cache_state == BTRFS_CACHE_FINISHED) {
@@ -251,7 +251,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
        struct rb_node *n;
        u64 count;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return;
 
        while (1) {
@@ -412,7 +412,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
        if (btrfs_root_refs(&root->root_item) == 0)
                return 0;
 
-       if (!btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE))
                return 0;
 
        path = btrfs_alloc_path();
@@ -458,7 +458,7 @@ again:
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_put;
        }
 
@@ -466,7 +466,7 @@ again:
                ret = btrfs_truncate_free_space_cache(root, trans, NULL, inode);
                if (ret) {
                        if (ret != -ENOSPC)
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                        goto out_put;
                }
        }
index 8078077..08dfc57 100644 (file)
@@ -60,6 +60,7 @@
 #include "hash.h"
 #include "props.h"
 #include "qgroup.h"
+#include "dedupe.h"
 
 struct btrfs_iget_args {
        struct btrfs_key *location;
@@ -105,8 +106,9 @@ static int btrfs_truncate(struct inode *inode);
 static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent);
 static noinline int cow_file_range(struct inode *inode,
                                   struct page *locked_page,
-                                  u64 start, u64 end, int *page_started,
-                                  unsigned long *nr_written, int unlock);
+                                  u64 start, u64 end, u64 delalloc_end,
+                                  int *page_started, unsigned long *nr_written,
+                                  int unlock, struct btrfs_dedupe_hash *hash);
 static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
                                           u64 len, u64 orig_start,
                                           u64 block_start, u64 block_len,
@@ -294,7 +296,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
                                   start, aligned_end, NULL,
                                   1, 1, extent_item_size, &extent_inserted);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -305,7 +307,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
                                   inline_len, compressed_size,
                                   compress_type, compressed_pages);
        if (ret && ret != -ENOSPC) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        } else if (ret == -ENOSPC) {
                ret = 1;
@@ -374,12 +376,12 @@ static inline int inode_need_compress(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
 
        /* force compress */
-       if (btrfs_test_opt(root, FORCE_COMPRESS))
+       if (btrfs_test_opt(root->fs_info, FORCE_COMPRESS))
                return 1;
        /* bad compression ratios */
        if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
                return 0;
-       if (btrfs_test_opt(root, COMPRESS) ||
+       if (btrfs_test_opt(root->fs_info, COMPRESS) ||
            BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS ||
            BTRFS_I(inode)->force_compress)
                return 1;
@@ -585,9 +587,27 @@ cont:
                        will_compress = 0;
                } else {
                        num_bytes = total_in;
+                       *num_added += 1;
+
+                       /*
+                        * The async work queues will take care of doing actual
+                        * allocation on disk for these compressed pages, and
+                        * will submit them to the elevator.
+                        */
+                       add_async_extent(async_cow, start, num_bytes,
+                                       total_compressed, pages, nr_pages_ret,
+                                       compress_type);
+
+                       if (start + num_bytes < end) {
+                               start += num_bytes;
+                               pages = NULL;
+                               cond_resched();
+                               goto again;
+                       }
+                       return;
                }
        }
-       if (!will_compress && pages) {
+       if (pages) {
                /*
                 * the compression code ran but failed to make things smaller,
                 * free any pages it allocated and our page pointer array
@@ -602,48 +622,28 @@ cont:
                nr_pages_ret = 0;
 
                /* flag the file so we don't compress in the future */
-               if (!btrfs_test_opt(root, FORCE_COMPRESS) &&
+               if (!btrfs_test_opt(root->fs_info, FORCE_COMPRESS) &&
                    !(BTRFS_I(inode)->force_compress)) {
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
                }
        }
-       if (will_compress) {
-               *num_added += 1;
-
-               /* the async work queues will take care of doing actual
-                * allocation on disk for these compressed pages,
-                * and will submit them to the elevator.
-                */
-               add_async_extent(async_cow, start, num_bytes,
-                                total_compressed, pages, nr_pages_ret,
-                                compress_type);
-
-               if (start + num_bytes < end) {
-                       start += num_bytes;
-                       pages = NULL;
-                       cond_resched();
-                       goto again;
-               }
-       } else {
 cleanup_and_bail_uncompressed:
-               /*
-                * No compression, but we still need to write the pages in
-                * the file we've been given so far.  redirty the locked
-                * page if it corresponds to our extent and set things up
-                * for the async work queue to run cow_file_range to do
-                * the normal delalloc dance
-                */
-               if (page_offset(locked_page) >= start &&
-                   page_offset(locked_page) <= end) {
-                       __set_page_dirty_nobuffers(locked_page);
-                       /* unlocked later on in the async handlers */
-               }
-               if (redirty)
-                       extent_range_redirty_for_io(inode, start, end);
-               add_async_extent(async_cow, start, end - start + 1,
-                                0, NULL, 0, BTRFS_COMPRESS_NONE);
-               *num_added += 1;
-       }
+       /*
+        * No compression, but we still need to write the pages in the file
+        * we've been given so far.  redirty the locked page if it corresponds
+        * to our extent and set things up for the async work queue to run
+        * cow_file_range to do the normal delalloc dance.
+        */
+       if (page_offset(locked_page) >= start &&
+           page_offset(locked_page) <= end)
+               __set_page_dirty_nobuffers(locked_page);
+               /* unlocked later on in the async handlers */
+
+       if (redirty)
+               extent_range_redirty_for_io(inode, start, end);
+       add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0,
+                        BTRFS_COMPRESS_NONE);
+       *num_added += 1;
 
        return;
 
@@ -712,7 +712,10 @@ retry:
                                             async_extent->start,
                                             async_extent->start +
                                             async_extent->ram_size - 1,
-                                            &page_started, &nr_written, 0);
+                                            async_extent->start +
+                                            async_extent->ram_size - 1,
+                                            &page_started, &nr_written, 0,
+                                            NULL);
 
                        /* JDM XXX */
 
@@ -925,9 +928,9 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
  */
 static noinline int cow_file_range(struct inode *inode,
                                   struct page *locked_page,
-                                  u64 start, u64 end, int *page_started,
-                                  unsigned long *nr_written,
-                                  int unlock)
+                                  u64 start, u64 end, u64 delalloc_end,
+                                  int *page_started, unsigned long *nr_written,
+                                  int unlock, struct btrfs_dedupe_hash *hash)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 alloc_hint = 0;
@@ -1156,7 +1159,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
                async_cow->start = start;
 
                if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
-                   !btrfs_test_opt(root, FORCE_COMPRESS))
+                   !btrfs_test_opt(root->fs_info, FORCE_COMPRESS))
                        cur_end = end;
                else
                        cur_end = min(end, start + SZ_512K - 1);
@@ -1418,7 +1421,8 @@ out_check:
                if (cow_start != (u64)-1) {
                        ret = cow_file_range(inode, locked_page,
                                             cow_start, found_key.offset - 1,
-                                            page_started, nr_written, 1);
+                                            end, page_started, nr_written, 1,
+                                            NULL);
                        if (ret) {
                                if (!nolock && nocow)
                                        btrfs_end_write_no_snapshoting(root);
@@ -1501,8 +1505,8 @@ out_check:
        }
 
        if (cow_start != (u64)-1) {
-               ret = cow_file_range(inode, locked_page, cow_start, end,
-                                    page_started, nr_written, 1);
+               ret = cow_file_range(inode, locked_page, cow_start, end, end,
+                                    page_started, nr_written, 1, NULL);
                if (ret)
                        goto error;
        }
@@ -1561,8 +1565,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
        } else if (!inode_need_compress(inode)) {
-               ret = cow_file_range(inode, locked_page, start, end,
-                                     page_started, nr_written, 1);
+               ret = cow_file_range(inode, locked_page, start, end, end,
+                                     page_started, nr_written, 1, NULL);
        } else {
                set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
                        &BTRFS_I(inode)->runtime_flags);
@@ -1740,7 +1744,7 @@ static void btrfs_set_bit_hook(struct inode *inode,
                }
 
                /* For sanity tests */
-               if (btrfs_test_is_dummy_root(root))
+               if (btrfs_is_testing(root->fs_info))
                        return;
 
                __percpu_counter_add(&root->fs_info->delalloc_bytes, len,
@@ -1799,7 +1803,7 @@ static void btrfs_clear_bit_hook(struct inode *inode,
                        btrfs_delalloc_release_metadata(inode, len);
 
                /* For sanity tests. */
-               if (btrfs_test_is_dummy_root(root))
+               if (btrfs_is_testing(root->fs_info))
                        return;
 
                if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
@@ -1822,6 +1826,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
 /*
  * extent_io.c merge_bio_hook, this must check the chunk tree to make sure
  * we don't create bios that span stripes or chunks
+ *
+ * return 1 if page cannot be merged to bio
+ * return 0 if page can be merged to bio
+ * return error otherwise
  */
 int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio,
@@ -1840,8 +1848,8 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
        map_length = length;
        ret = btrfs_map_block(root->fs_info, bio_op(bio), logical,
                              &map_length, NULL, 0);
-       /* Will always return 0 with map_multi == NULL */
-       BUG_ON(ret < 0);
+       if (ret < 0)
+               return ret;
        if (map_length < length + size)
                return 1;
        return 0;
@@ -2594,7 +2602,7 @@ again:
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                        sizeof(*extent));
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_free_path;
        }
 
@@ -2621,7 +2629,7 @@ again:
                        backref->root_id, backref->inum,
                        new->file_pos); /* start - extent_offset */
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_free_path;
        }
 
@@ -2890,7 +2898,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                ret = btrfs_update_inode_fallback(trans, root, inode);
                if (ret) /* -ENOMEM or corruption */
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -2950,7 +2958,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                           ordered_extent->file_offset, ordered_extent->len,
                           trans->transid);
        if (ret < 0) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_unlock;
        }
 
@@ -2960,7 +2968,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
        btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        ret = btrfs_update_inode_fallback(trans, root, inode);
        if (ret) { /* -ENOMEM or corruption */
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_unlock;
        }
        ret = 0;
@@ -3204,7 +3212,7 @@ void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
                ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root,
                                            root->root_key.objectid);
                if (ret)
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                else
                        clear_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
                                  &root->state);
@@ -3295,7 +3303,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
                        if (ret != -EEXIST) {
                                clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                                          &BTRFS_I(inode)->runtime_flags);
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                return ret;
                        }
                }
@@ -3307,7 +3315,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
                ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root,
                                               root->root_key.objectid);
                if (ret && ret != -EEXIST) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        return ret;
                }
        }
@@ -3427,10 +3435,10 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                found_key.offset = 0;
                inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
                ret = PTR_ERR_OR_ZERO(inode);
-               if (ret && ret != -ESTALE)
+               if (ret && ret != -ENOENT)
                        goto out;
 
-               if (ret == -ESTALE && root == root->fs_info->tree_root) {
+               if (ret == -ENOENT && root == root->fs_info->tree_root) {
                        struct btrfs_root *dead_root;
                        struct btrfs_fs_info *fs_info = root->fs_info;
                        int is_dead_root = 0;
@@ -3466,7 +3474,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                 * Inode is already gone but the orphan item is still there,
                 * kill the orphan item.
                 */
-               if (ret == -ESTALE) {
+               if (ret == -ENOENT) {
                        trans = btrfs_start_transaction(root, 1);
                        if (IS_ERR(trans)) {
                                ret = PTR_ERR(trans);
@@ -3625,7 +3633,7 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
 /*
  * read an inode from the btree into the in-memory inode
  */
-static void btrfs_read_locked_inode(struct inode *inode)
+static int btrfs_read_locked_inode(struct inode *inode)
 {
        struct btrfs_path *path;
        struct extent_buffer *leaf;
@@ -3644,14 +3652,19 @@ static void btrfs_read_locked_inode(struct inode *inode)
                filled = true;
 
        path = btrfs_alloc_path();
-       if (!path)
+       if (!path) {
+               ret = -ENOMEM;
                goto make_bad;
+       }
 
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
 
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
-       if (ret)
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
                goto make_bad;
+       }
 
        leaf = path->nodes[0];
 
@@ -3804,11 +3817,12 @@ cache_acl:
        }
 
        btrfs_update_iflags(inode);
-       return;
+       return 0;
 
 make_bad:
        btrfs_free_path(path);
        make_bad_inode(inode);
+       return ret;
 }
 
 /*
@@ -4006,20 +4020,20 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                btrfs_info(root->fs_info,
                        "failed to delete reference to %.*s, inode %llu parent %llu",
                        name_len, name, ino, dir_ino);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto err;
        }
 skip_backref:
        ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto err;
        }
 
        ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
                                         inode, dir_ino);
        if (ret != 0 && ret != -ENOENT) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto err;
        }
 
@@ -4028,7 +4042,7 @@ skip_backref:
        if (ret == -ENOENT)
                ret = 0;
        else if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 err:
        btrfs_free_path(path);
        if (ret)
@@ -4142,7 +4156,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
        WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
        btrfs_release_path(path);
@@ -4152,7 +4166,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
                                 dir_ino, &index, name, name_len);
        if (ret < 0) {
                if (ret != -ENOENT) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
                di = btrfs_search_dir_index_item(root, path, dir_ino,
@@ -4162,7 +4176,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
                                ret = -ENOENT;
                        else
                                ret = PTR_ERR(di);
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
@@ -4175,7 +4189,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
 
        ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -4184,7 +4198,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
        dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
        ret = btrfs_update_inode_fallback(trans, root, dir);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 out:
        btrfs_free_path(path);
        return ret;
@@ -4196,6 +4210,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        int err = 0;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_trans_handle *trans;
+       u64 last_unlink_trans;
 
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
@@ -4218,11 +4233,27 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (err)
                goto out;
 
+       last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
+
        /* now the directory is empty */
        err = btrfs_unlink_inode(trans, root, dir, d_inode(dentry),
                                 dentry->d_name.name, dentry->d_name.len);
-       if (!err)
+       if (!err) {
                btrfs_i_size_write(inode, 0);
+               /*
+                * Propagate the last_unlink_trans value of the deleted dir to
+                * its parent directory. This is to prevent an unrecoverable
+                * log tree in the case we do something like this:
+                * 1) create dir foo
+                * 2) create snapshot under dir foo
+                * 3) delete the snapshot
+                * 4) rmdir foo
+                * 5) mkdir foo
+                * 6) fsync foo or some file inside foo
+                */
+               if (last_unlink_trans >= trans->transid)
+                       BTRFS_I(dir)->last_unlink_trans = last_unlink_trans;
+       }
 out:
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
@@ -4505,7 +4536,6 @@ search_again:
                                                              pending_del_nr);
                                        if (err) {
                                                btrfs_abort_transaction(trans,
-                                                                       root,
                                                                        err);
                                                goto error;
                                        }
@@ -4517,8 +4547,7 @@ search_again:
                                                             item_end,
                                                             new_size);
                                if (err) {
-                                       btrfs_abort_transaction(trans,
-                                                               root, err);
+                                       btrfs_abort_transaction(trans, err);
                                        goto error;
                                }
                        } else if (test_bit(BTRFS_ROOT_REF_COWS,
@@ -4582,8 +4611,7 @@ delete:
                                                pending_del_slot,
                                                pending_del_nr);
                                if (ret) {
-                                       btrfs_abort_transaction(trans,
-                                                               root, ret);
+                                       btrfs_abort_transaction(trans, ret);
                                        goto error;
                                }
                                pending_del_nr = 0;
@@ -4616,7 +4644,7 @@ out:
                ret = btrfs_del_items(trans, root, path, pending_del_slot,
                                      pending_del_nr);
                if (ret)
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
        }
 error:
        if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
@@ -4785,7 +4813,7 @@ static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode,
 
        ret = btrfs_drop_extents(trans, root, inode, offset, offset + len, 1);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_end_transaction(trans, root);
                return ret;
        }
@@ -4793,7 +4821,7 @@ static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode,
        ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset,
                                       0, 0, len, 0, len, 0, 0, 0);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        else
                btrfs_update_inode(trans, root, inode);
        btrfs_end_transaction(trans, root);
@@ -5020,7 +5048,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
                        i_size_write(inode, BTRFS_I(inode)->disk_i_size);
                        err = btrfs_orphan_del(trans, inode);
                        if (err)
-                               btrfs_abort_transaction(trans, root, err);
+                               btrfs_abort_transaction(trans, err);
                        btrfs_end_transaction(trans, root);
                }
        }
@@ -5158,11 +5186,18 @@ void btrfs_evict_inode(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_block_rsv *rsv, *global_rsv;
        int steal_from_global = 0;
-       u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
+       u64 min_size;
        int ret;
 
        trace_btrfs_inode_evict(inode);
 
+       if (!root) {
+               kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
+               return;
+       }
+
+       min_size = btrfs_calc_trunc_metadata_size(root, 1);
+
        evict_inode_truncate_pages(inode);
 
        if (inode->i_nlink &&
@@ -5594,7 +5629,9 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                return ERR_PTR(-ENOMEM);
 
        if (inode->i_state & I_NEW) {
-               btrfs_read_locked_inode(inode);
+               int ret;
+
+               ret = btrfs_read_locked_inode(inode);
                if (!is_bad_inode(inode)) {
                        inode_tree_add(inode);
                        unlock_new_inode(inode);
@@ -5603,7 +5640,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                } else {
                        unlock_new_inode(inode);
                        iput(inode);
-                       inode = ERR_PTR(-ESTALE);
+                       ASSERT(ret < 0);
+                       inode = ERR_PTR(ret < 0 ? ret : -ESTALE);
                }
        }
 
@@ -6239,9 +6277,9 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        btrfs_inherit_iflags(inode, dir);
 
        if (S_ISREG(mode)) {
-               if (btrfs_test_opt(root, NODATASUM))
+               if (btrfs_test_opt(root->fs_info, NODATASUM))
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-               if (btrfs_test_opt(root, NODATACOW))
+               if (btrfs_test_opt(root->fs_info, NODATACOW))
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW |
                                BTRFS_INODE_NODATASUM;
        }
@@ -6319,7 +6357,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
        if (ret == -EEXIST || ret == -EOVERFLOW)
                goto fail_dir_item;
        else if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                return ret;
        }
 
@@ -6330,7 +6368,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
                current_fs_time(parent_inode->i_sb);
        ret = btrfs_update_inode(trans, root, parent_inode);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        return ret;
 
 fail_dir_item:
@@ -8197,7 +8235,7 @@ static void btrfs_end_dio_bio(struct bio *bio)
        if (err)
                btrfs_warn(BTRFS_I(dip->inode)->root->fs_info,
                           "direct IO failed ino %llu rw %d,%u sector %#Lx len %u err no %d",
-                          btrfs_ino(dip->inode), bio_op(bio), bio->bi_rw,
+                          btrfs_ino(dip->inode), bio_op(bio), bio->bi_opf,
                           (unsigned long long)bio->bi_iter.bi_sector,
                           bio->bi_iter.bi_size, err);
 
@@ -8361,7 +8399,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,
        if (!bio)
                return -ENOMEM;
 
-       bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_rw);
+       bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
        bio->bi_private = dip;
        bio->bi_end_io = btrfs_end_dio_bio;
        btrfs_io_bio(bio)->logical = file_offset;
@@ -8399,7 +8437,7 @@ next_block:
                                                  start_sector, GFP_NOFS);
                        if (!bio)
                                goto out_err;
-                       bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_rw);
+                       bio_set_op_attrs(bio, bio_op(orig_bio), orig_bio->bi_opf);
                        bio->bi_private = dip;
                        bio->bi_end_io = btrfs_end_dio_bio;
                        btrfs_io_bio(bio)->logical = file_offset;
@@ -9385,25 +9423,25 @@ int btrfs_init_cachep(void)
 
        btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle",
                        sizeof(struct btrfs_trans_handle), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
        if (!btrfs_trans_handle_cachep)
                goto fail;
 
        btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction",
                        sizeof(struct btrfs_transaction), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
        if (!btrfs_transaction_cachep)
                goto fail;
 
        btrfs_path_cachep = kmem_cache_create("btrfs_path",
                        sizeof(struct btrfs_path), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!btrfs_path_cachep)
                goto fail;
 
        btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space",
                        sizeof(struct btrfs_free_space), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!btrfs_free_space_cachep)
                goto fail;
 
@@ -9553,7 +9591,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
                        ret = btrfs_update_inode(trans, root, old_inode);
        }
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9573,7 +9611,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
                        ret = btrfs_update_inode(trans, dest, new_inode);
        }
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9581,7 +9619,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
                             new_dentry->d_name.name,
                             new_dentry->d_name.len, 0, old_idx);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9589,7 +9627,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
                             old_dentry->d_name.name,
                             old_dentry->d_name.len, 0, new_idx);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9828,7 +9866,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        ret = btrfs_update_inode(trans, root, old_inode);
        }
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9852,7 +9890,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!ret && new_inode->i_nlink == 0)
                        ret = btrfs_orphan_add(trans, d_inode(new_dentry));
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out_fail;
                }
        }
@@ -9861,7 +9899,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                             new_dentry->d_name.name,
                             new_dentry->d_name.len, 0, index);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_fail;
        }
 
@@ -9881,7 +9919,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                                old_dentry);
 
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out_fail;
                }
        }
@@ -10307,7 +10345,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
                if (ret) {
                        btrfs_free_reserved_extent(root, ins.objectid,
                                                   ins.offset, 0);
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        if (own_trans)
                                btrfs_end_transaction(trans, root);
                        break;
@@ -10367,7 +10405,7 @@ next:
                ret = btrfs_update_inode(trans, root, inode);
 
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        if (own_trans)
                                btrfs_end_transaction(trans, root);
                        break;
index 0517356..14ed1e9 100644 (file)
@@ -561,7 +561,7 @@ static noinline int create_subvol(struct inode *dir,
        new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
        if (IS_ERR(new_root)) {
                ret = PTR_ERR(new_root);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -570,7 +570,7 @@ static noinline int create_subvol(struct inode *dir,
        ret = btrfs_create_subvol_root(trans, new_root, root, new_dirid);
        if (ret) {
                /* We potentially lose an unused inode item here */
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -583,7 +583,7 @@ static noinline int create_subvol(struct inode *dir,
         */
        ret = btrfs_set_inode_index(dir, &index);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -591,7 +591,7 @@ static noinline int create_subvol(struct inode *dir,
                                    name, namelen, dir, &key,
                                    BTRFS_FT_DIR, index);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -608,7 +608,7 @@ static noinline int create_subvol(struct inode *dir,
                                  root_item->uuid, BTRFS_UUID_KEY_SUBVOL,
                                  objectid);
        if (ret)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 
 fail:
        kfree(root_item);
@@ -1948,8 +1948,7 @@ static noinline int key_in_sk(struct btrfs_key *key,
        return 1;
 }
 
-static noinline int copy_to_sk(struct btrfs_root *root,
-                              struct btrfs_path *path,
+static noinline int copy_to_sk(struct btrfs_path *path,
                               struct btrfs_key *key,
                               struct btrfs_ioctl_search_key *sk,
                               size_t *buf_size,
@@ -2120,7 +2119,7 @@ static noinline int search_ioctl(struct inode *inode,
                                ret = 0;
                        goto err;
                }
-               ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf,
+               ret = copy_to_sk(path, &key, sk, buf_size, ubuf,
                                 &sk_offset, &num_found);
                btrfs_release_path(path);
                if (ret)
@@ -2406,7 +2405,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                 * rmdir(2).
                 */
                err = -EPERM;
-               if (!btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED))
+               if (!btrfs_test_opt(root->fs_info, USER_SUBVOL_RM_ALLOWED))
                        goto out_dput;
 
                /*
@@ -2489,7 +2488,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                dentry->d_name.len);
        if (ret) {
                err = ret;
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_end_trans;
        }
 
@@ -2505,7 +2504,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                        root->fs_info->tree_root,
                                        dest->root_key.objectid);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        err = ret;
                        goto out_end_trans;
                }
@@ -2515,7 +2514,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                  dest->root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
                                  dest->root_key.objectid);
        if (ret && ret != -ENOENT) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                err = ret;
                goto out_end_trans;
        }
@@ -2525,7 +2524,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                                          BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                          dest->root_key.objectid);
                if (ret && ret != -ENOENT) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        err = ret;
                        goto out_end_trans;
                }
@@ -3292,7 +3291,7 @@ static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
 
        ret = btrfs_update_inode(trans, root, inode);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_end_transaction(trans, root);
                goto out;
        }
@@ -3694,7 +3693,7 @@ process_slot:
                                if (ret) {
                                        if (ret != -EOPNOTSUPP)
                                                btrfs_abort_transaction(trans,
-                                                               root, ret);
+                                                                       ret);
                                        btrfs_end_transaction(trans, root);
                                        goto out;
                                }
@@ -3702,8 +3701,7 @@ process_slot:
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
                                if (ret) {
-                                       btrfs_abort_transaction(trans, root,
-                                                               ret);
+                                       btrfs_abort_transaction(trans, ret);
                                        btrfs_end_transaction(trans, root);
                                        goto out;
                                }
@@ -3735,7 +3733,6 @@ process_slot:
                                                        new_key.offset - datao);
                                        if (ret) {
                                                btrfs_abort_transaction(trans,
-                                                                       root,
                                                                        ret);
                                                btrfs_end_transaction(trans,
                                                                      root);
@@ -3772,7 +3769,6 @@ process_slot:
                                if (ret) {
                                        if (ret != -EOPNOTSUPP)
                                                btrfs_abort_transaction(trans,
-                                                                       root,
                                                                        ret);
                                        btrfs_end_transaction(trans, root);
                                        goto out;
@@ -3828,7 +3824,7 @@ process_slot:
                                         last_dest_end, destoff + len, 1);
                if (ret) {
                        if (ret != -EOPNOTSUPP)
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                        btrfs_end_transaction(trans, root);
                        goto out;
                }
@@ -5164,13 +5160,13 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
                                          BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                          root->root_key.objectid);
                if (ret < 0 && ret != -EEXIST) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
        }
        ret = btrfs_commit_transaction(trans, root);
        if (ret < 0) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
index aca8264..3b78d38 100644 (file)
@@ -1122,7 +1122,7 @@ int __init ordered_data_init(void)
 {
        btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
                                     sizeof(struct btrfs_ordered_extent), 0,
-                                    SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                    SLAB_MEM_SPREAD,
                                     NULL);
        if (!btrfs_ordered_extent_cache)
                return -ENOMEM;
index 3699212..cf0b444 100644 (file)
@@ -350,6 +350,7 @@ int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root,
                               struct btrfs_root *parent_root)
 {
+       struct super_block *sb = root->fs_info->sb;
        struct btrfs_key key;
        struct inode *parent_inode, *child_inode;
        int ret;
@@ -358,12 +359,11 @@ int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
-       parent_inode = btrfs_iget(parent_root->fs_info->sb, &key,
-                                 parent_root, NULL);
+       parent_inode = btrfs_iget(sb, &key, parent_root, NULL);
        if (IS_ERR(parent_inode))
                return PTR_ERR(parent_inode);
 
-       child_inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
+       child_inode = btrfs_iget(sb, &key, root, NULL);
        if (IS_ERR(child_inode)) {
                iput(parent_inode);
                return PTR_ERR(child_inode);
index 9d4c05b..93ee1c1 100644 (file)
@@ -571,7 +571,7 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        struct btrfs_key key;
 
-       if (btrfs_test_is_dummy_root(quota_root))
+       if (btrfs_is_testing(quota_root->fs_info))
                return 0;
 
        path = btrfs_alloc_path();
@@ -728,7 +728,7 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
        int ret;
        int slot;
 
-       if (btrfs_test_is_dummy_root(root))
+       if (btrfs_is_testing(root->fs_info))
                return 0;
 
        key.objectid = 0;
@@ -1453,9 +1453,10 @@ int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-struct btrfs_qgroup_extent_record
-*btrfs_qgroup_insert_dirty_extent(struct btrfs_delayed_ref_root *delayed_refs,
-                                 struct btrfs_qgroup_extent_record *record)
+struct btrfs_qgroup_extent_record *
+btrfs_qgroup_insert_dirty_extent(struct btrfs_fs_info *fs_info,
+                                struct btrfs_delayed_ref_root *delayed_refs,
+                                struct btrfs_qgroup_extent_record *record)
 {
        struct rb_node **p = &delayed_refs->dirty_extent_root.rb_node;
        struct rb_node *parent_node = NULL;
@@ -1463,7 +1464,7 @@ struct btrfs_qgroup_extent_record
        u64 bytenr = record->bytenr;
 
        assert_spin_locked(&delayed_refs->lock);
-       trace_btrfs_qgroup_insert_dirty_extent(record);
+       trace_btrfs_qgroup_insert_dirty_extent(fs_info, record);
 
        while (*p) {
                parent_node = *p;
@@ -1595,8 +1596,8 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
                cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq);
                cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq);
 
-               trace_qgroup_update_counters(qg->qgroupid, cur_old_count,
-                                            cur_new_count);
+               trace_qgroup_update_counters(fs_info, qg->qgroupid,
+                                            cur_old_count, cur_new_count);
 
                /* Rfer update part */
                if (cur_old_count == 0 && cur_new_count > 0) {
@@ -1687,8 +1688,8 @@ btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans,
                goto out_free;
        BUG_ON(!fs_info->quota_root);
 
-       trace_btrfs_qgroup_account_extent(bytenr, num_bytes, nr_old_roots,
-                                         nr_new_roots);
+       trace_btrfs_qgroup_account_extent(fs_info, bytenr, num_bytes,
+                                         nr_old_roots, nr_new_roots);
 
        qgroups = ulist_alloc(GFP_NOFS);
        if (!qgroups) {
@@ -1759,7 +1760,7 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
                record = rb_entry(node, struct btrfs_qgroup_extent_record,
                                  node);
 
-               trace_btrfs_qgroup_account_extents(record);
+               trace_btrfs_qgroup_account_extents(fs_info, record);
 
                if (!ret) {
                        /*
@@ -2195,7 +2196,7 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans)
 {
        if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq)
                return;
-       btrfs_err(trans->root->fs_info,
+       btrfs_err(trans->fs_info,
                "qgroups not uptodate in trans handle %p:  list is%s empty, "
                "seq is %#x.%x",
                trans, list_empty(&trans->qgroup_ref_list) ? "" : " not",
index ecb2c14..710887c 100644 (file)
@@ -63,9 +63,10 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info);
 struct btrfs_delayed_extent_op;
 int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info);
-struct btrfs_qgroup_extent_record
-*btrfs_qgroup_insert_dirty_extent(struct btrfs_delayed_ref_root *delayed_refs,
-                                 struct btrfs_qgroup_extent_record *record);
+struct btrfs_qgroup_extent_record *
+btrfs_qgroup_insert_dirty_extent(struct btrfs_fs_info *fs_info,
+                                struct btrfs_delayed_ref_root *delayed_refs,
+                                struct btrfs_qgroup_extent_record *record);
 int
 btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans,
                            struct btrfs_fs_info *fs_info,
@@ -88,7 +89,7 @@ static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info,
                                                 u64 ref_root, u64 num_bytes)
 {
        btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes);
-       trace_btrfs_qgroup_free_delayed_ref(ref_root, num_bytes);
+       trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes);
 }
 void assert_qgroups_uptodate(struct btrfs_trans_handle *trans);
 
index fc067b0..b26a5ae 100644 (file)
@@ -235,12 +235,12 @@ static void backref_cache_cleanup(struct backref_cache *cache)
        cache->last_trans = 0;
 
        for (i = 0; i < BTRFS_MAX_LEVEL; i++)
-               BUG_ON(!list_empty(&cache->pending[i]));
-       BUG_ON(!list_empty(&cache->changed));
-       BUG_ON(!list_empty(&cache->detached));
-       BUG_ON(!RB_EMPTY_ROOT(&cache->rb_root));
-       BUG_ON(cache->nr_nodes);
-       BUG_ON(cache->nr_edges);
+               ASSERT(list_empty(&cache->pending[i]));
+       ASSERT(list_empty(&cache->changed));
+       ASSERT(list_empty(&cache->detached));
+       ASSERT(RB_EMPTY_ROOT(&cache->rb_root));
+       ASSERT(!cache->nr_nodes);
+       ASSERT(!cache->nr_edges);
 }
 
 static struct backref_node *alloc_backref_node(struct backref_cache *cache)
@@ -1171,8 +1171,12 @@ out:
                        lower = list_entry(useless.next,
                                           struct backref_node, list);
                        list_del_init(&lower->list);
+                       if (lower == node)
+                               node = NULL;
                        free_backref_node(cache, lower);
                }
+
+               free_backref_node(cache, node);
                return ERR_PTR(err);
        }
        ASSERT(!node || !node->detached);
@@ -1719,7 +1723,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
                                           btrfs_header_owner(leaf),
                                           key.objectid, key.offset);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        break;
                }
 
@@ -1727,7 +1731,7 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
                                        parent, btrfs_header_owner(leaf),
                                        key.objectid, key.offset);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        break;
                }
        }
index f1c3086..7fd7e18 100644 (file)
@@ -150,7 +150,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 
        ret = btrfs_search_slot(trans, root, key, path, 0, 1);
        if (ret < 0) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -176,20 +176,20 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
                ret = btrfs_search_slot(trans, root, key, path,
                                -1, 1);
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
                ret = btrfs_del_item(trans, root, path);
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
                btrfs_release_path(path);
                ret = btrfs_insert_empty_item(trans, root, path,
                                key, sizeof(*item));
                if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
                l = path->nodes[0];
@@ -448,7 +448,7 @@ again:
        ret = btrfs_insert_empty_item(trans, tree_root, path, &key,
                                      sizeof(*ref) + name_len);
        if (ret) {
-               btrfs_abort_transaction(trans, tree_root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_free_path(path);
                return ret;
        }
index e08b6bc..1d195d2 100644 (file)
@@ -3785,27 +3785,27 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
        if (fs_info->scrub_workers_refcnt == 0) {
                if (is_dev_replace)
                        fs_info->scrub_workers =
-                               btrfs_alloc_workqueue("scrub", flags,
+                               btrfs_alloc_workqueue(fs_info, "scrub", flags,
                                                      1, 4);
                else
                        fs_info->scrub_workers =
-                               btrfs_alloc_workqueue("scrub", flags,
+                               btrfs_alloc_workqueue(fs_info, "scrub", flags,
                                                      max_active, 4);
                if (!fs_info->scrub_workers)
                        goto fail_scrub_workers;
 
                fs_info->scrub_wr_completion_workers =
-                       btrfs_alloc_workqueue("scrubwrc", flags,
+                       btrfs_alloc_workqueue(fs_info, "scrubwrc", flags,
                                              max_active, 2);
                if (!fs_info->scrub_wr_completion_workers)
                        goto fail_scrub_wr_completion_workers;
 
                fs_info->scrub_nocow_workers =
-                       btrfs_alloc_workqueue("scrubnc", flags, 1, 0);
+                       btrfs_alloc_workqueue(fs_info, "scrubnc", flags, 1, 0);
                if (!fs_info->scrub_nocow_workers)
                        goto fail_scrub_nocow_workers;
                fs_info->scrub_parity_workers =
-                       btrfs_alloc_workqueue("scrubparity", flags,
+                       btrfs_alloc_workqueue(fs_info, "scrubparity", flags,
                                              max_active, 2);
                if (!fs_info->scrub_parity_workers)
                        goto fail_scrub_parity_workers;
@@ -3860,7 +3860,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
 
        if (fs_info->chunk_root->sectorsize != PAGE_SIZE) {
                /* not supported for data w/o checksums */
-               btrfs_err(fs_info,
+               btrfs_err_rl(fs_info,
                           "scrub: size assumption sectorsize != PAGE_SIZE "
                           "(%d != %lu) fails",
                       fs_info->chunk_root->sectorsize, PAGE_SIZE);
index b71dd29..efe129f 100644 (file)
@@ -231,7 +231,6 @@ struct pending_dir_move {
        u64 parent_ino;
        u64 ino;
        u64 gen;
-       bool is_orphan;
        struct list_head update_refs;
 };
 
@@ -274,6 +273,39 @@ struct name_cache_entry {
        char name[];
 };
 
+static void inconsistent_snapshot_error(struct send_ctx *sctx,
+                                       enum btrfs_compare_tree_result result,
+                                       const char *what)
+{
+       const char *result_string;
+
+       switch (result) {
+       case BTRFS_COMPARE_TREE_NEW:
+               result_string = "new";
+               break;
+       case BTRFS_COMPARE_TREE_DELETED:
+               result_string = "deleted";
+               break;
+       case BTRFS_COMPARE_TREE_CHANGED:
+               result_string = "updated";
+               break;
+       case BTRFS_COMPARE_TREE_SAME:
+               ASSERT(0);
+               result_string = "unchanged";
+               break;
+       default:
+               ASSERT(0);
+               result_string = "unexpected";
+       }
+
+       btrfs_err(sctx->send_root->fs_info,
+                 "Send: inconsistent snapshot, found %s %s for inode %llu without updated inode item, send root is %llu, parent root is %llu",
+                 result_string, what, sctx->cmp_key->objectid,
+                 sctx->send_root->root_key.objectid,
+                 (sctx->parent_root ?
+                  sctx->parent_root->root_key.objectid : 0));
+}
+
 static int is_waiting_for_move(struct send_ctx *sctx, u64 ino);
 
 static struct waiting_dir_move *
@@ -1861,7 +1893,8 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
         * was already unlinked/moved, so we can safely assume that we will not
         * overwrite anything at this point in time.
         */
-       if (other_inode > sctx->send_progress) {
+       if (other_inode > sctx->send_progress ||
+           is_waiting_for_move(sctx, other_inode)) {
                ret = get_inode_info(sctx->parent_root, other_inode, NULL,
                                who_gen, NULL, NULL, NULL, NULL);
                if (ret < 0)
@@ -2502,6 +2535,8 @@ verbose_printk("btrfs: send_utimes %llu\n", ino);
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
        ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0);
+       if (ret > 0)
+               ret = -ENOENT;
        if (ret < 0)
                goto out;
 
@@ -2947,6 +2982,10 @@ static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen,
                }
 
                if (loc.objectid > send_progress) {
+                       struct orphan_dir_info *odi;
+
+                       odi = get_orphan_dir_info(sctx, dir);
+                       free_orphan_dir_info(sctx, odi);
                        ret = 0;
                        goto out;
                }
@@ -3047,7 +3086,6 @@ static int add_pending_dir_move(struct send_ctx *sctx,
        pm->parent_ino = parent_ino;
        pm->ino = ino;
        pm->gen = ino_gen;
-       pm->is_orphan = is_orphan;
        INIT_LIST_HEAD(&pm->list);
        INIT_LIST_HEAD(&pm->update_refs);
        RB_CLEAR_NODE(&pm->node);
@@ -3113,6 +3151,48 @@ static struct pending_dir_move *get_pending_dir_moves(struct send_ctx *sctx,
        return NULL;
 }
 
+static int path_loop(struct send_ctx *sctx, struct fs_path *name,
+                    u64 ino, u64 gen, u64 *ancestor_ino)
+{
+       int ret = 0;
+       u64 parent_inode = 0;
+       u64 parent_gen = 0;
+       u64 start_ino = ino;
+
+       *ancestor_ino = 0;
+       while (ino != BTRFS_FIRST_FREE_OBJECTID) {
+               fs_path_reset(name);
+
+               if (is_waiting_for_rm(sctx, ino))
+                       break;
+               if (is_waiting_for_move(sctx, ino)) {
+                       if (*ancestor_ino == 0)
+                               *ancestor_ino = ino;
+                       ret = get_first_ref(sctx->parent_root, ino,
+                                           &parent_inode, &parent_gen, name);
+               } else {
+                       ret = __get_cur_name_and_parent(sctx, ino, gen,
+                                                       &parent_inode,
+                                                       &parent_gen, name);
+                       if (ret > 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret < 0)
+                       break;
+               if (parent_inode == start_ino) {
+                       ret = 1;
+                       if (*ancestor_ino == 0)
+                               *ancestor_ino = ino;
+                       break;
+               }
+               ino = parent_inode;
+               gen = parent_gen;
+       }
+       return ret;
+}
+
 static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
 {
        struct fs_path *from_path = NULL;
@@ -3123,6 +3203,8 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        u64 parent_ino, parent_gen;
        struct waiting_dir_move *dm = NULL;
        u64 rmdir_ino = 0;
+       u64 ancestor;
+       bool is_orphan;
        int ret;
 
        name = fs_path_alloc();
@@ -3135,9 +3217,10 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
        dm = get_waiting_dir_move(sctx, pm->ino);
        ASSERT(dm);
        rmdir_ino = dm->rmdir_ino;
+       is_orphan = dm->orphanized;
        free_waiting_dir_move(sctx, dm);
 
-       if (pm->is_orphan) {
+       if (is_orphan) {
                ret = gen_unique_name(sctx, pm->ino,
                                      pm->gen, from_path);
        } else {
@@ -3155,6 +3238,24 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                goto out;
 
        sctx->send_progress = sctx->cur_ino + 1;
+       ret = path_loop(sctx, name, pm->ino, pm->gen, &ancestor);
+       if (ret < 0)
+               goto out;
+       if (ret) {
+               LIST_HEAD(deleted_refs);
+               ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID);
+               ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor,
+                                          &pm->update_refs, &deleted_refs,
+                                          is_orphan);
+               if (ret < 0)
+                       goto out;
+               if (rmdir_ino) {
+                       dm = get_waiting_dir_move(sctx, pm->ino);
+                       ASSERT(dm);
+                       dm->rmdir_ino = rmdir_ino;
+               }
+               goto out;
+       }
        fs_path_reset(name);
        to_path = name;
        name = NULL;
@@ -3174,7 +3275,7 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
                        /* already deleted */
                        goto finish;
                }
-               ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino + 1);
+               ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino);
                if (ret < 0)
                        goto out;
                if (!ret)
@@ -3204,8 +3305,18 @@ finish:
         * and old parent(s).
         */
        list_for_each_entry(cur, &pm->update_refs, list) {
-               if (cur->dir == rmdir_ino)
+               /*
+                * The parent inode might have been deleted in the send snapshot
+                */
+               ret = get_inode_info(sctx->send_root, cur->dir, NULL,
+                                    NULL, NULL, NULL, NULL, NULL);
+               if (ret == -ENOENT) {
+                       ret = 0;
                        continue;
+               }
+               if (ret < 0)
+                       goto out;
+
                ret = send_utimes(sctx, cur->dir, cur->dir_gen);
                if (ret < 0)
                        goto out;
@@ -3325,6 +3436,7 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx,
        u64 left_gen;
        u64 right_gen;
        int ret = 0;
+       struct waiting_dir_move *wdm;
 
        if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves))
                return 0;
@@ -3383,7 +3495,8 @@ static int wait_for_dest_dir_move(struct send_ctx *sctx,
                goto out;
        }
 
-       if (is_waiting_for_move(sctx, di_key.objectid)) {
+       wdm = get_waiting_dir_move(sctx, di_key.objectid);
+       if (wdm && !wdm->orphanized) {
                ret = add_pending_dir_move(sctx,
                                           sctx->cur_ino,
                                           sctx->cur_inode_gen,
@@ -3470,7 +3583,8 @@ static int wait_for_parent_move(struct send_ctx *sctx,
                        ret = is_ancestor(sctx->parent_root,
                                          sctx->cur_ino, sctx->cur_inode_gen,
                                          ino, path_before);
-                       break;
+                       if (ret)
+                               break;
                }
 
                fs_path_reset(path_before);
@@ -3643,11 +3757,26 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                goto out;
                        if (ret) {
                                struct name_cache_entry *nce;
+                               struct waiting_dir_move *wdm;
 
                                ret = orphanize_inode(sctx, ow_inode, ow_gen,
                                                cur->full_path);
                                if (ret < 0)
                                        goto out;
+
+                               /*
+                                * If ow_inode has its rename operation delayed
+                                * make sure that its orphanized name is used in
+                                * the source path when performing its rename
+                                * operation.
+                                */
+                               if (is_waiting_for_move(sctx, ow_inode)) {
+                                       wdm = get_waiting_dir_move(sctx,
+                                                                  ow_inode);
+                                       ASSERT(wdm);
+                                       wdm->orphanized = true;
+                               }
+
                                /*
                                 * Make sure we clear our orphanized inode's
                                 * name from the name cache. This is because the
@@ -3663,6 +3792,19 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                        name_cache_delete(sctx, nce);
                                        kfree(nce);
                                }
+
+                               /*
+                                * ow_inode might currently be an ancestor of
+                                * cur_ino, therefore compute valid_path (the
+                                * current path of cur_ino) again because it
+                                * might contain the pre-orphanization name of
+                                * ow_inode, which is no longer valid.
+                                */
+                               fs_path_reset(valid_path);
+                               ret = get_cur_path(sctx, sctx->cur_ino,
+                                          sctx->cur_inode_gen, valid_path);
+                               if (ret < 0)
+                                       goto out;
                        } else {
                                ret = send_unlink(sctx, cur->full_path);
                                if (ret < 0)
@@ -5602,7 +5744,10 @@ static int changed_ref(struct send_ctx *sctx,
 {
        int ret = 0;
 
-       BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid);
+       if (sctx->cur_ino != sctx->cmp_key->objectid) {
+               inconsistent_snapshot_error(sctx, result, "reference");
+               return -EIO;
+       }
 
        if (!sctx->cur_inode_new_gen &&
            sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) {
@@ -5627,7 +5772,10 @@ static int changed_xattr(struct send_ctx *sctx,
 {
        int ret = 0;
 
-       BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid);
+       if (sctx->cur_ino != sctx->cmp_key->objectid) {
+               inconsistent_snapshot_error(sctx, result, "xattr");
+               return -EIO;
+       }
 
        if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) {
                if (result == BTRFS_COMPARE_TREE_NEW)
@@ -5651,7 +5799,10 @@ static int changed_extent(struct send_ctx *sctx,
 {
        int ret = 0;
 
-       BUG_ON(sctx->cur_ino != sctx->cmp_key->objectid);
+       if (sctx->cur_ino != sctx->cmp_key->objectid) {
+               inconsistent_snapshot_error(sctx, result, "extent");
+               return -EIO;
+       }
 
        if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) {
                if (result != BTRFS_COMPARE_TREE_DELETED)
index 60e7179..864ce33 100644 (file)
@@ -184,6 +184,22 @@ static const char * const logtypes[] = {
        "debug",
 };
 
+
+/*
+ * Use one ratelimit state per log level so that a flood of less important
+ * messages doesn't cause more important ones to be dropped.
+ */
+static struct ratelimit_state printk_limits[] = {
+       RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100),
+       RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100),
+};
+
 void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
 {
        struct super_block *sb = fs_info->sb;
@@ -192,6 +208,7 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
        va_list args;
        const char *type = logtypes[4];
        int kern_level;
+       struct ratelimit_state *ratelimit;
 
        va_start(args, fmt);
 
@@ -202,13 +219,18 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
                lvl[size] = '\0';
                fmt += size;
                type = logtypes[kern_level - '0'];
-       } else
+               ratelimit = &printk_limits[kern_level - '0'];
+       } else {
                *lvl = '\0';
+               /* Default to debug output */
+               ratelimit = &printk_limits[7];
+       }
 
        vaf.fmt = fmt;
        vaf.va = &args;
 
-       printk("%sBTRFS %s (device %s): %pV\n", lvl, type, sb->s_id, &vaf);
+       if (__ratelimit(ratelimit))
+               printk("%sBTRFS %s (device %s): %pV\n", lvl, type, sb->s_id, &vaf);
 
        va_end(args);
 }
@@ -229,9 +251,11 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
  */
 __cold
 void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *root, const char *function,
+                              const char *function,
                               unsigned int line, int errno)
 {
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+
        trans->aborted = errno;
        /* Nothing used. The other threads that have joined this
         * transaction may be able to continue. */
@@ -239,16 +263,16 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
                const char *errstr;
 
                errstr = btrfs_decode_error(errno);
-               btrfs_warn(root->fs_info,
+               btrfs_warn(fs_info,
                           "%s:%d: Aborting unused transaction(%s).",
                           function, line, errstr);
                return;
        }
        ACCESS_ONCE(trans->transaction->aborted) = errno;
        /* Wake up anybody who may be waiting on this transaction */
-       wake_up(&root->fs_info->transaction_wait);
-       wake_up(&root->fs_info->transaction_blocked_wait);
-       __btrfs_handle_fs_error(root->fs_info, function, line, errno, NULL);
+       wake_up(&fs_info->transaction_wait);
+       wake_up(&fs_info->transaction_blocked_wait);
+       __btrfs_handle_fs_error(fs_info, function, line, errno, NULL);
 }
 /*
  * __btrfs_panic decodes unexpected, fatal errors from the caller,
@@ -432,12 +456,12 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                         */
                        break;
                case Opt_nodatasum:
-                       btrfs_set_and_info(root, NODATASUM,
+                       btrfs_set_and_info(info, NODATASUM,
                                           "setting nodatasum");
                        break;
                case Opt_datasum:
-                       if (btrfs_test_opt(root, NODATASUM)) {
-                               if (btrfs_test_opt(root, NODATACOW))
+                       if (btrfs_test_opt(info, NODATASUM)) {
+                               if (btrfs_test_opt(info, NODATACOW))
                                        btrfs_info(root->fs_info, "setting datasum, datacow enabled");
                                else
                                        btrfs_info(root->fs_info, "setting datasum");
@@ -446,9 +470,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        btrfs_clear_opt(info->mount_opt, NODATASUM);
                        break;
                case Opt_nodatacow:
-                       if (!btrfs_test_opt(root, NODATACOW)) {
-                               if (!btrfs_test_opt(root, COMPRESS) ||
-                                   !btrfs_test_opt(root, FORCE_COMPRESS)) {
+                       if (!btrfs_test_opt(info, NODATACOW)) {
+                               if (!btrfs_test_opt(info, COMPRESS) ||
+                                   !btrfs_test_opt(info, FORCE_COMPRESS)) {
                                        btrfs_info(root->fs_info,
                                                   "setting nodatacow, compression disabled");
                                } else {
@@ -461,7 +485,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        btrfs_set_opt(info->mount_opt, NODATASUM);
                        break;
                case Opt_datacow:
-                       btrfs_clear_and_info(root, NODATACOW,
+                       btrfs_clear_and_info(info, NODATACOW,
                                             "setting datacow");
                        break;
                case Opt_compress_force:
@@ -470,10 +494,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        /* Fallthrough */
                case Opt_compress:
                case Opt_compress_type:
-                       saved_compress_type = btrfs_test_opt(root, COMPRESS) ?
+                       saved_compress_type = btrfs_test_opt(info,
+                                                            COMPRESS) ?
                                info->compress_type : BTRFS_COMPRESS_NONE;
                        saved_compress_force =
-                               btrfs_test_opt(root, FORCE_COMPRESS);
+                               btrfs_test_opt(info, FORCE_COMPRESS);
                        if (token == Opt_compress ||
                            token == Opt_compress_force ||
                            strcmp(args[0].from, "zlib") == 0) {
@@ -513,10 +538,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                                 */
                                btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
                        }
-                       if ((btrfs_test_opt(root, COMPRESS) &&
+                       if ((btrfs_test_opt(info, COMPRESS) &&
                             (info->compress_type != saved_compress_type ||
                              compress_force != saved_compress_force)) ||
-                           (!btrfs_test_opt(root, COMPRESS) &&
+                           (!btrfs_test_opt(info, COMPRESS) &&
                             no_compress == 1)) {
                                btrfs_info(root->fs_info,
                                           "%s %s compression",
@@ -526,25 +551,25 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        compress_force = false;
                        break;
                case Opt_ssd:
-                       btrfs_set_and_info(root, SSD,
+                       btrfs_set_and_info(info, SSD,
                                           "use ssd allocation scheme");
                        break;
                case Opt_ssd_spread:
-                       btrfs_set_and_info(root, SSD_SPREAD,
+                       btrfs_set_and_info(info, SSD_SPREAD,
                                           "use spread ssd allocation scheme");
                        btrfs_set_opt(info->mount_opt, SSD);
                        break;
                case Opt_nossd:
-                       btrfs_set_and_info(root, NOSSD,
+                       btrfs_set_and_info(info, NOSSD,
                                             "not using ssd allocation scheme");
                        btrfs_clear_opt(info->mount_opt, SSD);
                        break;
                case Opt_barrier:
-                       btrfs_clear_and_info(root, NOBARRIER,
+                       btrfs_clear_and_info(info, NOBARRIER,
                                             "turning on barriers");
                        break;
                case Opt_nobarrier:
-                       btrfs_set_and_info(root, NOBARRIER,
+                       btrfs_set_and_info(info, NOBARRIER,
                                           "turning off barriers");
                        break;
                case Opt_thread_pool:
@@ -604,24 +629,24 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        root->fs_info->sb->s_flags &= ~MS_POSIXACL;
                        break;
                case Opt_notreelog:
-                       btrfs_set_and_info(root, NOTREELOG,
+                       btrfs_set_and_info(info, NOTREELOG,
                                           "disabling tree log");
                        break;
                case Opt_treelog:
-                       btrfs_clear_and_info(root, NOTREELOG,
+                       btrfs_clear_and_info(info, NOTREELOG,
                                             "enabling tree log");
                        break;
                case Opt_norecovery:
                case Opt_nologreplay:
-                       btrfs_set_and_info(root, NOLOGREPLAY,
+                       btrfs_set_and_info(info, NOLOGREPLAY,
                                           "disabling log replay at mount time");
                        break;
                case Opt_flushoncommit:
-                       btrfs_set_and_info(root, FLUSHONCOMMIT,
+                       btrfs_set_and_info(info, FLUSHONCOMMIT,
                                           "turning on flush-on-commit");
                        break;
                case Opt_noflushoncommit:
-                       btrfs_clear_and_info(root, FLUSHONCOMMIT,
+                       btrfs_clear_and_info(info, FLUSHONCOMMIT,
                                             "turning off flush-on-commit");
                        break;
                case Opt_ratio:
@@ -638,11 +663,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        }
                        break;
                case Opt_discard:
-                       btrfs_set_and_info(root, DISCARD,
+                       btrfs_set_and_info(info, DISCARD,
                                           "turning on discard");
                        break;
                case Opt_nodiscard:
-                       btrfs_clear_and_info(root, DISCARD,
+                       btrfs_clear_and_info(info, DISCARD,
                                             "turning off discard");
                        break;
                case Opt_space_cache:
@@ -651,12 +676,13 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                            strcmp(args[0].from, "v1") == 0) {
                                btrfs_clear_opt(root->fs_info->mount_opt,
                                                FREE_SPACE_TREE);
-                               btrfs_set_and_info(root, SPACE_CACHE,
+                               btrfs_set_and_info(info, SPACE_CACHE,
                                                   "enabling disk space caching");
                        } else if (strcmp(args[0].from, "v2") == 0) {
                                btrfs_clear_opt(root->fs_info->mount_opt,
                                                SPACE_CACHE);
-                               btrfs_set_and_info(root, FREE_SPACE_TREE,
+                               btrfs_set_and_info(info,
+                                                  FREE_SPACE_TREE,
                                                   "enabling free space tree");
                        } else {
                                ret = -EINVAL;
@@ -667,12 +693,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE);
                        break;
                case Opt_no_space_cache:
-                       if (btrfs_test_opt(root, SPACE_CACHE)) {
-                               btrfs_clear_and_info(root, SPACE_CACHE,
+                       if (btrfs_test_opt(info, SPACE_CACHE)) {
+                               btrfs_clear_and_info(info,
+                                                    SPACE_CACHE,
                                                     "disabling disk space caching");
                        }
-                       if (btrfs_test_opt(root, FREE_SPACE_TREE)) {
-                               btrfs_clear_and_info(root, FREE_SPACE_TREE,
+                       if (btrfs_test_opt(info, FREE_SPACE_TREE)) {
+                               btrfs_clear_and_info(info,
+                                                    FREE_SPACE_TREE,
                                                     "disabling free space tree");
                        }
                        break;
@@ -685,7 +713,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                                             "disabling inode map caching");
                        break;
                case Opt_clear_cache:
-                       btrfs_set_and_info(root, CLEAR_CACHE,
+                       btrfs_set_and_info(info, CLEAR_CACHE,
                                           "force clearing of disk cache");
                        break;
                case Opt_user_subvol_rm_allowed:
@@ -698,11 +726,11 @@ int btrfs_parse_options(struct btrfs_root *root, char *options,
                        btrfs_clear_opt(info->mount_opt, ENOSPC_DEBUG);
                        break;
                case Opt_defrag:
-                       btrfs_set_and_info(root, AUTO_DEFRAG,
+                       btrfs_set_and_info(info, AUTO_DEFRAG,
                                           "enabling auto defrag");
                        break;
                case Opt_nodefrag:
-                       btrfs_clear_and_info(root, AUTO_DEFRAG,
+                       btrfs_clear_and_info(info, AUTO_DEFRAG,
                                             "disabling auto defrag");
                        break;
                case Opt_recovery:
@@ -810,22 +838,22 @@ check:
        /*
         * Extra check for current option against current flag
         */
-       if (btrfs_test_opt(root, NOLOGREPLAY) && !(new_flags & MS_RDONLY)) {
+       if (btrfs_test_opt(info, NOLOGREPLAY) && !(new_flags & MS_RDONLY)) {
                btrfs_err(root->fs_info,
                          "nologreplay must be used with ro mount option");
                ret = -EINVAL;
        }
 out:
        if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE) &&
-           !btrfs_test_opt(root, FREE_SPACE_TREE) &&
-           !btrfs_test_opt(root, CLEAR_CACHE)) {
+           !btrfs_test_opt(info, FREE_SPACE_TREE) &&
+           !btrfs_test_opt(info, CLEAR_CACHE)) {
                btrfs_err(root->fs_info, "cannot disable free space tree");
                ret = -EINVAL;
 
        }
-       if (!ret && btrfs_test_opt(root, SPACE_CACHE))
+       if (!ret && btrfs_test_opt(info, SPACE_CACHE))
                btrfs_info(root->fs_info, "disk space caching is enabled");
-       if (!ret && btrfs_test_opt(root, FREE_SPACE_TREE))
+       if (!ret && btrfs_test_opt(info, FREE_SPACE_TREE))
                btrfs_info(root->fs_info, "using free space tree");
        kfree(orig);
        return ret;
@@ -1149,7 +1177,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        struct btrfs_fs_info *fs_info = btrfs_sb(sb);
        struct btrfs_root *root = fs_info->tree_root;
 
-       trace_btrfs_sync_fs(wait);
+       trace_btrfs_sync_fs(fs_info, wait);
 
        if (!wait) {
                filemap_flush(fs_info->btree_inode->i_mapping);
@@ -1192,13 +1220,13 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        struct btrfs_root *root = info->tree_root;
        char *compress_type;
 
-       if (btrfs_test_opt(root, DEGRADED))
+       if (btrfs_test_opt(info, DEGRADED))
                seq_puts(seq, ",degraded");
-       if (btrfs_test_opt(root, NODATASUM))
+       if (btrfs_test_opt(info, NODATASUM))
                seq_puts(seq, ",nodatasum");
-       if (btrfs_test_opt(root, NODATACOW))
+       if (btrfs_test_opt(info, NODATACOW))
                seq_puts(seq, ",nodatacow");
-       if (btrfs_test_opt(root, NOBARRIER))
+       if (btrfs_test_opt(info, NOBARRIER))
                seq_puts(seq, ",nobarrier");
        if (info->max_inline != BTRFS_DEFAULT_MAX_INLINE)
                seq_printf(seq, ",max_inline=%llu", info->max_inline);
@@ -1207,56 +1235,56 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        if (info->thread_pool_size !=  min_t(unsigned long,
                                             num_online_cpus() + 2, 8))
                seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
-       if (btrfs_test_opt(root, COMPRESS)) {
+       if (btrfs_test_opt(info, COMPRESS)) {
                if (info->compress_type == BTRFS_COMPRESS_ZLIB)
                        compress_type = "zlib";
                else
                        compress_type = "lzo";
-               if (btrfs_test_opt(root, FORCE_COMPRESS))
+               if (btrfs_test_opt(info, FORCE_COMPRESS))
                        seq_printf(seq, ",compress-force=%s", compress_type);
                else
                        seq_printf(seq, ",compress=%s", compress_type);
        }
-       if (btrfs_test_opt(root, NOSSD))
+       if (btrfs_test_opt(info, NOSSD))
                seq_puts(seq, ",nossd");
-       if (btrfs_test_opt(root, SSD_SPREAD))
+       if (btrfs_test_opt(info, SSD_SPREAD))
                seq_puts(seq, ",ssd_spread");
-       else if (btrfs_test_opt(root, SSD))
+       else if (btrfs_test_opt(info, SSD))
                seq_puts(seq, ",ssd");
-       if (btrfs_test_opt(root, NOTREELOG))
+       if (btrfs_test_opt(info, NOTREELOG))
                seq_puts(seq, ",notreelog");
-       if (btrfs_test_opt(root, NOLOGREPLAY))
+       if (btrfs_test_opt(info, NOLOGREPLAY))
                seq_puts(seq, ",nologreplay");
-       if (btrfs_test_opt(root, FLUSHONCOMMIT))
+       if (btrfs_test_opt(info, FLUSHONCOMMIT))
                seq_puts(seq, ",flushoncommit");
-       if (btrfs_test_opt(root, DISCARD))
+       if (btrfs_test_opt(info, DISCARD))
                seq_puts(seq, ",discard");
        if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
                seq_puts(seq, ",noacl");
-       if (btrfs_test_opt(root, SPACE_CACHE))
+       if (btrfs_test_opt(info, SPACE_CACHE))
                seq_puts(seq, ",space_cache");
-       else if (btrfs_test_opt(root, FREE_SPACE_TREE))
+       else if (btrfs_test_opt(info, FREE_SPACE_TREE))
                seq_puts(seq, ",space_cache=v2");
        else
                seq_puts(seq, ",nospace_cache");
-       if (btrfs_test_opt(root, RESCAN_UUID_TREE))
+       if (btrfs_test_opt(info, RESCAN_UUID_TREE))
                seq_puts(seq, ",rescan_uuid_tree");
-       if (btrfs_test_opt(root, CLEAR_CACHE))
+       if (btrfs_test_opt(info, CLEAR_CACHE))
                seq_puts(seq, ",clear_cache");
-       if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED))
+       if (btrfs_test_opt(info, USER_SUBVOL_RM_ALLOWED))
                seq_puts(seq, ",user_subvol_rm_allowed");
-       if (btrfs_test_opt(root, ENOSPC_DEBUG))
+       if (btrfs_test_opt(info, ENOSPC_DEBUG))
                seq_puts(seq, ",enospc_debug");
-       if (btrfs_test_opt(root, AUTO_DEFRAG))
+       if (btrfs_test_opt(info, AUTO_DEFRAG))
                seq_puts(seq, ",autodefrag");
-       if (btrfs_test_opt(root, INODE_MAP_CACHE))
+       if (btrfs_test_opt(info, INODE_MAP_CACHE))
                seq_puts(seq, ",inode_cache");
-       if (btrfs_test_opt(root, SKIP_BALANCE))
+       if (btrfs_test_opt(info, SKIP_BALANCE))
                seq_puts(seq, ",skip_balance");
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
-       if (btrfs_test_opt(root, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
+       if (btrfs_test_opt(info, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
                seq_puts(seq, ",check_int_data");
-       else if (btrfs_test_opt(root, CHECK_INTEGRITY))
+       else if (btrfs_test_opt(info, CHECK_INTEGRITY))
                seq_puts(seq, ",check_int");
        if (info->check_integrity_print_mask)
                seq_printf(seq, ",check_int_print_mask=%d",
@@ -1265,14 +1293,14 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        if (info->metadata_ratio)
                seq_printf(seq, ",metadata_ratio=%d",
                                info->metadata_ratio);
-       if (btrfs_test_opt(root, PANIC_ON_FATAL_ERROR))
+       if (btrfs_test_opt(info, PANIC_ON_FATAL_ERROR))
                seq_puts(seq, ",fatal_errors=panic");
        if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
                seq_printf(seq, ",commit=%d", info->commit_interval);
 #ifdef CONFIG_BTRFS_DEBUG
-       if (btrfs_test_opt(root, FRAGMENT_DATA))
+       if (btrfs_test_opt(info, FRAGMENT_DATA))
                seq_puts(seq, ",fragment=data");
-       if (btrfs_test_opt(root, FRAGMENT_METADATA))
+       if (btrfs_test_opt(info, FRAGMENT_METADATA))
                seq_puts(seq, ",fragment=metadata");
 #endif
        seq_printf(seq, ",subvolid=%llu",
@@ -2030,9 +2058,6 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
  * chunk).
  *
  * If metadata is exhausted, f_bavail will be 0.
- *
- * FIXME: not accurate for mixed block groups, total and free/used are ok,
- * available appears slightly larger.
  */
 static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
@@ -2319,49 +2344,6 @@ static void btrfs_print_mod_info(void)
                        btrfs_crc32c_impl());
 }
 
-static int btrfs_run_sanity_tests(void)
-{
-       int ret, i;
-       u32 sectorsize, nodesize;
-       u32 test_sectorsize[] = {
-               PAGE_SIZE,
-       };
-       ret = btrfs_init_test_fs();
-       if (ret)
-               return ret;
-       for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) {
-               sectorsize = test_sectorsize[i];
-               for (nodesize = sectorsize;
-                    nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE;
-                    nodesize <<= 1) {
-                       pr_info("BTRFS: selftest: sectorsize: %u  nodesize: %u\n",
-                               sectorsize, nodesize);
-                       ret = btrfs_test_free_space_cache(sectorsize, nodesize);
-                       if (ret)
-                               goto out;
-                       ret = btrfs_test_extent_buffer_operations(sectorsize,
-                               nodesize);
-                       if (ret)
-                               goto out;
-                       ret = btrfs_test_extent_io(sectorsize, nodesize);
-                       if (ret)
-                               goto out;
-                       ret = btrfs_test_inodes(sectorsize, nodesize);
-                       if (ret)
-                               goto out;
-                       ret = btrfs_test_qgroups(sectorsize, nodesize);
-                       if (ret)
-                               goto out;
-                       ret = btrfs_test_free_space_tree(sectorsize, nodesize);
-                       if (ret)
-                               goto out;
-               }
-       }
-out:
-       btrfs_destroy_test_fs();
-       return ret;
-}
-
 static int __init init_btrfs_fs(void)
 {
        int err;
index 4879656..c656990 100644 (file)
@@ -326,6 +326,7 @@ SPACE_INFO_ATTR(bytes_used);
 SPACE_INFO_ATTR(bytes_pinned);
 SPACE_INFO_ATTR(bytes_reserved);
 SPACE_INFO_ATTR(bytes_may_use);
+SPACE_INFO_ATTR(bytes_readonly);
 SPACE_INFO_ATTR(disk_used);
 SPACE_INFO_ATTR(disk_total);
 BTRFS_ATTR(total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned);
@@ -337,6 +338,7 @@ static struct attribute *space_info_attrs[] = {
        BTRFS_ATTR_PTR(bytes_pinned),
        BTRFS_ATTR_PTR(bytes_reserved),
        BTRFS_ATTR_PTR(bytes_may_use),
+       BTRFS_ATTR_PTR(bytes_readonly),
        BTRFS_ATTR_PTR(disk_used),
        BTRFS_ATTR_PTR(disk_total),
        BTRFS_ATTR_PTR(total_bytes_pinned),
index 02223f3..bf62ad9 100644 (file)
@@ -54,7 +54,7 @@ struct inode *btrfs_new_test_inode(void)
        return new_inode(test_mnt->mnt_sb);
 }
 
-int btrfs_init_test_fs(void)
+static int btrfs_init_test_fs(void)
 {
        int ret;
 
@@ -73,7 +73,7 @@ int btrfs_init_test_fs(void)
        return 0;
 }
 
-void btrfs_destroy_test_fs(void)
+static void btrfs_destroy_test_fs(void)
 {
        kern_unmount(test_mnt);
        unregister_filesystem(&test_type);
@@ -128,14 +128,27 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void)
        extent_io_tree_init(&fs_info->freed_extents[0], NULL);
        extent_io_tree_init(&fs_info->freed_extents[1], NULL);
        fs_info->pinned_extents = &fs_info->freed_extents[0];
+       set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state);
+
+       test_mnt->mnt_sb->s_fs_info = fs_info;
+
        return fs_info;
 }
 
-static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
+void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 {
        struct radix_tree_iter iter;
        void **slot;
 
+       if (!fs_info)
+               return;
+
+       if (WARN_ON(!test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO,
+                             &fs_info->fs_state)))
+               return;
+
+       test_mnt->mnt_sb->s_fs_info = NULL;
+
        spin_lock(&fs_info->buffer_lock);
        radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
                struct extent_buffer *eb;
@@ -167,10 +180,11 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
 {
        if (!root)
                return;
+       /* Will be freed by btrfs_free_fs_roots */
+       if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
+               return;
        if (root->node)
                free_extent_buffer(root->node);
-       if (root->fs_info)
-               btrfs_free_dummy_fs_info(root->fs_info);
        kfree(root);
 }
 
@@ -220,3 +234,46 @@ void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans)
        INIT_LIST_HEAD(&trans->qgroup_ref_list);
        trans->type = __TRANS_DUMMY;
 }
+
+int btrfs_run_sanity_tests(void)
+{
+       int ret, i;
+       u32 sectorsize, nodesize;
+       u32 test_sectorsize[] = {
+               PAGE_SIZE,
+       };
+       ret = btrfs_init_test_fs();
+       if (ret)
+               return ret;
+       for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) {
+               sectorsize = test_sectorsize[i];
+               for (nodesize = sectorsize;
+                    nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE;
+                    nodesize <<= 1) {
+                       pr_info("BTRFS: selftest: sectorsize: %u  nodesize: %u\n",
+                               sectorsize, nodesize);
+                       ret = btrfs_test_free_space_cache(sectorsize, nodesize);
+                       if (ret)
+                               goto out;
+                       ret = btrfs_test_extent_buffer_operations(sectorsize,
+                               nodesize);
+                       if (ret)
+                               goto out;
+                       ret = btrfs_test_extent_io(sectorsize, nodesize);
+                       if (ret)
+                               goto out;
+                       ret = btrfs_test_inodes(sectorsize, nodesize);
+                       if (ret)
+                               goto out;
+                       ret = btrfs_test_qgroups(sectorsize, nodesize);
+                       if (ret)
+                               goto out;
+                       ret = btrfs_test_free_space_tree(sectorsize, nodesize);
+                       if (ret)
+                               goto out;
+               }
+       }
+out:
+       btrfs_destroy_test_fs();
+       return ret;
+}
index 66fb6b7..b17ffbe 100644 (file)
 #define __BTRFS_TESTS
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+int btrfs_run_sanity_tests(void);
 
 #define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__)
 
 struct btrfs_root;
 struct btrfs_trans_handle;
 
-int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize);
 int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize);
+int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize);
 int btrfs_test_extent_io(u32 sectorsize, u32 nodesize);
 int btrfs_test_inodes(u32 sectorsize, u32 nodesize);
 int btrfs_test_qgroups(u32 sectorsize, u32 nodesize);
 int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize);
-int btrfs_init_test_fs(void);
-void btrfs_destroy_test_fs(void);
 struct inode *btrfs_new_test_inode(void);
 struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void);
+void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info);
 void btrfs_free_dummy_root(struct btrfs_root *root);
 struct btrfs_block_group_cache *
 btrfs_alloc_dummy_block_group(unsigned long length, u32 sectorsize);
 void btrfs_free_dummy_block_group(struct btrfs_block_group_cache *cache);
 void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans);
 #else
-static inline int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize)
-{
-       return 0;
-}
-static inline int btrfs_test_extent_buffer_operations(u32 sectorsize,
-       u32 nodesize)
-{
-       return 0;
-}
-static inline int btrfs_init_test_fs(void)
-{
-       return 0;
-}
-static inline void btrfs_destroy_test_fs(void)
-{
-}
-static inline int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
-{
-       return 0;
-}
-static inline int btrfs_test_inodes(u32 sectorsize, u32 nodesize)
-{
-       return 0;
-}
-static inline int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
-{
-       return 0;
-}
-static inline int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize)
+static inline int btrfs_run_sanity_tests(void)
 {
        return 0;
 }
index 4f8cbd1..1995691 100644 (file)
@@ -24,8 +24,9 @@
 
 static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
 {
-       struct btrfs_path *path;
-       struct btrfs_root *root;
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_path *path = NULL;
+       struct btrfs_root *root = NULL;
        struct extent_buffer *eb;
        struct btrfs_item *item;
        char *value = "mary had a little lamb";
@@ -40,17 +41,24 @@ static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
 
        test_msg("Running btrfs_split_item tests\n");
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Could not allocate fs_info\n");
+               return -ENOMEM;
+       }
+
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
        if (IS_ERR(root)) {
                test_msg("Could not allocate root\n");
-               return PTR_ERR(root);
+               ret = PTR_ERR(root);
+               goto out;
        }
 
        path = btrfs_alloc_path();
        if (!path) {
                test_msg("Could not allocate path\n");
-               kfree(root);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        path->nodes[0] = eb = alloc_dummy_extent_buffer(NULL, nodesize,
@@ -219,7 +227,8 @@ static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
        }
 out:
        btrfs_free_path(path);
-       kfree(root);
+       btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
 
index 3956bb2..3221c8d 100644 (file)
@@ -837,6 +837,7 @@ test_steal_space_from_bitmap_to_extent(struct btrfs_block_group_cache *cache,
 
 int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info;
        struct btrfs_block_group_cache *cache;
        struct btrfs_root *root = NULL;
        int ret = -ENOMEM;
@@ -855,15 +856,17 @@ int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize)
                return 0;
        }
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               ret = PTR_ERR(root);
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               ret = -ENOMEM;
                goto out;
        }
 
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info)
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               ret = PTR_ERR(root);
                goto out;
+       }
 
        root->fs_info->extent_root = root;
        cache->fs_info = root->fs_info;
@@ -882,6 +885,7 @@ int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize)
 out:
        btrfs_free_dummy_block_group(cache);
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        test_msg("Free space cache tests finished\n");
        return ret;
 }
index aac5070..7508d3b 100644 (file)
@@ -443,23 +443,24 @@ typedef int (*test_func_t)(struct btrfs_trans_handle *,
 static int run_test(test_func_t test_func, int bitmaps,
                u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info;
        struct btrfs_root *root = NULL;
        struct btrfs_block_group_cache *cache = NULL;
        struct btrfs_trans_handle trans;
        struct btrfs_path *path = NULL;
        int ret;
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               test_msg("Couldn't allocate dummy root\n");
-               ret = PTR_ERR(root);
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               ret = -ENOMEM;
                goto out;
        }
 
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info) {
-               test_msg("Couldn't allocate dummy fs info\n");
-               ret = -ENOMEM;
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate dummy root\n");
+               ret = PTR_ERR(root);
                goto out;
        }
 
@@ -534,6 +535,7 @@ out:
        btrfs_free_path(path);
        btrfs_free_dummy_block_group(cache);
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
 
index 29648c0..9f72aed 100644 (file)
@@ -230,6 +230,7 @@ static unsigned long vacancy_only = 0;
 
 static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info = NULL;
        struct inode *inode = NULL;
        struct btrfs_root *root = NULL;
        struct extent_map *em = NULL;
@@ -248,19 +249,15 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
        BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
        BTRFS_I(inode)->location.offset = 0;
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               test_msg("Couldn't allocate root\n");
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
                goto out;
        }
 
-       /*
-        * We do this since btrfs_get_extent wants to assign em->bdev to
-        * root->fs_info->fs_devices->latest_bdev.
-        */
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info) {
-               test_msg("Couldn't allocate dummy fs info\n");
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
                goto out;
        }
 
@@ -835,11 +832,13 @@ out:
                free_extent_map(em);
        iput(inode);
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
 
 static int test_hole_first(u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info = NULL;
        struct inode *inode = NULL;
        struct btrfs_root *root = NULL;
        struct extent_map *em = NULL;
@@ -855,15 +854,15 @@ static int test_hole_first(u32 sectorsize, u32 nodesize)
        BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
        BTRFS_I(inode)->location.offset = 0;
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               test_msg("Couldn't allocate root\n");
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
                goto out;
        }
 
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info) {
-               test_msg("Couldn't allocate dummy fs info\n");
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
                goto out;
        }
 
@@ -934,11 +933,13 @@ out:
                free_extent_map(em);
        iput(inode);
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
 
 static int test_extent_accounting(u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info = NULL;
        struct inode *inode = NULL;
        struct btrfs_root *root = NULL;
        int ret = -ENOMEM;
@@ -949,15 +950,15 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
                return ret;
        }
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               test_msg("Couldn't allocate root\n");
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
                goto out;
        }
 
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info) {
-               test_msg("Couldn't allocate dummy fs info\n");
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
                goto out;
        }
 
@@ -1132,6 +1133,7 @@ out:
                                 NULL, GFP_KERNEL);
        iput(inode);
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
 
index 57a12c0..4407fef 100644 (file)
@@ -453,22 +453,24 @@ static int test_multiple_refs(struct btrfs_root *root,
 
 int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
 {
+       struct btrfs_fs_info *fs_info = NULL;
        struct btrfs_root *root;
        struct btrfs_root *tmp_root;
        int ret = 0;
 
-       root = btrfs_alloc_dummy_root(sectorsize, nodesize);
-       if (IS_ERR(root)) {
-               test_msg("Couldn't allocate root\n");
-               return PTR_ERR(root);
+       fs_info = btrfs_alloc_dummy_fs_info();
+       if (!fs_info) {
+               test_msg("Couldn't allocate dummy fs info\n");
+               return -ENOMEM;
        }
 
-       root->fs_info = btrfs_alloc_dummy_fs_info();
-       if (!root->fs_info) {
-               test_msg("Couldn't allocate dummy fs info\n");
-               ret = -ENOMEM;
+       root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
+       if (IS_ERR(root)) {
+               test_msg("Couldn't allocate root\n");
+               ret = PTR_ERR(root);
                goto out;
        }
+
        /* We are using this root as our extent root */
        root->fs_info->extent_root = root;
 
@@ -495,7 +497,7 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
        btrfs_set_header_nritems(root->node, 0);
        root->alloc_bytenr += 2 * nodesize;
 
-       tmp_root = btrfs_alloc_dummy_root(sectorsize, nodesize);
+       tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
        if (IS_ERR(tmp_root)) {
                test_msg("Couldn't allocate a fs root\n");
                ret = PTR_ERR(tmp_root);
@@ -510,7 +512,7 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
                goto out;
        }
 
-       tmp_root = btrfs_alloc_dummy_root(sectorsize, nodesize);
+       tmp_root = btrfs_alloc_dummy_root(fs_info, sectorsize, nodesize);
        if (IS_ERR(tmp_root)) {
                test_msg("Couldn't allocate a fs root\n");
                ret = PTR_ERR(tmp_root);
@@ -531,5 +533,6 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize)
        ret = test_multiple_refs(root, sectorsize, nodesize);
 out:
        btrfs_free_dummy_root(root);
+       btrfs_free_dummy_fs_info(fs_info);
        return ret;
 }
index 948aa18..9cca0a7 100644 (file)
@@ -561,6 +561,7 @@ again:
        h->transaction = cur_trans;
        h->root = root;
        h->use_count = 1;
+       h->fs_info = root->fs_info;
 
        h->type = type;
        h->can_flush_pending_bgs = true;
@@ -1491,7 +1492,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                goto dir_item_existed;
        } else if (IS_ERR(dir_item)) {
                ret = PTR_ERR(dir_item);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
        btrfs_release_path(path);
@@ -1504,7 +1505,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
         */
        ret = btrfs_run_delayed_items(trans, root);
        if (ret) {      /* Transaction aborted */
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1543,7 +1544,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        if (ret) {
                btrfs_tree_unlock(old);
                free_extent_buffer(old);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1554,7 +1555,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_tree_unlock(old);
        free_extent_buffer(old);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
        /* see comments in should_cow_block() */
@@ -1568,7 +1569,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_tree_unlock(tmp);
        free_extent_buffer(tmp);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1580,7 +1581,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                 btrfs_ino(parent_inode), index,
                                 dentry->d_name.name, dentry->d_name.len);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1588,19 +1589,19 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
        if (IS_ERR(pending->snap)) {
                ret = PTR_ERR(pending->snap);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
        ret = btrfs_reloc_post_snapshot(trans, pending);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1622,7 +1623,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        /* We have check then name at the beginning, so it is impossible. */
        BUG_ON(ret == -EEXIST || ret == -EOVERFLOW);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1632,13 +1633,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                current_fs_time(parent_inode->i_sb);
        ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
        ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, new_uuid.b,
                                  BTRFS_UUID_KEY_SUBVOL, objectid);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
        if (!btrfs_is_empty_uuid(new_root_item->received_uuid)) {
@@ -1647,14 +1648,14 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                          BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                          objectid);
                if (ret && ret != -EEXIST) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto fail;
                }
        }
 
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto fail;
        }
 
@@ -1709,7 +1710,7 @@ static void update_super_roots(struct btrfs_root *root)
        super->root = root_item->bytenr;
        super->generation = root_item->generation;
        super->root_level = root_item->level;
-       if (btrfs_test_opt(root, SPACE_CACHE))
+       if (btrfs_test_opt(root->fs_info, SPACE_CACHE))
                super->cache_generation = root_item->generation;
        if (root->fs_info->update_uuid_tree_gen)
                super->uuid_tree_generation = root_item->generation;
@@ -1850,7 +1851,7 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
 
        WARN_ON(trans->use_count > 1);
 
-       btrfs_abort_transaction(trans, root, err);
+       btrfs_abort_transaction(trans, err);
 
        spin_lock(&root->fs_info->trans_lock);
 
@@ -1895,14 +1896,14 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
 
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
-       if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
+       if (btrfs_test_opt(fs_info, FLUSHONCOMMIT))
                return btrfs_start_delalloc_roots(fs_info, 1, -1);
        return 0;
 }
 
 static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
-       if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
+       if (btrfs_test_opt(fs_info, FLUSHONCOMMIT))
                btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
 }
 
index c5abee4..efb1226 100644 (file)
@@ -128,6 +128,7 @@ struct btrfs_trans_handle {
         * Subvolume quota depends on this
         */
        struct btrfs_root *root;
+       struct btrfs_fs_info *fs_info;
        struct seq_list delayed_ref_elem;
        struct list_head qgroup_ref_list;
        struct list_head new_bgs;
index c05f69a..fff3f3e 100644 (file)
@@ -2757,7 +2757,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        while (1) {
                int batch = atomic_read(&root->log_batch);
                /* when we're on an ssd, just kick the log commit out */
-               if (!btrfs_test_opt(root, SSD) &&
+               if (!btrfs_test_opt(root->fs_info, SSD) &&
                    test_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state)) {
                        mutex_unlock(&root->log_mutex);
                        schedule_timeout_uninterruptible(1);
@@ -2788,7 +2788,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
        if (ret) {
                blk_finish_plug(&plug);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_free_logged_extents(log, log_transid);
                btrfs_set_log_full_commit(root->fs_info, trans);
                mutex_unlock(&root->log_mutex);
@@ -2838,7 +2838,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                btrfs_set_log_full_commit(root->fs_info, trans);
 
                if (ret != -ENOSPC) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        mutex_unlock(&log_root_tree->log_mutex);
                        goto out;
                }
@@ -2898,7 +2898,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        blk_finish_plug(&plug);
        if (ret) {
                btrfs_set_log_full_commit(root->fs_info, trans);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_free_logged_extents(log, log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
                goto out_wake_log_root;
@@ -2934,7 +2934,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
        ret = write_ctree_super(trans, root->fs_info->tree_root, 1);
        if (ret) {
                btrfs_set_log_full_commit(root->fs_info, trans);
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out_wake_log_root;
        }
 
@@ -2991,7 +2991,7 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
        ret = walk_log_tree(trans, log, &wc);
        /* I don't think this can happen but just in case */
        if (ret)
-               btrfs_abort_transaction(trans, log, ret);
+               btrfs_abort_transaction(trans, ret);
 
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
@@ -3160,7 +3160,7 @@ out_unlock:
                btrfs_set_log_full_commit(root->fs_info, trans);
                ret = 0;
        } else if (ret < 0)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
 
        btrfs_end_log_trans(root);
 
@@ -3193,7 +3193,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
                btrfs_set_log_full_commit(root->fs_info, trans);
                ret = 0;
        } else if (ret < 0 && ret != -ENOENT)
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
        btrfs_end_log_trans(root);
 
        return ret;
@@ -4469,7 +4469,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,
 static int btrfs_check_ref_name_override(struct extent_buffer *eb,
                                         const int slot,
                                         const struct btrfs_key *key,
-                                        struct inode *inode)
+                                        struct inode *inode,
+                                        u64 *other_ino)
 {
        int ret;
        struct btrfs_path *search_path;
@@ -4528,7 +4529,16 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb,
                                           search_path, parent,
                                           name, this_name_len, 0);
                if (di && !IS_ERR(di)) {
-                       ret = 1;
+                       struct btrfs_key di_key;
+
+                       btrfs_dir_item_key_to_cpu(search_path->nodes[0],
+                                                 di, &di_key);
+                       if (di_key.type == BTRFS_INODE_ITEM_KEY) {
+                               ret = 1;
+                               *other_ino = di_key.objectid;
+                       } else {
+                               ret = -EAGAIN;
+                       }
                        goto out;
                } else if (IS_ERR(di)) {
                        ret = PTR_ERR(di);
@@ -4703,6 +4713,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                ins_nr = 0;
                ret = btrfs_search_forward(root, &min_key,
                                           path, trans->transid);
+               if (ret < 0) {
+                       err = ret;
+                       goto out_unlock;
+               }
                if (ret != 0)
                        break;
 again:
@@ -4718,16 +4732,71 @@ again:
                if ((min_key.type == BTRFS_INODE_REF_KEY ||
                     min_key.type == BTRFS_INODE_EXTREF_KEY) &&
                    BTRFS_I(inode)->generation == trans->transid) {
+                       u64 other_ino = 0;
+
                        ret = btrfs_check_ref_name_override(path->nodes[0],
                                                            path->slots[0],
-                                                           &min_key, inode);
+                                                           &min_key, inode,
+                                                           &other_ino);
                        if (ret < 0) {
                                err = ret;
                                goto out_unlock;
                        } else if (ret > 0) {
-                               err = 1;
-                               btrfs_set_log_full_commit(root->fs_info, trans);
-                               goto out_unlock;
+                               struct btrfs_key inode_key;
+                               struct inode *other_inode;
+
+                               if (ins_nr > 0) {
+                                       ins_nr++;
+                               } else {
+                                       ins_nr = 1;
+                                       ins_start_slot = path->slots[0];
+                               }
+                               ret = copy_items(trans, inode, dst_path, path,
+                                                &last_extent, ins_start_slot,
+                                                ins_nr, inode_only,
+                                                logged_isize);
+                               if (ret < 0) {
+                                       err = ret;
+                                       goto out_unlock;
+                               }
+                               ins_nr = 0;
+                               btrfs_release_path(path);
+                               inode_key.objectid = other_ino;
+                               inode_key.type = BTRFS_INODE_ITEM_KEY;
+                               inode_key.offset = 0;
+                               other_inode = btrfs_iget(root->fs_info->sb,
+                                                        &inode_key, root,
+                                                        NULL);
+                               /*
+                                * If the other inode that had a conflicting dir
+                                * entry was deleted in the current transaction,
+                                * we don't need to do more work nor fallback to
+                                * a transaction commit.
+                                */
+                               if (IS_ERR(other_inode) &&
+                                   PTR_ERR(other_inode) == -ENOENT) {
+                                       goto next_key;
+                               } else if (IS_ERR(other_inode)) {
+                                       err = PTR_ERR(other_inode);
+                                       goto out_unlock;
+                               }
+                               /*
+                                * We are safe logging the other inode without
+                                * acquiring its i_mutex as long as we log with
+                                * the LOG_INODE_EXISTS mode. We're safe against
+                                * concurrent renames of the other inode as well
+                                * because during a rename we pin the log and
+                                * update the log with the new name before we
+                                * unpin it.
+                                */
+                               err = btrfs_log_inode(trans, root, other_inode,
+                                                     LOG_INODE_EXISTS,
+                                                     0, LLONG_MAX, ctx);
+                               iput(other_inode);
+                               if (err)
+                                       goto out_unlock;
+                               else
+                                       goto next_key;
                        }
                }
 
@@ -4795,7 +4864,7 @@ next_slot:
                        ins_nr = 0;
                }
                btrfs_release_path(path);
-
+next_key:
                if (min_key.offset < (u64)-1) {
                        min_key.offset++;
                } else if (min_key.type < max_key.type) {
@@ -4989,8 +5058,12 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
                if (!parent || d_really_is_negative(parent) || sb != parent->d_sb)
                        break;
 
-               if (IS_ROOT(parent))
+               if (IS_ROOT(parent)) {
+                       inode = d_inode(parent);
+                       if (btrfs_must_commit_transaction(trans, inode))
+                               ret = 1;
                        break;
+               }
 
                parent = dget_parent(parent);
                dput(old_parent);
@@ -5301,7 +5374,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
 
        sb = inode->i_sb;
 
-       if (btrfs_test_opt(root, NOTREELOG)) {
+       if (btrfs_test_opt(root->fs_info, NOTREELOG)) {
                ret = 1;
                goto end_no_trans;
        }
index 0fb4a95..51f1255 100644 (file)
@@ -140,7 +140,6 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
 static void __btrfs_reset_dev_stats(struct btrfs_device *dev);
 static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev);
 static void btrfs_dev_stat_print_on_load(struct btrfs_device *device);
-static void btrfs_close_one_device(struct btrfs_device *device);
 
 DEFINE_MUTEX(uuid_mutex);
 static LIST_HEAD(fs_uuids);
@@ -853,6 +852,46 @@ static void free_device(struct rcu_head *head)
        schedule_work(&device->rcu_work);
 }
 
+static void btrfs_close_one_device(struct btrfs_device *device)
+{
+       struct btrfs_fs_devices *fs_devices = device->fs_devices;
+       struct btrfs_device *new_device;
+       struct rcu_string *name;
+
+       if (device->bdev)
+               fs_devices->open_devices--;
+
+       if (device->writeable &&
+           device->devid != BTRFS_DEV_REPLACE_DEVID) {
+               list_del_init(&device->dev_alloc_list);
+               fs_devices->rw_devices--;
+       }
+
+       if (device->missing)
+               fs_devices->missing_devices--;
+
+       if (device->bdev && device->writeable) {
+               sync_blockdev(device->bdev);
+               invalidate_bdev(device->bdev);
+       }
+
+       new_device = btrfs_alloc_device(NULL, &device->devid,
+                                       device->uuid);
+       BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
+
+       /* Safe because we are under uuid_mutex */
+       if (device->name) {
+               name = rcu_string_strdup(device->name->str, GFP_NOFS);
+               BUG_ON(!name); /* -ENOMEM */
+               rcu_assign_pointer(new_device->name, name);
+       }
+
+       list_replace_rcu(&device->dev_list, &new_device->dev_list);
+       new_device->fs_devices = device->fs_devices;
+
+       call_rcu(&device->rcu, free_device);
+}
+
 static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device, *tmp;
@@ -2399,14 +2438,14 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
                ret = init_first_rw_device(trans, root, device);
                unlock_chunks(root);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto error_trans;
                }
        }
 
        ret = btrfs_add_device(trans, root, device);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto error_trans;
        }
 
@@ -2415,7 +2454,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
                ret = btrfs_finish_sprout(trans, root);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto error_trans;
                }
 
@@ -2801,7 +2840,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
                                            &dev_extent_len);
                if (ret) {
                        mutex_unlock(&fs_devices->device_list_mutex);
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
 
@@ -2820,7 +2859,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
                        ret = btrfs_update_device(trans, map->stripes[i].dev);
                        if (ret) {
                                mutex_unlock(&fs_devices->device_list_mutex);
-                               btrfs_abort_transaction(trans, root, ret);
+                               btrfs_abort_transaction(trans, ret);
                                goto out;
                        }
                }
@@ -2829,7 +2868,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
 
        ret = btrfs_free_chunk(trans, root, chunk_objectid, chunk_offset);
        if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -2838,14 +2877,14 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
        if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
                ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
                if (ret) {
-                       btrfs_abort_transaction(trans, root, ret);
+                       btrfs_abort_transaction(trans, ret);
                        goto out;
                }
        }
 
        ret = btrfs_remove_block_group(trans, extent_root, chunk_offset, em);
        if (ret) {
-               btrfs_abort_transaction(trans, extent_root, ret);
+               btrfs_abort_transaction(trans, ret);
                goto out;
        }
 
@@ -2902,7 +2941,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
         * chunk tree entries
         */
        ret = btrfs_remove_chunk(trans, root, chunk_offset);
-       btrfs_end_transaction(trans, root);
+       btrfs_end_transaction(trans, extent_root);
        return ret;
 }
 
@@ -3421,7 +3460,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
        u64 size_to_free;
        u64 chunk_type;
        struct btrfs_chunk *chunk;
-       struct btrfs_path *path;
+       struct btrfs_path *path = NULL;
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_trans_handle *trans;
@@ -3455,13 +3494,33 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
                ret = btrfs_shrink_device(device, old_size - size_to_free);
                if (ret == -ENOSPC)
                        break;
-               BUG_ON(ret);
+               if (ret) {
+                       /* btrfs_shrink_device never returns ret > 0 */
+                       WARN_ON(ret > 0);
+                       goto error;
+               }
 
                trans = btrfs_start_transaction(dev_root, 0);
-               BUG_ON(IS_ERR(trans));
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       btrfs_info_in_rcu(fs_info,
+                "resize: unable to start transaction after shrinking device %s (error %d), old size %llu, new size %llu",
+                                         rcu_str_deref(device->name), ret,
+                                         old_size, old_size - size_to_free);
+                       goto error;
+               }
 
                ret = btrfs_grow_device(trans, device, old_size);
-               BUG_ON(ret);
+               if (ret) {
+                       btrfs_end_transaction(trans, dev_root);
+                       /* btrfs_grow_device never returns ret > 0 */
+                       WARN_ON(ret > 0);
+                       btrfs_info_in_rcu(fs_info,
+                "resize: unable to grow device after shrinking device %s (error %d), old size %llu, new size %llu",
+                                         rcu_str_deref(device->name), ret,
+                                         old_size, old_size - size_to_free);
+                       goto error;
+               }
 
                btrfs_end_transaction(trans, dev_root);
        }
@@ -3885,7 +3944,7 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
        }
        spin_unlock(&fs_info->balance_lock);
 
-       if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
+       if (btrfs_test_opt(fs_info, SKIP_BALANCE)) {
                btrfs_info(fs_info, "force skipping balance");
                return 0;
        }
@@ -4240,7 +4299,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
                                      BTRFS_UUID_TREE_OBJECTID);
        if (IS_ERR(uuid_root)) {
                ret = PTR_ERR(uuid_root);
-               btrfs_abort_transaction(trans, tree_root, ret);
+               btrfs_abort_transaction(trans, ret);
                btrfs_end_transaction(trans, tree_root);
                return ret;
        }
@@ -4514,8 +4573,7 @@ static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type)
        btrfs_set_fs_incompat(info, RAID56);
 }
 
-#define BTRFS_MAX_DEVS(r) ((BTRFS_LEAF_DATA_SIZE(r)            \
-                       - sizeof(struct btrfs_item)             \
+#define BTRFS_MAX_DEVS(r) ((BTRFS_MAX_ITEM_SIZE(r)             \
                        - sizeof(struct btrfs_chunk))           \
                        / sizeof(struct btrfs_stripe) + 1)
 
@@ -5954,7 +6012,7 @@ static void btrfs_end_bio(struct bio *bio)
                                else
                                        btrfs_dev_stat_inc(dev,
                                                BTRFS_DEV_STAT_READ_ERRS);
-                               if ((bio->bi_rw & WRITE_FLUSH) == WRITE_FLUSH)
+                               if ((bio->bi_opf & WRITE_FLUSH) == WRITE_FLUSH)
                                        btrfs_dev_stat_inc(dev,
                                                BTRFS_DEV_STAT_FLUSH_ERRS);
                                btrfs_dev_stat_print_on_error(dev);
@@ -6031,7 +6089,7 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root,
        bio->bi_next = NULL;
 
        spin_lock(&device->io_lock);
-       if (bio->bi_rw & REQ_SYNC)
+       if (bio->bi_opf & REQ_SYNC)
                pending_bios = &device->pending_sync_bios;
        else
                pending_bios = &device->pending_bios;
@@ -6069,7 +6127,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
                rcu_read_lock();
                name = rcu_dereference(dev->name);
                pr_debug("btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu "
-                        "(%s id %llu), size=%u\n", bio_op(bio), bio->bi_rw,
+                        "(%s id %llu), size=%u\n", bio_op(bio), bio->bi_opf,
                         (u64)bio->bi_iter.bi_sector, (u_long)dev->bdev->bd_dev,
                         name->str, dev->devid, bio->bi_iter.bi_size);
                rcu_read_unlock();
@@ -6401,7 +6459,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                                   BTRFS_UUID_SIZE);
                map->stripes[i].dev = btrfs_find_device(root->fs_info, devid,
                                                        uuid, NULL);
-               if (!map->stripes[i].dev && !btrfs_test_opt(root, DEGRADED)) {
+               if (!map->stripes[i].dev &&
+                   !btrfs_test_opt(root->fs_info, DEGRADED)) {
                        free_extent_map(em);
                        return -EIO;
                }
@@ -6469,7 +6528,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_root *root,
 
        fs_devices = find_fsid(fsid);
        if (!fs_devices) {
-               if (!btrfs_test_opt(root, DEGRADED))
+               if (!btrfs_test_opt(root->fs_info, DEGRADED))
                        return ERR_PTR(-ENOENT);
 
                fs_devices = alloc_fs_devices(fsid);
@@ -6531,7 +6590,7 @@ static int read_one_dev(struct btrfs_root *root,
 
        device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid);
        if (!device) {
-               if (!btrfs_test_opt(root, DEGRADED))
+               if (!btrfs_test_opt(root->fs_info, DEGRADED))
                        return -EIO;
 
                device = add_missing_dev(root, fs_devices, devid, dev_uuid);
@@ -6540,7 +6599,7 @@ static int read_one_dev(struct btrfs_root *root,
                btrfs_warn(root->fs_info, "devid %llu uuid %pU missing",
                                devid, dev_uuid);
        } else {
-               if (!device->bdev && !btrfs_test_opt(root, DEGRADED))
+               if (!device->bdev && !btrfs_test_opt(root->fs_info, DEGRADED))
                        return -EIO;
 
                if(!device->bdev && !device->missing) {
@@ -7143,38 +7202,3 @@ void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info)
                fs_devices = fs_devices->seed;
        }
 }
-
-static void btrfs_close_one_device(struct btrfs_device *device)
-{
-       struct btrfs_fs_devices *fs_devices = device->fs_devices;
-       struct btrfs_device *new_device;
-       struct rcu_string *name;
-
-       if (device->bdev)
-               fs_devices->open_devices--;
-
-       if (device->writeable &&
-           device->devid != BTRFS_DEV_REPLACE_DEVID) {
-               list_del_init(&device->dev_alloc_list);
-               fs_devices->rw_devices--;
-       }
-
-       if (device->missing)
-               fs_devices->missing_devices--;
-
-       new_device = btrfs_alloc_device(NULL, &device->devid,
-                                       device->uuid);
-       BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
-
-       /* Safe because we are under uuid_mutex */
-       if (device->name) {
-               name = rcu_string_strdup(device->name->str, GFP_NOFS);
-               BUG_ON(!name); /* -ENOMEM */
-               rcu_assign_pointer(new_device->name, name);
-       }
-
-       list_replace_rcu(&device->dev_list, &new_device->dev_list);
-       new_device->fs_devices = device->fs_devices;
-
-       call_rcu(&device->rcu, free_device);
-}
index 4ae7500..3f7c2cd 100644 (file)
@@ -263,6 +263,8 @@ requeue:
 void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
                                     struct cachefiles_object *object)
 {
+       blkcnt_t i_blocks = d_backing_inode(object->dentry)->i_blocks;
+
        write_lock(&cache->active_lock);
        rb_erase(&object->active_node, &cache->active_nodes);
        clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
@@ -273,8 +275,7 @@ void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
        /* This object can now be culled, so we need to let the daemon know
         * that there is something it can remove if it needs to.
         */
-       atomic_long_add(d_backing_inode(object->dentry)->i_blocks,
-                       &cache->b_released);
+       atomic_long_add(i_blocks, &cache->b_released);
        if (atomic_inc_return(&cache->f_released))
                cachefiles_state_changed(cache);
 }
index 26a9d10..d5b6f95 100644 (file)
@@ -1730,7 +1730,8 @@ enum {
        POOL_WRITE      = 2,
 };
 
-static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
+static int __ceph_pool_perm_get(struct ceph_inode_info *ci,
+                               s64 pool, struct ceph_string *pool_ns)
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(&ci->vfs_inode);
        struct ceph_mds_client *mdsc = fsc->mdsc;
@@ -1738,6 +1739,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
        struct rb_node **p, *parent;
        struct ceph_pool_perm *perm;
        struct page **pages;
+       size_t pool_ns_len;
        int err = 0, err2 = 0, have = 0;
 
        down_read(&mdsc->pool_perm_rwsem);
@@ -1749,17 +1751,31 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
                else if (pool > perm->pool)
                        p = &(*p)->rb_right;
                else {
-                       have = perm->perm;
-                       break;
+                       int ret = ceph_compare_string(pool_ns,
+                                               perm->pool_ns,
+                                               perm->pool_ns_len);
+                       if (ret < 0)
+                               p = &(*p)->rb_left;
+                       else if (ret > 0)
+                               p = &(*p)->rb_right;
+                       else {
+                               have = perm->perm;
+                               break;
+                       }
                }
        }
        up_read(&mdsc->pool_perm_rwsem);
        if (*p)
                goto out;
 
-       dout("__ceph_pool_perm_get pool %u no perm cached\n", pool);
+       if (pool_ns)
+               dout("__ceph_pool_perm_get pool %lld ns %.*s no perm cached\n",
+                    pool, (int)pool_ns->len, pool_ns->str);
+       else
+               dout("__ceph_pool_perm_get pool %lld no perm cached\n", pool);
 
        down_write(&mdsc->pool_perm_rwsem);
+       p = &mdsc->pool_perm_tree.rb_node;
        parent = NULL;
        while (*p) {
                parent = *p;
@@ -1769,8 +1785,17 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
                else if (pool > perm->pool)
                        p = &(*p)->rb_right;
                else {
-                       have = perm->perm;
-                       break;
+                       int ret = ceph_compare_string(pool_ns,
+                                               perm->pool_ns,
+                                               perm->pool_ns_len);
+                       if (ret < 0)
+                               p = &(*p)->rb_left;
+                       else if (ret > 0)
+                               p = &(*p)->rb_right;
+                       else {
+                               have = perm->perm;
+                               break;
+                       }
                }
        }
        if (*p) {
@@ -1788,6 +1813,8 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
        rd_req->r_flags = CEPH_OSD_FLAG_READ;
        osd_req_op_init(rd_req, 0, CEPH_OSD_OP_STAT, 0);
        rd_req->r_base_oloc.pool = pool;
+       if (pool_ns)
+               rd_req->r_base_oloc.pool_ns = ceph_get_string(pool_ns);
        ceph_oid_printf(&rd_req->r_base_oid, "%llx.00000000", ci->i_vino.ino);
 
        err = ceph_osdc_alloc_messages(rd_req, GFP_NOFS);
@@ -1841,7 +1868,8 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
                goto out_unlock;
        }
 
-       perm = kmalloc(sizeof(*perm), GFP_NOFS);
+       pool_ns_len = pool_ns ? pool_ns->len : 0;
+       perm = kmalloc(sizeof(*perm) + pool_ns_len + 1, GFP_NOFS);
        if (!perm) {
                err = -ENOMEM;
                goto out_unlock;
@@ -1849,6 +1877,11 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, u32 pool)
 
        perm->pool = pool;
        perm->perm = have;
+       perm->pool_ns_len = pool_ns_len;
+       if (pool_ns_len > 0)
+               memcpy(perm->pool_ns, pool_ns->str, pool_ns_len);
+       perm->pool_ns[pool_ns_len] = 0;
+
        rb_link_node(&perm->node, parent, p);
        rb_insert_color(&perm->node, &mdsc->pool_perm_tree);
        err = 0;
@@ -1860,43 +1893,46 @@ out_unlock:
 out:
        if (!err)
                err = have;
-       dout("__ceph_pool_perm_get pool %u result = %d\n", pool, err);
+       if (pool_ns)
+               dout("__ceph_pool_perm_get pool %lld ns %.*s result = %d\n",
+                    pool, (int)pool_ns->len, pool_ns->str, err);
+       else
+               dout("__ceph_pool_perm_get pool %lld result = %d\n", pool, err);
        return err;
 }
 
 int ceph_pool_perm_check(struct ceph_inode_info *ci, int need)
 {
-       u32 pool;
+       s64 pool;
+       struct ceph_string *pool_ns;
        int ret, flags;
 
-       /* does not support pool namespace yet */
-       if (ci->i_pool_ns_len)
-               return -EIO;
-
        if (ceph_test_mount_opt(ceph_inode_to_client(&ci->vfs_inode),
                                NOPOOLPERM))
                return 0;
 
        spin_lock(&ci->i_ceph_lock);
        flags = ci->i_ceph_flags;
-       pool = ceph_file_layout_pg_pool(ci->i_layout);
+       pool = ci->i_layout.pool_id;
        spin_unlock(&ci->i_ceph_lock);
 check:
        if (flags & CEPH_I_POOL_PERM) {
                if ((need & CEPH_CAP_FILE_RD) && !(flags & CEPH_I_POOL_RD)) {
-                       dout("ceph_pool_perm_check pool %u no read perm\n",
+                       dout("ceph_pool_perm_check pool %lld no read perm\n",
                             pool);
                        return -EPERM;
                }
                if ((need & CEPH_CAP_FILE_WR) && !(flags & CEPH_I_POOL_WR)) {
-                       dout("ceph_pool_perm_check pool %u no write perm\n",
+                       dout("ceph_pool_perm_check pool %lld no write perm\n",
                             pool);
                        return -EPERM;
                }
                return 0;
        }
 
-       ret = __ceph_pool_perm_get(ci, pool);
+       pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
+       ret = __ceph_pool_perm_get(ci, pool, pool_ns);
+       ceph_put_string(pool_ns);
        if (ret < 0)
                return ret;
 
@@ -1907,10 +1943,11 @@ check:
                flags |= CEPH_I_POOL_WR;
 
        spin_lock(&ci->i_ceph_lock);
-       if (pool == ceph_file_layout_pg_pool(ci->i_layout)) {
-               ci->i_ceph_flags = flags;
+       if (pool == ci->i_layout.pool_id &&
+           pool_ns == rcu_dereference_raw(ci->i_layout.pool_ns)) {
+               ci->i_ceph_flags |= flags;
         } else {
-               pool = ceph_file_layout_pg_pool(ci->i_layout);
+               pool = ci->i_layout.pool_id;
                flags = ci->i_ceph_flags;
        }
        spin_unlock(&ci->i_ceph_lock);
index 238c55b..5bc5d37 100644 (file)
@@ -71,7 +71,7 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
                                              &ceph_fscache_fsid_object_def,
                                              fsc, true);
        if (!fsc->fscache)
-               pr_err("Unable to resgister fsid: %p fscache cookie", fsc);
+               pr_err("Unable to register fsid: %p fscache cookie\n", fsc);
 
        return 0;
 }
index 6f60d0a..16e6ded 100644 (file)
  * cluster to release server state.
  */
 
+static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc);
+static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_session *session,
+                                struct ceph_inode_info *ci,
+                                u64 oldest_flush_tid);
 
 /*
  * Generate readable cap strings for debugging output.
@@ -849,12 +854,14 @@ int __ceph_caps_used(struct ceph_inode_info *ci)
  */
 int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
 {
-       int want = 0;
-       int mode;
-       for (mode = 0; mode < CEPH_FILE_MODE_NUM; mode++)
-               if (ci->i_nr_by_mode[mode])
-                       want |= ceph_caps_for_mode(mode);
-       return want;
+       int i, bits = 0;
+       for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
+               if (ci->i_nr_by_mode[i])
+                       bits |= 1 << i;
+       }
+       if (bits == 0)
+               return 0;
+       return ceph_caps_for_mode(bits >> 1);
 }
 
 /*
@@ -991,7 +998,7 @@ static int send_cap_msg(struct ceph_mds_session *session,
                        u32 seq, u64 flush_tid, u64 oldest_flush_tid,
                        u32 issue_seq, u32 mseq, u64 size, u64 max_size,
                        struct timespec *mtime, struct timespec *atime,
-                       struct timespec *ctime, u64 time_warp_seq,
+                       struct timespec *ctime, u32 time_warp_seq,
                        kuid_t uid, kgid_t gid, umode_t mode,
                        u64 xattr_version,
                        struct ceph_buffer *xattrs_buf,
@@ -1116,8 +1123,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        struct inode *inode = &ci->vfs_inode;
        u64 cap_id = cap->cap_id;
        int held, revoking, dropping, keep;
-       u64 seq, issue_seq, mseq, time_warp_seq, follows;
-       u64 size, max_size;
+       u64 follows, size, max_size;
+       u32 seq, issue_seq, mseq, time_warp_seq;
        struct timespec mtime, atime, ctime;
        int wake = 0;
        umode_t mode;
@@ -1215,6 +1222,22 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
        return delayed;
 }
 
+static inline int __send_flush_snap(struct inode *inode,
+                                   struct ceph_mds_session *session,
+                                   struct ceph_cap_snap *capsnap,
+                                   u32 mseq, u64 oldest_flush_tid)
+{
+       return send_cap_msg(session, ceph_vino(inode).ino, 0,
+                       CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
+                       capsnap->dirty, 0, capsnap->cap_flush.tid,
+                       oldest_flush_tid, 0, mseq, capsnap->size, 0,
+                       &capsnap->mtime, &capsnap->atime,
+                       &capsnap->ctime, capsnap->time_warp_seq,
+                       capsnap->uid, capsnap->gid, capsnap->mode,
+                       capsnap->xattr_version, capsnap->xattr_blob,
+                       capsnap->follows, capsnap->inline_data);
+}
+
 /*
  * When a snapshot is taken, clients accumulate dirty metadata on
  * inodes with capabilities in ceph_cap_snaps to describe the file
@@ -1222,37 +1245,22 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
  * asynchronously back to the MDS once sync writes complete and dirty
  * data is written out.
  *
- * Unless @kick is true, skip cap_snaps that were already sent to
- * the MDS (i.e., during this session).
- *
  * Called under i_ceph_lock.  Takes s_mutex as needed.
  */
-void __ceph_flush_snaps(struct ceph_inode_info *ci,
-                       struct ceph_mds_session **psession,
-                       int kick)
+static void __ceph_flush_snaps(struct ceph_inode_info *ci,
+                              struct ceph_mds_session *session)
                __releases(ci->i_ceph_lock)
                __acquires(ci->i_ceph_lock)
 {
        struct inode *inode = &ci->vfs_inode;
-       int mds;
+       struct ceph_mds_client *mdsc = session->s_mdsc;
        struct ceph_cap_snap *capsnap;
-       u32 mseq;
-       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
-       struct ceph_mds_session *session = NULL; /* if session != NULL, we hold
-                                                   session->s_mutex */
-       u64 next_follows = 0;  /* keep track of how far we've gotten through the
-                            i_cap_snaps list, and skip these entries next time
-                            around to avoid an infinite loop */
+       u64 oldest_flush_tid = 0;
+       u64 first_tid = 1, last_tid = 0;
 
-       if (psession)
-               session = *psession;
+       dout("__flush_snaps %p session %p\n", inode, session);
 
-       dout("__flush_snaps %p\n", inode);
-retry:
        list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
-               /* avoid an infiniute loop after retry */
-               if (capsnap->follows < next_follows)
-                       continue;
                /*
                 * we need to wait for sync writes to complete and for dirty
                 * pages to be written out.
@@ -1263,97 +1271,132 @@ retry:
                /* should be removed by ceph_try_drop_cap_snap() */
                BUG_ON(!capsnap->need_flush);
 
-               /* pick mds, take s_mutex */
-               if (ci->i_auth_cap == NULL) {
-                       dout("no auth cap (migrating?), doing nothing\n");
-                       goto out;
-               }
-
                /* only flush each capsnap once */
-               if (!kick && !list_empty(&capsnap->flushing_item)) {
-                       dout("already flushed %p, skipping\n", capsnap);
+               if (capsnap->cap_flush.tid > 0) {
+                       dout(" already flushed %p, skipping\n", capsnap);
                        continue;
                }
 
-               mds = ci->i_auth_cap->session->s_mds;
-               mseq = ci->i_auth_cap->mseq;
+               spin_lock(&mdsc->cap_dirty_lock);
+               capsnap->cap_flush.tid = ++mdsc->last_cap_flush_tid;
+               list_add_tail(&capsnap->cap_flush.g_list,
+                             &mdsc->cap_flush_list);
+               if (oldest_flush_tid == 0)
+                       oldest_flush_tid = __get_oldest_flush_tid(mdsc);
+               if (list_empty(&ci->i_flushing_item)) {
+                       list_add_tail(&ci->i_flushing_item,
+                                     &session->s_cap_flushing);
+               }
+               spin_unlock(&mdsc->cap_dirty_lock);
+
+               list_add_tail(&capsnap->cap_flush.i_list,
+                             &ci->i_cap_flush_list);
 
-               if (session && session->s_mds != mds) {
-                       dout("oops, wrong session %p mutex\n", session);
-                       if (kick)
-                               goto out;
+               if (first_tid == 1)
+                       first_tid = capsnap->cap_flush.tid;
+               last_tid = capsnap->cap_flush.tid;
+       }
 
-                       mutex_unlock(&session->s_mutex);
-                       ceph_put_mds_session(session);
-                       session = NULL;
+       ci->i_ceph_flags &= ~CEPH_I_FLUSH_SNAPS;
+
+       while (first_tid <= last_tid) {
+               struct ceph_cap *cap = ci->i_auth_cap;
+               struct ceph_cap_flush *cf;
+               int ret;
+
+               if (!(cap && cap->session == session)) {
+                       dout("__flush_snaps %p auth cap %p not mds%d, "
+                            "stop\n", inode, cap, session->s_mds);
+                       break;
                }
-               if (!session) {
-                       spin_unlock(&ci->i_ceph_lock);
-                       mutex_lock(&mdsc->mutex);
-                       session = __ceph_lookup_mds_session(mdsc, mds);
-                       mutex_unlock(&mdsc->mutex);
-                       if (session) {
-                               dout("inverting session/ino locks on %p\n",
-                                    session);
-                               mutex_lock(&session->s_mutex);
+
+               ret = -ENOENT;
+               list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) {
+                       if (cf->tid >= first_tid) {
+                               ret = 0;
+                               break;
                        }
-                       /*
-                        * if session == NULL, we raced against a cap
-                        * deletion or migration.  retry, and we'll
-                        * get a better @mds value next time.
-                        */
-                       spin_lock(&ci->i_ceph_lock);
-                       goto retry;
                }
+               if (ret < 0)
+                       break;
 
-               spin_lock(&mdsc->cap_dirty_lock);
-               capsnap->flush_tid = ++mdsc->last_cap_flush_tid;
-               spin_unlock(&mdsc->cap_dirty_lock);
+               first_tid = cf->tid + 1;
 
+               capsnap = container_of(cf, struct ceph_cap_snap, cap_flush);
                atomic_inc(&capsnap->nref);
-               if (list_empty(&capsnap->flushing_item))
-                       list_add_tail(&capsnap->flushing_item,
-                                     &session->s_cap_snaps_flushing);
                spin_unlock(&ci->i_ceph_lock);
 
-               dout("flush_snaps %p cap_snap %p follows %lld tid %llu\n",
-                    inode, capsnap, capsnap->follows, capsnap->flush_tid);
-               send_cap_msg(session, ceph_vino(inode).ino, 0,
-                            CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
-                            capsnap->dirty, 0, capsnap->flush_tid, 0,
-                            0, mseq, capsnap->size, 0,
-                            &capsnap->mtime, &capsnap->atime,
-                            &capsnap->ctime, capsnap->time_warp_seq,
-                            capsnap->uid, capsnap->gid, capsnap->mode,
-                            capsnap->xattr_version, capsnap->xattr_blob,
-                            capsnap->follows, capsnap->inline_data);
-
-               next_follows = capsnap->follows + 1;
-               ceph_put_cap_snap(capsnap);
+               dout("__flush_snaps %p capsnap %p tid %llu %s\n",
+                    inode, capsnap, cf->tid, ceph_cap_string(capsnap->dirty));
 
+               ret = __send_flush_snap(inode, session, capsnap, cap->mseq,
+                                       oldest_flush_tid);
+               if (ret < 0) {
+                       pr_err("__flush_snaps: error sending cap flushsnap, "
+                              "ino (%llx.%llx) tid %llu follows %llu\n",
+                               ceph_vinop(inode), cf->tid, capsnap->follows);
+               }
+
+               ceph_put_cap_snap(capsnap);
                spin_lock(&ci->i_ceph_lock);
-               goto retry;
        }
+}
 
-       /* we flushed them all; remove this inode from the queue */
-       spin_lock(&mdsc->snap_flush_lock);
-       list_del_init(&ci->i_snap_flush_item);
-       spin_unlock(&mdsc->snap_flush_lock);
+void ceph_flush_snaps(struct ceph_inode_info *ci,
+                     struct ceph_mds_session **psession)
+{
+       struct inode *inode = &ci->vfs_inode;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_session *session = NULL;
+       int mds;
 
-out:
+       dout("ceph_flush_snaps %p\n", inode);
        if (psession)
-               *psession = session;
-       else if (session) {
+               session = *psession;
+retry:
+       spin_lock(&ci->i_ceph_lock);
+       if (!(ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS)) {
+               dout(" no capsnap needs flush, doing nothing\n");
+               goto out;
+       }
+       if (!ci->i_auth_cap) {
+               dout(" no auth cap (migrating?), doing nothing\n");
+               goto out;
+       }
+
+       mds = ci->i_auth_cap->session->s_mds;
+       if (session && session->s_mds != mds) {
+               dout(" oops, wrong session %p mutex\n", session);
                mutex_unlock(&session->s_mutex);
                ceph_put_mds_session(session);
+               session = NULL;
+       }
+       if (!session) {
+               spin_unlock(&ci->i_ceph_lock);
+               mutex_lock(&mdsc->mutex);
+               session = __ceph_lookup_mds_session(mdsc, mds);
+               mutex_unlock(&mdsc->mutex);
+               if (session) {
+                       dout(" inverting session/ino locks on %p\n", session);
+                       mutex_lock(&session->s_mutex);
+               }
+               goto retry;
        }
-}
 
-static void ceph_flush_snaps(struct ceph_inode_info *ci)
-{
-       spin_lock(&ci->i_ceph_lock);
-       __ceph_flush_snaps(ci, NULL, 0);
+       __ceph_flush_snaps(ci, session);
+out:
        spin_unlock(&ci->i_ceph_lock);
+
+       if (psession) {
+               *psession = session;
+       } else {
+               mutex_unlock(&session->s_mutex);
+               ceph_put_mds_session(session);
+       }
+       /* we flushed them all; remove this inode from the queue */
+       spin_lock(&mdsc->snap_flush_lock);
+       list_del_init(&ci->i_snap_flush_item);
+       spin_unlock(&mdsc->snap_flush_lock);
 }
 
 /*
@@ -1411,52 +1454,6 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask,
        return dirty;
 }
 
-static void __add_cap_flushing_to_inode(struct ceph_inode_info *ci,
-                                       struct ceph_cap_flush *cf)
-{
-       struct rb_node **p = &ci->i_cap_flush_tree.rb_node;
-       struct rb_node *parent = NULL;
-       struct ceph_cap_flush *other = NULL;
-
-       while (*p) {
-               parent = *p;
-               other = rb_entry(parent, struct ceph_cap_flush, i_node);
-
-               if (cf->tid < other->tid)
-                       p = &(*p)->rb_left;
-               else if (cf->tid > other->tid)
-                       p = &(*p)->rb_right;
-               else
-                       BUG();
-       }
-
-       rb_link_node(&cf->i_node, parent, p);
-       rb_insert_color(&cf->i_node, &ci->i_cap_flush_tree);
-}
-
-static void __add_cap_flushing_to_mdsc(struct ceph_mds_client *mdsc,
-                                      struct ceph_cap_flush *cf)
-{
-       struct rb_node **p = &mdsc->cap_flush_tree.rb_node;
-       struct rb_node *parent = NULL;
-       struct ceph_cap_flush *other = NULL;
-
-       while (*p) {
-               parent = *p;
-               other = rb_entry(parent, struct ceph_cap_flush, g_node);
-
-               if (cf->tid < other->tid)
-                       p = &(*p)->rb_left;
-               else if (cf->tid > other->tid)
-                       p = &(*p)->rb_right;
-               else
-                       BUG();
-       }
-
-       rb_link_node(&cf->g_node, parent, p);
-       rb_insert_color(&cf->g_node, &mdsc->cap_flush_tree);
-}
-
 struct ceph_cap_flush *ceph_alloc_cap_flush(void)
 {
        return kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL);
@@ -1470,15 +1467,46 @@ void ceph_free_cap_flush(struct ceph_cap_flush *cf)
 
 static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc)
 {
-       struct rb_node *n = rb_first(&mdsc->cap_flush_tree);
-       if (n) {
+       if (!list_empty(&mdsc->cap_flush_list)) {
                struct ceph_cap_flush *cf =
-                       rb_entry(n, struct ceph_cap_flush, g_node);
+                       list_first_entry(&mdsc->cap_flush_list,
+                                        struct ceph_cap_flush, g_list);
                return cf->tid;
        }
        return 0;
 }
 
+/*
+ * Remove cap_flush from the mdsc's or inode's flushing cap list.
+ * Return true if caller needs to wake up flush waiters.
+ */
+static bool __finish_cap_flush(struct ceph_mds_client *mdsc,
+                              struct ceph_inode_info *ci,
+                              struct ceph_cap_flush *cf)
+{
+       struct ceph_cap_flush *prev;
+       bool wake = cf->wake;
+       if (mdsc) {
+               /* are there older pending cap flushes? */
+               if (wake && cf->g_list.prev != &mdsc->cap_flush_list) {
+                       prev = list_prev_entry(cf, g_list);
+                       prev->wake = true;
+                       wake = false;
+               }
+               list_del(&cf->g_list);
+       } else if (ci) {
+               if (wake && cf->i_list.prev != &ci->i_cap_flush_list) {
+                       prev = list_prev_entry(cf, i_list);
+                       prev->wake = true;
+                       wake = false;
+               }
+               list_del(&cf->i_list);
+       } else {
+               BUG_ON(1);
+       }
+       return wake;
+}
+
 /*
  * Add dirty inode to the flushing list.  Assigned a seq number so we
  * can wait for caps to flush without starving.
@@ -1486,7 +1514,7 @@ static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc)
  * Called under i_ceph_lock.
  */
 static int __mark_caps_flushing(struct inode *inode,
-                               struct ceph_mds_session *session,
+                               struct ceph_mds_session *session, bool wake,
                                u64 *flush_tid, u64 *oldest_flush_tid)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
@@ -1509,26 +1537,22 @@ static int __mark_caps_flushing(struct inode *inode,
 
        swap(cf, ci->i_prealloc_cap_flush);
        cf->caps = flushing;
+       cf->wake = wake;
 
        spin_lock(&mdsc->cap_dirty_lock);
        list_del_init(&ci->i_dirty_item);
 
        cf->tid = ++mdsc->last_cap_flush_tid;
-       __add_cap_flushing_to_mdsc(mdsc, cf);
+       list_add_tail(&cf->g_list, &mdsc->cap_flush_list);
        *oldest_flush_tid = __get_oldest_flush_tid(mdsc);
 
        if (list_empty(&ci->i_flushing_item)) {
                list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing);
                mdsc->num_cap_flushing++;
-               dout(" inode %p now flushing tid %llu\n", inode, cf->tid);
-       } else {
-               list_move_tail(&ci->i_flushing_item, &session->s_cap_flushing);
-               dout(" inode %p now flushing (more) tid %llu\n",
-                    inode, cf->tid);
        }
        spin_unlock(&mdsc->cap_dirty_lock);
 
-       __add_cap_flushing_to_inode(ci, cf);
+       list_add_tail(&cf->i_list, &ci->i_cap_flush_list);
 
        *flush_tid = cf->tid;
        return flushing;
@@ -1583,10 +1607,11 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
        int mds = -1;   /* keep track of how far we've gone through i_caps list
                           to avoid an infinite loop on retry */
        struct rb_node *p;
-       int tried_invalidate = 0;
-       int delayed = 0, sent = 0, force_requeue = 0, num;
-       int queue_invalidate = 0;
-       int is_delayed = flags & CHECK_CAPS_NODELAY;
+       int delayed = 0, sent = 0, num;
+       bool is_delayed = flags & CHECK_CAPS_NODELAY;
+       bool queue_invalidate = false;
+       bool force_requeue = false;
+       bool tried_invalidate = false;
 
        /* if we are unmounting, flush any unused caps immediately. */
        if (mdsc->stopping)
@@ -1597,9 +1622,6 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags,
        if (ci->i_ceph_flags & CEPH_I_FLUSH)
                flags |= CHECK_CAPS_FLUSH;
 
-       /* flush snaps first time around only */
-       if (!list_empty(&ci->i_cap_snaps))
-               __ceph_flush_snaps(ci, &session, 0);
        goto retry_locked;
 retry:
        spin_lock(&ci->i_ceph_lock);
@@ -1666,17 +1688,17 @@ retry_locked:
                        if (revoking & (CEPH_CAP_FILE_CACHE|
                                        CEPH_CAP_FILE_LAZYIO)) {
                                dout("check_caps queuing invalidate\n");
-                               queue_invalidate = 1;
+                               queue_invalidate = true;
                                ci->i_rdcache_revoking = ci->i_rdcache_gen;
                        } else {
                                dout("check_caps failed to invalidate pages\n");
                                /* we failed to invalidate pages.  check these
                                   caps again later. */
-                               force_requeue = 1;
+                               force_requeue = true;
                                __cap_set_timeouts(mdsc, ci);
                        }
                }
-               tried_invalidate = 1;
+               tried_invalidate = true;
                goto retry_locked;
        }
 
@@ -1720,10 +1742,15 @@ retry_locked:
                        }
                }
                /* flush anything dirty? */
-               if (cap == ci->i_auth_cap && (flags & CHECK_CAPS_FLUSH) &&
-                   ci->i_dirty_caps) {
-                       dout("flushing dirty caps\n");
-                       goto ack;
+               if (cap == ci->i_auth_cap) {
+                       if ((flags & CHECK_CAPS_FLUSH) && ci->i_dirty_caps) {
+                               dout("flushing dirty caps\n");
+                               goto ack;
+                       }
+                       if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS) {
+                               dout("flushing snap caps\n");
+                               goto ack;
+                       }
                }
 
                /* completed revocation? going down and there are no caps? */
@@ -1782,6 +1809,26 @@ ack:
                                goto retry;
                        }
                }
+
+               /* kick flushing and flush snaps before sending normal
+                * cap message */
+               if (cap == ci->i_auth_cap &&
+                   (ci->i_ceph_flags &
+                    (CEPH_I_KICK_FLUSH | CEPH_I_FLUSH_SNAPS))) {
+                       if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH) {
+                               spin_lock(&mdsc->cap_dirty_lock);
+                               oldest_flush_tid = __get_oldest_flush_tid(mdsc);
+                               spin_unlock(&mdsc->cap_dirty_lock);
+                               __kick_flushing_caps(mdsc, session, ci,
+                                                    oldest_flush_tid);
+                               ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+                       }
+                       if (ci->i_ceph_flags & CEPH_I_FLUSH_SNAPS)
+                               __ceph_flush_snaps(ci, session);
+
+                       goto retry_locked;
+               }
+
                /* take snap_rwsem after session mutex */
                if (!took_snap_rwsem) {
                        if (down_read_trylock(&mdsc->snap_rwsem) == 0) {
@@ -1796,7 +1843,7 @@ ack:
                }
 
                if (cap == ci->i_auth_cap && ci->i_dirty_caps) {
-                       flushing = __mark_caps_flushing(inode, session,
+                       flushing = __mark_caps_flushing(inode, session, false,
                                                        &flush_tid,
                                                        &oldest_flush_tid);
                } else {
@@ -1822,7 +1869,7 @@ ack:
         * otherwise cancel.
         */
        if (delayed && is_delayed)
-               force_requeue = 1;   /* __send_cap delayed release; requeue */
+               force_requeue = true;   /* __send_cap delayed release; requeue */
        if (!delayed && !is_delayed)
                __cap_delay_cancel(mdsc, ci);
        else if (!is_delayed || force_requeue)
@@ -1873,8 +1920,8 @@ retry:
                if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
                        goto out;
 
-               flushing = __mark_caps_flushing(inode, session, &flush_tid,
-                                               &oldest_flush_tid);
+               flushing = __mark_caps_flushing(inode, session, true,
+                                               &flush_tid, &oldest_flush_tid);
 
                /* __send_cap drops i_ceph_lock */
                delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, used, want,
@@ -1887,10 +1934,11 @@ retry:
                        spin_unlock(&ci->i_ceph_lock);
                }
        } else {
-               struct rb_node *n = rb_last(&ci->i_cap_flush_tree);
-               if (n) {
+               if (!list_empty(&ci->i_cap_flush_list)) {
                        struct ceph_cap_flush *cf =
-                               rb_entry(n, struct ceph_cap_flush, i_node);
+                               list_last_entry(&ci->i_cap_flush_list,
+                                               struct ceph_cap_flush, i_list);
+                       cf->wake = true;
                        flush_tid = cf->tid;
                }
                flushing = ci->i_flushing_caps;
@@ -1910,14 +1958,13 @@ out:
 static int caps_are_flushed(struct inode *inode, u64 flush_tid)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_cap_flush *cf;
-       struct rb_node *n;
        int ret = 1;
 
        spin_lock(&ci->i_ceph_lock);
-       n = rb_first(&ci->i_cap_flush_tree);
-       if (n) {
-               cf = rb_entry(n, struct ceph_cap_flush, i_node);
+       if (!list_empty(&ci->i_cap_flush_list)) {
+               struct ceph_cap_flush * cf =
+                       list_first_entry(&ci->i_cap_flush_list,
+                                        struct ceph_cap_flush, i_list);
                if (cf->tid <= flush_tid)
                        ret = 0;
        }
@@ -1925,53 +1972,6 @@ static int caps_are_flushed(struct inode *inode, u64 flush_tid)
        return ret;
 }
 
-/*
- * Wait on any unsafe replies for the given inode.  First wait on the
- * newest request, and make that the upper bound.  Then, if there are
- * more requests, keep waiting on the oldest as long as it is still older
- * than the original request.
- */
-static void sync_write_wait(struct inode *inode)
-{
-       struct ceph_inode_info *ci = ceph_inode(inode);
-       struct list_head *head = &ci->i_unsafe_writes;
-       struct ceph_osd_request *req;
-       u64 last_tid;
-
-       if (!S_ISREG(inode->i_mode))
-               return;
-
-       spin_lock(&ci->i_unsafe_lock);
-       if (list_empty(head))
-               goto out;
-
-       /* set upper bound as _last_ entry in chain */
-       req = list_last_entry(head, struct ceph_osd_request,
-                             r_unsafe_item);
-       last_tid = req->r_tid;
-
-       do {
-               ceph_osdc_get_request(req);
-               spin_unlock(&ci->i_unsafe_lock);
-               dout("sync_write_wait on tid %llu (until %llu)\n",
-                    req->r_tid, last_tid);
-               wait_for_completion(&req->r_safe_completion);
-               spin_lock(&ci->i_unsafe_lock);
-               ceph_osdc_put_request(req);
-
-               /*
-                * from here on look at first entry in chain, since we
-                * only want to wait for anything older than last_tid
-                */
-               if (list_empty(head))
-                       break;
-               req = list_first_entry(head, struct ceph_osd_request,
-                                      r_unsafe_item);
-       } while (req->r_tid < last_tid);
-out:
-       spin_unlock(&ci->i_unsafe_lock);
-}
-
 /*
  * wait for any unsafe requests to complete.
  */
@@ -2024,7 +2024,8 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        int dirty;
 
        dout("fsync %p%s\n", inode, datasync ? " datasync" : "");
-       sync_write_wait(inode);
+
+       ceph_sync_write_wait(inode);
 
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (ret < 0)
@@ -2087,87 +2088,74 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
        return err;
 }
 
-/*
- * After a recovering MDS goes active, we need to resend any caps
- * we were flushing.
- *
- * Caller holds session->s_mutex.
- */
-static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
-                                  struct ceph_mds_session *session)
-{
-       struct ceph_cap_snap *capsnap;
-
-       dout("kick_flushing_capsnaps mds%d\n", session->s_mds);
-       list_for_each_entry(capsnap, &session->s_cap_snaps_flushing,
-                           flushing_item) {
-               struct ceph_inode_info *ci = capsnap->ci;
-               struct inode *inode = &ci->vfs_inode;
-               struct ceph_cap *cap;
-
-               spin_lock(&ci->i_ceph_lock);
-               cap = ci->i_auth_cap;
-               if (cap && cap->session == session) {
-                       dout("kick_flushing_caps %p cap %p capsnap %p\n", inode,
-                            cap, capsnap);
-                       __ceph_flush_snaps(ci, &session, 1);
-               } else {
-                       pr_err("%p auth cap %p not mds%d ???\n", inode,
-                              cap, session->s_mds);
-               }
-               spin_unlock(&ci->i_ceph_lock);
-       }
-}
-
-static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
-                               struct ceph_mds_session *session,
-                               struct ceph_inode_info *ci)
+static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
+                                struct ceph_mds_session *session,
+                                struct ceph_inode_info *ci,
+                                u64 oldest_flush_tid)
+       __releases(ci->i_ceph_lock)
+       __acquires(ci->i_ceph_lock)
 {
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
        struct ceph_cap_flush *cf;
-       struct rb_node *n;
-       int delayed = 0;
+       int ret;
        u64 first_tid = 0;
-       u64 oldest_flush_tid;
 
-       spin_lock(&mdsc->cap_dirty_lock);
-       oldest_flush_tid = __get_oldest_flush_tid(mdsc);
-       spin_unlock(&mdsc->cap_dirty_lock);
+       list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) {
+               if (cf->tid < first_tid)
+                       continue;
 
-       while (true) {
-               spin_lock(&ci->i_ceph_lock);
                cap = ci->i_auth_cap;
                if (!(cap && cap->session == session)) {
-                       pr_err("%p auth cap %p not mds%d ???\n", inode,
-                                       cap, session->s_mds);
-                       spin_unlock(&ci->i_ceph_lock);
+                       pr_err("%p auth cap %p not mds%d ???\n",
+                              inode, cap, session->s_mds);
                        break;
                }
 
-               for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
-                       cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       if (cf->tid >= first_tid)
-                               break;
-               }
-               if (!n) {
+               first_tid = cf->tid + 1;
+
+               if (cf->caps) {
+                       dout("kick_flushing_caps %p cap %p tid %llu %s\n",
+                            inode, cap, cf->tid, ceph_cap_string(cf->caps));
+                       ci->i_ceph_flags |= CEPH_I_NODELAY;
+                       ret = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                                         __ceph_caps_used(ci),
+                                         __ceph_caps_wanted(ci),
+                                         cap->issued | cap->implemented,
+                                         cf->caps, cf->tid, oldest_flush_tid);
+                       if (ret) {
+                               pr_err("kick_flushing_caps: error sending "
+                                       "cap flush, ino (%llx.%llx) "
+                                       "tid %llu flushing %s\n",
+                                       ceph_vinop(inode), cf->tid,
+                                       ceph_cap_string(cf->caps));
+                       }
+               } else {
+                       struct ceph_cap_snap *capsnap =
+                                       container_of(cf, struct ceph_cap_snap,
+                                                   cap_flush);
+                       dout("kick_flushing_caps %p capsnap %p tid %llu %s\n",
+                            inode, capsnap, cf->tid,
+                            ceph_cap_string(capsnap->dirty));
+
+                       atomic_inc(&capsnap->nref);
                        spin_unlock(&ci->i_ceph_lock);
-                       break;
-               }
 
-               cf = rb_entry(n, struct ceph_cap_flush, i_node);
+                       ret = __send_flush_snap(inode, session, capsnap, cap->mseq,
+                                               oldest_flush_tid);
+                       if (ret < 0) {
+                               pr_err("kick_flushing_caps: error sending "
+                                       "cap flushsnap, ino (%llx.%llx) "
+                                       "tid %llu follows %llu\n",
+                                       ceph_vinop(inode), cf->tid,
+                                       capsnap->follows);
+                       }
 
-               first_tid = cf->tid + 1;
+                       ceph_put_cap_snap(capsnap);
+               }
 
-               dout("kick_flushing_caps %p cap %p tid %llu %s\n", inode,
-                    cap, cf->tid, ceph_cap_string(cf->caps));
-               delayed |= __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
-                                     __ceph_caps_used(ci),
-                                     __ceph_caps_wanted(ci),
-                                     cap->issued | cap->implemented,
-                                     cf->caps, cf->tid, oldest_flush_tid);
+               spin_lock(&ci->i_ceph_lock);
        }
-       return delayed;
 }
 
 void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
@@ -2175,8 +2163,14 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
 {
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
+       u64 oldest_flush_tid;
 
        dout("early_kick_flushing_caps mds%d\n", session->s_mds);
+
+       spin_lock(&mdsc->cap_dirty_lock);
+       oldest_flush_tid = __get_oldest_flush_tid(mdsc);
+       spin_unlock(&mdsc->cap_dirty_lock);
+
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
                spin_lock(&ci->i_ceph_lock);
                cap = ci->i_auth_cap;
@@ -2196,10 +2190,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                 */
                if ((cap->issued & ci->i_flushing_caps) !=
                    ci->i_flushing_caps) {
-                       spin_unlock(&ci->i_ceph_lock);
-                       if (!__kick_flushing_caps(mdsc, session, ci))
-                               continue;
-                       spin_lock(&ci->i_ceph_lock);
+                       ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+                       __kick_flushing_caps(mdsc, session, ci,
+                                            oldest_flush_tid);
+               } else {
+                       ci->i_ceph_flags |= CEPH_I_KICK_FLUSH;
                }
 
                spin_unlock(&ci->i_ceph_lock);
@@ -2210,50 +2205,56 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                             struct ceph_mds_session *session)
 {
        struct ceph_inode_info *ci;
-
-       kick_flushing_capsnaps(mdsc, session);
+       struct ceph_cap *cap;
+       u64 oldest_flush_tid;
 
        dout("kick_flushing_caps mds%d\n", session->s_mds);
+
+       spin_lock(&mdsc->cap_dirty_lock);
+       oldest_flush_tid = __get_oldest_flush_tid(mdsc);
+       spin_unlock(&mdsc->cap_dirty_lock);
+
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
-               int delayed = __kick_flushing_caps(mdsc, session, ci);
-               if (delayed) {
-                       spin_lock(&ci->i_ceph_lock);
-                       __cap_delay_requeue(mdsc, ci);
+               spin_lock(&ci->i_ceph_lock);
+               cap = ci->i_auth_cap;
+               if (!(cap && cap->session == session)) {
+                       pr_err("%p auth cap %p not mds%d ???\n",
+                               &ci->vfs_inode, cap, session->s_mds);
                        spin_unlock(&ci->i_ceph_lock);
+                       continue;
+               }
+               if (ci->i_ceph_flags & CEPH_I_KICK_FLUSH) {
+                       ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+                       __kick_flushing_caps(mdsc, session, ci,
+                                            oldest_flush_tid);
                }
+               spin_unlock(&ci->i_ceph_lock);
        }
 }
 
 static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
                                     struct ceph_mds_session *session,
                                     struct inode *inode)
+       __releases(ci->i_ceph_lock)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_cap *cap;
 
-       spin_lock(&ci->i_ceph_lock);
        cap = ci->i_auth_cap;
        dout("kick_flushing_inode_caps %p flushing %s\n", inode,
             ceph_cap_string(ci->i_flushing_caps));
 
-       __ceph_flush_snaps(ci, &session, 1);
-
-       if (ci->i_flushing_caps) {
-               int delayed;
-
+       if (!list_empty(&ci->i_cap_flush_list)) {
+               u64 oldest_flush_tid;
                spin_lock(&mdsc->cap_dirty_lock);
                list_move_tail(&ci->i_flushing_item,
                               &cap->session->s_cap_flushing);
+               oldest_flush_tid = __get_oldest_flush_tid(mdsc);
                spin_unlock(&mdsc->cap_dirty_lock);
 
+               ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+               __kick_flushing_caps(mdsc, session, ci, oldest_flush_tid);
                spin_unlock(&ci->i_ceph_lock);
-
-               delayed = __kick_flushing_caps(mdsc, session, ci);
-               if (delayed) {
-                       spin_lock(&ci->i_ceph_lock);
-                       __cap_delay_requeue(mdsc, ci);
-                       spin_unlock(&ci->i_ceph_lock);
-               }
        } else {
                spin_unlock(&ci->i_ceph_lock);
        }
@@ -2580,16 +2581,19 @@ void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps)
  * drop cap_snap that is not associated with any snapshot.
  * we don't need to send FLUSHSNAP message for it.
  */
-static int ceph_try_drop_cap_snap(struct ceph_cap_snap *capsnap)
+static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci,
+                                 struct ceph_cap_snap *capsnap)
 {
        if (!capsnap->need_flush &&
            !capsnap->writing && !capsnap->dirty_pages) {
-
                dout("dropping cap_snap %p follows %llu\n",
                     capsnap, capsnap->follows);
+               BUG_ON(capsnap->cap_flush.tid > 0);
                ceph_put_snap_context(capsnap->context);
+               if (!list_is_last(&capsnap->ci_item, &ci->i_cap_snaps))
+                       ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+
                list_del(&capsnap->ci_item);
-               list_del(&capsnap->flushing_item);
                ceph_put_cap_snap(capsnap);
                return 1;
        }
@@ -2636,7 +2640,7 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
                                                        struct ceph_cap_snap,
                                                        ci_item);
                                capsnap->writing = 0;
-                               if (ceph_try_drop_cap_snap(capsnap))
+                               if (ceph_try_drop_cap_snap(ci, capsnap))
                                        put++;
                                else if (__ceph_finish_cap_snap(ci, capsnap))
                                        flushsnaps = 1;
@@ -2661,7 +2665,7 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
        if (last && !flushsnaps)
                ceph_check_caps(ci, 0, NULL);
        else if (flushsnaps)
-               ceph_flush_snaps(ci);
+               ceph_flush_snaps(ci, NULL);
        if (wake)
                wake_up_all(&ci->i_cap_wq);
        while (put-- > 0)
@@ -2679,15 +2683,19 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                                struct ceph_snap_context *snapc)
 {
        struct inode *inode = &ci->vfs_inode;
-       int last = 0;
-       int complete_capsnap = 0;
-       int drop_capsnap = 0;
-       int found = 0;
        struct ceph_cap_snap *capsnap = NULL;
+       int put = 0;
+       bool last = false;
+       bool found = false;
+       bool flush_snaps = false;
+       bool complete_capsnap = false;
 
        spin_lock(&ci->i_ceph_lock);
        ci->i_wrbuffer_ref -= nr;
-       last = !ci->i_wrbuffer_ref;
+       if (ci->i_wrbuffer_ref == 0) {
+               last = true;
+               put++;
+       }
 
        if (ci->i_head_snapc == snapc) {
                ci->i_wrbuffer_ref_head -= nr;
@@ -2707,15 +2715,22 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
        } else {
                list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
                        if (capsnap->context == snapc) {
-                               found = 1;
+                               found = true;
                                break;
                        }
                }
                BUG_ON(!found);
                capsnap->dirty_pages -= nr;
                if (capsnap->dirty_pages == 0) {
-                       complete_capsnap = 1;
-                       drop_capsnap = ceph_try_drop_cap_snap(capsnap);
+                       complete_capsnap = true;
+                       if (!capsnap->writing) {
+                               if (ceph_try_drop_cap_snap(ci, capsnap)) {
+                                       put++;
+                               } else {
+                                       ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+                                       flush_snaps = true;
+                               }
+                       }
                }
                dout("put_wrbuffer_cap_refs on %p cap_snap %p "
                     " snap %lld %d/%d -> %d/%d %s%s\n",
@@ -2730,12 +2745,12 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
 
        if (last) {
                ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
-               iput(inode);
-       } else if (complete_capsnap) {
-               ceph_flush_snaps(ci);
-               wake_up_all(&ci->i_cap_wq);
+       } else if (flush_snaps) {
+               ceph_flush_snaps(ci, NULL);
        }
-       if (drop_capsnap)
+       if (complete_capsnap)
+               wake_up_all(&ci->i_cap_wq);
+       while (put-- > 0)
                iput(inode);
 }
 
@@ -2779,12 +2794,11 @@ static void invalidate_aliases(struct inode *inode)
  */
 static void handle_cap_grant(struct ceph_mds_client *mdsc,
                             struct inode *inode, struct ceph_mds_caps *grant,
-                            u64 inline_version,
-                            void *inline_data, int inline_len,
+                            struct ceph_string **pns, u64 inline_version,
+                            void *inline_data, u32 inline_len,
                             struct ceph_buffer *xattr_buf,
                             struct ceph_mds_session *session,
-                            struct ceph_cap *cap, int issued,
-                            u32 pool_ns_len)
+                            struct ceph_cap *cap, int issued)
        __releases(ci->i_ceph_lock)
        __releases(mdsc->snap_rwsem)
 {
@@ -2895,8 +2909,18 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
 
        if (newcaps & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)) {
                /* file layout may have changed */
-               ci->i_layout = grant->layout;
-               ci->i_pool_ns_len = pool_ns_len;
+               s64 old_pool = ci->i_layout.pool_id;
+               struct ceph_string *old_ns;
+
+               ceph_file_layout_from_legacy(&ci->i_layout, &grant->layout);
+               old_ns = rcu_dereference_protected(ci->i_layout.pool_ns,
+                                       lockdep_is_held(&ci->i_ceph_lock));
+               rcu_assign_pointer(ci->i_layout.pool_ns, *pns);
+
+               if (ci->i_layout.pool_id != old_pool || *pns != old_ns)
+                       ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
+
+               *pns = old_ns;
 
                /* size/truncate_seq? */
                queue_trunc = ceph_fill_file_size(inode, issued,
@@ -2979,13 +3003,13 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                        fill_inline = true;
        }
 
-       spin_unlock(&ci->i_ceph_lock);
-
        if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) {
-               kick_flushing_inode_caps(mdsc, session, inode);
-               up_read(&mdsc->snap_rwsem);
                if (newcaps & ~issued)
                        wake = true;
+               kick_flushing_inode_caps(mdsc, session, inode);
+               up_read(&mdsc->snap_rwsem);
+       } else {
+               spin_unlock(&ci->i_ceph_lock);
        }
 
        if (fill_inline)
@@ -3029,23 +3053,24 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
-       struct ceph_cap_flush *cf;
-       struct rb_node *n;
+       struct ceph_cap_flush *cf, *tmp_cf;
        LIST_HEAD(to_remove);
        unsigned seq = le32_to_cpu(m->seq);
        int dirty = le32_to_cpu(m->dirty);
        int cleaned = 0;
-       int drop = 0;
+       bool drop = false;
+       bool wake_ci = 0;
+       bool wake_mdsc = 0;
 
-       n = rb_first(&ci->i_cap_flush_tree);
-       while (n) {
-               cf = rb_entry(n, struct ceph_cap_flush, i_node);
-               n = rb_next(&cf->i_node);
+       list_for_each_entry_safe(cf, tmp_cf, &ci->i_cap_flush_list, i_list) {
                if (cf->tid == flush_tid)
                        cleaned = cf->caps;
+               if (cf->caps == 0) /* capsnap */
+                       continue;
                if (cf->tid <= flush_tid) {
-                       rb_erase(&cf->i_node, &ci->i_cap_flush_tree);
-                       list_add_tail(&cf->list, &to_remove);
+                       if (__finish_cap_flush(NULL, ci, cf))
+                               wake_ci = true;
+                       list_add_tail(&cf->i_list, &to_remove);
                } else {
                        cleaned &= ~cf->caps;
                        if (!cleaned)
@@ -3066,31 +3091,29 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
 
        spin_lock(&mdsc->cap_dirty_lock);
 
-       if (!list_empty(&to_remove)) {
-               list_for_each_entry(cf, &to_remove, list)
-                       rb_erase(&cf->g_node, &mdsc->cap_flush_tree);
-
-               n = rb_first(&mdsc->cap_flush_tree);
-               cf = n ? rb_entry(n, struct ceph_cap_flush, g_node) : NULL;
-               if (!cf || cf->tid > flush_tid)
-                       wake_up_all(&mdsc->cap_flushing_wq);
+       list_for_each_entry(cf, &to_remove, i_list) {
+               if (__finish_cap_flush(mdsc, NULL, cf))
+                       wake_mdsc = true;
        }
 
        if (ci->i_flushing_caps == 0) {
-               list_del_init(&ci->i_flushing_item);
-               if (!list_empty(&session->s_cap_flushing))
-                       dout(" mds%d still flushing cap on %p\n",
-                            session->s_mds,
-                            &list_entry(session->s_cap_flushing.next,
-                                        struct ceph_inode_info,
-                                        i_flushing_item)->vfs_inode);
+               if (list_empty(&ci->i_cap_flush_list)) {
+                       list_del_init(&ci->i_flushing_item);
+                       if (!list_empty(&session->s_cap_flushing)) {
+                               dout(" mds%d still flushing cap on %p\n",
+                                    session->s_mds,
+                                    &list_first_entry(&session->s_cap_flushing,
+                                               struct ceph_inode_info,
+                                               i_flushing_item)->vfs_inode);
+                       }
+               }
                mdsc->num_cap_flushing--;
                dout(" inode %p now !flushing\n", inode);
 
                if (ci->i_dirty_caps == 0) {
                        dout(" inode %p now clean\n", inode);
                        BUG_ON(!list_empty(&ci->i_dirty_item));
-                       drop = 1;
+                       drop = true;
                        if (ci->i_wr_ref == 0 &&
                            ci->i_wrbuffer_ref_head == 0) {
                                BUG_ON(!ci->i_head_snapc);
@@ -3102,17 +3125,21 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
                }
        }
        spin_unlock(&mdsc->cap_dirty_lock);
-       wake_up_all(&ci->i_cap_wq);
 
 out:
        spin_unlock(&ci->i_ceph_lock);
 
        while (!list_empty(&to_remove)) {
                cf = list_first_entry(&to_remove,
-                                     struct ceph_cap_flush, list);
-               list_del(&cf->list);
+                                     struct ceph_cap_flush, i_list);
+               list_del(&cf->i_list);
                ceph_free_cap_flush(cf);
        }
+
+       if (wake_ci)
+               wake_up_all(&ci->i_cap_wq);
+       if (wake_mdsc)
+               wake_up_all(&mdsc->cap_flushing_wq);
        if (drop)
                iput(inode);
 }
@@ -3131,7 +3158,9 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid,
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        u64 follows = le64_to_cpu(m->snap_follows);
        struct ceph_cap_snap *capsnap;
-       int drop = 0;
+       bool flushed = false;
+       bool wake_ci = false;
+       bool wake_mdsc = false;
 
        dout("handle_cap_flushsnap_ack inode %p ci %p mds%d follows %lld\n",
             inode, ci, session->s_mds, follows);
@@ -3139,30 +3168,47 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid,
        spin_lock(&ci->i_ceph_lock);
        list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
                if (capsnap->follows == follows) {
-                       if (capsnap->flush_tid != flush_tid) {
+                       if (capsnap->cap_flush.tid != flush_tid) {
                                dout(" cap_snap %p follows %lld tid %lld !="
                                     " %lld\n", capsnap, follows,
-                                    flush_tid, capsnap->flush_tid);
+                                    flush_tid, capsnap->cap_flush.tid);
                                break;
                        }
-                       WARN_ON(capsnap->dirty_pages || capsnap->writing);
-                       dout(" removing %p cap_snap %p follows %lld\n",
-                            inode, capsnap, follows);
-                       ceph_put_snap_context(capsnap->context);
-                       list_del(&capsnap->ci_item);
-                       list_del(&capsnap->flushing_item);
-                       ceph_put_cap_snap(capsnap);
-                       wake_up_all(&mdsc->cap_flushing_wq);
-                       drop = 1;
+                       flushed = true;
                        break;
                } else {
                        dout(" skipping cap_snap %p follows %lld\n",
                             capsnap, capsnap->follows);
                }
        }
+       if (flushed) {
+               WARN_ON(capsnap->dirty_pages || capsnap->writing);
+               dout(" removing %p cap_snap %p follows %lld\n",
+                    inode, capsnap, follows);
+               list_del(&capsnap->ci_item);
+               if (__finish_cap_flush(NULL, ci, &capsnap->cap_flush))
+                       wake_ci = true;
+
+               spin_lock(&mdsc->cap_dirty_lock);
+
+               if (list_empty(&ci->i_cap_flush_list))
+                       list_del_init(&ci->i_flushing_item);
+
+               if (__finish_cap_flush(mdsc, NULL, &capsnap->cap_flush))
+                       wake_mdsc = true;
+
+               spin_unlock(&mdsc->cap_dirty_lock);
+       }
        spin_unlock(&ci->i_ceph_lock);
-       if (drop)
+       if (flushed) {
+               ceph_put_snap_context(capsnap->context);
+               ceph_put_cap_snap(capsnap);
+               if (wake_ci)
+                       wake_up_all(&ci->i_cap_wq);
+               if (wake_mdsc)
+                       wake_up_all(&mdsc->cap_flushing_wq);
                iput(inode);
+       }
 }
 
 /*
@@ -3267,7 +3313,8 @@ retry:
                        tcap->implemented |= issued;
                        if (cap == ci->i_auth_cap)
                                ci->i_auth_cap = tcap;
-                       if (ci->i_flushing_caps && ci->i_auth_cap == tcap) {
+                       if (!list_empty(&ci->i_cap_flush_list) &&
+                           ci->i_auth_cap == tcap) {
                                spin_lock(&mdsc->cap_dirty_lock);
                                list_move_tail(&ci->i_flushing_item,
                                               &tcap->session->s_cap_flushing);
@@ -3420,20 +3467,18 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        struct ceph_cap *cap;
        struct ceph_mds_caps *h;
        struct ceph_mds_cap_peer *peer = NULL;
-       struct ceph_snap_realm *realm;
+       struct ceph_snap_realm *realm = NULL;
+       struct ceph_string *pool_ns = NULL;
        int mds = session->s_mds;
        int op, issued;
        u32 seq, mseq;
        struct ceph_vino vino;
-       u64 cap_id;
-       u64 size, max_size;
        u64 tid;
        u64 inline_version = 0;
        void *inline_data = NULL;
        u32  inline_len = 0;
        void *snaptrace;
        size_t snaptrace_len;
-       u32 pool_ns_len = 0;
        void *p, *end;
 
        dout("handle_caps from mds%d\n", mds);
@@ -3447,11 +3492,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        op = le32_to_cpu(h->op);
        vino.ino = le64_to_cpu(h->ino);
        vino.snap = CEPH_NOSNAP;
-       cap_id = le64_to_cpu(h->cap_id);
        seq = le32_to_cpu(h->seq);
        mseq = le32_to_cpu(h->migrate_seq);
-       size = le64_to_cpu(h->size);
-       max_size = le64_to_cpu(h->max_size);
 
        snaptrace = h + 1;
        snaptrace_len = le32_to_cpu(h->snap_trace_len);
@@ -3490,6 +3532,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                u64 flush_tid;
                u32 caller_uid, caller_gid;
                u32 osd_epoch_barrier;
+               u32 pool_ns_len;
                /* version >= 5 */
                ceph_decode_32_safe(&p, end, osd_epoch_barrier, bad);
                /* version >= 6 */
@@ -3499,6 +3542,11 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                ceph_decode_32_safe(&p, end, caller_gid, bad);
                /* version >= 8 */
                ceph_decode_32_safe(&p, end, pool_ns_len, bad);
+               if (pool_ns_len > 0) {
+                       ceph_decode_need(&p, end, pool_ns_len, bad);
+                       pool_ns = ceph_find_or_create_string(p, pool_ns_len);
+                       p += pool_ns_len;
+               }
        }
 
        /* lookup ino */
@@ -3519,7 +3567,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                        cap = ceph_get_cap(mdsc, NULL);
                        cap->cap_ino = vino.ino;
                        cap->queue_release = 1;
-                       cap->cap_id = cap_id;
+                       cap->cap_id = le64_to_cpu(h->cap_id);
                        cap->mseq = mseq;
                        cap->seq = seq;
                        spin_lock(&session->s_cap_lock);
@@ -3554,10 +3602,9 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                }
                handle_cap_import(mdsc, inode, h, peer, session,
                                  &cap, &issued);
-               handle_cap_grant(mdsc, inode, h,
+               handle_cap_grant(mdsc, inode, h, &pool_ns,
                                 inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued,
-                                pool_ns_len);
+                                msg->middle, session, cap, issued);
                if (realm)
                        ceph_put_snap_realm(mdsc, realm);
                goto done_unlocked;
@@ -3579,10 +3626,9 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        case CEPH_CAP_OP_GRANT:
                __ceph_caps_issued(ci, &issued);
                issued |= __ceph_caps_dirty(ci);
-               handle_cap_grant(mdsc, inode, h,
+               handle_cap_grant(mdsc, inode, h, &pool_ns,
                                 inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued,
-                                pool_ns_len);
+                                msg->middle, session, cap, issued);
                goto done_unlocked;
 
        case CEPH_CAP_OP_FLUSH_ACK:
@@ -3613,6 +3659,7 @@ done:
        mutex_unlock(&session->s_mutex);
 done_unlocked:
        iput(inode);
+       ceph_put_string(pool_ns);
        return;
 
 bad:
@@ -3673,6 +3720,16 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
        dout("flush_dirty_caps done\n");
 }
 
+void __ceph_get_fmode(struct ceph_inode_info *ci, int fmode)
+{
+       int i;
+       int bits = (fmode << 1) | 1;
+       for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
+               if (bits & (1 << i))
+                       ci->i_nr_by_mode[i]++;
+       }
+}
+
 /*
  * Drop open file reference.  If we were the last open file,
  * we may need to release capabilities to the MDS (or schedule
@@ -3680,15 +3737,20 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
  */
 void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
 {
-       struct inode *inode = &ci->vfs_inode;
-       int last = 0;
-
+       int i, last = 0;
+       int bits = (fmode << 1) | 1;
        spin_lock(&ci->i_ceph_lock);
-       dout("put_fmode %p fmode %d %d -> %d\n", inode, fmode,
-            ci->i_nr_by_mode[fmode], ci->i_nr_by_mode[fmode]-1);
-       BUG_ON(ci->i_nr_by_mode[fmode] == 0);
-       if (--ci->i_nr_by_mode[fmode] == 0)
-               last++;
+       for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
+               if (bits & (1 << i)) {
+                       BUG_ON(ci->i_nr_by_mode[i] == 0);
+                       if (--ci->i_nr_by_mode[i] == 0)
+                               last++;
+               }
+       }
+       dout("put_fmode %p fmode %d {%d,%d,%d,%d}\n",
+            &ci->vfs_inode, fmode,
+            ci->i_nr_by_mode[0], ci->i_nr_by_mode[1],
+            ci->i_nr_by_mode[2], ci->i_nr_by_mode[3]);
        spin_unlock(&ci->i_ceph_lock);
 
        if (last && ci->i_vino.snap == CEPH_NOSNAP)
index 6e0fedf..c64a0b7 100644 (file)
@@ -59,7 +59,7 @@ int ceph_init_dentry(struct dentry *dentry)
 
        di->dentry = dentry;
        di->lease_session = NULL;
-       dentry->d_time = jiffies;
+       di->time = jiffies;
        /* avoid reordering d_fsdata setup so that the check above is safe */
        smp_mb();
        dentry->d_fsdata = di;
@@ -1124,7 +1124,7 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
 void ceph_invalidate_dentry_lease(struct dentry *dentry)
 {
        spin_lock(&dentry->d_lock);
-       dentry->d_time = jiffies;
+       ceph_dentry(dentry)->time = jiffies;
        ceph_dentry(dentry)->lease_shared_gen = 0;
        spin_unlock(&dentry->d_lock);
 }
@@ -1133,7 +1133,8 @@ void ceph_invalidate_dentry_lease(struct dentry *dentry)
  * Check if dentry lease is valid.  If not, delete the lease.  Try to
  * renew if the least is more than half up.
  */
-static int dentry_lease_is_valid(struct dentry *dentry)
+static int dentry_lease_is_valid(struct dentry *dentry, unsigned int flags,
+                                struct inode *dir)
 {
        struct ceph_dentry_info *di;
        struct ceph_mds_session *s;
@@ -1141,12 +1142,11 @@ static int dentry_lease_is_valid(struct dentry *dentry)
        u32 gen;
        unsigned long ttl;
        struct ceph_mds_session *session = NULL;
-       struct inode *dir = NULL;
        u32 seq = 0;
 
        spin_lock(&dentry->d_lock);
        di = ceph_dentry(dentry);
-       if (di->lease_session) {
+       if (di && di->lease_session) {
                s = di->lease_session;
                spin_lock(&s->s_gen_ttl_lock);
                gen = s->s_cap_gen;
@@ -1154,17 +1154,24 @@ static int dentry_lease_is_valid(struct dentry *dentry)
                spin_unlock(&s->s_gen_ttl_lock);
 
                if (di->lease_gen == gen &&
-                   time_before(jiffies, dentry->d_time) &&
+                   time_before(jiffies, di->time) &&
                    time_before(jiffies, ttl)) {
                        valid = 1;
                        if (di->lease_renew_after &&
                            time_after(jiffies, di->lease_renew_after)) {
-                               /* we should renew */
-                               dir = d_inode(dentry->d_parent);
-                               session = ceph_get_mds_session(s);
-                               seq = di->lease_seq;
-                               di->lease_renew_after = 0;
-                               di->lease_renew_from = jiffies;
+                               /*
+                                * We should renew. If we're in RCU walk mode
+                                * though, we can't do that so just return
+                                * -ECHILD.
+                                */
+                               if (flags & LOOKUP_RCU) {
+                                       valid = -ECHILD;
+                               } else {
+                                       session = ceph_get_mds_session(s);
+                                       seq = di->lease_seq;
+                                       di->lease_renew_after = 0;
+                                       di->lease_renew_from = jiffies;
+                               }
                        }
                }
        }
@@ -1207,15 +1214,19 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        struct dentry *parent;
        struct inode *dir;
 
-       if (flags & LOOKUP_RCU)
-               return -ECHILD;
+       if (flags & LOOKUP_RCU) {
+               parent = ACCESS_ONCE(dentry->d_parent);
+               dir = d_inode_rcu(parent);
+               if (!dir)
+                       return -ECHILD;
+       } else {
+               parent = dget_parent(dentry);
+               dir = d_inode(parent);
+       }
 
        dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
             dentry, d_inode(dentry), ceph_dentry(dentry)->offset);
 
-       parent = dget_parent(dentry);
-       dir = d_inode(parent);
-
        /* always trust cached snapped dentries, snapdir dentry */
        if (ceph_snap(dir) != CEPH_NOSNAP) {
                dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
@@ -1224,12 +1235,16 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
        } else if (d_really_is_positive(dentry) &&
                   ceph_snap(d_inode(dentry)) == CEPH_SNAPDIR) {
                valid = 1;
-       } else if (dentry_lease_is_valid(dentry) ||
-                  dir_lease_is_valid(dir, dentry)) {
-               if (d_really_is_positive(dentry))
-                       valid = ceph_is_any_caps(d_inode(dentry));
-               else
-                       valid = 1;
+       } else {
+               valid = dentry_lease_is_valid(dentry, flags, dir);
+               if (valid == -ECHILD)
+                       return valid;
+               if (valid || dir_lease_is_valid(dir, dentry)) {
+                       if (d_really_is_positive(dentry))
+                               valid = ceph_is_any_caps(d_inode(dentry));
+                       else
+                               valid = 1;
+               }
        }
 
        if (!valid) {
@@ -1238,6 +1253,9 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                struct ceph_mds_request *req;
                int op, mask, err;
 
+               if (flags & LOOKUP_RCU)
+                       return -ECHILD;
+
                op = ceph_snap(dir) == CEPH_SNAPDIR ?
                        CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
                req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
@@ -1273,7 +1291,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                ceph_dir_clear_complete(dir);
        }
 
-       dput(parent);
+       if (!(flags & LOOKUP_RCU))
+               dput(parent);
        return valid;
 }
 
@@ -1286,10 +1305,14 @@ static void ceph_d_release(struct dentry *dentry)
 
        dout("d_release %p\n", dentry);
        ceph_dentry_lru_del(dentry);
+
+       spin_lock(&dentry->d_lock);
+       dentry->d_fsdata = NULL;
+       spin_unlock(&dentry->d_lock);
+
        if (di->lease_session)
                ceph_put_mds_session(di->lease_session);
        kmem_cache_free(ceph_dentry_cachep, di);
-       dentry->d_fsdata = NULL;
 }
 
 static int ceph_snapdir_d_revalidate(struct dentry *dentry,
index 0daaf7c..0f5375d 100644 (file)
@@ -708,7 +708,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
                }
        }
 
-       ceph_put_page_vector(osd_data->pages, num_pages, false);
+       ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write);
        ceph_osdc_put_request(req);
 
        if (rc < 0)
@@ -821,6 +821,54 @@ static void ceph_sync_write_unsafe(struct ceph_osd_request *req, bool unsafe)
        }
 }
 
+/*
+ * Wait on any unsafe replies for the given inode.  First wait on the
+ * newest request, and make that the upper bound.  Then, if there are
+ * more requests, keep waiting on the oldest as long as it is still older
+ * than the original request.
+ */
+void ceph_sync_write_wait(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct list_head *head = &ci->i_unsafe_writes;
+       struct ceph_osd_request *req;
+       u64 last_tid;
+
+       if (!S_ISREG(inode->i_mode))
+               return;
+
+       spin_lock(&ci->i_unsafe_lock);
+       if (list_empty(head))
+               goto out;
+
+       /* set upper bound as _last_ entry in chain */
+
+       req = list_last_entry(head, struct ceph_osd_request,
+                             r_unsafe_item);
+       last_tid = req->r_tid;
+
+       do {
+               ceph_osdc_get_request(req);
+               spin_unlock(&ci->i_unsafe_lock);
+
+               dout("sync_write_wait on tid %llu (until %llu)\n",
+                    req->r_tid, last_tid);
+               wait_for_completion(&req->r_safe_completion);
+               ceph_osdc_put_request(req);
+
+               spin_lock(&ci->i_unsafe_lock);
+               /*
+                * from here on look at first entry in chain, since we
+                * only want to wait for anything older than last_tid
+                */
+               if (list_empty(head))
+                       break;
+               req = list_first_entry(head, struct ceph_osd_request,
+                                      r_unsafe_item);
+       } while (req->r_tid < last_tid);
+out:
+       spin_unlock(&ci->i_unsafe_lock);
+}
 
 static ssize_t
 ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
@@ -964,7 +1012,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                                len = ret;
                }
 
-               ceph_put_page_vector(pages, num_pages, false);
+               ceph_put_page_vector(pages, num_pages, !write);
 
                ceph_osdc_put_request(req);
                if (ret < 0)
@@ -985,6 +1033,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        }
 
        if (aio_req) {
+               LIST_HEAD(osd_reqs);
+
                if (aio_req->num_reqs == 0) {
                        kfree(aio_req);
                        return ret;
@@ -993,8 +1043,9 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                ceph_get_cap_refs(ci, write ? CEPH_CAP_FILE_WR :
                                              CEPH_CAP_FILE_RD);
 
-               while (!list_empty(&aio_req->osd_reqs)) {
-                       req = list_first_entry(&aio_req->osd_reqs,
+               list_splice(&aio_req->osd_reqs, &osd_reqs);
+               while (!list_empty(&osd_reqs)) {
+                       req = list_first_entry(&osd_reqs,
                                               struct ceph_osd_request,
                                               r_unsafe_item);
                        list_del_init(&req->r_unsafe_item);
@@ -1448,16 +1499,14 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
 {
        struct inode *inode = file->f_mapping->host;
        loff_t i_size;
-       int ret;
+       loff_t ret;
 
        inode_lock(inode);
 
        if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) {
                ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false);
-               if (ret < 0) {
-                       offset = ret;
+               if (ret < 0)
                        goto out;
-               }
        }
 
        i_size = i_size_read(inode);
@@ -1473,7 +1522,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
                 * write() or lseek() might have altered it
                 */
                if (offset == 0) {
-                       offset = file->f_pos;
+                       ret = file->f_pos;
                        goto out;
                }
                offset += file->f_pos;
@@ -1493,11 +1542,11 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
                break;
        }
 
-       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
+       ret = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out:
        inode_unlock(inode);
-       return offset;
+       return ret;
 }
 
 static inline void ceph_zero_partial_page(
@@ -1583,9 +1632,9 @@ static int ceph_zero_objects(struct inode *inode, loff_t offset, loff_t length)
 {
        int ret = 0;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       s32 stripe_unit = ceph_file_layout_su(ci->i_layout);
-       s32 stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
-       s32 object_size = ceph_file_layout_object_size(ci->i_layout);
+       s32 stripe_unit = ci->i_layout.stripe_unit;
+       s32 stripe_count = ci->i_layout.stripe_count;
+       s32 object_size = ci->i_layout.object_size;
        u64 object_set_size = object_size * stripe_count;
        u64 nearly, t;
 
index 99bdef6..dd3a6db 100644 (file)
@@ -446,7 +446,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_symlink = NULL;
 
        memset(&ci->i_dir_layout, 0, sizeof(ci->i_dir_layout));
-       ci->i_pool_ns_len = 0;
+       RCU_INIT_POINTER(ci->i_layout.pool_ns, NULL);
 
        ci->i_fragtree = RB_ROOT;
        mutex_init(&ci->i_fragtree_mutex);
@@ -468,7 +468,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        INIT_LIST_HEAD(&ci->i_dirty_item);
        INIT_LIST_HEAD(&ci->i_flushing_item);
        ci->i_prealloc_cap_flush = NULL;
-       ci->i_cap_flush_tree = RB_ROOT;
+       INIT_LIST_HEAD(&ci->i_cap_flush_list);
        init_waitqueue_head(&ci->i_cap_wq);
        ci->i_hold_caps_min = 0;
        ci->i_hold_caps_max = 0;
@@ -477,7 +477,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_head_snapc = NULL;
        ci->i_snap_caps = 0;
 
-       for (i = 0; i < CEPH_FILE_MODE_NUM; i++)
+       for (i = 0; i < CEPH_FILE_MODE_BITS; i++)
                ci->i_nr_by_mode[i] = 0;
 
        mutex_init(&ci->i_truncate_mutex);
@@ -570,6 +570,8 @@ void ceph_destroy_inode(struct inode *inode)
        if (ci->i_xattrs.prealloc_blob)
                ceph_buffer_put(ci->i_xattrs.prealloc_blob);
 
+       ceph_put_string(rcu_dereference_raw(ci->i_layout.pool_ns));
+
        call_rcu(&inode->i_rcu, ceph_i_callback);
 }
 
@@ -583,6 +585,14 @@ int ceph_drop_inode(struct inode *inode)
        return 1;
 }
 
+void ceph_evict_inode(struct inode *inode)
+{
+       /* wait unsafe sync writes */
+       ceph_sync_write_wait(inode);
+       truncate_inode_pages_final(&inode->i_data);
+       clear_inode(inode);
+}
+
 static inline blkcnt_t calc_inode_blocks(u64 size)
 {
        return (size + (1<<9) - 1) >> 9;
@@ -733,6 +743,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        int issued = 0, implemented, new_issued;
        struct timespec mtime, atime, ctime;
        struct ceph_buffer *xattr_blob = NULL;
+       struct ceph_string *pool_ns = NULL;
        struct ceph_cap *new_cap = NULL;
        int err = 0;
        bool wake = false;
@@ -760,6 +771,10 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                               iinfo->xattr_len);
        }
 
+       if (iinfo->pool_ns_len > 0)
+               pool_ns = ceph_find_or_create_string(iinfo->pool_ns_data,
+                                                    iinfo->pool_ns_len);
+
        spin_lock(&ci->i_ceph_lock);
 
        /*
@@ -814,10 +829,18 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
 
        if (new_version ||
            (new_issued & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR))) {
-               if (ci->i_layout.fl_pg_pool != info->layout.fl_pg_pool)
+               s64 old_pool = ci->i_layout.pool_id;
+               struct ceph_string *old_ns;
+
+               ceph_file_layout_from_legacy(&ci->i_layout, &info->layout);
+               old_ns = rcu_dereference_protected(ci->i_layout.pool_ns,
+                                       lockdep_is_held(&ci->i_ceph_lock));
+               rcu_assign_pointer(ci->i_layout.pool_ns, pool_ns);
+
+               if (ci->i_layout.pool_id != old_pool || pool_ns != old_ns)
                        ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
-               ci->i_layout = info->layout;
-               ci->i_pool_ns_len = iinfo->pool_ns_len;
+
+               pool_ns = old_ns;
 
                queue_trunc = ceph_fill_file_size(inode, issued,
                                        le32_to_cpu(info->truncate_seq),
@@ -985,6 +1008,7 @@ out:
                ceph_put_cap(mdsc, new_cap);
        if (xattr_blob)
                ceph_buffer_put(xattr_blob);
+       ceph_put_string(pool_ns);
        return err;
 }
 
@@ -1018,7 +1042,7 @@ static void update_dentry_lease(struct dentry *dentry,
                goto out_unlock;
 
        if (di->lease_gen == session->s_cap_gen &&
-           time_before(ttl, dentry->d_time))
+           time_before(ttl, di->time))
                goto out_unlock;  /* we already have a newer lease. */
 
        if (di->lease_session && di->lease_session != session)
@@ -1032,7 +1056,7 @@ static void update_dentry_lease(struct dentry *dentry,
        di->lease_seq = le32_to_cpu(lease->seq);
        di->lease_renew_after = half_ttl;
        di->lease_renew_from = 0;
-       dentry->d_time = ttl;
+       di->time = ttl;
 out_unlock:
        spin_unlock(&dentry->d_lock);
        return;
index be6b165..7d752d5 100644 (file)
@@ -21,10 +21,10 @@ static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
 
        err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
        if (!err) {
-               l.stripe_unit = ceph_file_layout_su(ci->i_layout);
-               l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
-               l.object_size = ceph_file_layout_object_size(ci->i_layout);
-               l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
+               l.stripe_unit = ci->i_layout.stripe_unit;
+               l.stripe_count = ci->i_layout.stripe_count;
+               l.object_size = ci->i_layout.object_size;
+               l.data_pool = ci->i_layout.pool_id;
                l.preferred_osd = (s32)-1;
                if (copy_to_user(arg, &l, sizeof(l)))
                        return -EFAULT;
@@ -82,19 +82,19 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
        if (l.stripe_count)
                nl.stripe_count = l.stripe_count;
        else
-               nl.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
+               nl.stripe_count = ci->i_layout.stripe_count;
        if (l.stripe_unit)
                nl.stripe_unit = l.stripe_unit;
        else
-               nl.stripe_unit = ceph_file_layout_su(ci->i_layout);
+               nl.stripe_unit = ci->i_layout.stripe_unit;
        if (l.object_size)
                nl.object_size = l.object_size;
        else
-               nl.object_size = ceph_file_layout_object_size(ci->i_layout);
+               nl.object_size = ci->i_layout.object_size;
        if (l.data_pool)
                nl.data_pool = l.data_pool;
        else
-               nl.data_pool = ceph_file_layout_pg_pool(ci->i_layout);
+               nl.data_pool = ci->i_layout.pool_id;
 
        /* this is obsolete, and always -1 */
        nl.preferred_osd = le64_to_cpu(-1);
@@ -183,7 +183,7 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        struct ceph_osd_client *osdc =
                &ceph_sb_to_client(inode->i_sb)->client->osdc;
        struct ceph_object_locator oloc;
-       struct ceph_object_id oid;
+       CEPH_DEFINE_OID_ONSTACK(oid);
        u64 len = 1, olen;
        u64 tmp;
        struct ceph_pg pgid;
@@ -202,8 +202,8 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
                return -EIO;
        }
        dl.file_offset -= dl.object_offset;
-       dl.object_size = ceph_file_layout_object_size(ci->i_layout);
-       dl.block_size = ceph_file_layout_su(ci->i_layout);
+       dl.object_size = ci->i_layout.object_size;
+       dl.block_size = ci->i_layout.stripe_unit;
 
        /* block_offset = object_offset % block_size */
        tmp = dl.object_offset;
@@ -212,10 +212,13 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
                 ceph_ino(inode), dl.object_no);
 
-       oloc.pool = ceph_file_layout_pg_pool(ci->i_layout);
+       oloc.pool = ci->i_layout.pool_id;
+       oloc.pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
        ceph_oid_printf(&oid, "%s", dl.object_name);
 
        r = ceph_object_locator_to_pg(osdc->osdmap, &oid, &oloc, &pgid);
+
+       ceph_oloc_destroy(&oloc);
        if (r < 0) {
                up_read(&osdc->lock);
                return r;
@@ -247,9 +250,8 @@ static long ceph_ioctl_lazyio(struct file *file)
 
        if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
                spin_lock(&ci->i_ceph_lock);
-               ci->i_nr_by_mode[fi->fmode]--;
                fi->fmode |= CEPH_FILE_MODE_LAZY;
-               ci->i_nr_by_mode[fi->fmode]++;
+               ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
                spin_unlock(&ci->i_ceph_lock);
                dout("ioctl_layzio: file %p marked lazy\n", file);
 
index 4e8678a..f72d4ae 100644 (file)
@@ -48,7 +48,7 @@
 struct ceph_reconnect_state {
        int nr_caps;
        struct ceph_pagelist *pagelist;
-       bool flock;
+       unsigned msg_version;
 };
 
 static void __wake_requests(struct ceph_mds_client *mdsc,
@@ -100,12 +100,15 @@ static int parse_reply_info_in(void **p, void *end,
        } else
                info->inline_version = CEPH_INLINE_NONE;
 
+       info->pool_ns_len = 0;
+       info->pool_ns_data = NULL;
        if (features & CEPH_FEATURE_FS_FILE_LAYOUT_V2) {
                ceph_decode_32_safe(p, end, info->pool_ns_len, bad);
-               ceph_decode_need(p, end, info->pool_ns_len, bad);
-               *p += info->pool_ns_len;
-       } else {
-               info->pool_ns_len = 0;
+               if (info->pool_ns_len > 0) {
+                       ceph_decode_need(p, end, info->pool_ns_len, bad);
+                       info->pool_ns_data = *p;
+                       *p += info->pool_ns_len;
+               }
        }
 
        return 0;
@@ -469,7 +472,6 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        s->s_cap_iterator = NULL;
        INIT_LIST_HEAD(&s->s_cap_releases);
        INIT_LIST_HEAD(&s->s_cap_flushing);
-       INIT_LIST_HEAD(&s->s_cap_snaps_flushing);
 
        dout("register_session mds%d\n", mds);
        if (mds >= mdsc->max_sessions) {
@@ -1145,19 +1147,17 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                    ACCESS_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN)
                        invalidate = true;
 
-               while (true) {
-                       struct rb_node *n = rb_first(&ci->i_cap_flush_tree);
-                       if (!n)
-                               break;
-                       cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       rb_erase(&cf->i_node, &ci->i_cap_flush_tree);
-                       list_add(&cf->list, &to_remove);
+               while (!list_empty(&ci->i_cap_flush_list)) {
+                       cf = list_first_entry(&ci->i_cap_flush_list,
+                                             struct ceph_cap_flush, i_list);
+                       list_del(&cf->i_list);
+                       list_add(&cf->i_list, &to_remove);
                }
 
                spin_lock(&mdsc->cap_dirty_lock);
 
-               list_for_each_entry(cf, &to_remove, list)
-                       rb_erase(&cf->g_node, &mdsc->cap_flush_tree);
+               list_for_each_entry(cf, &to_remove, i_list)
+                       list_del(&cf->g_list);
 
                if (!list_empty(&ci->i_dirty_item)) {
                        pr_warn_ratelimited(
@@ -1181,7 +1181,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                spin_unlock(&mdsc->cap_dirty_lock);
 
                if (!ci->i_dirty_caps && ci->i_prealloc_cap_flush) {
-                       list_add(&ci->i_prealloc_cap_flush->list, &to_remove);
+                       list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove);
                        ci->i_prealloc_cap_flush = NULL;
                }
        }
@@ -1189,8 +1189,8 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
        while (!list_empty(&to_remove)) {
                struct ceph_cap_flush *cf;
                cf = list_first_entry(&to_remove,
-                                     struct ceph_cap_flush, list);
-               list_del(&cf->list);
+                                     struct ceph_cap_flush, i_list);
+               list_del(&cf->i_list);
                ceph_free_cap_flush(cf);
        }
 
@@ -1212,6 +1212,8 @@ static void remove_session_caps(struct ceph_mds_session *session)
        dout("remove_session_caps on %p\n", session);
        iterate_session_caps(session, remove_session_caps_cb, fsc);
 
+       wake_up_all(&fsc->mdsc->cap_flushing_wq);
+
        spin_lock(&session->s_cap_lock);
        if (session->s_nr_caps > 0) {
                struct inode *inode;
@@ -1478,35 +1480,21 @@ static int trim_caps(struct ceph_mds_client *mdsc,
        return 0;
 }
 
-static int check_capsnap_flush(struct ceph_inode_info *ci,
-                              u64 want_snap_seq)
-{
-       int ret = 1;
-       spin_lock(&ci->i_ceph_lock);
-       if (want_snap_seq > 0 && !list_empty(&ci->i_cap_snaps)) {
-               struct ceph_cap_snap *capsnap =
-                       list_first_entry(&ci->i_cap_snaps,
-                                        struct ceph_cap_snap, ci_item);
-               ret = capsnap->follows >= want_snap_seq;
-       }
-       spin_unlock(&ci->i_ceph_lock);
-       return ret;
-}
-
 static int check_caps_flush(struct ceph_mds_client *mdsc,
                            u64 want_flush_tid)
 {
-       struct rb_node *n;
-       struct ceph_cap_flush *cf;
        int ret = 1;
 
        spin_lock(&mdsc->cap_dirty_lock);
-       n = rb_first(&mdsc->cap_flush_tree);
-       cf = n ? rb_entry(n, struct ceph_cap_flush, g_node) : NULL;
-       if (cf && cf->tid <= want_flush_tid) {
-               dout("check_caps_flush still flushing tid %llu <= %llu\n",
-                    cf->tid, want_flush_tid);
-               ret = 0;
+       if (!list_empty(&mdsc->cap_flush_list)) {
+               struct ceph_cap_flush *cf =
+                       list_first_entry(&mdsc->cap_flush_list,
+                                        struct ceph_cap_flush, g_list);
+               if (cf->tid <= want_flush_tid) {
+                       dout("check_caps_flush still flushing tid "
+                            "%llu <= %llu\n", cf->tid, want_flush_tid);
+                       ret = 0;
+               }
        }
        spin_unlock(&mdsc->cap_dirty_lock);
        return ret;
@@ -1518,54 +1506,9 @@ static int check_caps_flush(struct ceph_mds_client *mdsc,
  * returns true if we've flushed through want_flush_tid
  */
 static void wait_caps_flush(struct ceph_mds_client *mdsc,
-                           u64 want_flush_tid, u64 want_snap_seq)
+                           u64 want_flush_tid)
 {
-       int mds;
-
-       dout("check_caps_flush want %llu snap want %llu\n",
-            want_flush_tid, want_snap_seq);
-       mutex_lock(&mdsc->mutex);
-       for (mds = 0; mds < mdsc->max_sessions; ) {
-               struct ceph_mds_session *session = mdsc->sessions[mds];
-               struct inode *inode = NULL;
-
-               if (!session) {
-                       mds++;
-                       continue;
-               }
-               get_session(session);
-               mutex_unlock(&mdsc->mutex);
-
-               mutex_lock(&session->s_mutex);
-               if (!list_empty(&session->s_cap_snaps_flushing)) {
-                       struct ceph_cap_snap *capsnap =
-                               list_first_entry(&session->s_cap_snaps_flushing,
-                                                struct ceph_cap_snap,
-                                                flushing_item);
-                       struct ceph_inode_info *ci = capsnap->ci;
-                       if (!check_capsnap_flush(ci, want_snap_seq)) {
-                               dout("check_cap_flush still flushing snap %p "
-                                    "follows %lld <= %lld to mds%d\n",
-                                    &ci->vfs_inode, capsnap->follows,
-                                    want_snap_seq, mds);
-                               inode = igrab(&ci->vfs_inode);
-                       }
-               }
-               mutex_unlock(&session->s_mutex);
-               ceph_put_mds_session(session);
-
-               if (inode) {
-                       wait_event(mdsc->cap_flushing_wq,
-                                  check_capsnap_flush(ceph_inode(inode),
-                                                      want_snap_seq));
-                       iput(inode);
-               } else {
-                       mds++;
-               }
-
-               mutex_lock(&mdsc->mutex);
-       }
-       mutex_unlock(&mdsc->mutex);
+       dout("check_caps_flush want %llu\n", want_flush_tid);
 
        wait_event(mdsc->cap_flushing_wq,
                   check_caps_flush(mdsc, want_flush_tid));
@@ -2163,6 +2106,11 @@ static int __do_request(struct ceph_mds_client *mdsc,
        mds = __choose_mds(mdsc, req);
        if (mds < 0 ||
            ceph_mdsmap_get_state(mdsc->mdsmap, mds) < CEPH_MDS_STATE_ACTIVE) {
+               if (mdsc->mdsmap_err) {
+                       err = mdsc->mdsmap_err;
+                       dout("do_request mdsmap err %d\n", err);
+                       goto finish;
+               }
                dout("do_request no mds or not active, waiting for map\n");
                list_add(&req->r_wait, &mdsc->waiting_for_map);
                goto out;
@@ -2292,14 +2240,6 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
 
-       /* deny access to directories with pool_ns layouts */
-       if (req->r_inode && S_ISDIR(req->r_inode->i_mode) &&
-           ceph_inode(req->r_inode)->i_pool_ns_len)
-               return -EIO;
-       if (req->r_locked_dir &&
-           ceph_inode(req->r_locked_dir)->i_pool_ns_len)
-               return -EIO;
-
        /* issue */
        mutex_lock(&mdsc->mutex);
        __register_request(mdsc, req, dir);
@@ -2791,13 +2731,13 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                struct ceph_mds_cap_reconnect v2;
                struct ceph_mds_cap_reconnect_v1 v1;
        } rec;
-       size_t reclen;
        struct ceph_inode_info *ci;
        struct ceph_reconnect_state *recon_state = arg;
        struct ceph_pagelist *pagelist = recon_state->pagelist;
        char *path;
        int pathlen, err;
        u64 pathbase;
+       u64 snap_follows;
        struct dentry *dentry;
 
        ci = cap->ci;
@@ -2819,10 +2759,8 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
        } else {
                path = NULL;
                pathlen = 0;
+               pathbase = 0;
        }
-       err = ceph_pagelist_encode_string(pagelist, path, pathlen);
-       if (err)
-               goto out_free;
 
        spin_lock(&ci->i_ceph_lock);
        cap->seq = 0;        /* reset cap seq */
@@ -2830,14 +2768,13 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
        cap->mseq = 0;       /* and migrate_seq */
        cap->cap_gen = cap->session->s_cap_gen;
 
-       if (recon_state->flock) {
+       if (recon_state->msg_version >= 2) {
                rec.v2.cap_id = cpu_to_le64(cap->cap_id);
                rec.v2.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
                rec.v2.issued = cpu_to_le32(cap->issued);
                rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
                rec.v2.pathbase = cpu_to_le64(pathbase);
                rec.v2.flock_len = 0;
-               reclen = sizeof(rec.v2);
        } else {
                rec.v1.cap_id = cpu_to_le64(cap->cap_id);
                rec.v1.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
@@ -2847,13 +2784,23 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                ceph_encode_timespec(&rec.v1.atime, &inode->i_atime);
                rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
                rec.v1.pathbase = cpu_to_le64(pathbase);
-               reclen = sizeof(rec.v1);
+       }
+
+       if (list_empty(&ci->i_cap_snaps)) {
+               snap_follows = 0;
+       } else {
+               struct ceph_cap_snap *capsnap =
+                       list_first_entry(&ci->i_cap_snaps,
+                                        struct ceph_cap_snap, ci_item);
+               snap_follows = capsnap->follows;
        }
        spin_unlock(&ci->i_ceph_lock);
 
-       if (recon_state->flock) {
+       if (recon_state->msg_version >= 2) {
                int num_fcntl_locks, num_flock_locks;
                struct ceph_filelock *flocks;
+               size_t struct_len, total_len = 0;
+               u8 struct_v = 0;
 
 encode_again:
                ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
@@ -2872,20 +2819,51 @@ encode_again:
                                goto encode_again;
                        goto out_free;
                }
+
+               if (recon_state->msg_version >= 3) {
+                       /* version, compat_version and struct_len */
+                       total_len = 2 * sizeof(u8) + sizeof(u32);
+                       struct_v = 2;
+               }
                /*
                 * number of encoded locks is stable, so copy to pagelist
                 */
-               rec.v2.flock_len = cpu_to_le32(2*sizeof(u32) +
-                                   (num_fcntl_locks+num_flock_locks) *
-                                   sizeof(struct ceph_filelock));
-               err = ceph_pagelist_append(pagelist, &rec, reclen);
-               if (!err)
-                       err = ceph_locks_to_pagelist(flocks, pagelist,
-                                                    num_fcntl_locks,
-                                                    num_flock_locks);
+               struct_len = 2 * sizeof(u32) +
+                           (num_fcntl_locks + num_flock_locks) *
+                           sizeof(struct ceph_filelock);
+               rec.v2.flock_len = cpu_to_le32(struct_len);
+
+               struct_len += sizeof(rec.v2);
+               struct_len += sizeof(u32) + pathlen;
+
+               if (struct_v >= 2)
+                       struct_len += sizeof(u64); /* snap_follows */
+
+               total_len += struct_len;
+               err = ceph_pagelist_reserve(pagelist, total_len);
+
+               if (!err) {
+                       if (recon_state->msg_version >= 3) {
+                               ceph_pagelist_encode_8(pagelist, struct_v);
+                               ceph_pagelist_encode_8(pagelist, 1);
+                               ceph_pagelist_encode_32(pagelist, struct_len);
+                       }
+                       ceph_pagelist_encode_string(pagelist, path, pathlen);
+                       ceph_pagelist_append(pagelist, &rec, sizeof(rec.v2));
+                       ceph_locks_to_pagelist(flocks, pagelist,
+                                              num_fcntl_locks,
+                                              num_flock_locks);
+                       if (struct_v >= 2)
+                               ceph_pagelist_encode_64(pagelist, snap_follows);
+               }
                kfree(flocks);
        } else {
-               err = ceph_pagelist_append(pagelist, &rec, reclen);
+               size_t size = sizeof(u32) + pathlen + sizeof(rec.v1);
+               err = ceph_pagelist_reserve(pagelist, size);
+               if (!err) {
+                       ceph_pagelist_encode_string(pagelist, path, pathlen);
+                       ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
+               }
        }
 
        recon_state->nr_caps++;
@@ -2976,7 +2954,12 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
 
        recon_state.nr_caps = 0;
        recon_state.pagelist = pagelist;
-       recon_state.flock = session->s_con.peer_features & CEPH_FEATURE_FLOCK;
+       if (session->s_con.peer_features & CEPH_FEATURE_MDSENC)
+               recon_state.msg_version = 3;
+       else if (session->s_con.peer_features & CEPH_FEATURE_FLOCK)
+               recon_state.msg_version = 2;
+       else
+               recon_state.msg_version = 1;
        err = iterate_session_caps(session, encode_caps_cb, &recon_state);
        if (err < 0)
                goto fail;
@@ -3005,8 +2988,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
                        goto fail;
        }
 
-       if (recon_state.flock)
-               reply->hdr.version = cpu_to_le16(2);
+       reply->hdr.version = cpu_to_le16(recon_state.msg_version);
 
        /* raced with cap release? */
        if (s_nr_caps != recon_state.nr_caps) {
@@ -3231,7 +3213,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                                msecs_to_jiffies(le32_to_cpu(h->duration_ms));
 
                        di->lease_seq = seq;
-                       dentry->d_time = di->lease_renew_from + duration;
+                       di->time = di->lease_renew_from + duration;
                        di->lease_renew_after = di->lease_renew_from +
                                (duration >> 1);
                        di->lease_renew_from = 0;
@@ -3296,47 +3278,6 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
        ceph_con_send(&session->s_con, msg);
 }
 
-/*
- * Preemptively release a lease we expect to invalidate anyway.
- * Pass @inode always, @dentry is optional.
- */
-void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc, struct inode *inode,
-                            struct dentry *dentry)
-{
-       struct ceph_dentry_info *di;
-       struct ceph_mds_session *session;
-       u32 seq;
-
-       BUG_ON(inode == NULL);
-       BUG_ON(dentry == NULL);
-
-       /* is dentry lease valid? */
-       spin_lock(&dentry->d_lock);
-       di = ceph_dentry(dentry);
-       if (!di || !di->lease_session ||
-           di->lease_session->s_mds < 0 ||
-           di->lease_gen != di->lease_session->s_cap_gen ||
-           !time_before(jiffies, dentry->d_time)) {
-               dout("lease_release inode %p dentry %p -- "
-                    "no lease\n",
-                    inode, dentry);
-               spin_unlock(&dentry->d_lock);
-               return;
-       }
-
-       /* we do have a lease on this dentry; note mds and seq */
-       session = ceph_get_mds_session(di->lease_session);
-       seq = di->lease_seq;
-       __ceph_mdsc_drop_dentry_lease(dentry);
-       spin_unlock(&dentry->d_lock);
-
-       dout("lease_release inode %p dentry %p to mds%d\n",
-            inode, dentry, session->s_mds);
-       ceph_mdsc_lease_send_msg(session, inode, dentry,
-                                CEPH_MDS_LEASE_RELEASE, seq);
-       ceph_put_mds_session(session);
-}
-
 /*
  * drop all leases (and dentry refs) in preparation for umount
  */
@@ -3470,7 +3411,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        INIT_LIST_HEAD(&mdsc->snap_flush_list);
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->last_cap_flush_tid = 1;
-       mdsc->cap_flush_tree = RB_ROOT;
+       INIT_LIST_HEAD(&mdsc->cap_flush_list);
        INIT_LIST_HEAD(&mdsc->cap_dirty);
        INIT_LIST_HEAD(&mdsc->cap_dirty_migrating);
        mdsc->num_cap_flushing = 0;
@@ -3585,7 +3526,7 @@ restart:
 
 void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
 {
-       u64 want_tid, want_flush, want_snap;
+       u64 want_tid, want_flush;
 
        if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN)
                return;
@@ -3598,17 +3539,19 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
        ceph_flush_dirty_caps(mdsc);
        spin_lock(&mdsc->cap_dirty_lock);
        want_flush = mdsc->last_cap_flush_tid;
+       if (!list_empty(&mdsc->cap_flush_list)) {
+               struct ceph_cap_flush *cf =
+                       list_last_entry(&mdsc->cap_flush_list,
+                                       struct ceph_cap_flush, g_list);
+               cf->wake = true;
+       }
        spin_unlock(&mdsc->cap_dirty_lock);
 
-       down_read(&mdsc->snap_rwsem);
-       want_snap = mdsc->last_snap_seq;
-       up_read(&mdsc->snap_rwsem);
-
-       dout("sync want tid %lld flush_seq %lld snap_seq %lld\n",
-            want_tid, want_flush, want_snap);
+       dout("sync want tid %lld flush_seq %lld\n",
+            want_tid, want_flush);
 
        wait_unsafe_requests(mdsc, want_tid);
-       wait_caps_flush(mdsc, want_flush, want_snap);
+       wait_caps_flush(mdsc, want_flush);
 }
 
 /*
@@ -3729,11 +3672,86 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
        dout("mdsc_destroy %p done\n", mdsc);
 }
 
+void ceph_mdsc_handle_fsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+{
+       struct ceph_fs_client *fsc = mdsc->fsc;
+       const char *mds_namespace = fsc->mount_options->mds_namespace;
+       void *p = msg->front.iov_base;
+       void *end = p + msg->front.iov_len;
+       u32 epoch;
+       u32 map_len;
+       u32 num_fs;
+       u32 mount_fscid = (u32)-1;
+       u8 struct_v, struct_cv;
+       int err = -EINVAL;
+
+       ceph_decode_need(&p, end, sizeof(u32), bad);
+       epoch = ceph_decode_32(&p);
+
+       dout("handle_fsmap epoch %u\n", epoch);
+
+       ceph_decode_need(&p, end, 2 + sizeof(u32), bad);
+       struct_v = ceph_decode_8(&p);
+       struct_cv = ceph_decode_8(&p);
+       map_len = ceph_decode_32(&p);
+
+       ceph_decode_need(&p, end, sizeof(u32) * 3, bad);
+       p += sizeof(u32) * 2; /* skip epoch and legacy_client_fscid */
+
+       num_fs = ceph_decode_32(&p);
+       while (num_fs-- > 0) {
+               void *info_p, *info_end;
+               u32 info_len;
+               u8 info_v, info_cv;
+               u32 fscid, namelen;
+
+               ceph_decode_need(&p, end, 2 + sizeof(u32), bad);
+               info_v = ceph_decode_8(&p);
+               info_cv = ceph_decode_8(&p);
+               info_len = ceph_decode_32(&p);
+               ceph_decode_need(&p, end, info_len, bad);
+               info_p = p;
+               info_end = p + info_len;
+               p = info_end;
+
+               ceph_decode_need(&info_p, info_end, sizeof(u32) * 2, bad);
+               fscid = ceph_decode_32(&info_p);
+               namelen = ceph_decode_32(&info_p);
+               ceph_decode_need(&info_p, info_end, namelen, bad);
+
+               if (mds_namespace &&
+                   strlen(mds_namespace) == namelen &&
+                   !strncmp(mds_namespace, (char *)info_p, namelen)) {
+                       mount_fscid = fscid;
+                       break;
+               }
+       }
+
+       ceph_monc_got_map(&fsc->client->monc, CEPH_SUB_FSMAP, epoch);
+       if (mount_fscid != (u32)-1) {
+               fsc->client->monc.fs_cluster_id = mount_fscid;
+               ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP,
+                                  0, true);
+               ceph_monc_renew_subs(&fsc->client->monc);
+       } else {
+               err = -ENOENT;
+               goto err_out;
+       }
+       return;
+bad:
+       pr_err("error decoding fsmap\n");
+err_out:
+       mutex_lock(&mdsc->mutex);
+       mdsc->mdsmap_err = -ENOENT;
+       __wake_requests(mdsc, &mdsc->waiting_for_map);
+       mutex_unlock(&mdsc->mutex);
+       return;
+}
 
 /*
  * handle mds map update.
  */
-void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+void ceph_mdsc_handle_mdsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
 {
        u32 epoch;
        u32 maplen;
@@ -3840,7 +3858,10 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
 
        switch (type) {
        case CEPH_MSG_MDS_MAP:
-               ceph_mdsc_handle_map(mdsc, msg);
+               ceph_mdsc_handle_mdsmap(mdsc, msg);
+               break;
+       case CEPH_MSG_FS_MAP_USER:
+               ceph_mdsc_handle_fsmap(mdsc, msg);
                break;
        case CEPH_MSG_CLIENT_SESSION:
                handle_session(s, msg);
index e7d38aa..6b36797 100644 (file)
@@ -45,6 +45,7 @@ struct ceph_mds_reply_info_in {
        u32 inline_len;
        char *inline_data;
        u32 pool_ns_len;
+       char *pool_ns_data;
 };
 
 struct ceph_mds_reply_dir_entry {
@@ -151,7 +152,6 @@ struct ceph_mds_session {
 
        /* protected by mutex */
        struct list_head  s_cap_flushing;     /* inodes w/ flushing caps */
-       struct list_head  s_cap_snaps_flushing;
        unsigned long     s_renew_requested; /* last time we sent a renew req */
        u64               s_renew_seq;
 
@@ -275,8 +275,10 @@ struct ceph_mds_request {
 
 struct ceph_pool_perm {
        struct rb_node node;
-       u32 pool;
        int perm;
+       s64 pool;
+       size_t pool_ns_len;
+       char pool_ns[];
 };
 
 /*
@@ -290,6 +292,7 @@ struct ceph_mds_client {
        struct completion       safe_umount_waiters;
        wait_queue_head_t       session_close_wq;
        struct list_head        waiting_for_map;
+       int                     mdsmap_err;
 
        struct ceph_mds_session **sessions;    /* NULL for mds if no session */
        atomic_t                num_sessions;
@@ -321,7 +324,7 @@ struct ceph_mds_client {
        spinlock_t       snap_flush_lock;
 
        u64               last_cap_flush_tid;
-       struct rb_root    cap_flush_tree;
+       struct list_head  cap_flush_list;
        struct list_head  cap_dirty;        /* inodes with dirty caps */
        struct list_head  cap_dirty_migrating; /* ...that are migration... */
        int               num_cap_flushing; /* # caps we are flushing */
@@ -382,10 +385,6 @@ extern void ceph_mdsc_destroy(struct ceph_fs_client *fsc);
 
 extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
 
-extern void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc,
-                                   struct inode *inode,
-                                   struct dentry *dn);
-
 extern void ceph_invalidate_dir_request(struct ceph_mds_request *req);
 extern int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
                                           struct inode *dir);
@@ -420,8 +419,10 @@ extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
                                     struct dentry *dentry, char action,
                                     u32 seq);
 
-extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc,
-                                struct ceph_msg *msg);
+extern void ceph_mdsc_handle_mdsmap(struct ceph_mds_client *mdsc,
+                                   struct ceph_msg *msg);
+extern void ceph_mdsc_handle_fsmap(struct ceph_mds_client *mdsc,
+                                  struct ceph_msg *msg);
 
 extern struct ceph_mds_session *
 ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target);
index 9caaa7f..9ff5219 100644 (file)
@@ -520,9 +520,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        ihold(inode);
 
        atomic_set(&capsnap->nref, 1);
-       capsnap->ci = ci;
        INIT_LIST_HEAD(&capsnap->ci_item);
-       INIT_LIST_HEAD(&capsnap->flushing_item);
 
        capsnap->follows = old_snapc->seq;
        capsnap->issued = __ceph_caps_issued(ci, NULL);
@@ -551,7 +549,6 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
        ci->i_wrbuffer_ref_head = 0;
        capsnap->context = old_snapc;
        list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
-       old_snapc = NULL;
 
        if (used & CEPH_CAP_FILE_WR) {
                dout("queue_cap_snap %p cap_snap %p snapc %p"
@@ -563,6 +560,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
                __ceph_finish_cap_snap(ci, capsnap);
        }
        capsnap = NULL;
+       old_snapc = NULL;
 
 update_snapc:
        if (ci->i_head_snapc) {
@@ -603,6 +601,8 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
                     capsnap->dirty_pages);
                return 0;
        }
+
+       ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
        dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n",
             inode, capsnap, capsnap->context,
             capsnap->context->seq, ceph_cap_string(capsnap->dirty),
@@ -799,9 +799,7 @@ static void flush_snaps(struct ceph_mds_client *mdsc)
                inode = &ci->vfs_inode;
                ihold(inode);
                spin_unlock(&mdsc->snap_flush_lock);
-               spin_lock(&ci->i_ceph_lock);
-               __ceph_flush_snaps(ci, &session, 0);
-               spin_unlock(&ci->i_ceph_lock);
+               ceph_flush_snaps(ci, &session);
                iput(inode);
                spin_lock(&mdsc->snap_flush_lock);
        }
index 91e0248..e247f6f 100644 (file)
@@ -108,7 +108,6 @@ static int ceph_sync_fs(struct super_block *sb, int wait)
  * mount options
  */
 enum {
-       Opt_mds_namespace,
        Opt_wsize,
        Opt_rsize,
        Opt_rasize,
@@ -121,6 +120,7 @@ enum {
        Opt_last_int,
        /* int args above */
        Opt_snapdirname,
+       Opt_mds_namespace,
        Opt_last_string,
        /* string args above */
        Opt_dirstat,
@@ -144,7 +144,6 @@ enum {
 };
 
 static match_table_t fsopt_tokens = {
-       {Opt_mds_namespace, "mds_namespace=%d"},
        {Opt_wsize, "wsize=%d"},
        {Opt_rsize, "rsize=%d"},
        {Opt_rasize, "rasize=%d"},
@@ -156,6 +155,7 @@ static match_table_t fsopt_tokens = {
        {Opt_congestion_kb, "write_congestion_kb=%d"},
        /* int args above */
        {Opt_snapdirname, "snapdirname=%s"},
+       {Opt_mds_namespace, "mds_namespace=%s"},
        /* string args above */
        {Opt_dirstat, "dirstat"},
        {Opt_nodirstat, "nodirstat"},
@@ -212,11 +212,14 @@ static int parse_fsopt_token(char *c, void *private)
                if (!fsopt->snapdir_name)
                        return -ENOMEM;
                break;
-
-               /* misc */
        case Opt_mds_namespace:
-               fsopt->mds_namespace = intval;
+               fsopt->mds_namespace = kstrndup(argstr[0].from,
+                                               argstr[0].to-argstr[0].from,
+                                               GFP_KERNEL);
+               if (!fsopt->mds_namespace)
+                       return -ENOMEM;
                break;
+               /* misc */
        case Opt_wsize:
                fsopt->wsize = intval;
                break;
@@ -302,6 +305,7 @@ static void destroy_mount_options(struct ceph_mount_options *args)
 {
        dout("destroy_mount_options %p\n", args);
        kfree(args->snapdir_name);
+       kfree(args->mds_namespace);
        kfree(args->server_path);
        kfree(args);
 }
@@ -331,6 +335,9 @@ static int compare_mount_options(struct ceph_mount_options *new_fsopt,
                return ret;
 
        ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
+       if (ret)
+               return ret;
+       ret = strcmp_null(fsopt1->mds_namespace, fsopt2->mds_namespace);
        if (ret)
                return ret;
 
@@ -376,7 +383,6 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
        fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
        fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
        fsopt->congestion_kb = default_congestion_kb();
-       fsopt->mds_namespace = CEPH_FS_CLUSTER_ID_NONE;
 
        /*
         * Distinguish the server list from the path in "dev_name".
@@ -469,8 +475,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",noacl");
 #endif
 
-       if (fsopt->mds_namespace != CEPH_FS_CLUSTER_ID_NONE)
-               seq_printf(m, ",mds_namespace=%d", fsopt->mds_namespace);
+       if (fsopt->mds_namespace)
+               seq_printf(m, ",mds_namespace=%s", fsopt->mds_namespace);
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
        if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
@@ -509,9 +515,11 @@ static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
 
        switch (type) {
        case CEPH_MSG_MDS_MAP:
-               ceph_mdsc_handle_map(fsc->mdsc, msg);
+               ceph_mdsc_handle_mdsmap(fsc->mdsc, msg);
+               return 0;
+       case CEPH_MSG_FS_MAP_USER:
+               ceph_mdsc_handle_fsmap(fsc->mdsc, msg);
                return 0;
-
        default:
                return -1;
        }
@@ -543,8 +551,14 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
                goto fail;
        }
        fsc->client->extra_mon_dispatch = extra_mon_dispatch;
-       fsc->client->monc.fs_cluster_id = fsopt->mds_namespace;
-       ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP, 0, true);
+
+       if (fsopt->mds_namespace == NULL) {
+               ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP,
+                                  0, true);
+       } else {
+               ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_FSMAP,
+                                  0, false);
+       }
 
        fsc->mount_options = fsopt;
 
@@ -672,8 +686,8 @@ static int __init init_caches(void)
        if (ceph_dentry_cachep == NULL)
                goto bad_dentry;
 
-       ceph_file_cachep = KMEM_CACHE(ceph_file_info,
-                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
+
        if (ceph_file_cachep == NULL)
                goto bad_file;
 
@@ -731,6 +745,7 @@ static const struct super_operations ceph_super_ops = {
        .destroy_inode  = ceph_destroy_inode,
        .write_inode    = ceph_write_inode,
        .drop_inode     = ceph_drop_inode,
+       .evict_inode    = ceph_evict_inode,
        .sync_fs        = ceph_sync_fs,
        .put_super      = ceph_put_super,
        .show_options   = ceph_show_options,
index 0168b49..3e3fa91 100644 (file)
@@ -62,7 +62,6 @@ struct ceph_mount_options {
        int cap_release_safety;
        int max_readdir;       /* max readdir result (entires) */
        int max_readdir_bytes; /* max readdir result (bytes) */
-       int mds_namespace;
 
        /*
         * everything above this point can be memcmp'd; everything below
@@ -70,6 +69,7 @@ struct ceph_mount_options {
         */
 
        char *snapdir_name;   /* default ".snap" */
+       char *mds_namespace;  /* default NULL */
        char *server_path;    /* default  "/" */
 };
 
@@ -147,6 +147,14 @@ struct ceph_cap {
 #define CHECK_CAPS_AUTHONLY   2  /* only check auth cap */
 #define CHECK_CAPS_FLUSH      4  /* flush any dirty caps */
 
+struct ceph_cap_flush {
+       u64 tid;
+       int caps; /* 0 means capsnap */
+       bool wake; /* wake up flush waiters when finish ? */
+       struct list_head g_list; // global
+       struct list_head i_list; // per inode
+};
+
 /*
  * Snapped cap state that is pending flush to mds.  When a snapshot occurs,
  * we first complete any in-process sync writes and writeback any dirty
@@ -154,10 +162,11 @@ struct ceph_cap {
  */
 struct ceph_cap_snap {
        atomic_t nref;
-       struct ceph_inode_info *ci;
-       struct list_head ci_item, flushing_item;
+       struct list_head ci_item;
+
+       struct ceph_cap_flush cap_flush;
 
-       u64 follows, flush_tid;
+       u64 follows;
        int issued, dirty;
        struct ceph_snap_context *context;
 
@@ -186,16 +195,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
        }
 }
 
-struct ceph_cap_flush {
-       u64 tid;
-       int caps;
-       struct rb_node g_node; // global
-       union {
-               struct rb_node i_node; // inode
-               struct list_head list;
-       };
-};
-
 /*
  * The frag tree describes how a directory is fragmented, potentially across
  * multiple metadata servers.  It is also used to indicate points where
@@ -246,7 +245,7 @@ struct ceph_dentry_info {
        unsigned long lease_renew_after, lease_renew_from;
        struct list_head lru;
        struct dentry *dentry;
-       u64 time;
+       unsigned long time;
        u64 offset;
 };
 
@@ -287,7 +286,6 @@ struct ceph_inode_info {
 
        struct ceph_dir_layout i_dir_layout;
        struct ceph_file_layout i_layout;
-       size_t i_pool_ns_len;
        char *i_symlink;
 
        /* for dirs */
@@ -311,7 +309,7 @@ struct ceph_inode_info {
         * overlapping, pipelined cap flushes to the mds.  we can probably
         * reduce the tid to 8 bits if we're concerned about inode size. */
        struct ceph_cap_flush *i_prealloc_cap_flush;
-       struct rb_root i_cap_flush_tree;
+       struct list_head i_cap_flush_list;
        wait_queue_head_t i_cap_wq;      /* threads waiting on a capability */
        unsigned long i_hold_caps_min; /* jiffies */
        unsigned long i_hold_caps_max; /* jiffies */
@@ -322,7 +320,7 @@ struct ceph_inode_info {
                                                    dirty|flushing caps */
        unsigned i_snap_caps;           /* cap bits for snapped files */
 
-       int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */
+       int i_nr_by_mode[CEPH_FILE_MODE_BITS];  /* open file counts */
 
        struct mutex i_truncate_mutex;
        u32 i_truncate_seq;        /* last truncate to smaller size */
@@ -471,6 +469,8 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
 #define CEPH_I_POOL_WR         (1 << 6)  /* can write to pool */
 #define CEPH_I_SEC_INITED      (1 << 7)  /* security initialized */
 #define CEPH_I_CAP_DROPPED     (1 << 8)  /* caps were forcibly dropped */
+#define CEPH_I_KICK_FLUSH      (1 << 9)  /* kick flushing caps */
+#define CEPH_I_FLUSH_SNAPS     (1 << 10) /* need flush snapss */
 
 static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
                                           long long release_count,
@@ -750,6 +750,7 @@ extern const struct inode_operations ceph_file_iops;
 extern struct inode *ceph_alloc_inode(struct super_block *sb);
 extern void ceph_destroy_inode(struct inode *inode);
 extern int ceph_drop_inode(struct inode *inode);
+extern void ceph_evict_inode(struct inode *inode);
 
 extern struct inode *ceph_get_inode(struct super_block *sb,
                                    struct ceph_vino vino);
@@ -890,9 +891,8 @@ extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps);
 extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);
 extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                                       struct ceph_snap_context *snapc);
-extern void __ceph_flush_snaps(struct ceph_inode_info *ci,
-                              struct ceph_mds_session **psession,
-                              int again);
+extern void ceph_flush_snaps(struct ceph_inode_info *ci,
+                            struct ceph_mds_session **psession);
 extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
                            struct ceph_mds_session *session);
 extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
@@ -907,10 +907,7 @@ extern int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
                         loff_t endoff, int *got, struct page **pinned_page);
 
 /* for counting open files by mode */
-static inline void __ceph_get_fmode(struct ceph_inode_info *ci, int mode)
-{
-       ci->i_nr_by_mode[mode]++;
-}
+extern void __ceph_get_fmode(struct ceph_inode_info *ci, int mode);
 extern void ceph_put_fmode(struct ceph_inode_info *ci, int mode);
 
 /* addr.c */
@@ -931,6 +928,7 @@ extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
 extern int ceph_release(struct inode *inode, struct file *filp);
 extern void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
                                  char *data, size_t len);
+extern void ceph_sync_write_wait(struct inode *inode);
 /* dir.c */
 extern const struct file_operations ceph_dir_fops;
 extern const struct file_operations ceph_snapdir_fops;
index 4870b29..adc2318 100644 (file)
@@ -57,81 +57,88 @@ struct ceph_vxattr {
 
 static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
 {
-       size_t s;
-       char *p = (char *)&ci->i_layout;
-
-       for (s = 0; s < sizeof(ci->i_layout); s++, p++)
-               if (*p)
-                       return true;
-       return false;
+       struct ceph_file_layout *fl = &ci->i_layout;
+       return (fl->stripe_unit > 0 || fl->stripe_count > 0 ||
+               fl->object_size > 0 || fl->pool_id >= 0 ||
+               rcu_dereference_raw(fl->pool_ns) != NULL);
 }
 
 static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
                                   size_t size)
 {
-       int ret;
        struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
        struct ceph_osd_client *osdc = &fsc->client->osdc;
-       s64 pool = ceph_file_layout_pg_pool(ci->i_layout);
+       struct ceph_string *pool_ns;
+       s64 pool = ci->i_layout.pool_id;
        const char *pool_name;
+       const char *ns_field = " pool_namespace=";
        char buf[128];
+       size_t len, total_len = 0;
+       int ret;
+
+       pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
 
        dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode);
        down_read(&osdc->lock);
        pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
        if (pool_name) {
-               size_t len = strlen(pool_name);
-               ret = snprintf(buf, sizeof(buf),
-               "stripe_unit=%lld stripe_count=%lld object_size=%lld pool=",
-               (unsigned long long)ceph_file_layout_su(ci->i_layout),
-               (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
-               (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
-               if (!size) {
-                       ret += len;
-               } else if (ret + len > size) {
-                       ret = -ERANGE;
-               } else {
-                       memcpy(val, buf, ret);
+               len = snprintf(buf, sizeof(buf),
+               "stripe_unit=%u stripe_count=%u object_size=%u pool=",
+               ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
+               ci->i_layout.object_size);
+               total_len = len + strlen(pool_name);
+       } else {
+               len = snprintf(buf, sizeof(buf),
+               "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld",
+               ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
+               ci->i_layout.object_size, (unsigned long long)pool);
+               total_len = len;
+       }
+
+       if (pool_ns)
+               total_len += strlen(ns_field) + pool_ns->len;
+
+       if (!size) {
+               ret = total_len;
+       } else if (total_len > size) {
+               ret = -ERANGE;
+       } else {
+               memcpy(val, buf, len);
+               ret = len;
+               if (pool_name) {
+                       len = strlen(pool_name);
                        memcpy(val + ret, pool_name, len);
                        ret += len;
                }
-       } else {
-               ret = snprintf(buf, sizeof(buf),
-               "stripe_unit=%lld stripe_count=%lld object_size=%lld pool=%lld",
-               (unsigned long long)ceph_file_layout_su(ci->i_layout),
-               (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
-               (unsigned long long)ceph_file_layout_object_size(ci->i_layout),
-               (unsigned long long)pool);
-               if (size) {
-                       if (ret <= size)
-                               memcpy(val, buf, ret);
-                       else
-                               ret = -ERANGE;
+               if (pool_ns) {
+                       len = strlen(ns_field);
+                       memcpy(val + ret, ns_field, len);
+                       ret += len;
+                       memcpy(val + ret, pool_ns->str, pool_ns->len);
+                       ret += pool_ns->len;
                }
        }
        up_read(&osdc->lock);
+       ceph_put_string(pool_ns);
        return ret;
 }
 
 static size_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci,
                                               char *val, size_t size)
 {
-       return snprintf(val, size, "%lld",
-                       (unsigned long long)ceph_file_layout_su(ci->i_layout));
+       return snprintf(val, size, "%u", ci->i_layout.stripe_unit);
 }
 
 static size_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci,
                                                char *val, size_t size)
 {
-       return snprintf(val, size, "%lld",
-              (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout));
+       return snprintf(val, size, "%u", ci->i_layout.stripe_count);
 }
 
 static size_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci,
                                               char *val, size_t size)
 {
-       return snprintf(val, size, "%lld",
-              (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
+       return snprintf(val, size, "%u", ci->i_layout.object_size);
 }
 
 static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
@@ -140,7 +147,7 @@ static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
        int ret;
        struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
        struct ceph_osd_client *osdc = &fsc->client->osdc;
-       s64 pool = ceph_file_layout_pg_pool(ci->i_layout);
+       s64 pool = ci->i_layout.pool_id;
        const char *pool_name;
 
        down_read(&osdc->lock);
@@ -153,6 +160,18 @@ static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
        return ret;
 }
 
+static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
+                                                 char *val, size_t size)
+{
+       int ret = 0;
+       struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns);
+       if (ns) {
+               ret = snprintf(val, size, "%.*s", (int)ns->len, ns->str);
+               ceph_put_string(ns);
+       }
+       return ret;
+}
+
 /* directories */
 
 static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
@@ -241,6 +260,7 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = {
        XATTR_LAYOUT_FIELD(dir, layout, stripe_count),
        XATTR_LAYOUT_FIELD(dir, layout, object_size),
        XATTR_LAYOUT_FIELD(dir, layout, pool),
+       XATTR_LAYOUT_FIELD(dir, layout, pool_namespace),
        XATTR_NAME_CEPH(dir, entries),
        XATTR_NAME_CEPH(dir, files),
        XATTR_NAME_CEPH(dir, subdirs),
@@ -268,6 +288,7 @@ static struct ceph_vxattr ceph_file_vxattrs[] = {
        XATTR_LAYOUT_FIELD(file, layout, stripe_count),
        XATTR_LAYOUT_FIELD(file, layout, object_size),
        XATTR_LAYOUT_FIELD(file, layout, pool),
+       XATTR_LAYOUT_FIELD(file, layout, pool_namespace),
        { .name = NULL, 0 }     /* Required table terminator */
 };
 static size_t ceph_file_vxattrs_name_size;     /* total size of all names */
index 4e53253..4716c54 100644 (file)
@@ -903,10 +903,10 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
        return 0;
 }
 
-static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
+static int cifs_ci_compare(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
+       struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
        wchar_t c1, c2;
        int i, l1, l2;
 
index b90cf8e..5c7cc95 100644 (file)
@@ -316,20 +316,6 @@ static void dentry_free(struct dentry *dentry)
                call_rcu(&dentry->d_u.d_rcu, __d_free);
 }
 
-/**
- * dentry_rcuwalk_invalidate - invalidate in-progress rcu-walk lookups
- * @dentry: the target dentry
- * After this call, in-progress rcu-walk path lookup will fail. This
- * should be called after unhashing, and after changing d_inode (if
- * the dentry has not already been unhashed).
- */
-static inline void dentry_rcuwalk_invalidate(struct dentry *dentry)
-{
-       lockdep_assert_held(&dentry->d_lock);
-       /* Go through am invalidation barrier */
-       write_seqcount_invalidate(&dentry->d_seq);
-}
-
 /*
  * Release the dentry's inode, using the filesystem
  * d_iput() operation if defined.
@@ -468,7 +454,8 @@ void __d_drop(struct dentry *dentry)
                __hlist_bl_del(&dentry->d_hash);
                dentry->d_hash.pprev = NULL;
                hlist_bl_unlock(b);
-               dentry_rcuwalk_invalidate(dentry);
+               /* After this call, in-progress rcu-walk path lookup will fail. */
+               write_seqcount_invalidate(&dentry->d_seq);
        }
 }
 EXPORT_SYMBOL(__d_drop);
@@ -2060,7 +2047,7 @@ static inline bool d_same_name(const struct dentry *dentry,
                        return false;
                return dentry_cmp(dentry, name->name, name->len) == 0;
        }
-       return parent->d_op->d_compare(parent, dentry,
+       return parent->d_op->d_compare(dentry,
                                       dentry->d_name.len, dentry->d_name.name,
                                       name) == 0;
 }
@@ -2163,7 +2150,7 @@ seqretry:
                                cpu_relax();
                                goto seqretry;
                        }
-                       if (parent->d_op->d_compare(parent, dentry,
+                       if (parent->d_op->d_compare(dentry,
                                                    tlen, tname, name) != 0)
                                continue;
                } else {
@@ -2352,19 +2339,15 @@ again:
 }
 EXPORT_SYMBOL(d_delete);
 
-static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
+static void __d_rehash(struct dentry *entry)
 {
+       struct hlist_bl_head *b = d_hash(entry->d_name.hash);
        BUG_ON(!d_unhashed(entry));
        hlist_bl_lock(b);
        hlist_bl_add_head_rcu(&entry->d_hash, b);
        hlist_bl_unlock(b);
 }
 
-static void _d_rehash(struct dentry * entry)
-{
-       __d_rehash(entry, d_hash(entry->d_name.hash));
-}
-
 /**
  * d_rehash    - add an entry back to the hash
  * @entry: dentry to add to the hash
@@ -2375,7 +2358,7 @@ static void _d_rehash(struct dentry * entry)
 void d_rehash(struct dentry * entry)
 {
        spin_lock(&entry->d_lock);
-       _d_rehash(entry);
+       __d_rehash(entry);
        spin_unlock(&entry->d_lock);
 }
 EXPORT_SYMBOL(d_rehash);
@@ -2549,7 +2532,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
                raw_write_seqcount_end(&dentry->d_seq);
                fsnotify_update_flags(dentry);
        }
-       _d_rehash(dentry);
+       __d_rehash(dentry);
        if (dir)
                end_dir_add(dir, n);
        spin_unlock(&dentry->d_lock);
@@ -2611,7 +2594,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
                        alias = NULL;
                } else {
                        __dget_dlock(alias);
-                       _d_rehash(alias);
+                       __d_rehash(alias);
                        spin_unlock(&alias->d_lock);
                }
                spin_unlock(&inode->i_lock);
@@ -2636,7 +2619,7 @@ EXPORT_SYMBOL(d_exact_alias);
  * Parent inode i_mutex must be held over d_lookup and into this call (to
  * keep renames and concurrent inserts, and readdir(2) away).
  */
-void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
+void dentry_update_name_case(struct dentry *dentry, const struct qstr *name)
 {
        BUG_ON(!inode_is_locked(dentry->d_parent->d_inode));
        BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
@@ -2795,23 +2778,10 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
        write_seqcount_begin(&dentry->d_seq);
        write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
 
+       /* unhash both */
        /* __d_drop does write_seqcount_barrier, but they're OK to nest. */
-
-       /*
-        * Move the dentry to the target hash queue. Don't bother checking
-        * for the same hash queue because of how unlikely it is.
-        */
        __d_drop(dentry);
-       __d_rehash(dentry, d_hash(target->d_name.hash));
-
-       /*
-        * Unhash the target (d_delete() is not usable here).  If exchanging
-        * the two dentries, then rehash onto the other's hash queue.
-        */
        __d_drop(target);
-       if (exchange) {
-               __d_rehash(target, d_hash(dentry->d_name.hash));
-       }
 
        /* Switch the names.. */
        if (exchange)
@@ -2819,6 +2789,11 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
        else
                copy_name(dentry, target);
 
+       /* rehash in new place(s) */
+       __d_rehash(dentry);
+       if (exchange)
+               __d_rehash(target);
+
        /* ... and switch them in the tree */
        if (IS_ROOT(dentry)) {
                /* splicing a tree */
@@ -3038,7 +3013,7 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
  * Data dependency barrier is needed to make sure that we see that terminating
  * NUL.  Alpha strikes again, film at 11...
  */
-static int prepend_name(char **buffer, int *buflen, struct qstr *name)
+static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
 {
        const char *dname = ACCESS_ONCE(name->name);
        u32 dlen = ACCESS_ONCE(name->len);
index a5e607e..688ccc1 100644 (file)
@@ -45,8 +45,7 @@ static struct super_block *efivarfs_sb;
  * So we need to perform a case-sensitive match on part 1 and a
  * case-insensitive match on part 2.
  */
-static int efivarfs_d_compare(const struct dentry *parent,
-                             const struct dentry *dentry,
+static int efivarfs_d_compare(const struct dentry *dentry,
                              unsigned int len, const char *str,
                              const struct qstr *name)
 {
index ca239fc..6fcfb3f 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -762,6 +762,39 @@ out_unlock:
 }
 EXPORT_SYMBOL(setup_arg_pages);
 
+#else
+
+/*
+ * Transfer the program arguments and environment from the holding pages
+ * onto the stack. The provided stack pointer is adjusted accordingly.
+ */
+int transfer_args_to_stack(struct linux_binprm *bprm,
+                          unsigned long *sp_location)
+{
+       unsigned long index, stop, sp;
+       int ret = 0;
+
+       stop = bprm->p >> PAGE_SHIFT;
+       sp = *sp_location;
+
+       for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
+               unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0;
+               char *src = kmap(bprm->page[index]) + offset;
+               sp -= PAGE_SIZE - offset;
+               if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0)
+                       ret = -EFAULT;
+               kunmap(bprm->page[index]);
+               if (ret)
+                       goto out;
+       }
+
+       *sp_location = sp;
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(transfer_args_to_stack);
+
 #endif /* CONFIG_MMU */
 
 static struct file *do_open_execat(int fd, struct filename *name, int flags)
@@ -866,7 +899,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
                goto out;
        }
 
-       *buf = vmalloc(i_size);
+       if (id != READING_FIRMWARE_PREALLOC_BUFFER)
+               *buf = vmalloc(i_size);
        if (!*buf) {
                ret = -ENOMEM;
                goto out;
@@ -897,8 +931,10 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
 
 out_free:
        if (ret < 0) {
-               vfree(*buf);
-               *buf = NULL;
+               if (id != READING_FIRMWARE_PREALLOC_BUFFER) {
+                       vfree(*buf);
+                       *buf = NULL;
+               }
        }
 
 out:
index 19efd11..61ad490 100644 (file)
@@ -358,8 +358,8 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
  * and the entry itself. Page is returned mapped and unlocked.
  * Entry is guaranteed to be valid.
  */
-struct ext2_dir_entry_2 *ext2_find_entry (struct inode * dir,
-                       struct qstr *child, struct page ** res_page)
+struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
+                       const struct qstr *child, struct page **res_page)
 {
        const char *name = child->name;
        int namelen = child->len;
@@ -435,7 +435,7 @@ struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
        return de;
 }
 
-ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child)
+ino_t ext2_inode_by_name(struct inode *dir, const struct qstr *child)
 {
        ino_t res = 0;
        struct ext2_dir_entry_2 *de;
index 3fb9368..06af2f9 100644 (file)
@@ -757,9 +757,9 @@ extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_wind
 
 /* dir.c */
 extern int ext2_add_link (struct dentry *, struct inode *);
-extern ino_t ext2_inode_by_name(struct inode *, struct qstr *);
+extern ino_t ext2_inode_by_name(struct inode *, const struct qstr *);
 extern int ext2_make_empty(struct inode *, struct inode *);
-extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, struct page **);
+extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,const struct qstr *, struct page **);
 extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
 extern int ext2_empty_dir (struct inode *);
 extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
index e262427..d64d2a5 100644 (file)
@@ -245,7 +245,6 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
                bio_put(bio);
                return -EFAULT;
        }
-       bio->bi_rw = fio->op_flags;
        bio_set_op_attrs(bio, fio->op, fio->op_flags);
 
        __submit_bio(fio->sbi, bio, fio->type);
index a485f68..9054aea 100644 (file)
@@ -219,7 +219,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
  * Entry is guaranteed to be valid.
  */
 struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
-                       struct qstr *child, struct page **res_page)
+                       const struct qstr *child, struct page **res_page)
 {
        unsigned long npages = dir_blocks(dir);
        struct f2fs_dir_entry *de = NULL;
@@ -272,7 +272,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
        return f2fs_find_entry(dir, &dotdot, p);
 }
 
-ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr,
+ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr,
                                                        struct page **page)
 {
        ino_t res = 0;
index 7890e90..675fa79 100644 (file)
@@ -1914,10 +1914,10 @@ struct page *init_inode_metadata(struct inode *, struct inode *,
 void update_parent_metadata(struct inode *, struct inode *, unsigned int);
 int room_for_filename(const void *, int, int);
 void f2fs_drop_nlink(struct inode *, struct inode *);
-struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
+struct f2fs_dir_entry *f2fs_find_entry(struct inode *, const struct qstr *,
                                                        struct page **);
 struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
-ino_t f2fs_inode_by_name(struct inode *, struct qstr *, struct page **);
+ino_t f2fs_inode_by_name(struct inode *, const struct qstr *, struct page **);
 void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
                                struct page *, struct inode *);
 int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
index 1337c0c..664655b 100644 (file)
@@ -162,10 +162,10 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
  * Compare two msdos names. If either of the names are invalid,
  * we fall back to doing the standard name comparison.
  */
-static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
+static int msdos_cmp(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
+       struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
        unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
        int error;
 
index 6ccdf3f..92b7363 100644 (file)
@@ -138,10 +138,10 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
 /*
  * Case insensitive compare of two vfat names.
  */
-static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
+static int vfat_cmpi(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
+       struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
        unsigned int alen, blen;
 
        /* A filename cannot end in '.' or we treat it like it has none */
@@ -157,7 +157,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
 /*
  * Case sensitive compare of two vfat names.
  */
-static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
+static int vfat_cmp(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned int alen, blen;
@@ -652,8 +652,8 @@ out_free:
        return err;
 }
 
-static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
-                         int cluster, struct timespec *ts,
+static int vfat_add_entry(struct inode *dir, const struct qstr *qname,
+                         int is_dir, int cluster, struct timespec *ts,
                          struct fat_slot_info *sinfo)
 {
        struct msdos_dir_slot *slots;
@@ -688,7 +688,7 @@ cleanup:
        return err;
 }
 
-static int vfat_find(struct inode *dir, struct qstr *qname,
+static int vfat_find(struct inode *dir, const struct qstr *qname,
                     struct fat_slot_info *sinfo)
 {
        unsigned int len = vfat_striptail_len(qname);
index 56c8fda..4d09d44 100644 (file)
@@ -1327,6 +1327,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        dirty = inode->i_state & I_DIRTY;
        if (inode->i_state & I_DIRTY_TIME) {
                if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) ||
+                   wbc->sync_mode == WB_SYNC_ALL ||
                    unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) ||
                    unlikely(time_after(jiffies,
                                        (inode->dirtied_time_when +
index 5f16277..c47b778 100644 (file)
@@ -146,7 +146,7 @@ static void fuse_invalidate_entry(struct dentry *entry)
 }
 
 static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
-                            u64 nodeid, struct qstr *name,
+                            u64 nodeid, const struct qstr *name,
                             struct fuse_entry_out *outarg)
 {
        memset(outarg, 0, sizeof(struct fuse_entry_out));
@@ -282,7 +282,7 @@ int fuse_valid_type(int m)
                S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
 }
 
-int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
+int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode)
 {
        struct fuse_conn *fc = get_fuse_conn_super(sb);
index 5db5d24..d98d8cc 100644 (file)
@@ -704,7 +704,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
                        int generation, struct fuse_attr *attr,
                        u64 attr_valid, u64 attr_version);
 
-int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
+int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode);
 
 /**
index 9b7cb37..4e05b51 100644 (file)
@@ -673,13 +673,11 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
        inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
        if (!inode) {
                struct fuse_entry_out outarg;
-               struct qstr name;
+               const struct qstr name = QSTR_INIT(".", 1);
 
                if (!fc->export_support)
                        goto out_err;
 
-               name.len = 1;
-               name.name = ".";
                err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg,
                                       &inode);
                if (err && err != -ENOENT)
@@ -775,14 +773,12 @@ static struct dentry *fuse_get_parent(struct dentry *child)
        struct inode *inode;
        struct dentry *parent;
        struct fuse_entry_out outarg;
-       struct qstr name;
+       const struct qstr name = QSTR_INIT("..", 2);
        int err;
 
        if (!fc->export_support)
                return ERR_PTR(-ESTALE);
 
-       name.len = 2;
-       name.name = "..";
        err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
                               &name, &outarg, &inode);
        if (err) {
index e0621ca..e4da0ec 100644 (file)
@@ -1800,7 +1800,7 @@ int gfs2_permission(struct inode *inode, int mask)
        }
 
        if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
-               error = -EACCES;
+               error = -EPERM;
        else
                error = generic_permission(inode, mask);
        if (gfs2_holder_initialized(&i_gh))
index 98cde8b..8f4afd3 100644 (file)
@@ -20,7 +20,7 @@
  *
  * Given the ID of the parent and the name build a search key.
  */
-void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, struct qstr *name)
+void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, const struct qstr *name)
 {
        key->cat.reserved = 0;
        key->cat.ParID = cpu_to_be32(parent);
@@ -64,7 +64,7 @@ static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
 
 static int hfs_cat_build_thread(struct super_block *sb,
                                hfs_cat_rec *rec, int type,
-                               u32 parentid, struct qstr *name)
+                               u32 parentid, const struct qstr *name)
 {
        rec->type = type;
        memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
@@ -79,7 +79,7 @@ static int hfs_cat_build_thread(struct super_block *sb,
  * Add a new file or directory to the catalog B-tree and
  * return a (struct hfs_cat_entry) for it in '*result'.
  */
-int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
+int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct inode *inode)
 {
        struct hfs_find_data fd;
        struct super_block *sb;
@@ -210,7 +210,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
  * Delete the indicated file or directory.
  * The associated thread is also removed unless ('with_thread'==0).
  */
-int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
+int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
 {
        struct super_block *sb;
        struct hfs_find_data fd;
@@ -277,8 +277,8 @@ out:
  * If the destination exists it is removed and a
  * (struct hfs_cat_entry) for it is returned in '*result'.
  */
-int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
-                struct inode *dst_dir, struct qstr *dst_name)
+int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
+                struct inode *dst_dir, const struct qstr *dst_name)
 {
        struct super_block *sb;
        struct hfs_find_data src_fd, dst_fd;
index ee2f385..16f5172 100644 (file)
@@ -178,11 +178,11 @@ extern int hfs_clear_vbm_bits(struct super_block *, u16, u16);
 extern int hfs_cat_keycmp(const btree_key *, const btree_key *);
 struct hfs_find_data;
 extern int hfs_cat_find_brec(struct super_block *, u32, struct hfs_find_data *);
-extern int hfs_cat_create(u32, struct inode *, struct qstr *, struct inode *);
-extern int hfs_cat_delete(u32, struct inode *, struct qstr *);
-extern int hfs_cat_move(u32, struct inode *, struct qstr *,
-                       struct inode *, struct qstr *);
-extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
+extern int hfs_cat_create(u32, struct inode *, const struct qstr *, struct inode *);
+extern int hfs_cat_delete(u32, struct inode *, const struct qstr *);
+extern int hfs_cat_move(u32, struct inode *, const struct qstr *,
+                       struct inode *, const struct qstr *);
+extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, const struct qstr *);
 
 /* dir.c */
 extern const struct file_operations hfs_dir_operations;
@@ -201,7 +201,7 @@ extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 extern const struct address_space_operations hfs_aops;
 extern const struct address_space_operations hfs_btree_aops;
 
-extern struct inode *hfs_new_inode(struct inode *, struct qstr *, umode_t);
+extern struct inode *hfs_new_inode(struct inode *, const struct qstr *, umode_t);
 extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *);
 extern int hfs_write_inode(struct inode *, struct writeback_control *);
 extern int hfs_inode_setattr(struct dentry *, struct iattr *);
@@ -233,11 +233,11 @@ extern const struct dentry_operations hfs_dentry_operations;
 extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
 extern int hfs_strcmp(const unsigned char *, unsigned int,
                      const unsigned char *, unsigned int);
-extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+extern int hfs_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 /* trans.c */
-extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
+extern void hfs_asc2mac(struct super_block *, struct hfs_name *, const struct qstr *);
 extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
 
 /* super.c */
index 02a3845..c6a3241 100644 (file)
@@ -177,7 +177,7 @@ const struct address_space_operations hfs_aops = {
 /*
  * hfs_new_inode
  */
-struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
+struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t mode)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode = new_inode(sb);
index ec9f164..3912209 100644 (file)
@@ -92,7 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
  * Test for equality of two strings in the HFS filename character ordering.
  * return 1 on failure and 0 on success
  */
-int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+int hfs_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        const unsigned char *n1, *n2;
index b1ce4c7..39f5e34 100644 (file)
@@ -94,7 +94,7 @@ out:
  * This routine is a inverse to hfs_mac2triv().
  * A ':' is replaced by a '/'.
  */
-void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, struct qstr *in)
+void hfs_asc2mac(struct super_block *sb, struct hfs_name *out, const struct qstr *in)
 {
        struct nls_table *nls_disk = HFS_SB(sb)->nls_disk;
        struct nls_table *nls_io = HFS_SB(sb)->nls_io;
index fb707e8..142534d 100644 (file)
@@ -40,7 +40,7 @@ int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1,
 
 /* Generates key for catalog file/folders record. */
 int hfsplus_cat_build_key(struct super_block *sb,
-               hfsplus_btree_key *key, u32 parent, struct qstr *str)
+               hfsplus_btree_key *key, u32 parent, const struct qstr *str)
 {
        int len, err;
 
@@ -174,7 +174,7 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
 
 static int hfsplus_fill_cat_thread(struct super_block *sb,
                                   hfsplus_cat_entry *entry, int type,
-                                  u32 parentid, struct qstr *str)
+                                  u32 parentid, const struct qstr *str)
 {
        int err;
 
@@ -250,7 +250,7 @@ static void hfsplus_subfolders_dec(struct inode *dir)
 }
 
 int hfsplus_create_cat(u32 cnid, struct inode *dir,
-               struct qstr *str, struct inode *inode)
+               const struct qstr *str, struct inode *inode)
 {
        struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
@@ -318,7 +318,7 @@ err2:
        return err;
 }
 
-int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
+int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str)
 {
        struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
@@ -415,8 +415,8 @@ out:
 }
 
 int hfsplus_rename_cat(u32 cnid,
-                      struct inode *src_dir, struct qstr *src_name,
-                      struct inode *dst_dir, struct qstr *dst_name)
+                      struct inode *src_dir, const struct qstr *src_name,
+                      struct inode *dst_dir, const struct qstr *dst_name)
 {
        struct super_block *sb = src_dir->i_sb;
        struct hfs_find_data src_fd, dst_fd;
index 047245b..a3f03b2 100644 (file)
@@ -445,17 +445,17 @@ int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1,
 int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1,
                            const hfsplus_btree_key *k2);
 int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
-                          u32 parent, struct qstr *str);
+                          u32 parent, const struct qstr *str);
 void hfsplus_cat_build_key_with_cnid(struct super_block *sb,
                                     hfsplus_btree_key *key, u32 parent);
 void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
 int hfsplus_find_cat(struct super_block *sb, u32 cnid,
                     struct hfs_find_data *fd);
-int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str,
+int hfsplus_create_cat(u32 cnid, struct inode *dir, const struct qstr *str,
                       struct inode *inode);
-int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str);
-int hfsplus_rename_cat(u32 cnid, struct inode *src_dir, struct qstr *src_name,
-                      struct inode *dst_dir, struct qstr *dst_name);
+int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str);
+int hfsplus_rename_cat(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
+                      struct inode *dst_dir, const struct qstr *dst_name);
 
 /* dir.c */
 extern const struct inode_operations hfsplus_dir_inode_operations;
@@ -520,8 +520,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr,
 int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
                    int max_unistr_len, const char *astr, int len);
 int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
-int hfsplus_compare_dentry(const struct dentry *parent,
-                          const struct dentry *dentry, unsigned int len,
+int hfsplus_compare_dentry(const struct dentry *dentry, unsigned int len,
                           const char *str, const struct qstr *name);
 
 /* wrapper.c */
index c13c8a2..e563939 100644 (file)
@@ -385,10 +385,10 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+int hfsplus_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct super_block *sb = parent->d_sb;
+       struct super_block *sb = dentry->d_sb;
        int casefold, decompose, size;
        int dsize1, dsize2, len1, len2;
        const u16 *dstr1, *dstr2;
index 5c57654..90e46cd 100644 (file)
@@ -959,10 +959,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
 
        if (S_ISLNK(root_inode->i_mode)) {
                char *name = follow_link(host_root_path);
-               if (IS_ERR(name))
+               if (IS_ERR(name)) {
                        err = PTR_ERR(name);
-               else
-                       err = read_name(root_inode, name);
+                       goto out_put;
+               }
+               err = read_name(root_inode, name);
                kfree(name);
                if (err)
                        goto out_put;
index 60e6d33..bb87d65 100644 (file)
@@ -34,7 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
        return 0;
 }
 
-static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+static int hpfs_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned al = len;
@@ -50,7 +50,7 @@ static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry
 
        if (hpfs_chk_name(name->name, &bl))
                return 1;
-       if (hpfs_compare_names(parent->d_sb, str, al, name->name, bl, 0))
+       if (hpfs_compare_names(dentry->d_sb, str, al, name->name, bl, 0))
                return 1;
        return 0;
 }
index 9cef4e1..7e3ef3a 100644 (file)
@@ -345,7 +345,7 @@ EXPORT_SYMBOL(inc_nlink);
 void address_space_init_once(struct address_space *mapping)
 {
        memset(mapping, 0, sizeof(*mapping));
-       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
+       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT);
        spin_lock_init(&mapping->tree_lock);
        init_rwsem(&mapping->i_mmap_rwsem);
        INIT_LIST_HEAD(&mapping->private_list);
@@ -1729,7 +1729,6 @@ int dentry_needs_remove_privs(struct dentry *dentry)
                mask |= ATTR_KILL_PRIV;
        return mask;
 }
-EXPORT_SYMBOL(dentry_needs_remove_privs);
 
 static int __remove_privs(struct dentry *dentry, int kill)
 {
@@ -1749,8 +1748,8 @@ static int __remove_privs(struct dentry *dentry, int kill)
  */
 int file_remove_privs(struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
-       struct inode *inode = d_inode(dentry);
+       struct dentry *dentry = file_dentry(file);
+       struct inode *inode = file_inode(file);
        int kill;
        int error = 0;
 
@@ -1758,7 +1757,7 @@ int file_remove_privs(struct file *file)
        if (IS_NOSEC(inode))
                return 0;
 
-       kill = file_needs_remove_privs(file);
+       kill = dentry_needs_remove_privs(dentry);
        if (kill < 0)
                return kill;
        if (kill)
index cef0913..ba07376 100644 (file)
@@ -111,12 +111,14 @@ extern long do_handle_open(int mountdirfd,
                           struct file_handle __user *ufh, int open_flag);
 extern int open_check_o_direct(struct file *f);
 extern int vfs_open(const struct path *, struct file *, const struct cred *);
+extern struct file *filp_clone_open(struct file *);
 
 /*
  * inode.c
  */
 extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc);
 extern void inode_add_lru(struct inode *inode);
+extern int dentry_needs_remove_privs(struct dentry *dentry);
 
 /*
  * fs-writeback.c
index 761fade..ad0c745 100644 (file)
 #define BEQUIET
 
 static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
-static int isofs_dentry_cmpi(const struct dentry *parent,
-               const struct dentry *dentry,
+static int isofs_dentry_cmpi(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 #ifdef CONFIG_JOLIET
 static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
 static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
-static int isofs_dentry_cmpi_ms(const struct dentry *parent,
-               const struct dentry *dentry,
+static int isofs_dentry_cmpi_ms(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
-static int isofs_dentry_cmp_ms(const struct dentry *parent,
-               const struct dentry *dentry,
+static int isofs_dentry_cmp_ms(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 #endif
 
@@ -235,7 +232,7 @@ isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 }
 
 static int
-isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
+isofs_dentry_cmpi(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 0, 1);
@@ -276,14 +273,14 @@ isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
 }
 
 static int
-isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
+isofs_dentry_cmp_ms(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 0);
 }
 
 static int
-isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
+isofs_dentry_cmpi_ms(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 1);
index 7b543e6..aee5927 100644 (file)
@@ -22,7 +22,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
        qstr.len = dlen;
        if (likely(!dentry->d_op))
                return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
-       return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
+       return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
 }
 
 /*
index 04baf0d..814b0c5 100644 (file)
@@ -1572,7 +1572,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
        return 0;
 }
 
-static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
+static int jfs_ci_compare(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i, result = 1;
index bcd754d..9568064 100644 (file)
@@ -156,7 +156,7 @@ static pgoff_t hash_index(u32 hash, int round)
 
 static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry)
 {
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        struct page *page;
        struct logfs_disk_dentry *dd;
        u32 hash = logfs_hash_32(name->name, name->len, 0);
@@ -323,7 +323,7 @@ static int logfs_readdir(struct file *file, struct dir_context *ctx)
        return 0;
 }
 
-static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
+static void logfs_set_name(struct logfs_disk_dentry *dd, const struct qstr *name)
 {
        dd->namelen = cpu_to_be16(name->len);
        memcpy(dd->name, name->name, name->len);
index 2ca1f39..d2413af 100644 (file)
@@ -50,7 +50,7 @@ static void mpage_end_io(struct bio *bio)
 
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
-               page_endio(page, bio_data_dir(bio), bio->bi_error);
+               page_endio(page, op_is_write(bio_op(bio)), bio->bi_error);
        }
 
        bio_put(bio);
index c386a32..adb0414 100644 (file)
@@ -410,7 +410,7 @@ int __inode_permission(struct inode *inode, int mask)
                 * Nobody gets write access to an immutable file.
                 */
                if (IS_IMMUTABLE(inode))
-                       return -EACCES;
+                       return -EPERM;
 
                /*
                 * Updating mtime will likely cause i_uid and i_gid to be
index 9add7ab..17de5c1 100644 (file)
@@ -74,7 +74,7 @@ const struct inode_operations ncp_dir_inode_operations =
  */
 static int ncp_lookup_validate(struct dentry *, unsigned int);
 static int ncp_hash_dentry(const struct dentry *, struct qstr *);
-static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
+static int ncp_compare_dentry(const struct dentry *,
                unsigned int, const char *, const struct qstr *);
 static int ncp_delete_dentry(const struct dentry *);
 static void ncp_d_prune(struct dentry *dentry);
@@ -154,7 +154,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
  * the callers will handle races.
  */
 static int
-ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
+ncp_compare_dentry(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct inode *pinode;
@@ -162,7 +162,7 @@ ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
        if (len != name->len)
                return 1;
 
-       pinode = d_inode_rcu(parent);
+       pinode = d_inode_rcu(dentry->d_parent);
        if (!pinode)
                return 1;
 
index cb28cce..698be93 100644 (file)
@@ -144,7 +144,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 }
 
 static int
-nfs3_proc_lookup(struct inode *dir, struct qstr *name,
+nfs3_proc_lookup(struct inode *dir, const struct qstr *name,
                 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
                 struct nfs4_label *label)
 {
@@ -404,7 +404,7 @@ out:
 }
 
 static int
-nfs3_proc_remove(struct inode *dir, struct qstr *name)
+nfs3_proc_remove(struct inode *dir, const struct qstr *name)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
@@ -480,7 +480,7 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 }
 
 static int
-nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+nfs3_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
 {
        struct nfs3_linkargs    arg = {
                .fromfh         = NFS_FH(inode),
@@ -582,7 +582,7 @@ out:
 }
 
 static int
-nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
+nfs3_proc_rmdir(struct inode *dir, const struct qstr *name)
 {
        struct nfs_fattr        *dir_attr;
        struct nfs3_diropargs   arg = {
index 4be567a..324bfdc 100644 (file)
@@ -225,7 +225,8 @@ int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
 extern struct file_system_type nfs4_fs_type;
 
 /* nfs4namespace.c */
-struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, struct qstr *);
+struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
+                                        const struct qstr *);
 struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
                               struct nfs_fh *, struct nfs_fattr *);
 int nfs4_replace_transport(struct nfs_server *server,
@@ -252,7 +253,7 @@ extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struc
 extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *,
                struct page *page, struct rpc_cred *);
 extern int nfs4_proc_fsid_present(struct inode *, struct rpc_cred *);
-extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
+extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, const struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *);
 extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
 extern const struct xattr_handler *nfs4_xattr_handlers[];
index f592672..d211049 100644 (file)
@@ -208,7 +208,7 @@ static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt,
  */
 struct rpc_clnt *
 nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
-                                       struct qstr *name)
+                                       const struct qstr *name)
 {
        struct page *page;
        struct nfs4_secinfo_flavors *flavors;
@@ -397,7 +397,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
        rpc_authflavor_t flavor = server->client->cl_auth->au_flavor;
        struct dentry *parent = dget_parent(dentry);
        struct inode *dir = d_inode(parent);
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        struct rpc_clnt *client;
        struct vfsmount *mnt;
 
index da5c9e5..a036e93 100644 (file)
@@ -3538,7 +3538,7 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
 }
 
 static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
-                                  struct qstr *name, struct nfs_fh *fhandle,
+                                  const struct qstr *name, struct nfs_fh *fhandle,
                                   struct nfs_fattr *fattr, struct nfs4_label *label)
 {
        struct nfs4_exception exception = { };
@@ -3580,7 +3580,7 @@ out:
        return err;
 }
 
-static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+static int nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr,
                            struct nfs4_label *label)
 {
@@ -3596,7 +3596,7 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
 }
 
 struct rpc_clnt *
-nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
+nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        struct rpc_clnt *client = NFS_CLIENT(dir);
@@ -3755,7 +3755,7 @@ out:
        return status;
 }
 
-static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
+static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
 {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_removeargs args = {
@@ -3778,7 +3778,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
        return status;
 }
 
-static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
+static int nfs4_proc_remove(struct inode *dir, const struct qstr *name)
 {
        struct nfs4_exception exception = { };
        int err;
@@ -3861,7 +3861,7 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
        return 1;
 }
 
-static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_link_arg arg = {
@@ -3908,7 +3908,7 @@ out:
        return status;
 }
 
-static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
 {
        struct nfs4_exception exception = { };
        int err;
@@ -3930,7 +3930,7 @@ struct nfs4_createdata {
 };
 
 static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
-               struct qstr *name, struct iattr *sattr, u32 ftype)
+               const struct qstr *name, struct iattr *sattr, u32 ftype)
 {
        struct nfs4_createdata *data;
 
index b417bbc..b7bca83 100644 (file)
@@ -145,7 +145,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 }
 
 static int
-nfs_proc_lookup(struct inode *dir, struct qstr *name,
+nfs_proc_lookup(struct inode *dir, const struct qstr *name,
                struct nfs_fh *fhandle, struct nfs_fattr *fattr,
                struct nfs4_label *label)
 {
@@ -299,7 +299,7 @@ out:
 }
   
 static int
-nfs_proc_remove(struct inode *dir, struct qstr *name)
+nfs_proc_remove(struct inode *dir, const struct qstr *name)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
@@ -357,7 +357,7 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
 }
 
 static int
-nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+nfs_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
 {
        struct nfs_linkargs     arg = {
                .fromfh         = NFS_FH(inode),
@@ -456,7 +456,7 @@ out:
 }
 
 static int
-nfs_proc_rmdir(struct inode *dir, struct qstr *name)
+nfs_proc_rmdir(struct inode *dir, const struct qstr *name)
 {
        struct nfs_diropargs    arg = {
                .fh             = NFS_FH(dir),
index 1868246..191aa57 100644 (file)
@@ -162,7 +162,7 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
  * @dentry: dentry to unlink
  */
 static int
-nfs_async_unlink(struct dentry *dentry, struct qstr *name)
+nfs_async_unlink(struct dentry *dentry, const struct qstr *name)
 {
        struct nfs_unlinkdata *data;
        int status = -ENOMEM;
index c9f583d..47febcf 100644 (file)
@@ -90,6 +90,7 @@ config NFSD_BLOCKLAYOUT
        bool "NFSv4.1 server support for pNFS block layouts"
        depends on NFSD_V4 && BLOCK
        select NFSD_PNFS
+       select EXPORTFS_BLOCK_OPS
        help
          This option enables support for the exporting pNFS block layouts
          in the kernel's NFS server. The pNFS block layout enables NFS
@@ -102,6 +103,7 @@ config NFSD_SCSILAYOUT
        bool "NFSv4.1 server support for pNFS SCSI layouts"
        depends on NFSD_V4 && BLOCK
        select NFSD_PNFS
+       select EXPORTFS_BLOCK_OPS
        help
          This option enables support for the exporting pNFS SCSI layouts
          in the kernel's NFS server. The pNFS SCSI layout enables NFS
@@ -111,6 +113,23 @@ config NFSD_SCSILAYOUT
 
          If unsure, say N.
 
+config NFSD_FLEXFILELAYOUT
+       bool "NFSv4.1 server support for pNFS Flex File layouts"
+       depends on NFSD_V4
+       select NFSD_PNFS
+       help
+         This option enables support for the exporting pNFS Flex File
+         layouts in the kernel's NFS server. The pNFS Flex File  layout
+         enables NFS clients to directly perform I/O to NFSv3 devices
+         accesible to both the server and the clients.  See
+         draft-ietf-nfsv4-flex-files for more details.
+
+         Warning, this server implements the bare minimum functionality
+         to be a flex file server - it is for testing the client,
+         not for use in production.
+
+         If unsure, say N.
+
 config NFSD_V4_SECURITY_LABEL
        bool "Provide Security Label support for NFSv4 server"
        depends on NFSD_V4 && SECURITY
index 3ae5f3c..5f5d3a7 100644 (file)
@@ -20,3 +20,4 @@ nfsd-$(CONFIG_NFSD_V4)        += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
 nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
 nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
 nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
+nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o
index ad2c05e..5a17084 100644 (file)
@@ -163,6 +163,7 @@ nfsd4_block_get_device_info_simple(struct super_block *sb,
 
 static __be32
 nfsd4_block_proc_getdeviceinfo(struct super_block *sb,
+               struct svc_rqst *rqstp,
                struct nfs4_client *clp,
                struct nfsd4_getdeviceinfo *gdp)
 {
@@ -355,6 +356,7 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
 
 static __be32
 nfsd4_scsi_proc_getdeviceinfo(struct super_block *sb,
+               struct svc_rqst *rqstp,
                struct nfs4_client *clp,
                struct nfsd4_getdeviceinfo *gdp)
 {
index 4ebaaf4..ac6f545 100644 (file)
@@ -44,7 +44,7 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
 
        switch (b->type) {
        case PNFS_BLOCK_VOLUME_SIMPLE:
-               len = 4 + 4 + 8 + 4 + b->simple.sig_len;
+               len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2);
                p = xdr_reserve_space(xdr, len);
                if (!p)
                        return -ETOOSMALL;
@@ -55,7 +55,7 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
                p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
                break;
        case PNFS_BLOCK_VOLUME_SCSI:
-               len = 4 + 4 + 4 + 4 + b->scsi.designator_len + 8;
+               len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8;
                p = xdr_reserve_space(xdr, len);
                if (!p)
                        return -ETOOSMALL;
index b4d84b5..43e109c 100644 (file)
@@ -706,7 +706,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
        new->ex_fslocs.locations = NULL;
        new->ex_fslocs.locations_count = 0;
        new->ex_fslocs.migrated = 0;
-       new->ex_layout_type = 0;
+       new->ex_layout_types = 0;
        new->ex_uuid = NULL;
        new->cd = item->cd;
 }
@@ -731,7 +731,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
        item->ex_fslocs.locations_count = 0;
        new->ex_fslocs.migrated = item->ex_fslocs.migrated;
        item->ex_fslocs.migrated = 0;
-       new->ex_layout_type = item->ex_layout_type;
+       new->ex_layout_types = item->ex_layout_types;
        new->ex_nflavors = item->ex_nflavors;
        for (i = 0; i < MAX_SECINFO_LIST; i++) {
                new->ex_flavors[i] = item->ex_flavors[i];
@@ -954,6 +954,16 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
                    rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
                        return 0;
        }
+
+       /* If the compound op contains a spo_must_allowed op,
+        * it will be sent with integrity/protection which
+        * will have to be expressly allowed on mounts that
+        * don't support it
+        */
+
+       if (nfsd4_spo_must_allow(rqstp))
+               return 0;
+
        return nfserr_wrongsec;
 }
 
index 2e31507..730f15e 100644 (file)
@@ -57,7 +57,7 @@ struct svc_export {
        struct nfsd4_fs_locations ex_fslocs;
        uint32_t                ex_nflavors;
        struct exp_flavor_info  ex_flavors[MAX_SECINFO_LIST];
-       enum pnfs_layouttype    ex_layout_type;
+       u32                     ex_layout_types;
        struct nfsd4_deviceid_map *ex_devid_map;
        struct cache_detail     *cd;
 };
diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c
new file mode 100644 (file)
index 0000000..df880e9
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
+ *
+ * The following implements a super-simple flex-file server
+ * where the NFSv4.1 mds is also the ds. And the storage is
+ * the same. I.e., writing to the mds via a NFSv4.1 WRITE
+ * goes to the same location as the NFSv3 WRITE.
+ */
+#include <linux/slab.h>
+
+#include <linux/nfsd/debug.h>
+
+#include <linux/sunrpc/addr.h>
+
+#include "flexfilelayoutxdr.h"
+#include "pnfs.h"
+
+#define NFSDDBG_FACILITY       NFSDDBG_PNFS
+
+static __be32
+nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
+               struct nfsd4_layoutget *args)
+{
+       struct nfsd4_layout_seg *seg = &args->lg_seg;
+       u32 device_generation = 0;
+       int error;
+       uid_t u;
+
+       struct pnfs_ff_layout *fl;
+
+       /*
+        * The super simple flex file server has 1 mirror, 1 data server,
+        * and 1 file handle. So instead of 4 allocs, do 1 for now.
+        * Zero it out for the stateid - don't want junk in there!
+        */
+       error = -ENOMEM;
+       fl = kzalloc(sizeof(*fl), GFP_KERNEL);
+       if (!fl)
+               goto out_error;
+       args->lg_content = fl;
+
+       /*
+        * Avoid layout commit, try to force the I/O to the DS,
+        * and for fun, cause all IOMODE_RW layout segments to
+        * effectively be WRITE only.
+        */
+       fl->flags = FF_FLAGS_NO_LAYOUTCOMMIT | FF_FLAGS_NO_IO_THRU_MDS |
+                   FF_FLAGS_NO_READ_IO;
+
+       /* Do not allow a IOMODE_READ segment to have write pemissions */
+       if (seg->iomode == IOMODE_READ) {
+               u = from_kuid(&init_user_ns, inode->i_uid) + 1;
+               fl->uid = make_kuid(&init_user_ns, u);
+       } else
+               fl->uid = inode->i_uid;
+       fl->gid = inode->i_gid;
+
+       error = nfsd4_set_deviceid(&fl->deviceid, fhp, device_generation);
+       if (error)
+               goto out_error;
+
+       fl->fh.size = fhp->fh_handle.fh_size;
+       memcpy(fl->fh.data, &fhp->fh_handle.fh_base, fl->fh.size);
+
+       /* Give whole file layout segments */
+       seg->offset = 0;
+       seg->length = NFS4_MAX_UINT64;
+
+       dprintk("GET: 0x%llx:0x%llx %d\n", seg->offset, seg->length,
+               seg->iomode);
+       return 0;
+
+out_error:
+       seg->length = 0;
+       return nfserrno(error);
+}
+
+static __be32
+nfsd4_ff_proc_getdeviceinfo(struct super_block *sb, struct svc_rqst *rqstp,
+               struct nfs4_client *clp, struct nfsd4_getdeviceinfo *gdp)
+{
+       struct pnfs_ff_device_addr *da;
+
+       u16 port;
+       char addr[INET6_ADDRSTRLEN];
+
+       da = kzalloc(sizeof(struct pnfs_ff_device_addr), GFP_KERNEL);
+       if (!da)
+               return nfserrno(-ENOMEM);
+
+       gdp->gd_device = da;
+
+       da->version = 3;
+       da->minor_version = 0;
+
+       da->rsize = svc_max_payload(rqstp);
+       da->wsize = da->rsize;
+
+       rpc_ntop((struct sockaddr *)&rqstp->rq_daddr,
+                addr, INET6_ADDRSTRLEN);
+       if (rqstp->rq_daddr.ss_family == AF_INET) {
+               struct sockaddr_in *sin;
+
+               sin = (struct sockaddr_in *)&rqstp->rq_daddr;
+               port = ntohs(sin->sin_port);
+               snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp");
+               da->netaddr.netid_len = 3;
+       } else {
+               struct sockaddr_in6 *sin6;
+
+               sin6 = (struct sockaddr_in6 *)&rqstp->rq_daddr;
+               port = ntohs(sin6->sin6_port);
+               snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp6");
+               da->netaddr.netid_len = 4;
+       }
+
+       da->netaddr.addr_len =
+               snprintf(da->netaddr.addr, FF_ADDR_LEN + 1,
+                        "%s.%hhu.%hhu", addr, port >> 8, port & 0xff);
+
+       da->tightly_coupled = false;
+
+       return 0;
+}
+
+const struct nfsd4_layout_ops ff_layout_ops = {
+       .notify_types           =
+                       NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE,
+       .proc_getdeviceinfo     = nfsd4_ff_proc_getdeviceinfo,
+       .encode_getdeviceinfo   = nfsd4_ff_encode_getdeviceinfo,
+       .proc_layoutget         = nfsd4_ff_proc_layoutget,
+       .encode_layoutget       = nfsd4_ff_encode_layoutget,
+};
diff --git a/fs/nfsd/flexfilelayoutxdr.c b/fs/nfsd/flexfilelayoutxdr.c
new file mode 100644 (file)
index 0000000..5e3fd7f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
+ */
+#include <linux/sunrpc/svc.h>
+#include <linux/nfs4.h>
+
+#include "nfsd.h"
+#include "flexfilelayoutxdr.h"
+
+#define NFSDDBG_FACILITY       NFSDDBG_PNFS
+
+struct ff_idmap {
+       char buf[11];
+       int len;
+};
+
+__be32
+nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
+               struct nfsd4_layoutget *lgp)
+{
+       struct pnfs_ff_layout *fl = lgp->lg_content;
+       int len, mirror_len, ds_len, fh_len;
+       __be32 *p;
+
+       /*
+        * Unlike nfsd4_encode_user, we know these will
+        * always be stringified.
+        */
+       struct ff_idmap uid;
+       struct ff_idmap gid;
+
+       fh_len = 4 + fl->fh.size;
+
+       uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
+       gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
+
+       /* 8 + len for recording the length, name, and padding */
+       ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len +
+                8 + uid.len + 8 + gid.len;
+
+       mirror_len = 4 + ds_len;
+
+       /* The layout segment */
+       len = 20 + mirror_len;
+
+       p = xdr_reserve_space(xdr, sizeof(__be32) + len);
+       if (!p)
+               return nfserr_toosmall;
+
+       *p++ = cpu_to_be32(len);
+       p = xdr_encode_hyper(p, 0);             /* stripe unit of 1 */
+
+       *p++ = cpu_to_be32(1);                  /* single mirror */
+       *p++ = cpu_to_be32(1);                  /* single data server */
+
+       p = xdr_encode_opaque_fixed(p, &fl->deviceid,
+                       sizeof(struct nfsd4_deviceid));
+
+       *p++ = cpu_to_be32(1);                  /* efficiency */
+
+       *p++ = cpu_to_be32(fl->stateid.si_generation);
+       p = xdr_encode_opaque_fixed(p, &fl->stateid.si_opaque,
+                                   sizeof(stateid_opaque_t));
+
+       *p++ = cpu_to_be32(1);                  /* single file handle */
+       p = xdr_encode_opaque(p, fl->fh.data, fl->fh.size);
+
+       p = xdr_encode_opaque(p, uid.buf, uid.len);
+       p = xdr_encode_opaque(p, gid.buf, gid.len);
+
+       *p++ = cpu_to_be32(fl->flags);
+       *p++ = cpu_to_be32(0);                  /* No stats collect hint */
+
+       return 0;
+}
+
+__be32
+nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
+               struct nfsd4_getdeviceinfo *gdp)
+{
+       struct pnfs_ff_device_addr *da = gdp->gd_device;
+       int len;
+       int ver_len;
+       int addr_len;
+       __be32 *p;
+
+       /* len + padding for two strings */
+       addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len;
+       ver_len = 20;
+
+       len = 4 + ver_len + 4 + addr_len;
+
+       p = xdr_reserve_space(xdr, len + sizeof(__be32));
+       if (!p)
+               return nfserr_resource;
+
+       /*
+        * Fill in the overall length and number of volumes at the beginning
+        * of the layout.
+        */
+       *p++ = cpu_to_be32(len);
+       *p++ = cpu_to_be32(1);                  /* 1 netaddr */
+       p = xdr_encode_opaque(p, da->netaddr.netid, da->netaddr.netid_len);
+       p = xdr_encode_opaque(p, da->netaddr.addr, da->netaddr.addr_len);
+
+       *p++ = cpu_to_be32(1);                  /* 1 versions */
+
+       *p++ = cpu_to_be32(da->version);
+       *p++ = cpu_to_be32(da->minor_version);
+       *p++ = cpu_to_be32(da->rsize);
+       *p++ = cpu_to_be32(da->wsize);
+       *p++ = cpu_to_be32(da->tightly_coupled);
+
+       return 0;
+}
diff --git a/fs/nfsd/flexfilelayoutxdr.h b/fs/nfsd/flexfilelayoutxdr.h
new file mode 100644 (file)
index 0000000..467defd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
+ */
+#ifndef _NFSD_FLEXFILELAYOUTXDR_H
+#define _NFSD_FLEXFILELAYOUTXDR_H 1
+
+#include <linux/inet.h>
+#include "xdr4.h"
+
+#define FF_FLAGS_NO_LAYOUTCOMMIT 1
+#define FF_FLAGS_NO_IO_THRU_MDS  2
+#define FF_FLAGS_NO_READ_IO      4
+
+struct xdr_stream;
+
+#define FF_NETID_LEN           (4)
+#define FF_ADDR_LEN            (INET6_ADDRSTRLEN + 8)
+struct pnfs_ff_netaddr {
+       char                            netid[FF_NETID_LEN + 1];
+       char                            addr[FF_ADDR_LEN + 1];
+       u32                             netid_len;
+       u32                             addr_len;
+};
+
+struct pnfs_ff_device_addr {
+       struct pnfs_ff_netaddr          netaddr;
+       u32                             version;
+       u32                             minor_version;
+       u32                             rsize;
+       u32                             wsize;
+       bool                            tightly_coupled;
+};
+
+struct pnfs_ff_layout {
+       u32                             flags;
+       u32                             stats_collect_hint;
+       kuid_t                          uid;
+       kgid_t                          gid;
+       struct nfsd4_deviceid           deviceid;
+       stateid_t                       stateid;
+       struct nfs_fh                   fh;
+};
+
+__be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
+               struct nfsd4_getdeviceinfo *gdp);
+__be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
+               struct nfsd4_layoutget *lgp);
+
+#endif /* _NFSD_FLEXFILELAYOUTXDR_H */
index 953c075..2be9602 100644 (file)
@@ -27,6 +27,9 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
 static const struct lock_manager_operations nfsd4_layouts_lm_ops;
 
 const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] =  {
+#ifdef CONFIG_NFSD_FLEXFILELAYOUT
+       [LAYOUT_FLEX_FILES]     = &ff_layout_ops,
+#endif
 #ifdef CONFIG_NFSD_BLOCKLAYOUT
        [LAYOUT_BLOCK_VOLUME]   = &bl_layout_ops,
 #endif
@@ -122,28 +125,35 @@ nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp,
 
 void nfsd4_setup_layout_type(struct svc_export *exp)
 {
+#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
        struct super_block *sb = exp->ex_path.mnt->mnt_sb;
+#endif
 
        if (!(exp->ex_flags & NFSEXP_PNFS))
                return;
 
        /*
-        * Check if the file system supports exporting a block-like layout.
+        * If flex file is configured, use it by default. Otherwise
+        * check if the file system supports exporting a block-like layout.
         * If the block device supports reservations prefer the SCSI layout,
         * otherwise advertise the block layout.
         */
+#ifdef CONFIG_NFSD_FLEXFILELAYOUT
+       exp->ex_layout_types |= 1 << LAYOUT_FLEX_FILES;
+#endif
 #ifdef CONFIG_NFSD_BLOCKLAYOUT
+       /* overwrite flex file layout selection if needed */
        if (sb->s_export_op->get_uuid &&
            sb->s_export_op->map_blocks &&
            sb->s_export_op->commit_blocks)
-               exp->ex_layout_type = LAYOUT_BLOCK_VOLUME;
+               exp->ex_layout_types |= 1 << LAYOUT_BLOCK_VOLUME;
 #endif
 #ifdef CONFIG_NFSD_SCSILAYOUT
        /* overwrite block layout selection if needed */
        if (sb->s_export_op->map_blocks &&
            sb->s_export_op->commit_blocks &&
            sb->s_bdev && sb->s_bdev->bd_disk->fops->pr_ops)
-               exp->ex_layout_type = LAYOUT_SCSI;
+               exp->ex_layout_types |= 1 << LAYOUT_SCSI;
 #endif
 }
 
index de1ff1d..1fb2227 100644 (file)
@@ -605,8 +605,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        fh_init(&resfh, NFS4_FHSIZE);
 
-       status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
-                          NFSD_MAY_CREATE);
+       status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP);
        if (status)
                return status;
 
@@ -1219,12 +1218,12 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 static const struct nfsd4_layout_ops *
 nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
 {
-       if (!exp->ex_layout_type) {
+       if (!exp->ex_layout_types) {
                dprintk("%s: export does not support pNFS\n", __func__);
                return NULL;
        }
 
-       if (exp->ex_layout_type != layout_type) {
+       if (!(exp->ex_layout_types & (1 << layout_type))) {
                dprintk("%s: layout type %d not supported\n",
                        __func__, layout_type);
                return NULL;
@@ -1270,7 +1269,7 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
        nfserr = nfs_ok;
        if (gdp->gd_maxcount != 0) {
                nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb,
-                                       cstate->session->se_client, gdp);
+                               rqstp, cstate->session->se_client, gdp);
        }
 
        gdp->gd_notify_types &= ops->notify_types;
@@ -2335,6 +2334,45 @@ static struct nfsd4_operation nfsd4_ops[] = {
        },
 };
 
+/**
+ * nfsd4_spo_must_allow - Determine if the compound op contains an
+ * operation that is allowed to be sent with machine credentials
+ *
+ * @rqstp: a pointer to the struct svc_rqst
+ *
+ * Checks to see if the compound contains a spo_must_allow op
+ * and confirms that it was sent with the proper machine creds.
+ */
+
+bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
+{
+       struct nfsd4_compoundres *resp = rqstp->rq_resp;
+       struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+       struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
+       struct nfsd4_compound_state *cstate = &resp->cstate;
+       struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow;
+       u32 opiter;
+
+       if (!cstate->minorversion)
+               return false;
+
+       if (cstate->spo_must_allowed == true)
+               return true;
+
+       opiter = resp->opcnt;
+       while (opiter < argp->opcnt) {
+               this = &argp->ops[opiter++];
+               if (test_bit(this->opnum, allow->u.longs) &&
+                       cstate->clp->cl_mach_cred &&
+                       nfsd4_mach_creds_match(cstate->clp, rqstp)) {
+                       cstate->spo_must_allowed = true;
+                       return true;
+               }
+       }
+       cstate->spo_must_allowed = false;
+       return false;
+}
+
 int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
        struct nfsd4_operation *opdesc;
index 70d0b9b..8410ca2 100644 (file)
@@ -1200,27 +1200,6 @@ free_ol_stateid_reaplist(struct list_head *reaplist)
        }
 }
 
-static void release_lockowner(struct nfs4_lockowner *lo)
-{
-       struct nfs4_client *clp = lo->lo_owner.so_client;
-       struct nfs4_ol_stateid *stp;
-       struct list_head reaplist;
-
-       INIT_LIST_HEAD(&reaplist);
-
-       spin_lock(&clp->cl_lock);
-       unhash_lockowner_locked(lo);
-       while (!list_empty(&lo->lo_owner.so_stateids)) {
-               stp = list_first_entry(&lo->lo_owner.so_stateids,
-                               struct nfs4_ol_stateid, st_perstateowner);
-               WARN_ON(!unhash_lock_stateid(stp));
-               put_ol_stateid_locked(stp, &reaplist);
-       }
-       spin_unlock(&clp->cl_lock);
-       free_ol_stateid_reaplist(&reaplist);
-       nfs4_put_stateowner(&lo->lo_owner);
-}
-
 static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
                                       struct list_head *reaplist)
 {
@@ -1972,7 +1951,7 @@ static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
               service == RPC_GSS_SVC_PRIVACY;
 }
 
-static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
+bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
 {
        struct svc_cred *cr = &rqstp->rq_cred;
 
@@ -2388,6 +2367,22 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 
        switch (exid->spa_how) {
        case SP4_MACH_CRED:
+               exid->spo_must_enforce[0] = 0;
+               exid->spo_must_enforce[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));
+
+               exid->spo_must_allow[0] &= (1 << (OP_CLOSE) |
+                                       1 << (OP_OPEN_DOWNGRADE) |
+                                       1 << (OP_LOCKU) |
+                                       1 << (OP_DELEGRETURN));
+
+               exid->spo_must_allow[1] &= (
+                                       1 << (OP_TEST_STATEID - 32) |
+                                       1 << (OP_FREE_STATEID - 32));
                if (!svc_rqst_integrity_protected(rqstp)) {
                        status = nfserr_inval;
                        goto out_nolock;
@@ -2424,7 +2419,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
                                status = nfserr_inval;
                                goto out;
                        }
-                       if (!mach_creds_match(conf, rqstp)) {
+                       if (!nfsd4_mach_creds_match(conf, rqstp)) {
                                status = nfserr_wrong_cred;
                                goto out;
                        }
@@ -2473,6 +2468,8 @@ out_new:
                        goto out;
        }
        new->cl_minorversion = cstate->minorversion;
+       new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
+       new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1];
 
        gen_clid(new, nn);
        add_to_unconfirmed(new);
@@ -2676,7 +2673,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 
        if (conf) {
                status = nfserr_wrong_cred;
-               if (!mach_creds_match(conf, rqstp))
+               if (!nfsd4_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);
@@ -2692,7 +2689,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                        goto out_free_conn;
                }
                status = nfserr_wrong_cred;
-               if (!mach_creds_match(unconf, rqstp))
+               if (!nfsd4_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);
@@ -2801,7 +2798,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
        if (!session)
                goto out_no_session;
        status = nfserr_wrong_cred;
-       if (!mach_creds_match(session->se_client, rqstp))
+       if (!nfsd4_mach_creds_match(session->se_client, rqstp))
                goto out;
        status = nfsd4_map_bcts_dir(&bcts->dir);
        if (status)
@@ -2848,7 +2845,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
        if (!ses)
                goto out_client_lock;
        status = nfserr_wrong_cred;
-       if (!mach_creds_match(ses->se_client, r))
+       if (!nfsd4_mach_creds_match(ses->se_client, r))
                goto out_put_session;
        status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
        if (status)
@@ -3087,7 +3084,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
                status = nfserr_stale_clientid;
                goto out;
        }
-       if (!mach_creds_match(clp, rqstp)) {
+       if (!nfsd4_mach_creds_match(clp, rqstp)) {
                clp = NULL;
                status = nfserr_wrong_cred;
                goto out;
@@ -3112,7 +3109,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
                 * We don't take advantage of the rca_one_fs case.
                 * That's OK, it's optional, we can safely ignore it.
                 */
-                return nfs_ok;
+               return nfs_ok;
        }
 
        status = nfserr_complete_already;
@@ -5945,6 +5942,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        __be32 status;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        struct nfs4_client *clp;
+       LIST_HEAD (reaplist);
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
                clid->cl_boot, clid->cl_id);
@@ -5975,9 +5973,23 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
                nfs4_get_stateowner(sop);
                break;
        }
+       if (!lo) {
+               spin_unlock(&clp->cl_lock);
+               return status;
+       }
+
+       unhash_lockowner_locked(lo);
+       while (!list_empty(&lo->lo_owner.so_stateids)) {
+               stp = list_first_entry(&lo->lo_owner.so_stateids,
+                                      struct nfs4_ol_stateid,
+                                      st_perstateowner);
+               WARN_ON(!unhash_lock_stateid(stp));
+               put_ol_stateid_locked(stp, &reaplist);
+       }
        spin_unlock(&clp->cl_lock);
-       if (lo)
-               release_lockowner(lo);
+       free_ol_stateid_reaplist(&reaplist);
+       nfs4_put_stateowner(&lo->lo_owner);
+
        return status;
 }
 
index 9df898b..0aa0236 100644 (file)
@@ -1299,16 +1299,14 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
                break;
        case SP4_MACH_CRED:
                /* spo_must_enforce */
-               READ_BUF(4);
-               dummy = be32_to_cpup(p++);
-               READ_BUF(dummy * 4);
-               p += dummy;
-
+               status = nfsd4_decode_bitmap(argp,
+                                       exid->spo_must_enforce);
+               if (status)
+                       goto out;
                /* spo_must_allow */
-               READ_BUF(4);
-               dummy = be32_to_cpup(p++);
-               READ_BUF(dummy * 4);
-               p += dummy;
+               status = nfsd4_decode_bitmap(argp, exid->spo_must_allow);
+               if (status)
+                       goto out;
                break;
        case SP4_SSV:
                /* ssp_ops */
@@ -2164,22 +2162,20 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 }
 
 static inline __be32
-nfsd4_encode_layout_type(struct xdr_stream *xdr, enum pnfs_layouttype layout_type)
+nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types)
 {
-       __be32 *p;
+       __be32          *p;
+       unsigned long   i = hweight_long(layout_types);
 
-       if (layout_type) {
-               p = xdr_reserve_space(xdr, 8);
-               if (!p)
-                       return nfserr_resource;
-               *p++ = cpu_to_be32(1);
-               *p++ = cpu_to_be32(layout_type);
-       } else {
-               p = xdr_reserve_space(xdr, 4);
-               if (!p)
-                       return nfserr_resource;
-               *p++ = cpu_to_be32(0);
-       }
+       p = xdr_reserve_space(xdr, 4 + 4 * i);
+       if (!p)
+               return nfserr_resource;
+
+       *p++ = cpu_to_be32(i);
+
+       for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i)
+               if (layout_types & (1 << i))
+                       *p++ = cpu_to_be32(i);
 
        return 0;
 }
@@ -2754,13 +2750,13 @@ out_acl:
        }
 #ifdef CONFIG_NFSD_PNFS
        if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
-               status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type);
+               status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
                if (status)
                        goto out;
        }
 
        if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
-               status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type);
+               status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
                if (status)
                        goto out;
        }
@@ -3867,14 +3863,6 @@ 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)
@@ -3885,6 +3873,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
        char *server_scope;
        int major_id_sz;
        int server_scope_sz;
+       int status = 0;
        uint64_t minor_id = 0;
 
        if (nfserr)
@@ -3913,18 +3902,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
        case SP4_NONE:
                break;
        case SP4_MACH_CRED:
-               /* spo_must_enforce, spo_must_allow */
-               p = xdr_reserve_space(xdr, 16);
-               if (!p)
-                       return nfserr_resource;
-
                /* spo_must_enforce bitmap: */
-               *p++ = cpu_to_be32(2);
-               *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[0]);
-               *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[1]);
-               /* empty spo_must_allow bitmap: */
-               *p++ = cpu_to_be32(0);
-
+               status = nfsd4_encode_bitmap(xdr,
+                                       exid->spo_must_enforce[0],
+                                       exid->spo_must_enforce[1],
+                                       exid->spo_must_enforce[2]);
+               if (status)
+                       goto out;
+               /* spo_must_allow bitmap: */
+               status = nfsd4_encode_bitmap(xdr,
+                                       exid->spo_must_allow[0],
+                                       exid->spo_must_allow[1],
+                                       exid->spo_must_allow[2]);
+               if (status)
+                       goto out;
                break;
        default:
                WARN_ON_ONCE(1);
@@ -3951,6 +3942,8 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
        /* Implementation id */
        *p++ = cpu_to_be32(0);  /* zero length nfs_impl_id4 array */
        return 0;
+out:
+       return status;
 }
 
 static __be32
index cf98052..9446849 100644 (file)
@@ -124,6 +124,7 @@ void nfs4_state_shutdown_net(struct net *net);
 void nfs4_reset_lease(time_t leasetime);
 int nfs4_reset_recoverydir(char *recdir);
 char * nfs4_recoverydir(void);
+bool nfsd4_spo_must_allow(struct svc_rqst *rqstp);
 #else
 static inline int nfsd4_init_slabs(void) { return 0; }
 static inline void nfsd4_free_slabs(void) { }
@@ -134,6 +135,10 @@ static inline void nfs4_state_shutdown_net(struct net *net) { }
 static inline void nfs4_reset_lease(time_t leasetime) { }
 static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
 static inline char * nfs4_recoverydir(void) {return NULL; }
+static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
+{
+       return false;
+}
 #endif
 
 /*
index a891944..cfe7500 100644 (file)
@@ -59,14 +59,20 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
  * the write call).
  */
 static inline __be32
-nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, umode_t requested)
+nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
+               umode_t requested)
 {
-       mode &= S_IFMT;
+       umode_t mode = d_inode(dentry)->i_mode & S_IFMT;
 
        if (requested == 0) /* the caller doesn't care */
                return nfs_ok;
-       if (mode == requested)
+       if (mode == requested) {
+               if (mode == S_IFDIR && !d_can_lookup(dentry)) {
+                       WARN_ON_ONCE(1);
+                       return nfserr_notdir;
+               }
                return nfs_ok;
+       }
        /*
         * v4 has an error more specific than err_notdir which we should
         * return in preference to err_notdir:
@@ -298,7 +304,7 @@ out:
  * that it expects something not of the given type.
  *
  * @access is formed from the NFSD_MAY_* constants defined in
- * include/linux/nfsd/nfsd.h.
+ * fs/nfsd/vfs.h.
  */
 __be32
 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
@@ -340,7 +346,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
        if (error)
                goto out;
 
-       error = nfsd_mode_check(rqstp, d_inode(dentry)->i_mode, type);
+       error = nfsd_mode_check(rqstp, dentry, type);
        if (error)
                goto out;
 
@@ -533,7 +539,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
         * the reference filehandle (if it is in the same export)
         * or the export options.
         */
-        set_version_and_fsid_type(fhp, exp, ref_fh);
+       set_version_and_fsid_type(fhp, exp, ref_fh);
 
        if (ref_fh == fhp)
                fh_put(ref_fh);
index 4cd78ef..e921476 100644 (file)
@@ -251,9 +251,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 
        /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
 
-       nfserr = nfserr_acces;
-       if (!argp->len)
-               goto done;
        nfserr = nfserr_exist;
        if (isdotent(argp->name, argp->len))
                goto done;
@@ -362,8 +359,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
        nfserr = 0;
        if (!inode) {
                /* File doesn't exist. Create it and set attrs */
-               nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
-                                       attr, type, rdev, newfhp);
+               nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name,
+                                       argp->len, attr, type, rdev, newfhp);
        } else if (type == S_IFREG) {
                dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
                        argp->name, attr->ia_valid, (long) attr->ia_size);
index 79d964a..41b468a 100644 (file)
@@ -240,7 +240,7 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
         || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
 
-        return xdr_argsize_check(rqstp, p);
+       return xdr_argsize_check(rqstp, p);
 }
 
 int
index 7d073b9..0c2a716 100644 (file)
@@ -21,6 +21,7 @@ struct nfsd4_layout_ops {
        u32             notify_types;
 
        __be32 (*proc_getdeviceinfo)(struct super_block *sb,
+                       struct svc_rqst *rqstp,
                        struct nfs4_client *clp,
                        struct nfsd4_getdeviceinfo *gdevp);
        __be32 (*encode_getdeviceinfo)(struct xdr_stream *xdr,
@@ -44,6 +45,9 @@ extern const struct nfsd4_layout_ops bl_layout_ops;
 #ifdef CONFIG_NFSD_SCSILAYOUT
 extern const struct nfsd4_layout_ops scsi_layout_ops;
 #endif
+#ifdef CONFIG_NFSD_FLEXFILELAYOUT
+extern const struct nfsd4_layout_ops ff_layout_ops;
+#endif
 
 __be32 nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *cstate, stateid_t *stateid,
index 64053ea..b95adf9 100644 (file)
@@ -345,6 +345,7 @@ struct nfs4_client {
        u32                     cl_exchange_flags;
        /* number of rpc's in progress over an associated session: */
        atomic_t                cl_refcount;
+       struct nfs4_op_map      cl_spo_must_allow;
 
        /* for nfs41 callbacks */
        /* We currently support a single back channel with a single slot */
index 6fbd81e..ba94412 100644 (file)
@@ -1135,96 +1135,37 @@ nfsd_check_ignore_resizing(struct iattr *iap)
                iap->ia_valid &= ~ATTR_SIZE;
 }
 
-/*
- * Create a file (regular, directory, device, fifo); UNIX sockets 
- * not yet implemented.
- * If the response fh has been verified, the parent directory should
- * already be locked. Note that the parent directory is left locked.
- *
- * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
- */
+/* The parent directory should already be locked: */
 __be32
-nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
                char *fname, int flen, struct iattr *iap,
                int type, dev_t rdev, struct svc_fh *resfhp)
 {
-       struct dentry   *dentry, *dchild = NULL;
+       struct dentry   *dentry, *dchild;
        struct inode    *dirp;
        __be32          err;
        __be32          err2;
        int             host_err;
 
-       err = nfserr_perm;
-       if (!flen)
-               goto out;
-       err = nfserr_exist;
-       if (isdotent(fname, flen))
-               goto out;
-
-       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
-       if (err)
-               goto out;
-
        dentry = fhp->fh_dentry;
        dirp = d_inode(dentry);
 
-       err = nfserr_notdir;
-       if (!dirp->i_op->lookup)
-               goto out;
-       /*
-        * Check whether the response file handle has been verified yet.
-        * If it has, the parent directory should already be locked.
-        */
-       if (!resfhp->fh_dentry) {
-               host_err = fh_want_write(fhp);
-               if (host_err)
-                       goto out_nfserr;
-
-               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
-               fh_lock_nested(fhp, I_MUTEX_PARENT);
-               dchild = lookup_one_len(fname, dentry, flen);
-               host_err = PTR_ERR(dchild);
-               if (IS_ERR(dchild))
-                       goto out_nfserr;
-               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
-               if (err)
-                       goto out;
-       } else {
-               /* called from nfsd_proc_create */
-               dchild = dget(resfhp->fh_dentry);
-               if (!fhp->fh_locked) {
-                       /* not actually possible */
-                       printk(KERN_ERR
-                               "nfsd_create: parent %pd2 not locked!\n",
+       dchild = dget(resfhp->fh_dentry);
+       if (!fhp->fh_locked) {
+               WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
                                dentry);
-                       err = nfserr_io;
-                       goto out;
-               }
-       }
-       /*
-        * Make sure the child dentry is still negative ...
-        */
-       err = nfserr_exist;
-       if (d_really_is_positive(dchild)) {
-               dprintk("nfsd_create: dentry %pd/%pd not negative!\n",
-                       dentry, dchild);
-               goto out; 
+               err = nfserr_io;
+               goto out;
        }
 
+       err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
+       if (err)
+               goto out;
+
        if (!(iap->ia_valid & ATTR_MODE))
                iap->ia_mode = 0;
        iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
 
-       err = nfserr_inval;
-       if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) {
-               printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
-                      type);
-               goto out;
-       }
-
-       /*
-        * Get the dir op function pointer.
-        */
        err = 0;
        host_err = 0;
        switch (type) {
@@ -1242,6 +1183,10 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        case S_IFSOCK:
                host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
                break;
+       default:
+               printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
+                      type);
+               host_err = -EINVAL;
        }
        if (host_err < 0)
                goto out_nfserr;
@@ -1251,7 +1196,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        /*
         * nfsd_create_setattr already committed the child.  Transactional
         * filesystems had a chance to commit changes for both parent and
-        * child simultaneously making the following commit_metadata a
+        * child simultaneously making the following commit_metadata a
         * noop.
         */
        err2 = nfserrno(commit_metadata(fhp));
@@ -1263,8 +1208,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (!err)
                err = fh_update(resfhp);
 out:
-       if (dchild && !IS_ERR(dchild))
-               dput(dchild);
+       dput(dchild);
        return err;
 
 out_nfserr:
@@ -1272,6 +1216,50 @@ out_nfserr:
        goto out;
 }
 
+/*
+ * Create a filesystem object (regular, directory, special).
+ * Note that the parent directory is left locked.
+ *
+ * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
+ */
+__be32
+nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               char *fname, int flen, struct iattr *iap,
+               int type, dev_t rdev, struct svc_fh *resfhp)
+{
+       struct dentry   *dentry, *dchild = NULL;
+       struct inode    *dirp;
+       __be32          err;
+       int             host_err;
+
+       if (isdotent(fname, flen))
+               return nfserr_exist;
+
+       err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_NOP);
+       if (err)
+               return err;
+
+       dentry = fhp->fh_dentry;
+       dirp = d_inode(dentry);
+
+       host_err = fh_want_write(fhp);
+       if (host_err)
+               return nfserrno(host_err);
+
+       fh_lock_nested(fhp, I_MUTEX_PARENT);
+       dchild = lookup_one_len(fname, dentry, flen);
+       host_err = PTR_ERR(dchild);
+       if (IS_ERR(dchild))
+               return nfserrno(host_err);
+       err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+       if (err) {
+               dput(dchild);
+               return err;
+       }
+       return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
+                                       rdev, resfhp);
+}
+
 #ifdef CONFIG_NFSD_V3
 
 /*
@@ -1304,12 +1292,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        dentry = fhp->fh_dentry;
        dirp = d_inode(dentry);
 
-       /* Get all the sanity checks out of the way before
-        * we lock the parent. */
-       err = nfserr_notdir;
-       if (!dirp->i_op->lookup)
-               goto out;
-
        host_err = fh_want_write(fhp);
        if (host_err)
                goto out_nfserr;
index 2d573ec..3cbb1b3 100644 (file)
@@ -59,6 +59,9 @@ __be32                nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd4_clone_file_range(struct file *, u64, struct file *,
                        u64, u64);
 #endif /* CONFIG_NFSD_V4 */
+__be32         nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
+                               char *name, int len, struct iattr *attrs,
+                               int type, dev_t rdev, struct svc_fh *res);
 __be32         nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
                                int type, dev_t rdev, struct svc_fh *res);
index d955481..beea0c5 100644 (file)
@@ -59,6 +59,7 @@ struct nfsd4_compound_state {
        struct nfsd4_session    *session;
        struct nfsd4_slot       *slot;
        int                     data_offset;
+       bool                    spo_must_allowed;
        size_t                  iovlen;
        u32                     minorversion;
        __be32                  status;
@@ -403,6 +404,8 @@ struct nfsd4_exchange_id {
        clientid_t      clientid;
        u32             seqid;
        int             spa_how;
+       u32             spo_must_enforce[3];
+       u32             spo_must_allow[3];
 };
 
 struct nfsd4_sequence {
@@ -654,6 +657,8 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
 
 }
 
+
+bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp);
 int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
 int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
                struct nfsd4_compoundargs *);
index 1a85d94..2c90e28 100644 (file)
@@ -622,10 +622,10 @@ void nilfs_palloc_commit_free_entry(struct inode *inode,
        lock = nilfs_mdt_bgl_lock(inode, group);
 
        if (!nilfs_clear_bit_atomic(lock, group_offset, bitmap))
-               nilfs_warning(inode->i_sb, __func__,
-                             "entry number %llu already freed: ino=%lu",
-                             (unsigned long long)req->pr_entry_nr,
-                             (unsigned long)inode->i_ino);
+               nilfs_msg(inode->i_sb, KERN_WARNING,
+                         "%s (ino=%lu): entry number %llu already freed",
+                         __func__, inode->i_ino,
+                         (unsigned long long)req->pr_entry_nr);
        else
                nilfs_palloc_group_desc_add_entries(desc, lock, 1);
 
@@ -663,10 +663,10 @@ void nilfs_palloc_abort_alloc_entry(struct inode *inode,
        lock = nilfs_mdt_bgl_lock(inode, group);
 
        if (!nilfs_clear_bit_atomic(lock, group_offset, bitmap))
-               nilfs_warning(inode->i_sb, __func__,
-                             "entry number %llu already freed: ino=%lu",
-                             (unsigned long long)req->pr_entry_nr,
-                             (unsigned long)inode->i_ino);
+               nilfs_msg(inode->i_sb, KERN_WARNING,
+                         "%s (ino=%lu): entry number %llu already freed",
+                         __func__, inode->i_ino,
+                         (unsigned long long)req->pr_entry_nr);
        else
                nilfs_palloc_group_desc_add_entries(desc, lock, 1);
 
@@ -772,10 +772,10 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
                do {
                        if (!nilfs_clear_bit_atomic(lock, group_offset,
                                                    bitmap)) {
-                               nilfs_warning(inode->i_sb, __func__,
-                                             "entry number %llu already freed: ino=%lu",
-                                             (unsigned long long)entry_nrs[j],
-                                             (unsigned long)inode->i_ino);
+                               nilfs_msg(inode->i_sb, KERN_WARNING,
+                                         "%s (ino=%lu): entry number %llu already freed",
+                                         __func__, inode->i_ino,
+                                         (unsigned long long)entry_nrs[j]);
                        } else {
                                n++;
                        }
@@ -816,12 +816,11 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
                for (k = 0; k < nempties; k++) {
                        ret = nilfs_palloc_delete_entry_block(inode,
                                                              last_nrs[k]);
-                       if (ret && ret != -ENOENT) {
-                               nilfs_warning(inode->i_sb, __func__,
-                                             "failed to delete block of entry %llu: ino=%lu, err=%d",
-                                             (unsigned long long)last_nrs[k],
-                                             (unsigned long)inode->i_ino, ret);
-                       }
+                       if (ret && ret != -ENOENT)
+                               nilfs_msg(inode->i_sb, KERN_WARNING,
+                                         "error %d deleting block that object (entry=%llu, ino=%lu) belongs to",
+                                         ret, (unsigned long long)last_nrs[k],
+                                         inode->i_ino);
                }
 
                desc_kaddr = kmap_atomic(desc_bh->b_page);
@@ -835,12 +834,10 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
 
                if (nfree == nilfs_palloc_entries_per_group(inode)) {
                        ret = nilfs_palloc_delete_bitmap_block(inode, group);
-                       if (ret && ret != -ENOENT) {
-                               nilfs_warning(inode->i_sb, __func__,
-                                             "failed to delete bitmap block of group %lu: ino=%lu, err=%d",
-                                             group,
-                                             (unsigned long)inode->i_ino, ret);
-                       }
+                       if (ret && ret != -ENOENT)
+                               nilfs_msg(inode->i_sb, KERN_WARNING,
+                                         "error %d deleting bitmap block of group=%lu, ino=%lu",
+                                         ret, group, inode->i_ino);
                }
        }
        return 0;
index f2a7877..01fb183 100644 (file)
@@ -41,8 +41,8 @@ static int nilfs_bmap_convert_error(struct nilfs_bmap *bmap,
        struct inode *inode = bmap->b_inode;
 
        if (err == -EINVAL) {
-               nilfs_error(inode->i_sb, fname,
-                           "broken bmap (inode number=%lu)", inode->i_ino);
+               __nilfs_error(inode->i_sb, fname,
+                             "broken bmap (inode number=%lu)", inode->i_ino);
                err = -EIO;
        }
        return err;
index b6a4c8f..2b6ffbe 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/nilfs2_fs.h>
+#include <linux/nilfs2_ondisk.h>       /* nilfs_binfo, nilfs_inode, etc */
 #include "alloc.h"
 #include "dat.h"
 
index 4cca998..d5c23da 100644 (file)
@@ -41,7 +41,7 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr)
        struct inode *inode = NILFS_BTNC_I(btnc);
        struct buffer_head *bh;
 
-       bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
+       bh = nilfs_grab_buffer(inode, btnc, blocknr, BIT(BH_NILFS_Node));
        if (unlikely(!bh))
                return NULL;
 
@@ -70,7 +70,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr,
        struct page *page;
        int err;
 
-       bh = nilfs_grab_buffer(inode, btnc, blocknr, 1 << BH_NILFS_Node);
+       bh = nilfs_grab_buffer(inode, btnc, blocknr, BIT(BH_NILFS_Node));
        if (unlikely(!bh))
                return -ENOMEM;
 
index 982d1e3..2e315f9 100644 (file)
@@ -339,12 +339,14 @@ static int nilfs_btree_node_lookup(const struct nilfs_btree_node *node,
  * nilfs_btree_node_broken - verify consistency of btree node
  * @node: btree node block to be examined
  * @size: node size (in bytes)
+ * @inode: host inode of btree
  * @blocknr: block number
  *
  * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
  */
 static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
-                                  size_t size, sector_t blocknr)
+                                  size_t size, struct inode *inode,
+                                  sector_t blocknr)
 {
        int level, flags, nchildren;
        int ret = 0;
@@ -358,9 +360,10 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
                     (flags & NILFS_BTREE_NODE_ROOT) ||
                     nchildren < 0 ||
                     nchildren > NILFS_BTREE_NODE_NCHILDREN_MAX(size))) {
-               printk(KERN_CRIT "NILFS: bad btree node (blocknr=%llu): "
-                      "level = %d, flags = 0x%x, nchildren = %d\n",
-                      (unsigned long long)blocknr, level, flags, nchildren);
+               nilfs_msg(inode->i_sb, KERN_CRIT,
+                         "bad btree node (ino=%lu, blocknr=%llu): level = %d, flags = 0x%x, nchildren = %d",
+                         inode->i_ino, (unsigned long long)blocknr, level,
+                         flags, nchildren);
                ret = 1;
        }
        return ret;
@@ -369,12 +372,12 @@ static int nilfs_btree_node_broken(const struct nilfs_btree_node *node,
 /**
  * nilfs_btree_root_broken - verify consistency of btree root node
  * @node: btree root node to be examined
- * @ino: inode number
+ * @inode: host inode of btree
  *
  * Return Value: If node is broken, 1 is returned. Otherwise, 0 is returned.
  */
 static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
-                                  unsigned long ino)
+                                  struct inode *inode)
 {
        int level, flags, nchildren;
        int ret = 0;
@@ -387,8 +390,9 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
                     level >= NILFS_BTREE_LEVEL_MAX ||
                     nchildren < 0 ||
                     nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
-               pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
-                       ino, level, flags, nchildren);
+               nilfs_msg(inode->i_sb, KERN_CRIT,
+                         "bad btree root (ino=%lu): level = %d, flags = 0x%x, nchildren = %d",
+                         inode->i_ino, level, flags, nchildren);
                ret = 1;
        }
        return ret;
@@ -396,13 +400,15 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
 
 int nilfs_btree_broken_node_block(struct buffer_head *bh)
 {
+       struct inode *inode;
        int ret;
 
        if (buffer_nilfs_checked(bh))
                return 0;
 
+       inode = bh->b_page->mapping->host;
        ret = nilfs_btree_node_broken((struct nilfs_btree_node *)bh->b_data,
-                                      bh->b_size, bh->b_blocknr);
+                                     bh->b_size, inode, bh->b_blocknr);
        if (likely(!ret))
                set_buffer_nilfs_checked(bh);
        return ret;
@@ -448,13 +454,15 @@ nilfs_btree_get_node(const struct nilfs_bmap *btree,
        return node;
 }
 
-static int
-nilfs_btree_bad_node(struct nilfs_btree_node *node, int level)
+static int nilfs_btree_bad_node(const struct nilfs_bmap *btree,
+                               struct nilfs_btree_node *node, int level)
 {
        if (unlikely(nilfs_btree_node_get_level(node) != level)) {
                dump_stack();
-               printk(KERN_CRIT "NILFS: btree level mismatch: %d != %d\n",
-                      nilfs_btree_node_get_level(node), level);
+               nilfs_msg(btree->b_inode->i_sb, KERN_CRIT,
+                         "btree level mismatch (ino=%lu): %d != %d",
+                         btree->b_inode->i_ino,
+                         nilfs_btree_node_get_level(node), level);
                return 1;
        }
        return 0;
@@ -509,6 +517,9 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
 
  out_no_wait:
        if (!buffer_uptodate(bh)) {
+               nilfs_msg(btree->b_inode->i_sb, KERN_ERR,
+                         "I/O error reading b-tree node block (ino=%lu, blocknr=%llu)",
+                         btree->b_inode->i_ino, (unsigned long long)ptr);
                brelse(bh);
                return -EIO;
        }
@@ -568,7 +579,7 @@ static int nilfs_btree_do_lookup(const struct nilfs_bmap *btree,
                        return ret;
 
                node = nilfs_btree_get_nonroot_node(path, level);
-               if (nilfs_btree_bad_node(node, level))
+               if (nilfs_btree_bad_node(btree, node, level))
                        return -EINVAL;
                if (!found)
                        found = nilfs_btree_node_lookup(node, key, &index);
@@ -616,7 +627,7 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_bmap *btree,
                if (ret < 0)
                        return ret;
                node = nilfs_btree_get_nonroot_node(path, level);
-               if (nilfs_btree_bad_node(node, level))
+               if (nilfs_btree_bad_node(btree, node, level))
                        return -EINVAL;
                index = nilfs_btree_node_get_nchildren(node) - 1;
                ptr = nilfs_btree_node_get_ptr(node, index, ncmax);
@@ -2072,8 +2083,10 @@ static int nilfs_btree_propagate(struct nilfs_bmap *btree,
        ret = nilfs_btree_do_lookup(btree, path, key, NULL, level + 1, 0);
        if (ret < 0) {
                if (unlikely(ret == -ENOENT))
-                       printk(KERN_CRIT "%s: key = %llu, level == %d\n",
-                              __func__, (unsigned long long)key, level);
+                       nilfs_msg(btree->b_inode->i_sb, KERN_CRIT,
+                                 "writing node/leaf block does not appear in b-tree (ino=%lu) at key=%llu, level=%d",
+                                 btree->b_inode->i_ino,
+                                 (unsigned long long)key, level);
                goto out;
        }
 
@@ -2110,12 +2123,11 @@ static void nilfs_btree_add_dirty_buffer(struct nilfs_bmap *btree,
        if (level < NILFS_BTREE_LEVEL_NODE_MIN ||
            level >= NILFS_BTREE_LEVEL_MAX) {
                dump_stack();
-               printk(KERN_WARNING
-                      "%s: invalid btree level: %d (key=%llu, ino=%lu, "
-                      "blocknr=%llu)\n",
-                      __func__, level, (unsigned long long)key,
-                      NILFS_BMAP_I(btree)->vfs_inode.i_ino,
-                      (unsigned long long)bh->b_blocknr);
+               nilfs_msg(btree->b_inode->i_sb, KERN_WARNING,
+                         "invalid btree level: %d (key=%llu, ino=%lu, blocknr=%llu)",
+                         level, (unsigned long long)key,
+                         btree->b_inode->i_ino,
+                         (unsigned long long)bh->b_blocknr);
                return;
        }
 
@@ -2394,8 +2406,7 @@ int nilfs_btree_init(struct nilfs_bmap *bmap)
 
        __nilfs_btree_init(bmap);
 
-       if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap),
-                                   bmap->b_inode->i_ino))
+       if (nilfs_btree_root_broken(nilfs_btree_get_root(bmap), bmap->b_inode))
                ret = -EIO;
        return ret;
 }
index df1a25f..2184e47 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/types.h>
 #include <linux/buffer_head.h>
 #include <linux/list.h>
-#include <linux/nilfs2_fs.h>
+#include <linux/nilfs2_ondisk.h>       /* nilfs_btree_node */
 #include "btnode.h"
 #include "bmap.h"
 
index 8a3d3b6..a15a160 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/string.h>
 #include <linux/buffer_head.h>
 #include <linux/errno.h>
-#include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "cpfile.h"
 
@@ -332,9 +331,9 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
        int ret, ncps, nicps, nss, count, i;
 
        if (unlikely(start == 0 || start > end)) {
-               printk(KERN_ERR "%s: invalid range of checkpoint numbers: "
-                      "[%llu, %llu)\n", __func__,
-                      (unsigned long long)start, (unsigned long long)end);
+               nilfs_msg(cpfile->i_sb, KERN_ERR,
+                         "cannot delete checkpoints: invalid range [%llu, %llu)",
+                         (unsigned long long)start, (unsigned long long)end);
                return -EINVAL;
        }
 
@@ -386,9 +385,9 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
                                                                   cpfile, cno);
                                        if (ret == 0)
                                                continue;
-                                       printk(KERN_ERR
-                                              "%s: cannot delete block\n",
-                                              __func__);
+                                       nilfs_msg(cpfile->i_sb, KERN_ERR,
+                                                 "error %d deleting checkpoint block",
+                                                 ret);
                                        break;
                                }
                        }
@@ -991,14 +990,12 @@ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
        int err;
 
        if (cpsize > sb->s_blocksize) {
-               printk(KERN_ERR
-                      "NILFS: too large checkpoint size: %zu bytes.\n",
-                      cpsize);
+               nilfs_msg(sb, KERN_ERR,
+                         "too large checkpoint size: %zu bytes", cpsize);
                return -EINVAL;
        } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
-               printk(KERN_ERR
-                      "NILFS: too small checkpoint size: %zu bytes.\n",
-                      cpsize);
+               nilfs_msg(sb, KERN_ERR,
+                         "too small checkpoint size: %zu bytes", cpsize);
                return -EINVAL;
        }
 
index 0249744..6eca972 100644 (file)
@@ -21,7 +21,8 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/nilfs2_fs.h>
+#include <linux/nilfs2_api.h>          /* nilfs_cpstat */
+#include <linux/nilfs2_ondisk.h>       /* nilfs_inode, nilfs_checkpoint */
 
 
 int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int,
index 7367610..dffedb2 100644 (file)
@@ -349,10 +349,11 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
        kaddr = kmap_atomic(entry_bh->b_page);
        entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
        if (unlikely(entry->de_blocknr == cpu_to_le64(0))) {
-               printk(KERN_CRIT "%s: vbn = %llu, [%llu, %llu)\n", __func__,
-                      (unsigned long long)vblocknr,
-                      (unsigned long long)le64_to_cpu(entry->de_start),
-                      (unsigned long long)le64_to_cpu(entry->de_end));
+               nilfs_msg(dat->i_sb, KERN_CRIT,
+                         "%s: invalid vblocknr = %llu, [%llu, %llu)",
+                         __func__, (unsigned long long)vblocknr,
+                         (unsigned long long)le64_to_cpu(entry->de_start),
+                         (unsigned long long)le64_to_cpu(entry->de_end));
                kunmap_atomic(kaddr);
                brelse(entry_bh);
                return -EINVAL;
@@ -479,14 +480,12 @@ int nilfs_dat_read(struct super_block *sb, size_t entry_size,
        int err;
 
        if (entry_size > sb->s_blocksize) {
-               printk(KERN_ERR
-                      "NILFS: too large DAT entry size: %zu bytes.\n",
-                      entry_size);
+               nilfs_msg(sb, KERN_ERR, "too large DAT entry size: %zu bytes",
+                         entry_size);
                return -EINVAL;
        } else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) {
-               printk(KERN_ERR
-                      "NILFS: too small DAT entry size: %zu bytes.\n",
-                      entry_size);
+               nilfs_msg(sb, KERN_ERR, "too small DAT entry size: %zu bytes",
+                         entry_size);
                return -EINVAL;
        }
 
index abbfdab..57dc6cf 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
+#include <linux/nilfs2_ondisk.h>       /* nilfs_inode, nilfs_checkpoint */
 
 
 struct nilfs_palloc_req;
index e506f4f..908ebbf 100644 (file)
 #include "nilfs.h"
 #include "page.h"
 
+static inline unsigned int nilfs_rec_len_from_disk(__le16 dlen)
+{
+       unsigned int len = le16_to_cpu(dlen);
+
+#if (PAGE_SIZE >= 65536)
+       if (len == NILFS_MAX_REC_LEN)
+               return 1 << 16;
+#endif
+       return len;
+}
+
+static inline __le16 nilfs_rec_len_to_disk(unsigned int len)
+{
+#if (PAGE_SIZE >= 65536)
+       if (len == (1 << 16))
+               return cpu_to_le16(NILFS_MAX_REC_LEN);
+
+       BUG_ON(len > (1 << 16));
+#endif
+       return cpu_to_le16(len);
+}
+
 /*
  * nilfs uses block-sized chunks. Arguably, sector-sized ones would be
  * more robust, but we have what we have
@@ -140,10 +162,9 @@ out:
        /* Too bad, we had an error */
 
 Ebadsize:
-       nilfs_error(sb, "nilfs_check_page",
+       nilfs_error(sb,
                    "size of directory #%lu is not a multiple of chunk size",
-                   dir->i_ino
-       );
+                   dir->i_ino);
        goto fail;
 Eshort:
        error = "rec_len is smaller than minimal";
@@ -157,19 +178,18 @@ Enamelen:
 Espan:
        error = "directory entry across blocks";
 bad_entry:
-       nilfs_error(sb, "nilfs_check_page", "bad entry in directory #%lu: %s - "
-                   "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
-                   dir->i_ino, error, (page->index<<PAGE_SHIFT)+offs,
-                   (unsigned long) le64_to_cpu(p->inode),
+       nilfs_error(sb,
+                   "bad entry in directory #%lu: %s - offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+                   dir->i_ino, error, (page->index << PAGE_SHIFT) + offs,
+                   (unsigned long)le64_to_cpu(p->inode),
                    rec_len, p->name_len);
        goto fail;
 Eend:
        p = (struct nilfs_dir_entry *)(kaddr + offs);
-       nilfs_error(sb, "nilfs_check_page",
-                   "entry in directory #%lu spans the page boundary"
-                   "offset=%lu, inode=%lu",
-                   dir->i_ino, (page->index<<PAGE_SHIFT)+offs,
-                   (unsigned long) le64_to_cpu(p->inode));
+       nilfs_error(sb,
+                   "entry in directory #%lu spans the page boundary offset=%lu, inode=%lu",
+                   dir->i_ino, (page->index << PAGE_SHIFT) + offs,
+                   (unsigned long)le64_to_cpu(p->inode));
 fail:
        SetPageError(page);
        return false;
@@ -267,8 +287,7 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx)
                struct page *page = nilfs_get_page(inode, n);
 
                if (IS_ERR(page)) {
-                       nilfs_error(sb, __func__, "bad page in #%lu",
-                                   inode->i_ino);
+                       nilfs_error(sb, "bad page in #%lu", inode->i_ino);
                        ctx->pos += PAGE_SIZE - offset;
                        return -EIO;
                }
@@ -278,8 +297,7 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx)
                        NILFS_DIR_REC_LEN(1);
                for ( ; (char *)de <= limit; de = nilfs_next_entry(de)) {
                        if (de->rec_len == 0) {
-                               nilfs_error(sb, __func__,
-                                           "zero-length directory entry");
+                               nilfs_error(sb, "zero-length directory entry");
                                nilfs_put_page(page);
                                return -EIO;
                        }
@@ -345,7 +363,7 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
                        kaddr += nilfs_last_byte(dir, n) - reclen;
                        while ((char *) de <= kaddr) {
                                if (de->rec_len == 0) {
-                                       nilfs_error(dir->i_sb, __func__,
+                                       nilfs_error(dir->i_sb,
                                                "zero-length directory entry");
                                        nilfs_put_page(page);
                                        goto out;
@@ -360,7 +378,7 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
                        n = 0;
                /* next page is past the blocks we've got */
                if (unlikely(n > (dir->i_blocks >> (PAGE_SHIFT - 9)))) {
-                       nilfs_error(dir->i_sb, __func__,
+                       nilfs_error(dir->i_sb,
                               "dir %lu size %lld exceeds block count %llu",
                               dir->i_ino, dir->i_size,
                               (unsigned long long)dir->i_blocks);
@@ -469,7 +487,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
                                goto got_it;
                        }
                        if (de->rec_len == 0) {
-                               nilfs_error(dir->i_sb, __func__,
+                               nilfs_error(dir->i_sb,
                                            "zero-length directory entry");
                                err = -EIO;
                                goto out_unlock;
@@ -541,7 +559,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
 
        while ((char *)de < (char *)dir) {
                if (de->rec_len == 0) {
-                       nilfs_error(inode->i_sb, __func__,
+                       nilfs_error(inode->i_sb,
                                    "zero-length directory entry");
                        err = -EIO;
                        goto out;
@@ -628,7 +646,7 @@ int nilfs_empty_dir(struct inode *inode)
 
                while ((char *)de <= kaddr) {
                        if (de->rec_len == 0) {
-                               nilfs_error(inode->i_sb, __func__,
+                               nilfs_error(inode->i_sb,
                                            "zero-length directory entry (kaddr=%p, de=%p)",
                                            kaddr, de);
                                goto not_empty;
index 251a449..96e3ed0 100644 (file)
@@ -337,14 +337,16 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap,
 
        key = nilfs_bmap_data_get_key(bmap, *bh);
        if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
-               printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
-                      (unsigned long long)key);
+               nilfs_msg(bmap->b_inode->i_sb, KERN_CRIT,
+                         "%s (ino=%lu): invalid key: %llu", __func__,
+                         bmap->b_inode->i_ino, (unsigned long long)key);
                return -EINVAL;
        }
        ptr = nilfs_direct_get_ptr(bmap, key);
        if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
-               printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
-                      (unsigned long long)ptr);
+               nilfs_msg(bmap->b_inode->i_sb, KERN_CRIT,
+                         "%s (ino=%lu): invalid pointer: %llu", __func__,
+                         bmap->b_inode->i_ino, (unsigned long long)ptr);
                return -EINVAL;
        }
 
index 3015a6e..cfe85e8 100644 (file)
 #include "bmap.h"
 
 
-/**
- * struct nilfs_direct_node - direct node
- * @dn_flags: flags
- * @dn_pad: padding
- */
-struct nilfs_direct_node {
-       __u8 dn_flags;
-       __u8 pad[7];
-};
-
 #define NILFS_DIRECT_NBLOCKS   (NILFS_BMAP_SIZE / sizeof(__le64) - 1)
 #define NILFS_DIRECT_KEY_MIN   0
 #define NILFS_DIRECT_KEY_MAX   (NILFS_DIRECT_NBLOCKS - 1)
index e9148f9..853a831 100644 (file)
@@ -148,8 +148,15 @@ int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn,
 int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh)
 {
        wait_on_buffer(bh);
-       if (!buffer_uptodate(bh))
+       if (!buffer_uptodate(bh)) {
+               struct inode *inode = bh->b_page->mapping->host;
+
+               nilfs_msg(inode->i_sb, KERN_ERR,
+                         "I/O error reading %s block for GC (ino=%lu, vblocknr=%llu)",
+                         buffer_nilfs_node(bh) ? "node" : "data",
+                         inode->i_ino, (unsigned long long)bh->b_blocknr);
                return -EIO;
+       }
        if (buffer_dirty(bh))
                return -EEXIST;
 
index 1d2b180..b8fa45c 100644 (file)
@@ -145,15 +145,14 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino,
        int err;
 
        if (unlikely(!NILFS_VALID_INODE(sb, ino))) {
-               nilfs_error(sb, __func__, "bad inode number: %lu",
-                           (unsigned long) ino);
+               nilfs_error(sb, "bad inode number: %lu", (unsigned long)ino);
                return -EINVAL;
        }
 
        err = nilfs_palloc_get_entry_block(ifile, ino, 0, out_bh);
        if (unlikely(err))
-               nilfs_warning(sb, __func__, "unable to read inode: %lu",
-                             (unsigned long) ino);
+               nilfs_msg(sb, KERN_WARNING, "error %d reading inode: ino=%lu",
+                         err, (unsigned long)ino);
        return err;
 }
 
index 23ad2f0..188b94f 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "alloc.h"
 
index a0ebdb1..af04f55 100644 (file)
@@ -112,13 +112,10 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
                                 * However, the page having this block must
                                 * be locked in this case.
                                 */
-                               printk(KERN_WARNING
-                                      "nilfs_get_block: a race condition "
-                                      "while inserting a data block. "
-                                      "(inode number=%lu, file block "
-                                      "offset=%llu)\n",
-                                      inode->i_ino,
-                                      (unsigned long long)blkoff);
+                               nilfs_msg(inode->i_sb, KERN_WARNING,
+                                         "%s (ino=%lu): a race condition while inserting a data block at offset=%llu",
+                                         __func__, inode->i_ino,
+                                         (unsigned long long)blkoff);
                                err = 0;
                        }
                        nilfs_transaction_abort(inode->i_sb);
@@ -359,7 +356,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
 
        root = NILFS_I(dir)->i_root;
        ii = NILFS_I(inode);
-       ii->i_state = 1 << NILFS_I_NEW;
+       ii->i_state = BIT(NILFS_I_NEW);
        ii->i_root = root;
 
        err = nilfs_ifile_create_inode(root->ifile, &ino, &ii->i_bh);
@@ -558,7 +555,7 @@ static int nilfs_iget_set(struct inode *inode, void *opaque)
 
        inode->i_ino = args->ino;
        if (args->for_gc) {
-               NILFS_I(inode)->i_state = 1 << NILFS_I_GCINODE;
+               NILFS_I(inode)->i_state = BIT(NILFS_I_GCINODE);
                NILFS_I(inode)->i_cno = args->cno;
                NILFS_I(inode)->i_root = NULL;
        } else {
@@ -726,9 +723,9 @@ repeat:
                goto repeat;
 
 failed:
-       nilfs_warning(ii->vfs_inode.i_sb, __func__,
-                     "failed to truncate bmap (ino=%lu, err=%d)",
-                     ii->vfs_inode.i_ino, ret);
+       nilfs_msg(ii->vfs_inode.i_sb, KERN_WARNING,
+                 "error %d truncating bmap (ino=%lu)", ret,
+                 ii->vfs_inode.i_ino);
 }
 
 void nilfs_truncate(struct inode *inode)
@@ -939,9 +936,9 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned int nr_dirty)
                         * This will happen when somebody is freeing
                         * this inode.
                         */
-                       nilfs_warning(inode->i_sb, __func__,
-                                     "cannot get inode (ino=%lu)",
-                                     inode->i_ino);
+                       nilfs_msg(inode->i_sb, KERN_WARNING,
+                                 "cannot set file dirty (ino=%lu): the file is being freed",
+                                 inode->i_ino);
                        spin_unlock(&nilfs->ns_inode_lock);
                        return -EINVAL; /*
                                         * NILFS_I_DIRTY may remain for
@@ -962,8 +959,9 @@ int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
 
        err = nilfs_load_inode_block(inode, &ibh);
        if (unlikely(err)) {
-               nilfs_warning(inode->i_sb, __func__,
-                             "failed to reget inode block.");
+               nilfs_msg(inode->i_sb, KERN_WARNING,
+                         "cannot mark inode dirty (ino=%lu): error %d loading inode block",
+                         inode->i_ino, err);
                return err;
        }
        nilfs_update_inode(inode, ibh, flags);
@@ -989,8 +987,8 @@ void nilfs_dirty_inode(struct inode *inode, int flags)
        struct nilfs_mdt_info *mdi = NILFS_MDT(inode);
 
        if (is_bad_inode(inode)) {
-               nilfs_warning(inode->i_sb, __func__,
-                             "tried to mark bad_inode dirty. ignored.");
+               nilfs_msg(inode->i_sb, KERN_WARNING,
+                         "tried to mark bad_inode dirty. ignored.");
                dump_stack();
                return;
        }
index 358b57e..f1d7989 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/compat.h>      /* compat_ptr() */
 #include <linux/mount.h>       /* mnt_want_write_file(), mnt_drop_write_file() */
 #include <linux/buffer_head.h>
-#include <linux/nilfs2_fs.h>
 #include "nilfs.h"
 #include "segment.h"
 #include "bmap.h"
@@ -584,27 +583,25 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
 
        if (unlikely(ret < 0)) {
                if (ret == -ENOENT)
-                       printk(KERN_CRIT
-                              "%s: invalid virtual block address (%s): "
-                              "ino=%llu, cno=%llu, offset=%llu, "
-                              "blocknr=%llu, vblocknr=%llu\n",
-                              __func__, vdesc->vd_flags ? "node" : "data",
-                              (unsigned long long)vdesc->vd_ino,
-                              (unsigned long long)vdesc->vd_cno,
-                              (unsigned long long)vdesc->vd_offset,
-                              (unsigned long long)vdesc->vd_blocknr,
-                              (unsigned long long)vdesc->vd_vblocknr);
+                       nilfs_msg(inode->i_sb, KERN_CRIT,
+                                 "%s: invalid virtual block address (%s): ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu",
+                                 __func__, vdesc->vd_flags ? "node" : "data",
+                                 (unsigned long long)vdesc->vd_ino,
+                                 (unsigned long long)vdesc->vd_cno,
+                                 (unsigned long long)vdesc->vd_offset,
+                                 (unsigned long long)vdesc->vd_blocknr,
+                                 (unsigned long long)vdesc->vd_vblocknr);
                return ret;
        }
        if (unlikely(!list_empty(&bh->b_assoc_buffers))) {
-               printk(KERN_CRIT "%s: conflicting %s buffer: ino=%llu, "
-                      "cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu\n",
-                      __func__, vdesc->vd_flags ? "node" : "data",
-                      (unsigned long long)vdesc->vd_ino,
-                      (unsigned long long)vdesc->vd_cno,
-                      (unsigned long long)vdesc->vd_offset,
-                      (unsigned long long)vdesc->vd_blocknr,
-                      (unsigned long long)vdesc->vd_vblocknr);
+               nilfs_msg(inode->i_sb, KERN_CRIT,
+                         "%s: conflicting %s buffer: ino=%llu, cno=%llu, offset=%llu, blocknr=%llu, vblocknr=%llu",
+                         __func__, vdesc->vd_flags ? "node" : "data",
+                         (unsigned long long)vdesc->vd_ino,
+                         (unsigned long long)vdesc->vd_cno,
+                         (unsigned long long)vdesc->vd_offset,
+                         (unsigned long long)vdesc->vd_blocknr,
+                         (unsigned long long)vdesc->vd_vblocknr);
                brelse(bh);
                return -EEXIST;
        }
@@ -854,8 +851,8 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs,
        return 0;
 
  failed:
-       printk(KERN_ERR "NILFS: GC failed during preparation: %s: err=%d\n",
-              msg, ret);
+       nilfs_msg(nilfs->ns_sb, KERN_ERR, "error %d preparing GC: %s", ret,
+                 msg);
        return ret;
 }
 
@@ -963,10 +960,11 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
        }
 
        ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
-       if (ret < 0)
-               printk(KERN_ERR "NILFS: GC failed during preparation: "
-                       "cannot read source blocks: err=%d\n", ret);
-       else {
+       if (ret < 0) {
+               nilfs_msg(inode->i_sb, KERN_ERR,
+                         "error %d preparing GC: cannot read source blocks",
+                         ret);
+       } else {
                if (nilfs_sb_need_update(nilfs))
                        set_nilfs_discontinued(nilfs);
                ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
index 0d7b71f..d56d3a5 100644 (file)
@@ -207,8 +207,12 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block,
 
  out_no_wait:
        err = -EIO;
-       if (!buffer_uptodate(first_bh))
+       if (!buffer_uptodate(first_bh)) {
+               nilfs_msg(inode->i_sb, KERN_ERR,
+                         "I/O error reading meta-data file (ino=%lu, block-offset=%lu)",
+                         inode->i_ino, block);
                goto failed_bh;
+       }
  out:
        *out_bh = first_bh;
        return 0;
index 1ec8ae5..dbcf1dc 100644 (file)
@@ -283,9 +283,9 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
                goto out;
 
        if (!inode->i_nlink) {
-               nilfs_warning(inode->i_sb, __func__,
-                             "deleting nonexistent file (%lu), %d",
-                             inode->i_ino, inode->i_nlink);
+               nilfs_msg(inode->i_sb, KERN_WARNING,
+                         "deleting nonexistent file (ino=%lu), %d",
+                         inode->i_ino, inode->i_nlink);
                set_nlink(inode, 1);
        }
        err = nilfs_delete_entry(de, page);
index b1d48bc..33f8c8f 100644 (file)
@@ -23,7 +23,8 @@
 #include <linux/buffer_head.h>
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
-#include <linux/nilfs2_fs.h>
+#include <linux/nilfs2_api.h>
+#include <linux/nilfs2_ondisk.h>
 #include "the_nilfs.h"
 #include "bmap.h"
 
@@ -119,20 +120,19 @@ enum {
 /*
  * Macros to check inode numbers
  */
-#define NILFS_MDT_INO_BITS   \
-       ((unsigned int)(1 << NILFS_DAT_INO | 1 << NILFS_CPFILE_INO |    \
-                       1 << NILFS_SUFILE_INO | 1 << NILFS_IFILE_INO |  \
-                       1 << NILFS_ATIME_INO | 1 << NILFS_SKETCH_INO))
+#define NILFS_MDT_INO_BITS                                             \
+       (BIT(NILFS_DAT_INO) | BIT(NILFS_CPFILE_INO) |                   \
+        BIT(NILFS_SUFILE_INO) | BIT(NILFS_IFILE_INO) |                 \
+        BIT(NILFS_ATIME_INO) | BIT(NILFS_SKETCH_INO))
 
-#define NILFS_SYS_INO_BITS   \
-       ((unsigned int)(1 << NILFS_ROOT_INO) | NILFS_MDT_INO_BITS)
+#define NILFS_SYS_INO_BITS (BIT(NILFS_ROOT_INO) | NILFS_MDT_INO_BITS)
 
 #define NILFS_FIRST_INO(sb) (((struct the_nilfs *)sb->s_fs_info)->ns_first_ino)
 
 #define NILFS_MDT_INODE(sb, ino) \
-       ((ino) < NILFS_FIRST_INO(sb) && (NILFS_MDT_INO_BITS & (1 << (ino))))
+       ((ino) < NILFS_FIRST_INO(sb) && (NILFS_MDT_INO_BITS & BIT(ino)))
 #define NILFS_VALID_INODE(sb, ino) \
-       ((ino) >= NILFS_FIRST_INO(sb) || (NILFS_SYS_INO_BITS & (1 << (ino))))
+       ((ino) >= NILFS_FIRST_INO(sb) || (NILFS_SYS_INO_BITS & BIT(ino)))
 
 /**
  * struct nilfs_transaction_info: context information for synchronization
@@ -299,10 +299,36 @@ static inline int nilfs_mark_inode_dirty_sync(struct inode *inode)
 /* super.c */
 extern struct inode *nilfs_alloc_inode(struct super_block *);
 extern void nilfs_destroy_inode(struct inode *);
+
 extern __printf(3, 4)
-void nilfs_error(struct super_block *, const char *, const char *, ...);
+void __nilfs_msg(struct super_block *sb, const char *level,
+                const char *fmt, ...);
 extern __printf(3, 4)
-void nilfs_warning(struct super_block *, const char *, const char *, ...);
+void __nilfs_error(struct super_block *sb, const char *function,
+                  const char *fmt, ...);
+
+#ifdef CONFIG_PRINTK
+
+#define nilfs_msg(sb, level, fmt, ...)                                 \
+       __nilfs_msg(sb, level, fmt, ##__VA_ARGS__)
+#define nilfs_error(sb, fmt, ...)                                      \
+       __nilfs_error(sb, __func__, fmt, ##__VA_ARGS__)
+
+#else
+
+#define nilfs_msg(sb, level, fmt, ...)                                 \
+       do {                                                            \
+               no_printk(fmt, ##__VA_ARGS__);                          \
+               (void)(sb);                                             \
+       } while (0)
+#define nilfs_error(sb, fmt, ...)                                      \
+       do {                                                            \
+               no_printk(fmt, ##__VA_ARGS__);                          \
+               __nilfs_error(sb, "", " ");                             \
+       } while (0)
+
+#endif /* CONFIG_PRINTK */
+
 extern struct nilfs_super_block *
 nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
 extern int nilfs_store_magic_and_option(struct super_block *,
index d97ba5f..f11a3ad 100644 (file)
@@ -30,9 +30,9 @@
 #include "mdt.h"
 
 
-#define NILFS_BUFFER_INHERENT_BITS  \
-       ((1UL << BH_Uptodate) | (1UL << BH_Mapped) | (1UL << BH_NILFS_Node) | \
-        (1UL << BH_NILFS_Volatile) | (1UL << BH_NILFS_Checked))
+#define NILFS_BUFFER_INHERENT_BITS                                     \
+       (BIT(BH_Uptodate) | BIT(BH_Mapped) | BIT(BH_NILFS_Node) |       \
+        BIT(BH_NILFS_Volatile) | BIT(BH_NILFS_Checked))
 
 static struct buffer_head *
 __nilfs_get_page_block(struct page *page, unsigned long block, pgoff_t index,
@@ -85,9 +85,9 @@ void nilfs_forget_buffer(struct buffer_head *bh)
 {
        struct page *page = bh->b_page;
        const unsigned long clear_bits =
-               (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped |
-                1 << BH_Async_Write | 1 << BH_NILFS_Volatile |
-                1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected);
+               (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) |
+                BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) |
+                BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected));
 
        lock_buffer(bh);
        set_mask_bits(&bh->b_state, clear_bits, 0);
@@ -124,17 +124,17 @@ void nilfs_copy_buffer(struct buffer_head *dbh, struct buffer_head *sbh)
        dbh->b_bdev = sbh->b_bdev;
 
        bh = dbh;
-       bits = sbh->b_state & ((1UL << BH_Uptodate) | (1UL << BH_Mapped));
+       bits = sbh->b_state & (BIT(BH_Uptodate) | BIT(BH_Mapped));
        while ((bh = bh->b_this_page) != dbh) {
                lock_buffer(bh);
                bits &= bh->b_state;
                unlock_buffer(bh);
        }
-       if (bits & (1UL << BH_Uptodate))
+       if (bits & BIT(BH_Uptodate))
                SetPageUptodate(dpage);
        else
                ClearPageUptodate(dpage);
-       if (bits & (1UL << BH_Mapped))
+       if (bits & BIT(BH_Mapped))
                SetPageMappedToDisk(dpage);
        else
                ClearPageMappedToDisk(dpage);
@@ -215,7 +215,7 @@ static void nilfs_copy_page(struct page *dst, struct page *src, int copy_dirty)
                create_empty_buffers(dst, sbh->b_size, 0);
 
        if (copy_dirty)
-               mask |= (1UL << BH_Dirty);
+               mask |= BIT(BH_Dirty);
 
        dbh = dbufs = page_buffers(dst);
        do {
@@ -403,11 +403,10 @@ void nilfs_clear_dirty_page(struct page *page, bool silent)
 
        BUG_ON(!PageLocked(page));
 
-       if (!silent) {
-               nilfs_warning(sb, __func__,
-                               "discard page: offset %lld, ino %lu",
-                               page_offset(page), inode->i_ino);
-       }
+       if (!silent)
+               nilfs_msg(sb, KERN_WARNING,
+                         "discard dirty page: offset=%lld, ino=%lu",
+                         page_offset(page), inode->i_ino);
 
        ClearPageUptodate(page);
        ClearPageMappedToDisk(page);
@@ -415,18 +414,18 @@ void nilfs_clear_dirty_page(struct page *page, bool silent)
        if (page_has_buffers(page)) {
                struct buffer_head *bh, *head;
                const unsigned long clear_bits =
-                       (1 << BH_Uptodate | 1 << BH_Dirty | 1 << BH_Mapped |
-                        1 << BH_Async_Write | 1 << BH_NILFS_Volatile |
-                        1 << BH_NILFS_Checked | 1 << BH_NILFS_Redirected);
+                       (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) |
+                        BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) |
+                        BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected));
 
                bh = head = page_buffers(page);
                do {
                        lock_buffer(bh);
-                       if (!silent) {
-                               nilfs_warning(sb, __func__,
-                                       "discard block %llu, size %zu",
-                                       (u64)bh->b_blocknr, bh->b_size);
-                       }
+                       if (!silent)
+                               nilfs_msg(sb, KERN_WARNING,
+                                         "discard dirty block: blocknr=%llu, size=%zu",
+                                         (u64)bh->b_blocknr, bh->b_size);
+
                        set_mask_bits(&bh->b_state, clear_bits, 0);
                        unlock_buffer(bh);
                } while (bh = bh->b_this_page, bh != head);
index d893dc9..5139efe 100644 (file)
@@ -54,38 +54,37 @@ struct nilfs_recovery_block {
 };
 
 
-static int nilfs_warn_segment_error(int err)
+static int nilfs_warn_segment_error(struct super_block *sb, int err)
 {
+       const char *msg = NULL;
+
        switch (err) {
        case NILFS_SEG_FAIL_IO:
-               printk(KERN_WARNING
-                      "NILFS warning: I/O error on loading last segment\n");
+               nilfs_msg(sb, KERN_ERR, "I/O error reading segment");
                return -EIO;
        case NILFS_SEG_FAIL_MAGIC:
-               printk(KERN_WARNING
-                      "NILFS warning: Segment magic number invalid\n");
+               msg = "Magic number mismatch";
                break;
        case NILFS_SEG_FAIL_SEQ:
-               printk(KERN_WARNING
-                      "NILFS warning: Sequence number mismatch\n");
+               msg = "Sequence number mismatch";
                break;
        case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:
-               printk(KERN_WARNING
-                      "NILFS warning: Checksum error in super root\n");
+               msg = "Checksum error in super root";
                break;
        case NILFS_SEG_FAIL_CHECKSUM_FULL:
-               printk(KERN_WARNING
-                      "NILFS warning: Checksum error in segment payload\n");
+               msg = "Checksum error in segment payload";
                break;
        case NILFS_SEG_FAIL_CONSISTENCY:
-               printk(KERN_WARNING
-                      "NILFS warning: Inconsistent segment\n");
+               msg = "Inconsistency found";
                break;
        case NILFS_SEG_NO_SUPER_ROOT:
-               printk(KERN_WARNING
-                      "NILFS warning: No super root in the last segment\n");
+               msg = "No super root in the last segment";
                break;
+       default:
+               nilfs_msg(sb, KERN_ERR, "unrecognized segment error %d", err);
+               return -EINVAL;
        }
+       nilfs_msg(sb, KERN_WARNING, "invalid segment: %s", msg);
        return -EINVAL;
 }
 
@@ -178,7 +177,7 @@ int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
        brelse(bh_sr);
 
  failed:
-       return nilfs_warn_segment_error(ret);
+       return nilfs_warn_segment_error(nilfs->ns_sb, ret);
 }
 
 /**
@@ -553,11 +552,10 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
                put_page(page);
 
  failed_inode:
-               printk(KERN_WARNING
-                      "NILFS warning: error recovering data block "
-                      "(err=%d, ino=%lu, block-offset=%llu)\n",
-                      err, (unsigned long)rb->ino,
-                      (unsigned long long)rb->blkoff);
+               nilfs_msg(sb, KERN_WARNING,
+                         "error %d recovering data block (ino=%lu, block-offset=%llu)",
+                         err, (unsigned long)rb->ino,
+                         (unsigned long long)rb->blkoff);
                if (!err2)
                        err2 = err;
  next:
@@ -680,8 +678,8 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
        }
 
        if (nsalvaged_blocks) {
-               printk(KERN_INFO "NILFS (device %s): salvaged %lu blocks\n",
-                      sb->s_id, nsalvaged_blocks);
+               nilfs_msg(sb, KERN_INFO, "salvaged %lu blocks",
+                         nsalvaged_blocks);
                ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
        }
  out:
@@ -692,10 +690,9 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
  confused:
        err = -EINVAL;
  failed:
-       printk(KERN_ERR
-              "NILFS (device %s): Error roll-forwarding "
-              "(err=%d, pseg block=%llu). ",
-              sb->s_id, err, (unsigned long long)pseg_start);
+       nilfs_msg(sb, KERN_ERR,
+                 "error %d roll-forwarding partial segment at blocknr = %llu",
+                 err, (unsigned long long)pseg_start);
        goto out;
 }
 
@@ -715,9 +712,8 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
        set_buffer_dirty(bh);
        err = sync_dirty_buffer(bh);
        if (unlikely(err))
-               printk(KERN_WARNING
-                      "NILFS warning: buffer sync write failed during "
-                      "post-cleaning of recovery.\n");
+               nilfs_msg(nilfs->ns_sb, KERN_WARNING,
+                         "buffer sync write failed during post-cleaning of recovery.");
        brelse(bh);
 }
 
@@ -752,8 +748,8 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
 
        err = nilfs_attach_checkpoint(sb, ri->ri_cno, true, &root);
        if (unlikely(err)) {
-               printk(KERN_ERR
-                      "NILFS: error loading the latest checkpoint.\n");
+               nilfs_msg(sb, KERN_ERR,
+                         "error %d loading the latest checkpoint", err);
                return err;
        }
 
@@ -764,8 +760,9 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
        if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {
                err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);
                if (unlikely(err)) {
-                       printk(KERN_ERR "NILFS: Error preparing segments for "
-                              "recovery.\n");
+                       nilfs_msg(sb, KERN_ERR,
+                                 "error %d preparing segment for recovery",
+                                 err);
                        goto failed;
                }
 
@@ -778,8 +775,9 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
                nilfs_detach_log_writer(sb);
 
                if (unlikely(err)) {
-                       printk(KERN_ERR "NILFS: Oops! recovery failed. "
-                              "(err=%d)\n", err);
+                       nilfs_msg(sb, KERN_ERR,
+                                 "error %d writing segment for recovery",
+                                 err);
                        goto failed;
                }
 
@@ -961,5 +959,5 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
  failed:
        brelse(bh_sum);
        nilfs_dispose_segment_list(&segments);
-       return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
+       return ret < 0 ? ret : nilfs_warn_segment_error(nilfs->ns_sb, ret);
 }
index a962d7d..6f87b2a 100644 (file)
@@ -514,7 +514,11 @@ static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf)
        } while (--segbuf->sb_nbio > 0);
 
        if (unlikely(atomic_read(&segbuf->sb_err) > 0)) {
-               printk(KERN_ERR "NILFS: IO error writing segment\n");
+               nilfs_msg(segbuf->sb_super, KERN_ERR,
+                         "I/O error writing log (start-blocknr=%llu, block-count=%lu) in segment %llu",
+                         (unsigned long long)segbuf->sb_pseg_start,
+                         segbuf->sb_sum.nblocks,
+                         (unsigned long long)segbuf->sb_segnum);
                err = -EIO;
        }
        return err;
index e78b68a..bedcae2 100644 (file)
@@ -150,7 +150,8 @@ static void nilfs_dispose_list(struct the_nilfs *, struct list_head *, int);
 #define nilfs_cnt32_lt(a, b)  nilfs_cnt32_gt(b, a)
 #define nilfs_cnt32_le(a, b)  nilfs_cnt32_ge(b, a)
 
-static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti)
+static int nilfs_prepare_segment_lock(struct super_block *sb,
+                                     struct nilfs_transaction_info *ti)
 {
        struct nilfs_transaction_info *cur_ti = current->journal_info;
        void *save = NULL;
@@ -164,8 +165,7 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti)
                 * it is saved and will be restored on
                 * nilfs_transaction_commit().
                 */
-               printk(KERN_WARNING
-                      "NILFS warning: journal info from a different FS\n");
+               nilfs_msg(sb, KERN_WARNING, "journal info from a different FS");
                save = current->journal_info;
        }
        if (!ti) {
@@ -215,7 +215,7 @@ int nilfs_transaction_begin(struct super_block *sb,
                            int vacancy_check)
 {
        struct the_nilfs *nilfs;
-       int ret = nilfs_prepare_segment_lock(ti);
+       int ret = nilfs_prepare_segment_lock(sb, ti);
        struct nilfs_transaction_info *trace_ti;
 
        if (unlikely(ret < 0))
@@ -373,7 +373,7 @@ static void nilfs_transaction_lock(struct super_block *sb,
                nilfs_segctor_do_immediate_flush(sci);
 
                up_write(&nilfs->ns_segctor_sem);
-               yield();
+               cond_resched();
        }
        if (gcflag)
                ti->ti_flags |= NILFS_TI_GC;
@@ -1858,11 +1858,11 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
                 */
                list_for_each_entry(bh, &segbuf->sb_payload_buffers,
                                    b_assoc_buffers) {
-                       const unsigned long set_bits = (1 << BH_Uptodate);
+                       const unsigned long set_bits = BIT(BH_Uptodate);
                        const unsigned long clear_bits =
-                               (1 << BH_Dirty | 1 << BH_Async_Write |
-                                1 << BH_Delay | 1 << BH_NILFS_Volatile |
-                                1 << BH_NILFS_Redirected);
+                               (BIT(BH_Dirty) | BIT(BH_Async_Write) |
+                                BIT(BH_Delay) | BIT(BH_NILFS_Volatile) |
+                                BIT(BH_NILFS_Redirected));
 
                        set_mask_bits(&bh->b_state, clear_bits, set_bits);
                        if (bh == segbuf->sb_super_root) {
@@ -1951,8 +1951,9 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci,
                        err = nilfs_ifile_get_inode_block(
                                ifile, ii->vfs_inode.i_ino, &ibh);
                        if (unlikely(err)) {
-                               nilfs_warning(sci->sc_super, __func__,
-                                             "failed to get inode block.");
+                               nilfs_msg(sci->sc_super, KERN_WARNING,
+                                         "log writer: error %d getting inode block (ino=%lu)",
+                                         err, ii->vfs_inode.i_ino);
                                return err;
                        }
                        mark_buffer_dirty(ibh);
@@ -2131,10 +2132,10 @@ static void nilfs_segctor_start_timer(struct nilfs_sc_info *sci)
 static void nilfs_segctor_do_flush(struct nilfs_sc_info *sci, int bn)
 {
        spin_lock(&sci->sc_state_lock);
-       if (!(sci->sc_flush_request & (1 << bn))) {
+       if (!(sci->sc_flush_request & BIT(bn))) {
                unsigned long prev_req = sci->sc_flush_request;
 
-               sci->sc_flush_request |= (1 << bn);
+               sci->sc_flush_request |= BIT(bn);
                if (!prev_req)
                        wake_up(&sci->sc_wait_daemon);
        }
@@ -2318,7 +2319,7 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
 }
 
 #define FLUSH_FILE_BIT (0x1) /* data file only */
-#define FLUSH_DAT_BIT  (1 << NILFS_DAT_INO) /* DAT only */
+#define FLUSH_DAT_BIT  BIT(NILFS_DAT_INO) /* DAT only */
 
 /**
  * nilfs_segctor_accept - record accepted sequence count of log-write requests
@@ -2458,8 +2459,7 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
                if (likely(!err))
                        break;
 
-               nilfs_warning(sb, __func__,
-                             "segment construction failed. (err=%d)", err);
+               nilfs_msg(sb, KERN_WARNING, "error %d cleaning segments", err);
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(sci->sc_interval);
        }
@@ -2467,9 +2467,9 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
                int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs,
                                                 sci->sc_nfreesegs);
                if (ret) {
-                       printk(KERN_WARNING
-                              "NILFS warning: error %d on discard request, "
-                              "turning discards off for the device\n", ret);
+                       nilfs_msg(sb, KERN_WARNING,
+                                 "error %d on discard request, turning discards off for the device",
+                                 ret);
                        nilfs_clear_opt(nilfs, DISCARD);
                }
        }
@@ -2551,10 +2551,9 @@ static int nilfs_segctor_thread(void *arg)
        /* start sync. */
        sci->sc_task = current;
        wake_up(&sci->sc_wait_task); /* for nilfs_segctor_start_thread() */
-       printk(KERN_INFO
-              "segctord starting. Construction interval = %lu seconds, "
-              "CP frequency < %lu seconds\n",
-              sci->sc_interval / HZ, sci->sc_mjcp_freq / HZ);
+       nilfs_msg(sci->sc_super, KERN_INFO,
+                 "segctord starting. Construction interval = %lu seconds, CP frequency < %lu seconds",
+                 sci->sc_interval / HZ, sci->sc_mjcp_freq / HZ);
 
        spin_lock(&sci->sc_state_lock);
  loop:
@@ -2628,8 +2627,8 @@ static int nilfs_segctor_start_thread(struct nilfs_sc_info *sci)
        if (IS_ERR(t)) {
                int err = PTR_ERR(t);
 
-               printk(KERN_ERR "NILFS: error %d creating segctord thread\n",
-                      err);
+               nilfs_msg(sci->sc_super, KERN_ERR,
+                         "error %d creating segctord thread", err);
                return err;
        }
        wait_event(sci->sc_wait_task, sci->sc_task != NULL);
@@ -2739,14 +2738,14 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
                nilfs_segctor_write_out(sci);
 
        if (!list_empty(&sci->sc_dirty_files)) {
-               nilfs_warning(sci->sc_super, __func__,
-                             "dirty file(s) after the final construction");
+               nilfs_msg(sci->sc_super, KERN_WARNING,
+                         "disposed unprocessed dirty file(s) when stopping log writer");
                nilfs_dispose_list(nilfs, &sci->sc_dirty_files, 1);
        }
 
        if (!list_empty(&sci->sc_iput_queue)) {
-               nilfs_warning(sci->sc_super, __func__,
-                             "iput queue is not empty");
+               nilfs_msg(sci->sc_super, KERN_WARNING,
+                         "disposed unprocessed inode(s) in iput queue when stopping log writer");
                nilfs_dispose_list(nilfs, &sci->sc_iput_queue, 1);
        }
 
@@ -2822,8 +2821,8 @@ void nilfs_detach_log_writer(struct super_block *sb)
        spin_lock(&nilfs->ns_inode_lock);
        if (!list_empty(&nilfs->ns_dirty_files)) {
                list_splice_init(&nilfs->ns_dirty_files, &garbage_list);
-               nilfs_warning(sb, __func__,
-                             "Hit dirty file after stopped log writer");
+               nilfs_msg(sb, KERN_WARNING,
+                         "disposed unprocessed dirty file(s) when detaching log writer");
        }
        spin_unlock(&nilfs->ns_inode_lock);
        up_write(&nilfs->ns_segctor_sem);
index 6565c10..1060949 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/workqueue.h>
-#include <linux/nilfs2_fs.h>
 #include "nilfs.h"
 
 struct nilfs_root;
index 1963595..1541a1e 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/string.h>
 #include <linux/buffer_head.h>
 #include <linux/errno.h>
-#include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "sufile.h"
 
@@ -181,9 +180,9 @@ int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
        down_write(&NILFS_MDT(sufile)->mi_sem);
        for (seg = segnumv; seg < segnumv + nsegs; seg++) {
                if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
-                       printk(KERN_WARNING
-                              "%s: invalid segment number: %llu\n", __func__,
-                              (unsigned long long)*seg);
+                       nilfs_msg(sufile->i_sb, KERN_WARNING,
+                                 "%s: invalid segment number: %llu",
+                                 __func__, (unsigned long long)*seg);
                        nerr++;
                }
        }
@@ -240,8 +239,9 @@ int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
        int ret;
 
        if (unlikely(segnum >= nilfs_sufile_get_nsegments(sufile))) {
-               printk(KERN_WARNING "%s: invalid segment number: %llu\n",
-                      __func__, (unsigned long long)segnum);
+               nilfs_msg(sufile->i_sb, KERN_WARNING,
+                         "%s: invalid segment number: %llu",
+                         __func__, (unsigned long long)segnum);
                return -EINVAL;
        }
        down_write(&NILFS_MDT(sufile)->mi_sem);
@@ -419,8 +419,9 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
        kaddr = kmap_atomic(su_bh->b_page);
        su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
        if (unlikely(!nilfs_segment_usage_clean(su))) {
-               printk(KERN_WARNING "%s: segment %llu must be clean\n",
-                      __func__, (unsigned long long)segnum);
+               nilfs_msg(sufile->i_sb, KERN_WARNING,
+                         "%s: segment %llu must be clean", __func__,
+                         (unsigned long long)segnum);
                kunmap_atomic(kaddr);
                return;
        }
@@ -444,7 +445,7 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
 
        kaddr = kmap_atomic(su_bh->b_page);
        su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
-       if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) &&
+       if (su->su_flags == cpu_to_le32(BIT(NILFS_SEGMENT_USAGE_DIRTY)) &&
            su->su_nblocks == cpu_to_le32(0)) {
                kunmap_atomic(kaddr);
                return;
@@ -455,7 +456,7 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
        /* make the segment garbage */
        su->su_lastmod = cpu_to_le64(0);
        su->su_nblocks = cpu_to_le32(0);
-       su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
+       su->su_flags = cpu_to_le32(BIT(NILFS_SEGMENT_USAGE_DIRTY));
        kunmap_atomic(kaddr);
 
        nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
@@ -476,8 +477,9 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
        kaddr = kmap_atomic(su_bh->b_page);
        su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
        if (nilfs_segment_usage_clean(su)) {
-               printk(KERN_WARNING "%s: segment %llu is already clean\n",
-                      __func__, (unsigned long long)segnum);
+               nilfs_msg(sufile->i_sb, KERN_WARNING,
+                         "%s: segment %llu is already clean",
+                         __func__, (unsigned long long)segnum);
                kunmap_atomic(kaddr);
                return;
        }
@@ -692,7 +694,7 @@ static int nilfs_sufile_truncate_range(struct inode *sufile,
                su2 = su;
                for (j = 0; j < n; j++, su = (void *)su + susz) {
                        if ((le32_to_cpu(su->su_flags) &
-                            ~(1UL << NILFS_SEGMENT_USAGE_ERROR)) ||
+                            ~BIT(NILFS_SEGMENT_USAGE_ERROR)) ||
                            nilfs_segment_is_active(nilfs, segnum + j)) {
                                ret = -EBUSY;
                                kunmap_atomic(kaddr);
@@ -859,10 +861,10 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
                        si->sui_lastmod = le64_to_cpu(su->su_lastmod);
                        si->sui_nblocks = le32_to_cpu(su->su_nblocks);
                        si->sui_flags = le32_to_cpu(su->su_flags) &
-                               ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+                               ~BIT(NILFS_SEGMENT_USAGE_ACTIVE);
                        if (nilfs_segment_is_active(nilfs, segnum + j))
                                si->sui_flags |=
-                                       (1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+                                       BIT(NILFS_SEGMENT_USAGE_ACTIVE);
                }
                kunmap_atomic(kaddr);
                brelse(su_bh);
@@ -950,7 +952,7 @@ ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
                         * disk.
                         */
                        sup->sup_sui.sui_flags &=
-                                       ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+                                       ~BIT(NILFS_SEGMENT_USAGE_ACTIVE);
 
                        cleansi = nilfs_suinfo_clean(&sup->sup_sui);
                        cleansu = nilfs_segment_usage_clean(su);
@@ -1175,14 +1177,12 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize,
        int err;
 
        if (susize > sb->s_blocksize) {
-               printk(KERN_ERR
-                      "NILFS: too large segment usage size: %zu bytes.\n",
-                      susize);
+               nilfs_msg(sb, KERN_ERR,
+                         "too large segment usage size: %zu bytes", susize);
                return -EINVAL;
        } else if (susize < NILFS_MIN_SEGMENT_USAGE_SIZE) {
-               printk(KERN_ERR
-                      "NILFS: too small segment usage size: %zu bytes.\n",
-                      susize);
+               nilfs_msg(sb, KERN_ERR,
+                         "too small segment usage size: %zu bytes", susize);
                return -EINVAL;
        }
 
index 46e8987..158a919 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
-#include <linux/nilfs2_fs.h>
 #include "mdt.h"
 
 
index 666107a..c95d369 100644 (file)
@@ -71,6 +71,22 @@ struct kmem_cache *nilfs_btree_path_cache;
 static int nilfs_setup_super(struct super_block *sb, int is_mount);
 static int nilfs_remount(struct super_block *sb, int *flags, char *data);
 
+void __nilfs_msg(struct super_block *sb, const char *level, const char *fmt,
+                ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       if (sb)
+               printk("%sNILFS (%s): %pV\n", level, sb->s_id, &vaf);
+       else
+               printk("%sNILFS: %pV\n", level, &vaf);
+       va_end(args);
+}
+
 static void nilfs_set_error(struct super_block *sb)
 {
        struct the_nilfs *nilfs = sb->s_fs_info;
@@ -91,19 +107,20 @@ static void nilfs_set_error(struct super_block *sb)
 }
 
 /**
- * nilfs_error() - report failure condition on a filesystem
+ * __nilfs_error() - report failure condition on a filesystem
+ *
+ * __nilfs_error() sets an ERROR_FS flag on the superblock as well as
+ * reporting an error message.  This function should be called when
+ * NILFS detects incoherences or defects of meta data on disk.
  *
- * nilfs_error() sets an ERROR_FS flag on the superblock as well as
- * reporting an error message.  It should be called when NILFS detects
- * incoherences or defects of meta data on disk.  As for sustainable
- * errors such as a single-shot I/O error, nilfs_warning() or the printk()
- * function should be used instead.
+ * This implements the body of nilfs_error() macro.  Normally,
+ * nilfs_error() should be used.  As for sustainable errors such as a
+ * single-shot I/O error, nilfs_msg() should be used instead.
  *
- * The segment constructor must not call this function because it can
- * kill itself.
+ * Callers should not add a trailing newline since this will do it.
  */
-void nilfs_error(struct super_block *sb, const char *function,
-                const char *fmt, ...)
+void __nilfs_error(struct super_block *sb, const char *function,
+                  const char *fmt, ...)
 {
        struct the_nilfs *nilfs = sb->s_fs_info;
        struct va_format vaf;
@@ -133,24 +150,6 @@ void nilfs_error(struct super_block *sb, const char *function,
                      sb->s_id);
 }
 
-void nilfs_warning(struct super_block *sb, const char *function,
-                  const char *fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-
-       va_start(args, fmt);
-
-       vaf.fmt = fmt;
-       vaf.va = &args;
-
-       printk(KERN_WARNING "NILFS warning (device %s): %s: %pV\n",
-              sb->s_id, function, &vaf);
-
-       va_end(args);
-}
-
-
 struct inode *nilfs_alloc_inode(struct super_block *sb)
 {
        struct nilfs_inode_info *ii;
@@ -196,8 +195,8 @@ static int nilfs_sync_super(struct super_block *sb, int flag)
        }
 
        if (unlikely(err)) {
-               printk(KERN_ERR
-                      "NILFS: unable to write superblock (err=%d)\n", err);
+               nilfs_msg(sb, KERN_ERR, "unable to write superblock: err=%d",
+                         err);
                if (err == -EIO && nilfs->ns_sbh[1]) {
                        /*
                         * sbp[0] points to newer log than sbp[1],
@@ -267,8 +266,7 @@ struct nilfs_super_block **nilfs_prepare_super(struct super_block *sb,
                    sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) {
                        memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
                } else {
-                       printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
-                              sb->s_id);
+                       nilfs_msg(sb, KERN_CRIT, "superblock broke");
                        return NULL;
                }
        } else if (sbp[1] &&
@@ -378,9 +376,9 @@ static int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off)
        offset = sb2off & (nilfs->ns_blocksize - 1);
        nsbh = sb_getblk(sb, newblocknr);
        if (!nsbh) {
-               printk(KERN_WARNING
-                      "NILFS warning: unable to move secondary superblock "
-                      "to block %llu\n", (unsigned long long)newblocknr);
+               nilfs_msg(sb, KERN_WARNING,
+                         "unable to move secondary superblock to block %llu",
+                         (unsigned long long)newblocknr);
                ret = -EIO;
                goto out;
        }
@@ -543,10 +541,9 @@ int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
        up_read(&nilfs->ns_segctor_sem);
        if (unlikely(err)) {
                if (err == -ENOENT || err == -EINVAL) {
-                       printk(KERN_ERR
-                              "NILFS: Invalid checkpoint "
-                              "(checkpoint number=%llu)\n",
-                              (unsigned long long)cno);
+                       nilfs_msg(sb, KERN_ERR,
+                                 "Invalid checkpoint (checkpoint number=%llu)",
+                                 (unsigned long long)cno);
                        err = -EINVAL;
                }
                goto failed;
@@ -642,9 +639,8 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        err = nilfs_ifile_count_free_inodes(root->ifile,
                                            &nmaxinodes, &nfreeinodes);
        if (unlikely(err)) {
-               printk(KERN_WARNING
-                       "NILFS warning: fail to count free inodes: err %d.\n",
-                       err);
+               nilfs_msg(sb, KERN_WARNING,
+                         "failed to count free inodes: err=%d", err);
                if (err == -ERANGE) {
                        /*
                         * If nilfs_palloc_count_max_entries() returns
@@ -776,9 +772,9 @@ static int parse_options(char *options, struct super_block *sb, int is_remount)
                        break;
                case Opt_snapshot:
                        if (is_remount) {
-                               printk(KERN_ERR
-                                      "NILFS: \"%s\" option is invalid "
-                                      "for remount.\n", p);
+                               nilfs_msg(sb, KERN_ERR,
+                                         "\"%s\" option is invalid for remount",
+                                         p);
                                return 0;
                        }
                        break;
@@ -792,8 +788,8 @@ static int parse_options(char *options, struct super_block *sb, int is_remount)
                        nilfs_clear_opt(nilfs, DISCARD);
                        break;
                default:
-                       printk(KERN_ERR
-                              "NILFS: Unrecognized mount option \"%s\"\n", p);
+                       nilfs_msg(sb, KERN_ERR,
+                                 "unrecognized mount option \"%s\"", p);
                        return 0;
                }
        }
@@ -829,12 +825,10 @@ static int nilfs_setup_super(struct super_block *sb, int is_mount)
        mnt_count = le16_to_cpu(sbp[0]->s_mnt_count);
 
        if (nilfs->ns_mount_state & NILFS_ERROR_FS) {
-               printk(KERN_WARNING
-                      "NILFS warning: mounting fs with errors\n");
+               nilfs_msg(sb, KERN_WARNING, "mounting fs with errors");
 #if 0
        } else if (max_mnt_count >= 0 && mnt_count >= max_mnt_count) {
-               printk(KERN_WARNING
-                      "NILFS warning: maximal mount count reached\n");
+               nilfs_msg(sb, KERN_WARNING, "maximal mount count reached");
 #endif
        }
        if (!max_mnt_count)
@@ -897,17 +891,17 @@ int nilfs_check_feature_compatibility(struct super_block *sb,
        features = le64_to_cpu(sbp->s_feature_incompat) &
                ~NILFS_FEATURE_INCOMPAT_SUPP;
        if (features) {
-               printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
-                      "optional features (%llx)\n",
-                      (unsigned long long)features);
+               nilfs_msg(sb, KERN_ERR,
+                         "couldn't mount because of unsupported optional features (%llx)",
+                         (unsigned long long)features);
                return -EINVAL;
        }
        features = le64_to_cpu(sbp->s_feature_compat_ro) &
                ~NILFS_FEATURE_COMPAT_RO_SUPP;
        if (!(sb->s_flags & MS_RDONLY) && features) {
-               printk(KERN_ERR "NILFS: couldn't mount RDWR because of "
-                      "unsupported optional features (%llx)\n",
-                      (unsigned long long)features);
+               nilfs_msg(sb, KERN_ERR,
+                         "couldn't mount RDWR because of unsupported optional features (%llx)",
+                         (unsigned long long)features);
                return -EINVAL;
        }
        return 0;
@@ -923,13 +917,13 @@ static int nilfs_get_root_dentry(struct super_block *sb,
 
        inode = nilfs_iget(sb, root, NILFS_ROOT_INO);
        if (IS_ERR(inode)) {
-               printk(KERN_ERR "NILFS: get root inode failed\n");
                ret = PTR_ERR(inode);
+               nilfs_msg(sb, KERN_ERR, "error %d getting root inode", ret);
                goto out;
        }
        if (!S_ISDIR(inode->i_mode) || !inode->i_blocks || !inode->i_size) {
                iput(inode);
-               printk(KERN_ERR "NILFS: corrupt root inode.\n");
+               nilfs_msg(sb, KERN_ERR, "corrupt root inode");
                ret = -EINVAL;
                goto out;
        }
@@ -957,7 +951,7 @@ static int nilfs_get_root_dentry(struct super_block *sb,
        return ret;
 
  failed_dentry:
-       printk(KERN_ERR "NILFS: get root dentry failed\n");
+       nilfs_msg(sb, KERN_ERR, "error %d getting root dentry", ret);
        goto out;
 }
 
@@ -977,18 +971,18 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
                ret = (ret == -ENOENT) ? -EINVAL : ret;
                goto out;
        } else if (!ret) {
-               printk(KERN_ERR "NILFS: The specified checkpoint is "
-                      "not a snapshot (checkpoint number=%llu).\n",
-                      (unsigned long long)cno);
+               nilfs_msg(s, KERN_ERR,
+                         "The specified checkpoint is not a snapshot (checkpoint number=%llu)",
+                         (unsigned long long)cno);
                ret = -EINVAL;
                goto out;
        }
 
        ret = nilfs_attach_checkpoint(s, cno, false, &root);
        if (ret) {
-               printk(KERN_ERR "NILFS: error loading snapshot "
-                      "(checkpoint number=%llu).\n",
-              (unsigned long long)cno);
+               nilfs_msg(s, KERN_ERR,
+                         "error %d while loading snapshot (checkpoint number=%llu)",
+                         ret, (unsigned long long)cno);
                goto out;
        }
        ret = nilfs_get_root_dentry(s, root, root_dentry);
@@ -1058,7 +1052,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        __u64 cno;
        int err;
 
-       nilfs = alloc_nilfs(sb->s_bdev);
+       nilfs = alloc_nilfs(sb);
        if (!nilfs)
                return -ENOMEM;
 
@@ -1083,8 +1077,9 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        cno = nilfs_last_cno(nilfs);
        err = nilfs_attach_checkpoint(sb, cno, true, &fsroot);
        if (err) {
-               printk(KERN_ERR "NILFS: error loading last checkpoint "
-                      "(checkpoint number=%llu).\n", (unsigned long long)cno);
+               nilfs_msg(sb, KERN_ERR,
+                         "error %d while loading last checkpoint (checkpoint number=%llu)",
+                         err, (unsigned long long)cno);
                goto failed_unload;
        }
 
@@ -1144,9 +1139,8 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
        err = -EINVAL;
 
        if (!nilfs_valid_fs(nilfs)) {
-               printk(KERN_WARNING "NILFS (device %s): couldn't "
-                      "remount because the filesystem is in an "
-                      "incomplete recovery state.\n", sb->s_id);
+               nilfs_msg(sb, KERN_WARNING,
+                         "couldn't remount because the filesystem is in an incomplete recovery state");
                goto restore_opts;
        }
 
@@ -1178,10 +1172,9 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
                        ~NILFS_FEATURE_COMPAT_RO_SUPP;
                up_read(&nilfs->ns_sem);
                if (features) {
-                       printk(KERN_WARNING "NILFS (device %s): couldn't "
-                              "remount RDWR because of unsupported optional "
-                              "features (%llx)\n",
-                              sb->s_id, (unsigned long long)features);
+                       nilfs_msg(sb, KERN_WARNING,
+                                 "couldn't remount RDWR because of unsupported optional features (%llx)",
+                                 (unsigned long long)features);
                        err = -EROFS;
                        goto restore_opts;
                }
@@ -1212,6 +1205,38 @@ struct nilfs_super_data {
        int flags;
 };
 
+static int nilfs_parse_snapshot_option(const char *option,
+                                      const substring_t *arg,
+                                      struct nilfs_super_data *sd)
+{
+       unsigned long long val;
+       const char *msg = NULL;
+       int err;
+
+       if (!(sd->flags & MS_RDONLY)) {
+               msg = "read-only option is not specified";
+               goto parse_error;
+       }
+
+       err = kstrtoull(arg->from, 0, &val);
+       if (err) {
+               if (err == -ERANGE)
+                       msg = "too large checkpoint number";
+               else
+                       msg = "malformed argument";
+               goto parse_error;
+       } else if (val == 0) {
+               msg = "invalid checkpoint number 0";
+               goto parse_error;
+       }
+       sd->cno = val;
+       return 0;
+
+parse_error:
+       nilfs_msg(NULL, KERN_ERR, "invalid option \"%s\": %s", option, msg);
+       return 1;
+}
+
 /**
  * nilfs_identify - pre-read mount options needed to identify mount instance
  * @data: mount options
@@ -1228,24 +1253,9 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd)
                p = strsep(&options, ",");
                if (p != NULL && *p) {
                        token = match_token(p, tokens, args);
-                       if (token == Opt_snapshot) {
-                               if (!(sd->flags & MS_RDONLY)) {
-                                       ret++;
-                               } else {
-                                       sd->cno = simple_strtoull(args[0].from,
-                                                                 NULL, 0);
-                                       /*
-                                        * No need to see the end pointer;
-                                        * match_token() has done syntax
-                                        * checking.
-                                        */
-                                       if (sd->cno == 0)
-                                               ret++;
-                               }
-                       }
-                       if (ret)
-                               printk(KERN_ERR
-                                      "NILFS: invalid mount option: %s\n", p);
+                       if (token == Opt_snapshot)
+                               ret = nilfs_parse_snapshot_option(p, &args[0],
+                                                                 sd);
                }
                if (!options)
                        break;
@@ -1326,10 +1336,10 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
        } else if (!sd.cno) {
                if (nilfs_tree_is_busy(s->s_root)) {
                        if ((flags ^ s->s_flags) & MS_RDONLY) {
-                               printk(KERN_ERR "NILFS: the device already "
-                                      "has a %s mount.\n",
-                                      (s->s_flags & MS_RDONLY) ?
-                                      "read-only" : "read/write");
+                               nilfs_msg(s, KERN_ERR,
+                                         "the device already has a %s mount.",
+                                         (s->s_flags & MS_RDONLY) ?
+                                         "read-only" : "read/write");
                                err = -EBUSY;
                                goto failed_super;
                        }
index 8ffa42b..490303e 100644 (file)
@@ -272,8 +272,8 @@ nilfs_checkpoints_checkpoints_number_show(struct nilfs_checkpoints_attr *attr,
        err = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
        up_read(&nilfs->ns_segctor_sem);
        if (err < 0) {
-               printk(KERN_ERR "NILFS: unable to get checkpoint stat: err=%d\n",
-                       err);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "unable to get checkpoint stat: err=%d", err);
                return err;
        }
 
@@ -295,8 +295,8 @@ nilfs_checkpoints_snapshots_number_show(struct nilfs_checkpoints_attr *attr,
        err = nilfs_cpfile_get_stat(nilfs->ns_cpfile, &cpstat);
        up_read(&nilfs->ns_segctor_sem);
        if (err < 0) {
-               printk(KERN_ERR "NILFS: unable to get checkpoint stat: err=%d\n",
-                       err);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "unable to get checkpoint stat: err=%d", err);
                return err;
        }
 
@@ -326,9 +326,9 @@ nilfs_checkpoints_next_checkpoint_show(struct nilfs_checkpoints_attr *attr,
 {
        __u64 cno;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        cno = nilfs->ns_cno;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", cno);
 }
@@ -414,8 +414,8 @@ nilfs_segments_dirty_segments_show(struct nilfs_segments_attr *attr,
        err = nilfs_sufile_get_stat(nilfs->ns_sufile, &sustat);
        up_read(&nilfs->ns_segctor_sem);
        if (err < 0) {
-               printk(KERN_ERR "NILFS: unable to get segment stat: err=%d\n",
-                       err);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "unable to get segment stat: err=%d", err);
                return err;
        }
 
@@ -511,9 +511,9 @@ nilfs_segctor_current_seg_sequence_show(struct nilfs_segctor_attr *attr,
 {
        u64 seg_seq;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        seg_seq = nilfs->ns_seg_seq;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", seg_seq);
 }
@@ -525,9 +525,9 @@ nilfs_segctor_current_last_full_seg_show(struct nilfs_segctor_attr *attr,
 {
        __u64 segnum;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        segnum = nilfs->ns_segnum;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", segnum);
 }
@@ -539,9 +539,9 @@ nilfs_segctor_next_full_seg_show(struct nilfs_segctor_attr *attr,
 {
        __u64 nextnum;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        nextnum = nilfs->ns_nextnum;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", nextnum);
 }
@@ -553,9 +553,9 @@ nilfs_segctor_next_pseg_offset_show(struct nilfs_segctor_attr *attr,
 {
        unsigned long pseg_offset;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        pseg_offset = nilfs->ns_pseg_offset;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%lu\n", pseg_offset);
 }
@@ -567,9 +567,9 @@ nilfs_segctor_next_checkpoint_show(struct nilfs_segctor_attr *attr,
 {
        __u64 cno;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        cno = nilfs->ns_cno;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", cno);
 }
@@ -581,9 +581,9 @@ nilfs_segctor_last_seg_write_time_show(struct nilfs_segctor_attr *attr,
 {
        time_t ctime;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        ctime = nilfs->ns_ctime;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return NILFS_SHOW_TIME(ctime, buf);
 }
@@ -595,9 +595,9 @@ nilfs_segctor_last_seg_write_time_secs_show(struct nilfs_segctor_attr *attr,
 {
        time_t ctime;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        ctime = nilfs->ns_ctime;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)ctime);
 }
@@ -609,9 +609,9 @@ nilfs_segctor_last_nongc_write_time_show(struct nilfs_segctor_attr *attr,
 {
        time_t nongc_ctime;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        nongc_ctime = nilfs->ns_nongc_ctime;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return NILFS_SHOW_TIME(nongc_ctime, buf);
 }
@@ -623,9 +623,9 @@ nilfs_segctor_last_nongc_write_time_secs_show(struct nilfs_segctor_attr *attr,
 {
        time_t nongc_ctime;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        nongc_ctime = nilfs->ns_nongc_ctime;
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%llu\n",
                        (unsigned long long)nongc_ctime);
@@ -638,9 +638,9 @@ nilfs_segctor_dirty_data_blocks_count_show(struct nilfs_segctor_attr *attr,
 {
        u32 ndirtyblks;
 
-       down_read(&nilfs->ns_sem);
+       down_read(&nilfs->ns_segctor_sem);
        ndirtyblks = atomic_read(&nilfs->ns_ndirtyblks);
-       up_read(&nilfs->ns_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", ndirtyblks);
 }
@@ -789,14 +789,15 @@ nilfs_superblock_sb_update_frequency_store(struct nilfs_superblock_attr *attr,
 
        err = kstrtouint(skip_spaces(buf), 0, &val);
        if (err) {
-               printk(KERN_ERR "NILFS: unable to convert string: err=%d\n",
-                       err);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "unable to convert string: err=%d", err);
                return err;
        }
 
        if (val < NILFS_SB_FREQ) {
                val = NILFS_SB_FREQ;
-               printk(KERN_WARNING "NILFS: superblock update frequency cannot be lesser than 10 seconds\n");
+               nilfs_msg(nilfs->ns_sb, KERN_WARNING,
+                         "superblock update frequency cannot be lesser than 10 seconds");
        }
 
        down_write(&nilfs->ns_sem);
@@ -999,7 +1000,8 @@ int nilfs_sysfs_create_device_group(struct super_block *sb)
        nilfs->ns_dev_subgroups = kzalloc(devgrp_size, GFP_KERNEL);
        if (unlikely(!nilfs->ns_dev_subgroups)) {
                err = -ENOMEM;
-               printk(KERN_ERR "NILFS: unable to allocate memory for device group\n");
+               nilfs_msg(sb, KERN_ERR,
+                         "unable to allocate memory for device group");
                goto failed_create_device_group;
        }
 
@@ -1109,15 +1111,15 @@ int __init nilfs_sysfs_init(void)
        nilfs_kset = kset_create_and_add(NILFS_ROOT_GROUP_NAME, NULL, fs_kobj);
        if (!nilfs_kset) {
                err = -ENOMEM;
-               printk(KERN_ERR "NILFS: unable to create sysfs entry: err %d\n",
-                       err);
+               nilfs_msg(NULL, KERN_ERR,
+                         "unable to create sysfs entry: err=%d", err);
                goto failed_sysfs_init;
        }
 
        err = sysfs_create_group(&nilfs_kset->kobj, &nilfs_feature_attr_group);
        if (unlikely(err)) {
-               printk(KERN_ERR "NILFS: unable to create feature group: err %d\n",
-                       err);
+               nilfs_msg(NULL, KERN_ERR,
+                         "unable to create feature group: err=%d", err);
                goto cleanup_sysfs_init;
        }
 
index e9fd241..2dd75bf 100644 (file)
@@ -56,12 +56,12 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
 
 /**
  * alloc_nilfs - allocate a nilfs object
- * @bdev: block device to which the_nilfs is related
+ * @sb: super block instance
  *
  * Return Value: On success, pointer to the_nilfs is returned.
  * On error, NULL is returned.
  */
-struct the_nilfs *alloc_nilfs(struct block_device *bdev)
+struct the_nilfs *alloc_nilfs(struct super_block *sb)
 {
        struct the_nilfs *nilfs;
 
@@ -69,7 +69,8 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
        if (!nilfs)
                return NULL;
 
-       nilfs->ns_bdev = bdev;
+       nilfs->ns_sb = sb;
+       nilfs->ns_bdev = sb->s_bdev;
        atomic_set(&nilfs->ns_ndirtyblks, 0);
        init_rwsem(&nilfs->ns_sem);
        mutex_init(&nilfs->ns_snapshot_mount_mutex);
@@ -191,7 +192,10 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
                nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
        nilfs->ns_cno = nilfs->ns_last_cno + 1;
        if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
-               printk(KERN_ERR "NILFS invalid last segment number.\n");
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "pointed segment number is out of range: segnum=%llu, nsegments=%lu",
+                         (unsigned long long)nilfs->ns_segnum,
+                         nilfs->ns_nsegments);
                ret = -EINVAL;
        }
        return ret;
@@ -215,12 +219,12 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
        int err;
 
        if (!valid_fs) {
-               printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n");
+               nilfs_msg(sb, KERN_WARNING, "mounting unchecked fs");
                if (s_flags & MS_RDONLY) {
-                       printk(KERN_INFO "NILFS: INFO: recovery "
-                              "required for readonly filesystem.\n");
-                       printk(KERN_INFO "NILFS: write access will "
-                              "be enabled during recovery.\n");
+                       nilfs_msg(sb, KERN_INFO,
+                                 "recovery required for readonly filesystem");
+                       nilfs_msg(sb, KERN_INFO,
+                                 "write access will be enabled during recovery");
                }
        }
 
@@ -235,13 +239,12 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
                        goto scan_error;
 
                if (!nilfs_valid_sb(sbp[1])) {
-                       printk(KERN_WARNING
-                              "NILFS warning: unable to fall back to spare"
-                              "super block\n");
+                       nilfs_msg(sb, KERN_WARNING,
+                                 "unable to fall back to spare super block");
                        goto scan_error;
                }
-               printk(KERN_INFO
-                      "NILFS: try rollback from an earlier position\n");
+               nilfs_msg(sb, KERN_INFO,
+                         "trying rollback from an earlier position");
 
                /*
                 * restore super block with its spare and reconfigure
@@ -254,10 +257,9 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
                /* verify consistency between two super blocks */
                blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
                if (blocksize != nilfs->ns_blocksize) {
-                       printk(KERN_WARNING
-                              "NILFS warning: blocksize differs between "
-                              "two super blocks (%d != %d)\n",
-                              blocksize, nilfs->ns_blocksize);
+                       nilfs_msg(sb, KERN_WARNING,
+                                 "blocksize differs between two super blocks (%d != %d)",
+                                 blocksize, nilfs->ns_blocksize);
                        goto scan_error;
                }
 
@@ -276,7 +278,8 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
 
        err = nilfs_load_super_root(nilfs, sb, ri.ri_super_root);
        if (unlikely(err)) {
-               printk(KERN_ERR "NILFS: error loading super root.\n");
+               nilfs_msg(sb, KERN_ERR, "error %d while loading super root",
+                         err);
                goto failed;
        }
 
@@ -287,30 +290,29 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
                __u64 features;
 
                if (nilfs_test_opt(nilfs, NORECOVERY)) {
-                       printk(KERN_INFO "NILFS: norecovery option specified. "
-                              "skipping roll-forward recovery\n");
+                       nilfs_msg(sb, KERN_INFO,
+                                 "norecovery option specified, skipping roll-forward recovery");
                        goto skip_recovery;
                }
                features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
                        ~NILFS_FEATURE_COMPAT_RO_SUPP;
                if (features) {
-                       printk(KERN_ERR "NILFS: couldn't proceed with "
-                              "recovery because of unsupported optional "
-                              "features (%llx)\n",
-                              (unsigned long long)features);
+                       nilfs_msg(sb, KERN_ERR,
+                                 "couldn't proceed with recovery because of unsupported optional features (%llx)",
+                                 (unsigned long long)features);
                        err = -EROFS;
                        goto failed_unload;
                }
                if (really_read_only) {
-                       printk(KERN_ERR "NILFS: write access "
-                              "unavailable, cannot proceed.\n");
+                       nilfs_msg(sb, KERN_ERR,
+                                 "write access unavailable, cannot proceed");
                        err = -EROFS;
                        goto failed_unload;
                }
                sb->s_flags &= ~MS_RDONLY;
        } else if (nilfs_test_opt(nilfs, NORECOVERY)) {
-               printk(KERN_ERR "NILFS: recovery cancelled because norecovery "
-                      "option was specified for a read/write mount\n");
+               nilfs_msg(sb, KERN_ERR,
+                         "recovery cancelled because norecovery option was specified for a read/write mount");
                err = -EINVAL;
                goto failed_unload;
        }
@@ -325,11 +327,12 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
        up_write(&nilfs->ns_sem);
 
        if (err) {
-               printk(KERN_ERR "NILFS: failed to update super block. "
-                      "recovery unfinished.\n");
+               nilfs_msg(sb, KERN_ERR,
+                         "error %d updating super block. recovery unfinished.",
+                         err);
                goto failed_unload;
        }
-       printk(KERN_INFO "NILFS: recovery complete.\n");
+       nilfs_msg(sb, KERN_INFO, "recovery complete");
 
  skip_recovery:
        nilfs_clear_recovery_info(&ri);
@@ -337,7 +340,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
        return 0;
 
  scan_error:
-       printk(KERN_ERR "NILFS: error searching super root.\n");
+       nilfs_msg(sb, KERN_ERR, "error %d while searching super root", err);
        goto failed;
 
  failed_unload:
@@ -384,12 +387,11 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                                   struct nilfs_super_block *sbp)
 {
        if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) {
-               printk(KERN_ERR "NILFS: unsupported revision "
-                      "(superblock rev.=%d.%d, current rev.=%d.%d). "
-                      "Please check the version of mkfs.nilfs.\n",
-                      le32_to_cpu(sbp->s_rev_level),
-                      le16_to_cpu(sbp->s_minor_rev_level),
-                      NILFS_CURRENT_REV, NILFS_MINOR_REV);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "unsupported revision (superblock rev.=%d.%d, current rev.=%d.%d). Please check the version of mkfs.nilfs(2).",
+                         le32_to_cpu(sbp->s_rev_level),
+                         le16_to_cpu(sbp->s_minor_rev_level),
+                         NILFS_CURRENT_REV, NILFS_MINOR_REV);
                return -EINVAL;
        }
        nilfs->ns_sbsize = le16_to_cpu(sbp->s_bytes);
@@ -398,12 +400,14 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
 
        nilfs->ns_inode_size = le16_to_cpu(sbp->s_inode_size);
        if (nilfs->ns_inode_size > nilfs->ns_blocksize) {
-               printk(KERN_ERR "NILFS: too large inode size: %d bytes.\n",
-                      nilfs->ns_inode_size);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "too large inode size: %d bytes",
+                         nilfs->ns_inode_size);
                return -EINVAL;
        } else if (nilfs->ns_inode_size < NILFS_MIN_INODE_SIZE) {
-               printk(KERN_ERR "NILFS: too small inode size: %d bytes.\n",
-                      nilfs->ns_inode_size);
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "too small inode size: %d bytes",
+                         nilfs->ns_inode_size);
                return -EINVAL;
        }
 
@@ -411,7 +415,9 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
 
        nilfs->ns_blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment);
        if (nilfs->ns_blocks_per_segment < NILFS_SEG_MIN_BLOCKS) {
-               printk(KERN_ERR "NILFS: too short segment.\n");
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "too short segment: %lu blocks",
+                         nilfs->ns_blocks_per_segment);
                return -EINVAL;
        }
 
@@ -420,7 +426,9 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                le32_to_cpu(sbp->s_r_segments_percentage);
        if (nilfs->ns_r_segments_percentage < 1 ||
            nilfs->ns_r_segments_percentage > 99) {
-               printk(KERN_ERR "NILFS: invalid reserved segments percentage.\n");
+               nilfs_msg(nilfs->ns_sb, KERN_ERR,
+                         "invalid reserved segments percentage: %lu",
+                         nilfs->ns_r_segments_percentage);
                return -EINVAL;
        }
 
@@ -504,16 +512,16 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
 
        if (!sbp[0]) {
                if (!sbp[1]) {
-                       printk(KERN_ERR "NILFS: unable to read superblock\n");
+                       nilfs_msg(sb, KERN_ERR, "unable to read superblock");
                        return -EIO;
                }
-               printk(KERN_WARNING
-                      "NILFS warning: unable to read primary superblock "
-                      "(blocksize = %d)\n", blocksize);
+               nilfs_msg(sb, KERN_WARNING,
+                         "unable to read primary superblock (blocksize = %d)",
+                         blocksize);
        } else if (!sbp[1]) {
-               printk(KERN_WARNING
-                      "NILFS warning: unable to read secondary superblock "
-                      "(blocksize = %d)\n", blocksize);
+               nilfs_msg(sb, KERN_WARNING,
+                         "unable to read secondary superblock (blocksize = %d)",
+                         blocksize);
        }
 
        /*
@@ -535,14 +543,14 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
        }
        if (!valid[swp]) {
                nilfs_release_super_block(nilfs);
-               printk(KERN_ERR "NILFS: Can't find nilfs on dev %s.\n",
-                      sb->s_id);
+               nilfs_msg(sb, KERN_ERR, "couldn't find nilfs on the device");
                return -EINVAL;
        }
 
        if (!valid[!swp])
-               printk(KERN_WARNING "NILFS warning: broken superblock. "
-                      "using spare superblock (blocksize = %d).\n", blocksize);
+               nilfs_msg(sb, KERN_WARNING,
+                         "broken superblock, retrying with spare superblock (blocksize = %d)",
+                         blocksize);
        if (swp)
                nilfs_swap_super_block(nilfs);
 
@@ -576,7 +584,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
 
        blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE);
        if (!blocksize) {
-               printk(KERN_ERR "NILFS: unable to set blocksize\n");
+               nilfs_msg(sb, KERN_ERR, "unable to set blocksize");
                err = -EINVAL;
                goto out;
        }
@@ -595,8 +603,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
        blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
        if (blocksize < NILFS_MIN_BLOCK_SIZE ||
            blocksize > NILFS_MAX_BLOCK_SIZE) {
-               printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
-                      "filesystem blocksize %d\n", blocksize);
+               nilfs_msg(sb, KERN_ERR,
+                         "couldn't mount because of unsupported filesystem blocksize %d",
+                         blocksize);
                err = -EINVAL;
                goto failed_sbh;
        }
@@ -604,10 +613,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
                int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
 
                if (blocksize < hw_blocksize) {
-                       printk(KERN_ERR
-                              "NILFS: blocksize %d too small for device "
-                              "(sector-size = %d).\n",
-                              blocksize, hw_blocksize);
+                       nilfs_msg(sb, KERN_ERR,
+                                 "blocksize %d too small for device (sector-size = %d)",
+                                 blocksize, hw_blocksize);
                        err = -EINVAL;
                        goto failed_sbh;
                }
index 79369fd..b305c6f 100644 (file)
@@ -43,6 +43,7 @@ enum {
  * struct the_nilfs - struct to supervise multiple nilfs mount points
  * @ns_flags: flags
  * @ns_flushed_device: flag indicating if all volatile data was flushed
+ * @ns_sb: back pointer to super block instance
  * @ns_bdev: block device
  * @ns_sem: semaphore for shared states
  * @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
@@ -102,6 +103,7 @@ struct the_nilfs {
        unsigned long           ns_flags;
        int                     ns_flushed_device;
 
+       struct super_block     *ns_sb;
        struct block_device    *ns_bdev;
        struct rw_semaphore     ns_sem;
        struct mutex            ns_snapshot_mount_mutex;
@@ -120,11 +122,8 @@ struct the_nilfs {
        unsigned int            ns_sb_update_freq;
 
        /*
-        * Following fields are dedicated to a writable FS-instance.
-        * Except for the period seeking checkpoint, code outside the segment
-        * constructor must lock a segment semaphore while accessing these
-        * fields.
-        * The writable FS-instance is sole during a lifetime of the_nilfs.
+        * The following fields are updated by a writable FS-instance.
+        * These fields are protected by ns_segctor_sem outside load_nilfs().
         */
        u64                     ns_seg_seq;
        __u64                   ns_segnum;
@@ -281,7 +280,7 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
 }
 
 void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
-struct the_nilfs *alloc_nilfs(struct block_device *bdev);
+struct the_nilfs *alloc_nilfs(struct super_block *sb);
 void destroy_nilfs(struct the_nilfs *nilfs);
 int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data);
 int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb);
index 460c0ce..7dabbc3 100644 (file)
@@ -6106,6 +6106,43 @@ void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
        }
 }
 
+/*
+ * Try to flush truncate logs if we can free enough clusters from it.
+ * As for return value, "< 0" means error, "0" no space and "1" means
+ * we have freed enough spaces and let the caller try to allocate again.
+ */
+int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
+                                       unsigned int needed)
+{
+       tid_t target;
+       int ret = 0;
+       unsigned int truncated_clusters;
+
+       inode_lock(osb->osb_tl_inode);
+       truncated_clusters = osb->truncated_clusters;
+       inode_unlock(osb->osb_tl_inode);
+
+       /*
+        * Check whether we can succeed in allocating if we free
+        * the truncate log.
+        */
+       if (truncated_clusters < needed)
+               goto out;
+
+       ret = ocfs2_flush_truncate_log(osb);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (jbd2_journal_start_commit(osb->journal->j_journal, &target)) {
+               jbd2_log_wait_commit(osb->journal->j_journal, target);
+               ret = 1;
+       }
+out:
+       return ret;
+}
+
 static int ocfs2_get_truncate_log_info(struct ocfs2_super *osb,
                                       int slot_num,
                                       struct inode **tl_inode,
index f3dc1b0..4a5152e 100644 (file)
@@ -188,6 +188,8 @@ int ocfs2_truncate_log_append(struct ocfs2_super *osb,
                              u64 start_blk,
                              unsigned int num_clusters);
 int __ocfs2_flush_truncate_log(struct ocfs2_super *osb);
+int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
+                                  unsigned int needed);
 
 /*
  * Process local structure which describes the block unlinks done
index af2adfc..98d3654 100644 (file)
@@ -1645,43 +1645,6 @@ static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
        return ret;
 }
 
-/*
- * Try to flush truncate logs if we can free enough clusters from it.
- * As for return value, "< 0" means error, "0" no space and "1" means
- * we have freed enough spaces and let the caller try to allocate again.
- */
-static int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
-                                         unsigned int needed)
-{
-       tid_t target;
-       int ret = 0;
-       unsigned int truncated_clusters;
-
-       inode_lock(osb->osb_tl_inode);
-       truncated_clusters = osb->truncated_clusters;
-       inode_unlock(osb->osb_tl_inode);
-
-       /*
-        * Check whether we can succeed in allocating if we free
-        * the truncate log.
-        */
-       if (truncated_clusters < needed)
-               goto out;
-
-       ret = ocfs2_flush_truncate_log(osb);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       if (jbd2_journal_start_commit(osb->journal->j_journal, &target)) {
-               jbd2_log_wait_commit(osb->journal->j_journal, target);
-               ret = 1;
-       }
-out:
-       return ret;
-}
-
 int ocfs2_write_begin_nolock(struct address_space *mapping,
                             loff_t pos, unsigned len, ocfs2_write_type_t type,
                             struct page **pagep, void **fsdata,
index 8107d0d..e9f3705 100644 (file)
@@ -1004,6 +1004,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
 int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
                          u8 nodenum, u8 *real_master);
 
+void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
+               struct dlm_lock_resource *res);
 
 int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
                               struct dlm_lock_resource *res,
index 12e064b..533bd52 100644 (file)
@@ -172,12 +172,10 @@ void __dlm_unhash_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
 void __dlm_insert_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
 {
        struct hlist_head *bucket;
-       struct qstr *q;
 
        assert_spin_locked(&dlm->spinlock);
 
-       q = &res->lockname;
-       bucket = dlm_lockres_hash(dlm, q->hash);
+       bucket = dlm_lockres_hash(dlm, res->lockname.hash);
 
        /* get a reference for our hashtable */
        dlm_lockres_get(res);
index 13719d3..6ea06f8 100644 (file)
@@ -2276,9 +2276,12 @@ int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
                mlog(ML_ERROR, "%s: res %.*s, DEREF to node %u got %d\n",
                     dlm->name, namelen, lockname, res->owner, r);
                dlm_print_one_lock_resource(res);
-               BUG();
-       }
-       return ret ? ret : r;
+               if (r == -ENOMEM)
+                       BUG();
+       } else
+               ret = r;
+
+       return ret;
 }
 
 int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
@@ -2416,48 +2419,26 @@ int dlm_deref_lockres_done_handler(struct o2net_msg *msg, u32 len, void *data,
        }
 
        spin_lock(&res->spinlock);
-       BUG_ON(!(res->state & DLM_LOCK_RES_DROPPING_REF));
-       if (!list_empty(&res->purge)) {
-               mlog(0, "%s: Removing res %.*s from purgelist\n",
-                       dlm->name, res->lockname.len, res->lockname.name);
-               list_del_init(&res->purge);
-               dlm_lockres_put(res);
-               dlm->purge_count--;
-       }
-
-       if (!__dlm_lockres_unused(res)) {
-               mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
-                       dlm->name, res->lockname.len, res->lockname.name);
-               __dlm_print_one_lock_resource(res);
-               BUG();
-       }
-
-       __dlm_unhash_lockres(dlm, res);
-
-       spin_lock(&dlm->track_lock);
-       if (!list_empty(&res->tracking))
-               list_del_init(&res->tracking);
-       else {
-               mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
-                    dlm->name, res->lockname.len, res->lockname.name);
-               __dlm_print_one_lock_resource(res);
+       if (!(res->state & DLM_LOCK_RES_DROPPING_REF)) {
+               spin_unlock(&res->spinlock);
+               spin_unlock(&dlm->spinlock);
+               mlog(ML_NOTICE, "%s:%.*s: node %u sends deref done "
+                       "but it is already derefed!\n", dlm->name,
+                       res->lockname.len, res->lockname.name, node);
+               ret = 0;
+               goto done;
        }
-       spin_unlock(&dlm->track_lock);
 
-       /* lockres is not in the hash now. drop the flag and wake up
-        * any processes waiting in dlm_get_lock_resource.
-        */
-       res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+       __dlm_do_purge_lockres(dlm, res);
        spin_unlock(&res->spinlock);
        wake_up(&res->wq);
 
-       dlm_lockres_put(res);
-
        spin_unlock(&dlm->spinlock);
 
        ret = 0;
-
 done:
+       if (res)
+               dlm_lockres_put(res);
        dlm_put(dlm);
        return ret;
 }
index f6b3138..dd5cb8b 100644 (file)
@@ -2343,6 +2343,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
        struct dlm_lock_resource *res;
        int i;
        struct hlist_head *bucket;
+       struct hlist_node *tmp;
        struct dlm_lock *lock;
 
 
@@ -2365,7 +2366,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
         */
        for (i = 0; i < DLM_HASH_BUCKETS; i++) {
                bucket = dlm_lockres_hash(dlm, i);
-               hlist_for_each_entry(res, bucket, hash_node) {
+               hlist_for_each_entry_safe(res, tmp, bucket, hash_node) {
                        /* always prune any $RECOVERY entries for dead nodes,
                         * otherwise hangs can occur during later recovery */
                        if (dlm_is_recovery_lock(res->lockname.name,
@@ -2386,8 +2387,17 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
                                                break;
                                        }
                                }
-                               dlm_lockres_clear_refmap_bit(dlm, res,
-                                               dead_node);
+
+                               if ((res->owner == dead_node) &&
+                                                       (res->state & DLM_LOCK_RES_DROPPING_REF)) {
+                                       dlm_lockres_get(res);
+                                       __dlm_do_purge_lockres(dlm, res);
+                                       spin_unlock(&res->spinlock);
+                                       wake_up(&res->wq);
+                                       dlm_lockres_put(res);
+                                       continue;
+                               } else if (res->owner == dlm->node_num)
+                                       dlm_lockres_clear_refmap_bit(dlm, res, dead_node);
                                spin_unlock(&res->spinlock);
                                continue;
                        }
@@ -2398,14 +2408,17 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
                                if (res->state & DLM_LOCK_RES_DROPPING_REF) {
                                        mlog(0, "%s:%.*s: owned by "
                                                "dead node %u, this node was "
-                                               "dropping its ref when it died. "
-                                               "continue, dropping the flag.\n",
+                                               "dropping its ref when master died. "
+                                               "continue, purging the lockres.\n",
                                                dlm->name, res->lockname.len,
                                                res->lockname.name, dead_node);
+                                       dlm_lockres_get(res);
+                                       __dlm_do_purge_lockres(dlm, res);
+                                       spin_unlock(&res->spinlock);
+                                       wake_up(&res->wq);
+                                       dlm_lockres_put(res);
+                                       continue;
                                }
-                               res->state &= ~DLM_LOCK_RES_DROPPING_REF;
-                               dlm_move_lockres_to_recovery_list(dlm,
-                                               res);
                        } else if (res->owner == dlm->node_num) {
                                dlm_free_dead_locks(dlm, res, dead_node);
                                __dlm_lockres_calc_usage(dlm, res);
index 68d239b..838a06d 100644 (file)
@@ -160,6 +160,52 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
        spin_unlock(&dlm->spinlock);
 }
 
+/*
+ * Do the real purge work:
+ *     unhash the lockres, and
+ *     clear flag DLM_LOCK_RES_DROPPING_REF.
+ * It requires dlm and lockres spinlock to be taken.
+ */
+void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
+               struct dlm_lock_resource *res)
+{
+       assert_spin_locked(&dlm->spinlock);
+       assert_spin_locked(&res->spinlock);
+
+       if (!list_empty(&res->purge)) {
+               mlog(0, "%s: Removing res %.*s from purgelist\n",
+                    dlm->name, res->lockname.len, res->lockname.name);
+               list_del_init(&res->purge);
+               dlm_lockres_put(res);
+               dlm->purge_count--;
+       }
+
+       if (!__dlm_lockres_unused(res)) {
+               mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
+                    dlm->name, res->lockname.len, res->lockname.name);
+               __dlm_print_one_lock_resource(res);
+               BUG();
+       }
+
+       __dlm_unhash_lockres(dlm, res);
+
+       spin_lock(&dlm->track_lock);
+       if (!list_empty(&res->tracking))
+               list_del_init(&res->tracking);
+       else {
+               mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
+                    dlm->name, res->lockname.len, res->lockname.name);
+               __dlm_print_one_lock_resource(res);
+       }
+       spin_unlock(&dlm->track_lock);
+
+       /*
+        * lockres is not in the hash now. drop the flag and wake up
+        * any processes waiting in dlm_get_lock_resource.
+        */
+       res->state &= ~DLM_LOCK_RES_DROPPING_REF;
+}
+
 static void dlm_purge_lockres(struct dlm_ctxt *dlm,
                             struct dlm_lock_resource *res)
 {
@@ -175,6 +221,13 @@ static void dlm_purge_lockres(struct dlm_ctxt *dlm,
             res->lockname.len, res->lockname.name, master);
 
        if (!master) {
+               if (res->state & DLM_LOCK_RES_DROPPING_REF) {
+                       mlog(ML_NOTICE, "%s: res %.*s already in DLM_LOCK_RES_DROPPING_REF state\n",
+                               dlm->name, res->lockname.len, res->lockname.name);
+                       spin_unlock(&res->spinlock);
+                       return;
+               }
+
                res->state |= DLM_LOCK_RES_DROPPING_REF;
                /* drop spinlock...  retake below */
                spin_unlock(&res->spinlock);
@@ -203,8 +256,8 @@ static void dlm_purge_lockres(struct dlm_ctxt *dlm,
                dlm->purge_count--;
        }
 
-       if (!master && ret != 0) {
-               mlog(0, "%s: deref %.*s in progress or master goes down\n",
+       if (!master && ret == DLM_DEREF_RESPONSE_INPROG) {
+               mlog(0, "%s: deref %.*s in progress\n",
                        dlm->name, res->lockname.len, res->lockname.name);
                spin_unlock(&res->spinlock);
                return;
index 47b3b2d..ef474cd 100644 (file)
@@ -469,7 +469,7 @@ static int dlmfs_mkdir(struct inode * dir,
 {
        int status;
        struct inode *inode = NULL;
-       struct qstr *domain = &dentry->d_name;
+       const struct qstr *domain = &dentry->d_name;
        struct dlmfs_inode_private *ip;
        struct ocfs2_cluster_connection *conn;
 
@@ -518,7 +518,7 @@ static int dlmfs_create(struct inode *dir,
 {
        int status = 0;
        struct inode *inode;
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
 
        mlog(0, "create %.*s\n", name->len, name->name);
 
index 0499e3f..f70cda2 100644 (file)
@@ -667,7 +667,7 @@ void user_dlm_set_locking_protocol(void)
        ocfs2_stack_glue_set_max_proto_version(&user_dlm_lproto.lp_max_version);
 }
 
-struct ocfs2_cluster_connection *user_dlm_register(struct qstr *name)
+struct ocfs2_cluster_connection *user_dlm_register(const struct qstr *name)
 {
        int rc;
        struct ocfs2_cluster_connection *conn;
index 3b42d79..ede94a6 100644 (file)
@@ -83,7 +83,7 @@ void user_dlm_write_lvb(struct inode *inode,
 ssize_t user_dlm_read_lvb(struct inode *inode,
                          char *val,
                          unsigned int len);
-struct ocfs2_cluster_connection *user_dlm_register(struct qstr *name);
+struct ocfs2_cluster_connection *user_dlm_register(const struct qstr *name);
 void user_dlm_unregister(struct ocfs2_cluster_connection *conn);
 void user_dlm_set_locking_protocol(void);
 
index ced70c8..c9e828e 100644 (file)
@@ -1007,10 +1007,17 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn)
        lc->oc_type = NO_CONTROLD;
 
        rc = dlm_new_lockspace(conn->cc_name, conn->cc_cluster_name,
-                              DLM_LSFL_FS, DLM_LVB_LEN,
+                              DLM_LSFL_FS | DLM_LSFL_NEWEXCL, DLM_LVB_LEN,
                               &ocfs2_ls_ops, conn, &ops_rv, &fsdlm);
-       if (rc)
+       if (rc) {
+               if (rc == -EEXIST || rc == -EPROTO)
+                       printk(KERN_ERR "ocfs2: Unable to create the "
+                               "lockspace %s (%d), because a ocfs2-tools "
+                               "program is running on this file system "
+                               "with the same name lockspace\n",
+                               conn->cc_name, rc);
                goto out;
+       }
 
        if (ops_rv == -EOPNOTSUPP) {
                lc->oc_type = WITH_CONTROLD;
index 2f19aee..ea47120 100644 (file)
@@ -1164,7 +1164,8 @@ static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
                                             int flags,
                                             struct ocfs2_alloc_context **ac)
 {
-       int status;
+       int status, ret = 0;
+       int retried = 0;
 
        *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
        if (!(*ac)) {
@@ -1189,7 +1190,24 @@ static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
        }
 
        if (status == -ENOSPC) {
+retry:
                status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
+               /* Retry if there is sufficient space cached in truncate log */
+               if (status == -ENOSPC && !retried) {
+                       retried = 1;
+                       ocfs2_inode_unlock((*ac)->ac_inode, 1);
+                       inode_unlock((*ac)->ac_inode);
+
+                       ret = ocfs2_try_to_free_truncate_log(osb, bits_wanted);
+                       if (ret == 1)
+                               goto retry;
+
+                       if (ret < 0)
+                               mlog_errno(ret);
+
+                       inode_lock((*ac)->ac_inode);
+                       ocfs2_inode_lock((*ac)->ac_inode, NULL, 1);
+               }
                if (status < 0) {
                        if (status != -ENOSPC)
                                mlog_errno(status);
index bf66cf1..4fd6e25 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -998,6 +998,26 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 }
 EXPORT_SYMBOL(file_open_root);
 
+struct file *filp_clone_open(struct file *oldfile)
+{
+       struct file *file;
+       int retval;
+
+       file = get_empty_filp();
+       if (IS_ERR(file))
+               return file;
+
+       file->f_flags = oldfile->f_flags;
+       retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred);
+       if (retval) {
+               put_filp(file);
+               return ERR_PTR(retval);
+       }
+
+       return file;
+}
+EXPORT_SYMBOL(filp_clone_open);
+
 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
        struct open_flags op;
index 5dfc4f3..00235bf 100644 (file)
@@ -73,6 +73,7 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
                }
        }
 
+       dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
        ret = 1;
 out_release_op:
        op_release(new_op);
@@ -94,6 +95,9 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        int ret;
 
+       if (time_before(jiffies, dentry->d_time))
+               return 1;
+
        if (flags & LOOKUP_RCU)
                return -ECHILD;
 
index 2e63e6d..28a0557 100644 (file)
@@ -262,7 +262,7 @@ int orangefs_getattr(struct vfsmount *mnt,
                     "orangefs_getattr: called on %s\n",
                     dentry->d_name.name);
 
-       ret = orangefs_inode_getattr(inode, 0, 1);
+       ret = orangefs_inode_getattr(inode, 0, 0);
        if (ret == 0) {
                generic_fillattr(inode, kstat);
 
@@ -384,7 +384,7 @@ struct inode *orangefs_iget(struct super_block *sb, struct orangefs_object_kref
        if (!inode || !(inode->i_state & I_NEW))
                return inode;
 
-       error = orangefs_inode_getattr(inode, 1, 0);
+       error = orangefs_inode_getattr(inode, 1, 1);
        if (error) {
                iget_failed(inode);
                return ERR_PTR(error);
@@ -429,7 +429,7 @@ struct inode *orangefs_new_inode(struct super_block *sb, struct inode *dir,
        orangefs_set_inode(inode, ref);
        inode->i_ino = hash;    /* needed for stat etc */
 
-       error = orangefs_inode_getattr(inode, 1, 0);
+       error = orangefs_inode_getattr(inode, 1, 1);
        if (error)
                goto out_iput;
 
index 7e8dfa9..62c5259 100644 (file)
@@ -72,6 +72,8 @@ static int orangefs_create(struct inode *dir,
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
+       ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
                     "%s: dentry instantiated for %s\n",
@@ -181,6 +183,8 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
                goto out;
        }
 
+       dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
+
        inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
        if (IS_ERR(inode)) {
                gossip_debug(GOSSIP_NAME_DEBUG,
@@ -189,6 +193,8 @@ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
                goto out;
        }
 
+       ORANGEFS_I(inode)->getattr_time = jiffies - 1;
+
        gossip_debug(GOSSIP_NAME_DEBUG,
                     "%s:%s:%d "
                     "Found good inode [%lu] with count [%d]\n",
@@ -316,6 +322,8 @@ static int orangefs_symlink(struct inode *dir,
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
+       ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
                     "Inode (Symlink) %pU -> %s\n",
@@ -378,6 +386,8 @@ static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
 
        d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000;
+       ORANGEFS_I(inode)->getattr_time = jiffies - 1;
 
        gossip_debug(GOSSIP_NAME_DEBUG,
                     "Inode (Directory) %pU -> %s\n",
@@ -408,6 +418,8 @@ static int orangefs_rename(struct inode *old_dir,
                     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
                     old_dentry, new_dentry, d_count(new_dentry));
 
+       ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;
+
        new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
        if (!new_op)
                return -EINVAL;
index 4b6e132..633c07a 100644 (file)
@@ -246,6 +246,8 @@ struct orangefs_inode_s {
         * with this object
         */
        unsigned long pinode_flags;
+
+       unsigned long getattr_time;
 };
 
 #define P_ATIME_FLAG 0
@@ -527,7 +529,7 @@ int orangefs_inode_setxattr(struct inode *inode,
                         size_t size,
                         int flags);
 
-int orangefs_inode_getattr(struct inode *inode, int new, int size);
+int orangefs_inode_getattr(struct inode *inode, int new, int bypass);
 
 int orangefs_inode_check_changed(struct inode *inode);
 
@@ -546,6 +548,8 @@ extern struct mutex request_mutex;
 extern int debug;
 extern int op_timeout_secs;
 extern int slot_timeout_secs;
+extern int dcache_timeout_msecs;
+extern int getattr_timeout_msecs;
 extern struct list_head orangefs_superblocks;
 extern spinlock_t orangefs_superblocks_lock;
 extern struct list_head orangefs_request_list;
index 6f072a8..e9fd575 100644 (file)
@@ -47,6 +47,8 @@ struct client_debug_mask client_debug_mask = { NULL, 0, 0 };
 unsigned int kernel_mask_set_mod_init; /* implicitly false */
 int op_timeout_secs = ORANGEFS_DEFAULT_OP_TIMEOUT_SECS;
 int slot_timeout_secs = ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS;
+int dcache_timeout_msecs = 50;
+int getattr_timeout_msecs = 50;
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("ORANGEFS Development Team");
index 5c03113..375708c 100644 (file)
  *                     Slots are requested and waited for,
  *                     the wait times out after slot_timeout_secs.
  *
+ * What:               /sys/fs/orangefs/dcache_timeout_msecs
+ * Date:               Jul 2016
+ * Contact:            Martin Brandenburg <martin@omnibond.com>
+ * Description:
+ *                     Time lookup is valid in milliseconds.
+ *
+ * What:               /sys/fs/orangefs/getattr_timeout_msecs
+ * Date:               Jul 2016
+ * Contact:            Martin Brandenburg <martin@omnibond.com>
+ * Description:
+ *                     Time getattr is valid in milliseconds.
  *
  * What:               /sys/fs/orangefs/acache/...
  * Date:               Jun 2015
- * Contact:            Mike Marshall <hubcap@omnibond.com>
+ * Contact:            Martin Brandenburg <martin@omnibond.com>
  * Description:
  *                     Attribute cache configurable settings.
  *
@@ -117,6 +128,8 @@ struct orangefs_obj {
        int perf_history_size;
        int perf_time_interval_secs;
        int slot_timeout_secs;
+       int dcache_timeout_msecs;
+       int getattr_timeout_msecs;
 };
 
 struct acache_orangefs_obj {
@@ -658,6 +671,20 @@ static ssize_t sysfs_int_show(char *kobj_id, char *buf, void *attr)
                                       "%d\n",
                                       slot_timeout_secs);
                        goto out;
+               } else if (!strcmp(orangefs_attr->attr.name,
+                                  "dcache_timeout_msecs")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%d\n",
+                                      dcache_timeout_msecs);
+                       goto out;
+               } else if (!strcmp(orangefs_attr->attr.name,
+                                  "getattr_timeout_msecs")) {
+                       rc = scnprintf(buf,
+                                      PAGE_SIZE,
+                                      "%d\n",
+                                      getattr_timeout_msecs);
+                       goto out;
                } else {
                        goto out;
                }
@@ -734,6 +761,12 @@ static ssize_t int_store(struct orangefs_obj *orangefs_obj,
        } else if (!strcmp(attr->attr.name, "slot_timeout_secs")) {
                rc = kstrtoint(buf, 0, &slot_timeout_secs);
                goto out;
+       } else if (!strcmp(attr->attr.name, "dcache_timeout_msecs")) {
+               rc = kstrtoint(buf, 0, &dcache_timeout_msecs);
+               goto out;
+       } else if (!strcmp(attr->attr.name, "getattr_timeout_msecs")) {
+               rc = kstrtoint(buf, 0, &getattr_timeout_msecs);
+               goto out;
        } else {
                goto out;
        }
@@ -1361,6 +1394,12 @@ static struct orangefs_attribute op_timeout_secs_attribute =
 static struct orangefs_attribute slot_timeout_secs_attribute =
        __ATTR(slot_timeout_secs, 0664, int_orangefs_show, int_store);
 
+static struct orangefs_attribute dcache_timeout_msecs_attribute =
+       __ATTR(dcache_timeout_msecs, 0664, int_orangefs_show, int_store);
+
+static struct orangefs_attribute getattr_timeout_msecs_attribute =
+       __ATTR(getattr_timeout_msecs, 0664, int_orangefs_show, int_store);
+
 static struct orangefs_attribute perf_counter_reset_attribute =
        __ATTR(perf_counter_reset,
               0664,
@@ -1382,6 +1421,8 @@ static struct orangefs_attribute perf_time_interval_secs_attribute =
 static struct attribute *orangefs_default_attrs[] = {
        &op_timeout_secs_attribute.attr,
        &slot_timeout_secs_attribute.attr,
+       &dcache_timeout_msecs_attribute.attr,
+       &getattr_timeout_msecs_attribute.attr,
        &perf_counter_reset_attribute.attr,
        &perf_history_size_attribute.attr,
        &perf_time_interval_secs_attribute.attr,
index c5fbc62..d13c729 100644 (file)
@@ -251,7 +251,7 @@ static int orangefs_inode_is_stale(struct inode *inode, int new,
        return 0;
 }
 
-int orangefs_inode_getattr(struct inode *inode, int new, int size)
+int orangefs_inode_getattr(struct inode *inode, int new, int bypass)
 {
        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
        struct orangefs_kernel_op_s *new_op;
@@ -261,12 +261,16 @@ int orangefs_inode_getattr(struct inode *inode, int new, int size)
        gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
            get_khandle_from_ino(inode));
 
+       if (!new && !bypass) {
+               if (time_before(jiffies, orangefs_inode->getattr_time))
+                       return 0;
+       }
+
        new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
        if (!new_op)
                return -ENOMEM;
        new_op->upcall.req.getattr.refn = orangefs_inode->refn;
-       new_op->upcall.req.getattr.mask = size ?
-           ORANGEFS_ATTR_SYS_ALL_NOHINT : ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE;
+       new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_ALL_NOHINT;
 
        ret = service_operation(new_op, __func__,
            get_interruptible_flag(inode));
@@ -287,20 +291,18 @@ int orangefs_inode_getattr(struct inode *inode, int new, int size)
        case S_IFREG:
                inode->i_flags = orangefs_inode_flags(&new_op->
                    downcall.resp.getattr.attributes);
-               if (size) {
-                       inode_size = (loff_t)new_op->
-                           downcall.resp.getattr.attributes.size;
-                       rounded_up_size =
-                           (inode_size + (4096 - (inode_size % 4096)));
-                       inode->i_size = inode_size;
-                       orangefs_inode->blksize =
-                           new_op->downcall.resp.getattr.attributes.blksize;
-                       spin_lock(&inode->i_lock);
-                       inode->i_bytes = inode_size;
-                       inode->i_blocks =
-                           (unsigned long)(rounded_up_size / 512);
-                       spin_unlock(&inode->i_lock);
-               }
+               inode_size = (loff_t)new_op->
+                   downcall.resp.getattr.attributes.size;
+               rounded_up_size =
+                   (inode_size + (4096 - (inode_size % 4096)));
+               inode->i_size = inode_size;
+               orangefs_inode->blksize =
+                   new_op->downcall.resp.getattr.attributes.blksize;
+               spin_lock(&inode->i_lock);
+               inode->i_bytes = inode_size;
+               inode->i_blocks =
+                   (unsigned long)(rounded_up_size / 512);
+               spin_unlock(&inode->i_lock);
                break;
        case S_IFDIR:
                inode->i_size = PAGE_SIZE;
@@ -345,6 +347,7 @@ int orangefs_inode_getattr(struct inode *inode, int new, int size)
        inode->i_mode = type | (is_root_handle(inode) ? S_ISVTX : 0) |
            orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);
 
+       orangefs_inode->getattr_time = jiffies + getattr_timeout_msecs*HZ/1000;
        ret = 0;
 out:
        op_release(new_op);
@@ -418,6 +421,7 @@ int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
                ClearMtimeFlag(orangefs_inode);
                ClearCtimeFlag(orangefs_inode);
                ClearModeFlag(orangefs_inode);
+               orangefs_inode->getattr_time = jiffies - 1;
        }
 
        return ret;
index 1efc6f8..3d7418c 100644 (file)
@@ -207,14 +207,6 @@ typedef __s64 ORANGEFS_offset;
         ORANGEFS_ATTR_SYS_DIRENT_COUNT         |       \
         ORANGEFS_ATTR_SYS_BLKSIZE)
 
-#define ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE            \
-       (ORANGEFS_ATTR_SYS_COMMON_ALL           |       \
-        ORANGEFS_ATTR_SYS_LNK_TARGET           |       \
-        ORANGEFS_ATTR_SYS_DFILE_COUNT          |       \
-        ORANGEFS_ATTR_SYS_MIRROR_COPIES_COUNT  |       \
-        ORANGEFS_ATTR_SYS_DIRENT_COUNT         |       \
-        ORANGEFS_ATTR_SYS_BLKSIZE)
-
 #define ORANGEFS_XATTR_REPLACE 0x2
 #define ORANGEFS_XATTR_CREATE  0x1
 #define ORANGEFS_MAX_SERVER_ADDR_LEN 256
index 4b32928..4ebe6b2 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -144,10 +144,8 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
        struct page *page = buf->page;
 
        if (page_count(page) == 1) {
-               if (memcg_kmem_enabled()) {
+               if (memcg_kmem_enabled())
                        memcg_kmem_uncharge(page, 0);
-                       __ClearPageKmemcg(page);
-               }
                __SetPageLocked(page);
                return 0;
        }
index 7151ea4..12c6922 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-y   += proc.o
 
+CFLAGS_task_mmu.o      += $(call cc-option,-Wno-override-init,)
 proc-y                 := nommu.o task_nommu.o
 proc-$(CONFIG_MMU)     := task_mmu.o
 
index 31370da..54e2702 100644 (file)
@@ -579,11 +579,8 @@ static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns,
        unsigned long totalpages = totalram_pages + total_swap_pages;
        unsigned long points = 0;
 
-       read_lock(&tasklist_lock);
-       if (pid_alive(task))
-               points = oom_badness(task, NULL, NULL, totalpages) *
-                                               1000 / totalpages;
-       read_unlock(&tasklist_lock);
+       points = oom_badness(task, NULL, NULL, totalpages) *
+                                       1000 / totalpages;
        seq_printf(m, "%lu\n", points);
 
        return 0;
index b59db94..1b93650 100644 (file)
@@ -474,7 +474,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
 {
        struct ctl_table_header *head = grab_header(dir);
        struct ctl_table_header *h = NULL;
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        struct ctl_table *p;
        struct inode *inode;
        struct dentry *err = ERR_PTR(-ENOENT);
@@ -834,7 +834,7 @@ static int sysctl_is_seen(struct ctl_table_header *p)
        return res;
 }
 
-static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
+static int proc_sys_compare(const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct ctl_table_header *head;
index 510413e..7907e45 100644 (file)
@@ -80,19 +80,17 @@ static u64 get_iowait_time(int cpu)
 static int show_stat(struct seq_file *p, void *v)
 {
        int i, j;
-       unsigned long jif;
        u64 user, nice, system, idle, iowait, irq, softirq, steal;
        u64 guest, guest_nice;
        u64 sum = 0;
        u64 sum_softirq = 0;
        unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
-       struct timespec boottime;
+       struct timespec64 boottime;
 
        user = nice = system = idle = iowait =
                irq = softirq = steal = 0;
        guest = guest_nice = 0;
-       getboottime(&boottime);
-       jif = boottime.tv_sec;
+       getboottime64(&boottime);
 
        for_each_possible_cpu(i) {
                user += kcpustat_cpu(i).cpustat[CPUTIME_USER];
@@ -163,12 +161,12 @@ static int show_stat(struct seq_file *p, void *v)
 
        seq_printf(p,
                "\nctxt %llu\n"
-               "btime %lu\n"
+               "btime %llu\n"
                "processes %lu\n"
                "procs_running %lu\n"
                "procs_blocked %lu\n",
                nr_context_switches(),
-               (unsigned long)jif,
+               (unsigned long long)boottime.tv_sec,
                total_forks,
                nr_running(),
                nr_iowait());
index 47516a7..7a034d6 100644 (file)
@@ -486,30 +486,21 @@ static int ramoops_parse_dt(struct platform_device *pdev,
                            struct ramoops_platform_data *pdata)
 {
        struct device_node *of_node = pdev->dev.of_node;
-       struct device_node *mem_region;
-       struct resource res;
+       struct resource *res;
        u32 value;
        int ret;
 
        dev_dbg(&pdev->dev, "using Device Tree\n");
 
-       mem_region = of_parse_phandle(of_node, "memory-region", 0);
-       if (!mem_region) {
-               dev_err(&pdev->dev, "no memory-region phandle\n");
-               return -ENODEV;
-       }
-
-       ret = of_address_to_resource(mem_region, 0, &res);
-       of_node_put(mem_region);
-       if (ret) {
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
                dev_err(&pdev->dev,
-                       "failed to translate memory-region to resource: %d\n",
-                       ret);
-               return ret;
+                       "failed to locate DT /reserved-memory resource\n");
+               return -EINVAL;
        }
 
-       pdata->mem_size = resource_size(&res);
-       pdata->mem_address = res.start;
+       pdata->mem_size = resource_size(res);
+       pdata->mem_address = res->start;
        pdata->mem_type = of_property_read_bool(of_node, "unbuffered");
        pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops");
 
@@ -652,11 +643,11 @@ fail_buf:
        kfree(cxt->pstore.buf);
 fail_clear:
        cxt->pstore.bufsize = 0;
-       kfree(cxt->mprz);
+       persistent_ram_free(cxt->mprz);
 fail_init_mprz:
-       kfree(cxt->fprz);
+       persistent_ram_free(cxt->fprz);
 fail_init_fprz:
-       kfree(cxt->cprz);
+       persistent_ram_free(cxt->cprz);
 fail_init_cprz:
        ramoops_free_przs(cxt);
 fail_out:
index b751eea..5db6f45 100644 (file)
@@ -1153,8 +1153,9 @@ int balance_internal(struct tree_balance *tb,
                                       insert_ptr);
        }
 
-       memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
        insert_ptr[0] = new_insert_ptr;
+       if (new_insert_ptr)
+               memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
 
        return order;
 }
index 9718da8..821b348 100644 (file)
@@ -100,10 +100,6 @@ static int switch_gc_head(struct ubifs_info *c)
        if (err)
                return err;
 
-       err = ubifs_wbuf_sync_nolock(wbuf);
-       if (err)
-               return err;
-
        err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
        if (err)
                return err;
index 7034995..4ec0510 100644 (file)
@@ -520,19 +520,19 @@ static int init_constants_early(struct ubifs_info *c)
        c->max_write_shift = fls(c->max_write_size) - 1;
 
        if (c->leb_size < UBIFS_MIN_LEB_SZ) {
-               ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
-                         c->leb_size, UBIFS_MIN_LEB_SZ);
+               ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
+                          c->leb_size, UBIFS_MIN_LEB_SZ);
                return -EINVAL;
        }
 
        if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
-               ubifs_err(c, "too few LEBs (%d), min. is %d",
-                         c->leb_cnt, UBIFS_MIN_LEB_CNT);
+               ubifs_errc(c, "too few LEBs (%d), min. is %d",
+                          c->leb_cnt, UBIFS_MIN_LEB_CNT);
                return -EINVAL;
        }
 
        if (!is_power_of_2(c->min_io_size)) {
-               ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
+               ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
                return -EINVAL;
        }
 
@@ -543,8 +543,8 @@ static int init_constants_early(struct ubifs_info *c)
        if (c->max_write_size < c->min_io_size ||
            c->max_write_size % c->min_io_size ||
            !is_power_of_2(c->max_write_size)) {
-               ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
-                         c->max_write_size, c->min_io_size);
+               ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
+                          c->max_write_size, c->min_io_size);
                return -EINVAL;
        }
 
@@ -2108,8 +2108,9 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
         */
        ubi = open_ubi(name, UBI_READONLY);
        if (IS_ERR(ubi)) {
-               pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
-                      current->pid, name, (int)PTR_ERR(ubi));
+               if (!(flags & MS_SILENT))
+                       pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
+                              current->pid, name, (int)PTR_ERR(ubi));
                return ERR_CAST(ubi);
        }
 
index ddf9f6b..4617d45 100644 (file)
@@ -1783,8 +1783,8 @@ void ubifs_err(const struct ubifs_info *c, const char *fmt, ...);
 __printf(2, 3)
 void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
 /*
- * A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
- * object as an argument.
+ * A conditional variant of 'ubifs_err()' which doesn't output anything
+ * if probing (ie. MS_SILENT set).
  */
 #define ubifs_errc(c, fmt, ...)                                                \
 do {                                                                   \
index b5fc279..e237811 100644 (file)
@@ -592,19 +592,19 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
                return __ubifs_removexattr(inode, name);
 }
 
-const struct xattr_handler ubifs_user_xattr_handler = {
+static const struct xattr_handler ubifs_user_xattr_handler = {
        .prefix = XATTR_USER_PREFIX,
        .get = ubifs_xattr_get,
        .set = ubifs_xattr_set,
 };
 
-const struct xattr_handler ubifs_trusted_xattr_handler = {
+static const struct xattr_handler ubifs_trusted_xattr_handler = {
        .prefix = XATTR_TRUSTED_PREFIX,
        .get = ubifs_xattr_get,
        .set = ubifs_xattr_set,
 };
 
-const struct xattr_handler ubifs_security_xattr_handler = {
+static const struct xattr_handler ubifs_security_xattr_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .get = ubifs_xattr_get,
        .set = ubifs_xattr_set,
index 85c40f4..794f5f5 100644 (file)
@@ -92,10 +92,11 @@ static int utimes_common(struct path *path, struct timespec *times)
                 * then we need to check permissions, because
                 * inode_change_ok() won't do it.
                 */
-               error = -EACCES;
+               error = -EPERM;
                 if (IS_IMMUTABLE(inode))
                        goto mnt_drop_write_and_out;
 
+               error = -EACCES;
                if (!inode_owner_or_capable(inode)) {
                        error = inode_permission(inode, MAY_WRITE);
                        if (error)
index 3542d94..fc593c8 100644 (file)
@@ -39,6 +39,7 @@ xfs-y                         += $(addprefix libxfs/, \
                                   xfs_btree.o \
                                   xfs_da_btree.o \
                                   xfs_da_format.o \
+                                  xfs_defer.o \
                                   xfs_dir2.o \
                                   xfs_dir2_block.o \
                                   xfs_dir2_data.o \
@@ -51,6 +52,8 @@ xfs-y                         += $(addprefix libxfs/, \
                                   xfs_inode_fork.o \
                                   xfs_inode_buf.o \
                                   xfs_log_rlimit.o \
+                                  xfs_rmap.o \
+                                  xfs_rmap_btree.o \
                                   xfs_sb.o \
                                   xfs_symlink_remote.o \
                                   xfs_trans_resv.o \
@@ -100,11 +103,13 @@ xfs-y                             += xfs_log.o \
                                   xfs_extfree_item.o \
                                   xfs_icreate_item.o \
                                   xfs_inode_item.o \
+                                  xfs_rmap_item.o \
                                   xfs_log_recover.o \
                                   xfs_trans_ail.o \
                                   xfs_trans_buf.o \
                                   xfs_trans_extfree.o \
                                   xfs_trans_inode.o \
+                                  xfs_trans_rmap.o \
 
 # optional features
 xfs-$(CONFIG_XFS_QUOTA)                += xfs_dquot.o \
@@ -121,5 +126,4 @@ xfs-$(CONFIG_XFS_RT)                += xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
 xfs-$(CONFIG_SYSCTL)           += xfs_sysctl.o
 xfs-$(CONFIG_COMPAT)           += xfs_ioctl32.o
-xfs-$(CONFIG_NFSD_BLOCKLAYOUT) += xfs_pnfs.o
-xfs-$(CONFIG_NFSD_SCSILAYOUT)  += xfs_pnfs.o
+xfs-$(CONFIG_EXPORTFS_BLOCK_OPS)       += xfs_pnfs.o
index 88c26b8..776ae2f 100644 (file)
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
+#include "xfs_rmap.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_alloc.h"
 #include "xfs_extent_busy.h"
@@ -49,6 +51,81 @@ STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);
 STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
                xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
 
+xfs_extlen_t
+xfs_prealloc_blocks(
+       struct xfs_mount        *mp)
+{
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return XFS_RMAP_BLOCK(mp) + 1;
+       if (xfs_sb_version_hasfinobt(&mp->m_sb))
+               return XFS_FIBT_BLOCK(mp) + 1;
+       return XFS_IBT_BLOCK(mp) + 1;
+}
+
+/*
+ * In order to avoid ENOSPC-related deadlock caused by out-of-order locking of
+ * AGF buffer (PV 947395), we place constraints on the relationship among
+ * actual allocations for data blocks, freelist blocks, and potential file data
+ * bmap btree blocks. However, these restrictions may result in no actual space
+ * allocated for a delayed extent, for example, a data block in a certain AG is
+ * allocated but there is no additional block for the additional bmap btree
+ * block due to a split of the bmap btree of the file. The result of this may
+ * lead to an infinite loop when the file gets flushed to disk and all delayed
+ * extents need to be actually allocated. To get around this, we explicitly set
+ * aside a few blocks which will not be reserved in delayed allocation.
+ *
+ * When rmap is disabled, we need to reserve 4 fsbs _per AG_ for the freelist
+ * and 4 more to handle a potential split of the file's bmap btree.
+ *
+ * When rmap is enabled, we must also be able to handle two rmap btree inserts
+ * to record both the file data extent and a new bmbt block.  The bmbt block
+ * might not be in the same AG as the file data extent.  In the worst case
+ * the bmap btree splits multiple levels and all the new blocks come from
+ * different AGs, so set aside enough to handle rmap btree splits in all AGs.
+ */
+unsigned int
+xfs_alloc_set_aside(
+       struct xfs_mount        *mp)
+{
+       unsigned int            blocks;
+
+       blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE);
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               blocks += mp->m_sb.sb_agcount * mp->m_rmap_maxlevels;
+       return blocks;
+}
+
+/*
+ * When deciding how much space to allocate out of an AG, we limit the
+ * allocation maximum size to the size the AG. However, we cannot use all the
+ * blocks in the AG - some are permanently used by metadata. These
+ * blocks are generally:
+ *     - the AG superblock, AGF, AGI and AGFL
+ *     - the AGF (bno and cnt) and AGI btree root blocks, and optionally
+ *       the AGI free inode and rmap btree root blocks.
+ *     - blocks on the AGFL according to xfs_alloc_set_aside() limits
+ *     - the rmapbt root block
+ *
+ * The AG headers are sector sized, so the amount of space they take up is
+ * dependent on filesystem geometry. The others are all single blocks.
+ */
+unsigned int
+xfs_alloc_ag_max_usable(
+       struct xfs_mount        *mp)
+{
+       unsigned int            blocks;
+
+       blocks = XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)); /* ag headers */
+       blocks += XFS_ALLOC_AGFL_RESERVE;
+       blocks += 3;                    /* AGF, AGI btree root blocks */
+       if (xfs_sb_version_hasfinobt(&mp->m_sb))
+               blocks++;               /* finobt root block */
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               blocks++;               /* rmap root block */
+
+       return mp->m_sb.sb_agblocks - blocks;
+}
+
 /*
  * Lookup the record equal to [bno, len] in the btree given by cur.
  */
@@ -636,6 +713,14 @@ xfs_alloc_ag_vextent(
        ASSERT(!args->wasfromfl || !args->isfl);
        ASSERT(args->agbno % args->alignment == 0);
 
+       /* if not file data, insert new block into the reverse map btree */
+       if (args->oinfo.oi_owner != XFS_RMAP_OWN_UNKNOWN) {
+               error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
+                                      args->agbno, args->len, &args->oinfo);
+               if (error)
+                       return error;
+       }
+
        if (!args->wasfromfl) {
                error = xfs_alloc_update_counters(args->tp, args->pag,
                                                  args->agbp,
@@ -1577,14 +1662,15 @@ error0:
 /*
  * Free the extent starting at agno/bno for length.
  */
-STATIC int                     /* error */
+STATIC int
 xfs_free_ag_extent(
-       xfs_trans_t     *tp,    /* transaction pointer */
-       xfs_buf_t       *agbp,  /* buffer for a.g. freelist header */
-       xfs_agnumber_t  agno,   /* allocation group number */
-       xfs_agblock_t   bno,    /* starting block number */
-       xfs_extlen_t    len,    /* length of extent */
-       int             isfl)   /* set if is freelist blocks - no sb acctg */
+       xfs_trans_t             *tp,
+       xfs_buf_t               *agbp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       struct xfs_owner_info   *oinfo,
+       int                     isfl)
 {
        xfs_btree_cur_t *bno_cur;       /* cursor for by-block btree */
        xfs_btree_cur_t *cnt_cur;       /* cursor for by-size btree */
@@ -1601,12 +1687,19 @@ xfs_free_ag_extent(
        xfs_extlen_t    nlen;           /* new length of freespace */
        xfs_perag_t     *pag;           /* per allocation group data */
 
+       bno_cur = cnt_cur = NULL;
        mp = tp->t_mountp;
+
+       if (oinfo->oi_owner != XFS_RMAP_OWN_UNKNOWN) {
+               error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
+               if (error)
+                       goto error0;
+       }
+
        /*
         * Allocate and initialize a cursor for the by-block btree.
         */
        bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO);
-       cnt_cur = NULL;
        /*
         * Look for a neighboring block on the left (lower block numbers)
         * that is contiguous with this space.
@@ -1875,6 +1968,11 @@ xfs_alloc_min_freelist(
        /* space needed by-size freespace btree */
        min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_CNTi] + 1,
                                       mp->m_ag_maxlevels);
+       /* space needed reverse mapping used space btree */
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               min_free += min_t(unsigned int,
+                                 pag->pagf_levels[XFS_BTNUM_RMAPi] + 1,
+                                 mp->m_rmap_maxlevels);
 
        return min_free;
 }
@@ -1992,21 +2090,34 @@ xfs_alloc_fix_freelist(
         * anything other than extra overhead when we need to put more blocks
         * back on the free list? Maybe we should only do this when space is
         * getting low or the AGFL is more than half full?
+        *
+        * The NOSHRINK flag prevents the AGFL from being shrunk if it's too
+        * big; the NORMAP flag prevents AGFL expand/shrink operations from
+        * updating the rmapbt.  Both flags are used in xfs_repair while we're
+        * rebuilding the rmapbt, and neither are used by the kernel.  They're
+        * both required to ensure that rmaps are correctly recorded for the
+        * regenerated AGFL, bnobt, and cntbt.  See repair/phase5.c and
+        * repair/rmap.c in xfsprogs for details.
         */
-       while (pag->pagf_flcount > need) {
+       memset(&targs, 0, sizeof(targs));
+       if (flags & XFS_ALLOC_FLAG_NORMAP)
+               xfs_rmap_skip_owner_update(&targs.oinfo);
+       else
+               xfs_rmap_ag_owner(&targs.oinfo, XFS_RMAP_OWN_AG);
+       while (!(flags & XFS_ALLOC_FLAG_NOSHRINK) && pag->pagf_flcount > need) {
                struct xfs_buf  *bp;
 
                error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
                if (error)
                        goto out_agbp_relse;
-               error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1);
+               error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1,
+                                          &targs.oinfo, 1);
                if (error)
                        goto out_agbp_relse;
                bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
                xfs_trans_binval(tp, bp);
        }
 
-       memset(&targs, 0, sizeof(targs));
        targs.tp = tp;
        targs.mp = mp;
        targs.agbp = agbp;
@@ -2271,6 +2382,10 @@ xfs_agf_verify(
            be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
                return false;
 
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&
+           be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS)
+               return false;
+
        /*
         * during growfs operations, the perag is not fully initialised,
         * so we can't use it for any useful checking. growfs ensures we can't
@@ -2402,6 +2517,8 @@ xfs_alloc_read_agf(
                        be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]);
                pag->pagf_levels[XFS_BTNUM_CNTi] =
                        be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]);
+               pag->pagf_levels[XFS_BTNUM_RMAPi] =
+                       be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]);
                spin_lock_init(&pag->pagb_lock);
                pag->pagb_count = 0;
                pag->pagb_tree = RB_ROOT;
@@ -2691,7 +2808,8 @@ int                               /* error */
 xfs_free_extent(
        struct xfs_trans        *tp,    /* transaction pointer */
        xfs_fsblock_t           bno,    /* starting block number of extent */
-       xfs_extlen_t            len)    /* length of extent */
+       xfs_extlen_t            len,    /* length of extent */
+       struct xfs_owner_info   *oinfo) /* extent owner */
 {
        struct xfs_mount        *mp = tp->t_mountp;
        struct xfs_buf          *agbp;
@@ -2701,6 +2819,11 @@ xfs_free_extent(
 
        ASSERT(len != 0);
 
+       if (XFS_TEST_ERROR(false, mp,
+                       XFS_ERRTAG_FREE_EXTENT,
+                       XFS_RANDOM_FREE_EXTENT))
+               return -EIO;
+
        error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
        if (error)
                return error;
@@ -2712,7 +2835,7 @@ xfs_free_extent(
                agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length),
                                err);
 
-       error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, 0);
+       error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, 0);
        if (error)
                goto err;
 
index cf268b2..6fe2d6b 100644 (file)
@@ -54,41 +54,8 @@ typedef unsigned int xfs_alloctype_t;
  */
 #define        XFS_ALLOC_FLAG_TRYLOCK  0x00000001  /* use trylock for buffer locking */
 #define        XFS_ALLOC_FLAG_FREEING  0x00000002  /* indicate caller is freeing extents*/
-
-/*
- * In order to avoid ENOSPC-related deadlock caused by
- * out-of-order locking of AGF buffer (PV 947395), we place
- * constraints on the relationship among actual allocations for
- * data blocks, freelist blocks, and potential file data bmap
- * btree blocks. However, these restrictions may result in no
- * actual space allocated for a delayed extent, for example, a data
- * block in a certain AG is allocated but there is no additional
- * block for the additional bmap btree block due to a split of the
- * bmap btree of the file. The result of this may lead to an
- * infinite loop in xfssyncd when the file gets flushed to disk and
- * all delayed extents need to be actually allocated. To get around
- * this, we explicitly set aside a few blocks which will not be
- * reserved in delayed allocation. Considering the minimum number of
- * needed freelist blocks is 4 fsbs _per AG_, a potential split of file's bmap
- * btree requires 1 fsb, so we set the number of set-aside blocks
- * to 4 + 4*agcount.
- */
-#define XFS_ALLOC_SET_ASIDE(mp)  (4 + ((mp)->m_sb.sb_agcount * 4))
-
-/*
- * When deciding how much space to allocate out of an AG, we limit the
- * allocation maximum size to the size the AG. However, we cannot use all the
- * blocks in the AG - some are permanently used by metadata. These
- * blocks are generally:
- *     - the AG superblock, AGF, AGI and AGFL
- *     - the AGF (bno and cnt) and AGI btree root blocks
- *     - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits
- *
- * The AG headers are sector sized, so the amount of space they take up is
- * dependent on filesystem geometry. The others are all single blocks.
- */
-#define XFS_ALLOC_AG_MAX_USABLE(mp)    \
-       ((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7)
+#define        XFS_ALLOC_FLAG_NORMAP   0x00000004  /* don't modify the rmapbt */
+#define        XFS_ALLOC_FLAG_NOSHRINK 0x00000008  /* don't shrink the freelist */
 
 
 /*
@@ -123,6 +90,7 @@ typedef struct xfs_alloc_arg {
        char            isfl;           /* set if is freelist blocks - !acctg */
        char            userdata;       /* mask defining userdata treatment */
        xfs_fsblock_t   firstblock;     /* io first block allocated */
+       struct xfs_owner_info   oinfo;  /* owner of blocks being allocated */
 } xfs_alloc_arg_t;
 
 /*
@@ -132,6 +100,11 @@ typedef struct xfs_alloc_arg {
 #define XFS_ALLOC_INITIAL_USER_DATA    (1 << 1)/* special case start of file */
 #define XFS_ALLOC_USERDATA_ZERO                (1 << 2)/* zero extent on allocation */
 
+/* freespace limit calculations */
+#define XFS_ALLOC_AGFL_RESERVE 4
+unsigned int xfs_alloc_set_aside(struct xfs_mount *mp);
+unsigned int xfs_alloc_ag_max_usable(struct xfs_mount *mp);
+
 xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp,
                struct xfs_perag *pag, xfs_extlen_t need);
 unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp,
@@ -208,9 +181,10 @@ xfs_alloc_vextent(
  */
 int                            /* error */
 xfs_free_extent(
-       struct xfs_trans *tp,   /* transaction pointer */
-       xfs_fsblock_t   bno,    /* starting block number of extent */
-       xfs_extlen_t    len);   /* length of extent */
+       struct xfs_trans        *tp,    /* transaction pointer */
+       xfs_fsblock_t           bno,    /* starting block number of extent */
+       xfs_extlen_t            len,    /* length of extent */
+       struct xfs_owner_info   *oinfo);/* extent owner */
 
 int                            /* error */
 xfs_alloc_lookup_ge(
@@ -232,4 +206,6 @@ int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
 int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
                struct xfs_buf **agbp);
 
+xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp);
+
 #endif /* __XFS_ALLOC_H__ */
index d9b4242..5ba2dac 100644 (file)
@@ -211,17 +211,6 @@ xfs_allocbt_init_key_from_rec(
        key->alloc.ar_blockcount = rec->alloc.ar_blockcount;
 }
 
-STATIC void
-xfs_allocbt_init_rec_from_key(
-       union xfs_btree_key     *key,
-       union xfs_btree_rec     *rec)
-{
-       ASSERT(key->alloc.ar_startblock != 0);
-
-       rec->alloc.ar_startblock = key->alloc.ar_startblock;
-       rec->alloc.ar_blockcount = key->alloc.ar_blockcount;
-}
-
 STATIC void
 xfs_allocbt_init_rec_from_cur(
        struct xfs_btree_cur    *cur,
@@ -406,7 +395,6 @@ static const struct xfs_btree_ops xfs_allocbt_ops = {
        .get_minrecs            = xfs_allocbt_get_minrecs,
        .get_maxrecs            = xfs_allocbt_get_maxrecs,
        .init_key_from_rec      = xfs_allocbt_init_key_from_rec,
-       .init_rec_from_key      = xfs_allocbt_init_rec_from_key,
        .init_rec_from_cur      = xfs_allocbt_init_rec_from_cur,
        .init_ptr_from_cur      = xfs_allocbt_init_ptr_from_cur,
        .key_diff               = xfs_allocbt_key_diff,
index 4e126f4..af1ecb1 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_attr_sf.h"
@@ -203,7 +204,7 @@ xfs_attr_set(
 {
        struct xfs_mount        *mp = dp->i_mount;
        struct xfs_da_args      args;
-       struct xfs_bmap_free    flist;
+       struct xfs_defer_ops    dfops;
        struct xfs_trans_res    tres;
        xfs_fsblock_t           firstblock;
        int                     rsvd = (flags & ATTR_ROOT) != 0;
@@ -221,7 +222,7 @@ xfs_attr_set(
        args.value = value;
        args.valuelen = valuelen;
        args.firstblock = &firstblock;
-       args.flist = &flist;
+       args.dfops = &dfops;
        args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
        args.total = xfs_attr_calc_size(&args, &local);
 
@@ -316,13 +317,13 @@ xfs_attr_set(
                 * It won't fit in the shortform, transform to a leaf block.
                 * GROT: another possible req'mt for a double-split btree op.
                 */
-               xfs_bmap_init(args.flist, args.firstblock);
+               xfs_defer_init(args.dfops, args.firstblock);
                error = xfs_attr_shortform_to_leaf(&args);
                if (!error)
-                       error = xfs_bmap_finish(&args.trans, args.flist, dp);
+                       error = xfs_defer_finish(&args.trans, args.dfops, dp);
                if (error) {
                        args.trans = NULL;
-                       xfs_bmap_cancel(&flist);
+                       xfs_defer_cancel(&dfops);
                        goto out;
                }
 
@@ -382,7 +383,7 @@ xfs_attr_remove(
 {
        struct xfs_mount        *mp = dp->i_mount;
        struct xfs_da_args      args;
-       struct xfs_bmap_free    flist;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           firstblock;
        int                     error;
 
@@ -399,7 +400,7 @@ xfs_attr_remove(
                return error;
 
        args.firstblock = &firstblock;
-       args.flist = &flist;
+       args.dfops = &dfops;
 
        /*
         * we have no control over the attribute names that userspace passes us
@@ -584,13 +585,13 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * Commit that transaction so that the node_addname() call
                 * can manage its own transactions.
                 */
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_attr3_leaf_to_node(args);
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist, dp);
+                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        return error;
                }
 
@@ -674,15 +675,15 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * If the result is small enough, shrink it all into the inode.
                 */
                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-                       xfs_bmap_init(args->flist, args->firstblock);
+                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                        /* bp is gone due to xfs_da_shrink_inode */
                        if (!error)
-                               error = xfs_bmap_finish(&args->trans,
-                                                       args->flist, dp);
+                               error = xfs_defer_finish(&args->trans,
+                                                       args->dfops, dp);
                        if (error) {
                                args->trans = NULL;
-                               xfs_bmap_cancel(args->flist);
+                               xfs_defer_cancel(args->dfops);
                                return error;
                        }
                }
@@ -737,14 +738,14 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
         * If the result is small enough, shrink it all into the inode.
         */
        if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                /* bp is gone due to xfs_da_shrink_inode */
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist, dp);
+                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        return error;
                }
        }
@@ -863,14 +864,14 @@ restart:
                         */
                        xfs_da_state_free(state);
                        state = NULL;
-                       xfs_bmap_init(args->flist, args->firstblock);
+                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_node(args);
                        if (!error)
-                               error = xfs_bmap_finish(&args->trans,
-                                                       args->flist, dp);
+                               error = xfs_defer_finish(&args->trans,
+                                                       args->dfops, dp);
                        if (error) {
                                args->trans = NULL;
-                               xfs_bmap_cancel(args->flist);
+                               xfs_defer_cancel(args->dfops);
                                goto out;
                        }
 
@@ -891,13 +892,13 @@ restart:
                 * in the index/blkno/rmtblkno/rmtblkcnt fields and
                 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
                 */
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_da3_split(state);
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist, dp);
+                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        goto out;
                }
        } else {
@@ -990,14 +991,14 @@ restart:
                 * Check to see if the tree needs to be collapsed.
                 */
                if (retval && (state->path.active > 1)) {
-                       xfs_bmap_init(args->flist, args->firstblock);
+                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_da3_join(state);
                        if (!error)
-                               error = xfs_bmap_finish(&args->trans,
-                                                       args->flist, dp);
+                               error = xfs_defer_finish(&args->trans,
+                                                       args->dfops, dp);
                        if (error) {
                                args->trans = NULL;
-                               xfs_bmap_cancel(args->flist);
+                               xfs_defer_cancel(args->dfops);
                                goto out;
                        }
                }
@@ -1113,13 +1114,13 @@ xfs_attr_node_removename(xfs_da_args_t *args)
         * Check to see if the tree needs to be collapsed.
         */
        if (retval && (state->path.active > 1)) {
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_da3_join(state);
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist, dp);
+                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        goto out;
                }
                /*
@@ -1146,15 +1147,15 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                        goto out;
 
                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-                       xfs_bmap_init(args->flist, args->firstblock);
+                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                        /* bp is gone due to xfs_da_shrink_inode */
                        if (!error)
-                               error = xfs_bmap_finish(&args->trans,
-                                                       args->flist, dp);
+                               error = xfs_defer_finish(&args->trans,
+                                                       args->dfops, dp);
                        if (error) {
                                args->trans = NULL;
-                               xfs_bmap_cancel(args->flist);
+                               xfs_defer_cancel(args->dfops);
                                goto out;
                        }
                } else
index 01a5ecf..8ea91f3 100644 (file)
@@ -792,7 +792,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
        nargs.dp = dp;
        nargs.geo = args->geo;
        nargs.firstblock = args->firstblock;
-       nargs.flist = args->flist;
+       nargs.dfops = args->dfops;
        nargs.total = args->total;
        nargs.whichfork = XFS_ATTR_FORK;
        nargs.trans = args->trans;
@@ -922,7 +922,7 @@ xfs_attr3_leaf_to_shortform(
        nargs.geo = args->geo;
        nargs.dp = dp;
        nargs.firstblock = args->firstblock;
-       nargs.flist = args->flist;
+       nargs.dfops = args->dfops;
        nargs.total = args->total;
        nargs.whichfork = XFS_ATTR_FORK;
        nargs.trans = args->trans;
index a572532..d52f525 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
@@ -460,16 +461,16 @@ xfs_attr_rmtval_set(
                 * extent and then crash then the block may not contain the
                 * correct metadata after log recovery occurs.
                 */
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                nmap = 1;
                error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
                                  blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
-                                 args->total, &map, &nmap, args->flist);
+                                 args->total, &map, &nmap, args->dfops);
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist, dp);
+                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        return error;
                }
 
@@ -503,7 +504,7 @@ xfs_attr_rmtval_set(
 
                ASSERT(blkcnt > 0);
 
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                nmap = 1;
                error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
                                       blkcnt, &map, &nmap,
@@ -603,16 +604,16 @@ xfs_attr_rmtval_remove(
        blkcnt = args->rmtblkcnt;
        done = 0;
        while (!done) {
-               xfs_bmap_init(args->flist, args->firstblock);
+               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
                                    XFS_BMAPI_ATTRFORK, 1, args->firstblock,
-                                   args->flist, &done);
+                                   args->dfops, &done);
                if (!error)
-                       error = xfs_bmap_finish(&args->trans, args->flist,
+                       error = xfs_defer_finish(&args->trans, args->dfops,
                                                args->dp);
                if (error) {
                        args->trans = NULL;
-                       xfs_bmap_cancel(args->flist);
+                       xfs_defer_cancel(args->dfops);
                        return error;
                }
 
index 2f2c85c..b060bca 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_dir2.h"
@@ -45,6 +46,7 @@
 #include "xfs_symlink.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_filestream.h"
+#include "xfs_rmap.h"
 
 
 kmem_zone_t            *xfs_bmap_free_item_zone;
@@ -570,12 +572,13 @@ xfs_bmap_validate_ret(
  */
 void
 xfs_bmap_add_free(
-       struct xfs_mount        *mp,            /* mount point structure */
-       struct xfs_bmap_free    *flist,         /* list of extents */
-       xfs_fsblock_t           bno,            /* fs block number of extent */
-       xfs_filblks_t           len)            /* length of extent */
+       struct xfs_mount                *mp,
+       struct xfs_defer_ops            *dfops,
+       xfs_fsblock_t                   bno,
+       xfs_filblks_t                   len,
+       struct xfs_owner_info           *oinfo)
 {
-       struct xfs_bmap_free_item       *new;           /* new element */
+       struct xfs_extent_free_item     *new;           /* new element */
 #ifdef DEBUG
        xfs_agnumber_t          agno;
        xfs_agblock_t           agbno;
@@ -592,44 +595,17 @@ xfs_bmap_add_free(
        ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
 #endif
        ASSERT(xfs_bmap_free_item_zone != NULL);
-       new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
-       new->xbfi_startblock = bno;
-       new->xbfi_blockcount = (xfs_extlen_t)len;
-       list_add(&new->xbfi_list, &flist->xbf_flist);
-       flist->xbf_count++;
-}
-
-/*
- * Remove the entry "free" from the free item list.  Prev points to the
- * previous entry, unless "free" is the head of the list.
- */
-void
-xfs_bmap_del_free(
-       struct xfs_bmap_free            *flist, /* free item list header */
-       struct xfs_bmap_free_item       *free)  /* list item to be freed */
-{
-       list_del(&free->xbfi_list);
-       flist->xbf_count--;
-       kmem_zone_free(xfs_bmap_free_item_zone, free);
-}
-
-/*
- * Free up any items left in the list.
- */
-void
-xfs_bmap_cancel(
-       struct xfs_bmap_free            *flist) /* list of bmap_free_items */
-{
-       struct xfs_bmap_free_item       *free;  /* free list item */
 
-       if (flist->xbf_count == 0)
-               return;
-       while (!list_empty(&flist->xbf_flist)) {
-               free = list_first_entry(&flist->xbf_flist,
-                               struct xfs_bmap_free_item, xbfi_list);
-               xfs_bmap_del_free(flist, free);
-       }
-       ASSERT(flist->xbf_count == 0);
+       new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP);
+       new->xefi_startblock = bno;
+       new->xefi_blockcount = (xfs_extlen_t)len;
+       if (oinfo)
+               new->xefi_oinfo = *oinfo;
+       else
+               xfs_rmap_skip_owner_update(&new->xefi_oinfo);
+       trace_xfs_bmap_free_defer(mp, XFS_FSB_TO_AGNO(mp, bno), 0,
+                       XFS_FSB_TO_AGBNO(mp, bno), len);
+       xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_FREE, &new->xefi_list);
 }
 
 /*
@@ -659,6 +635,7 @@ xfs_bmap_btree_to_extents(
        xfs_mount_t             *mp;    /* mount point structure */
        __be64                  *pp;    /* ptr to block address */
        struct xfs_btree_block  *rblock;/* root btree block */
+       struct xfs_owner_info   oinfo;
 
        mp = ip->i_mount;
        ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -682,7 +659,8 @@ xfs_bmap_btree_to_extents(
        cblock = XFS_BUF_TO_BLOCK(cbp);
        if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
                return error;
-       xfs_bmap_add_free(mp, cur->bc_private.b.flist, cbno, 1);
+       xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
+       xfs_bmap_add_free(mp, cur->bc_private.b.dfops, cbno, 1, &oinfo);
        ip->i_d.di_nblocks--;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
@@ -705,7 +683,7 @@ xfs_bmap_extents_to_btree(
        xfs_trans_t             *tp,            /* transaction pointer */
        xfs_inode_t             *ip,            /* incore inode pointer */
        xfs_fsblock_t           *firstblock,    /* first-block-allocated */
-       xfs_bmap_free_t         *flist,         /* blocks freed in xaction */
+       struct xfs_defer_ops    *dfops,         /* blocks freed in xaction */
        xfs_btree_cur_t         **curp,         /* cursor returned to caller */
        int                     wasdel,         /* converting a delayed alloc */
        int                     *logflagsp,     /* inode logging flags */
@@ -754,7 +732,7 @@ xfs_bmap_extents_to_btree(
         */
        cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
        cur->bc_private.b.firstblock = *firstblock;
-       cur->bc_private.b.flist = flist;
+       cur->bc_private.b.dfops = dfops;
        cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
        /*
         * Convert to a btree with two levels, one record in root.
@@ -763,11 +741,12 @@ xfs_bmap_extents_to_btree(
        memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = mp;
+       xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork);
        args.firstblock = *firstblock;
        if (*firstblock == NULLFSBLOCK) {
                args.type = XFS_ALLOCTYPE_START_BNO;
                args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
-       } else if (flist->xbf_low) {
+       } else if (dfops->dop_low) {
                args.type = XFS_ALLOCTYPE_START_BNO;
                args.fsbno = *firstblock;
        } else {
@@ -788,7 +767,7 @@ xfs_bmap_extents_to_btree(
        ASSERT(args.fsbno != NULLFSBLOCK);
        ASSERT(*firstblock == NULLFSBLOCK ||
               args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) ||
-              (flist->xbf_low &&
+              (dfops->dop_low &&
                args.agno > XFS_FSB_TO_AGNO(mp, *firstblock)));
        *firstblock = cur->bc_private.b.firstblock = args.fsbno;
        cur->bc_private.b.allocated++;
@@ -909,6 +888,7 @@ xfs_bmap_local_to_extents(
        memset(&args, 0, sizeof(args));
        args.tp = tp;
        args.mp = ip->i_mount;
+       xfs_rmap_ino_owner(&args.oinfo, ip->i_ino, whichfork, 0);
        args.firstblock = *firstblock;
        /*
         * Allocate a block.  We know we need only one, since the
@@ -973,7 +953,7 @@ xfs_bmap_add_attrfork_btree(
        xfs_trans_t             *tp,            /* transaction pointer */
        xfs_inode_t             *ip,            /* incore inode pointer */
        xfs_fsblock_t           *firstblock,    /* first block allocated */
-       xfs_bmap_free_t         *flist,         /* blocks to free at commit */
+       struct xfs_defer_ops    *dfops,         /* blocks to free at commit */
        int                     *flags)         /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;           /* btree cursor */
@@ -986,7 +966,7 @@ xfs_bmap_add_attrfork_btree(
                *flags |= XFS_ILOG_DBROOT;
        else {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
-               cur->bc_private.b.flist = flist;
+               cur->bc_private.b.dfops = dfops;
                cur->bc_private.b.firstblock = *firstblock;
                if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
                        goto error0;
@@ -1016,7 +996,7 @@ xfs_bmap_add_attrfork_extents(
        xfs_trans_t             *tp,            /* transaction pointer */
        xfs_inode_t             *ip,            /* incore inode pointer */
        xfs_fsblock_t           *firstblock,    /* first block allocated */
-       xfs_bmap_free_t         *flist,         /* blocks to free at commit */
+       struct xfs_defer_ops    *dfops,         /* blocks to free at commit */
        int                     *flags)         /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;           /* bmap btree cursor */
@@ -1025,7 +1005,7 @@ xfs_bmap_add_attrfork_extents(
        if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip))
                return 0;
        cur = NULL;
-       error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0,
+       error = xfs_bmap_extents_to_btree(tp, ip, firstblock, dfops, &cur, 0,
                flags, XFS_DATA_FORK);
        if (cur) {
                cur->bc_private.b.allocated = 0;
@@ -1051,7 +1031,7 @@ xfs_bmap_add_attrfork_local(
        xfs_trans_t             *tp,            /* transaction pointer */
        xfs_inode_t             *ip,            /* incore inode pointer */
        xfs_fsblock_t           *firstblock,    /* first block allocated */
-       xfs_bmap_free_t         *flist,         /* blocks to free at commit */
+       struct xfs_defer_ops    *dfops,         /* blocks to free at commit */
        int                     *flags)         /* inode logging flags */
 {
        xfs_da_args_t           dargs;          /* args for dir/attr code */
@@ -1064,7 +1044,7 @@ xfs_bmap_add_attrfork_local(
                dargs.geo = ip->i_mount->m_dir_geo;
                dargs.dp = ip;
                dargs.firstblock = firstblock;
-               dargs.flist = flist;
+               dargs.dfops = dfops;
                dargs.total = dargs.geo->fsbcount;
                dargs.whichfork = XFS_DATA_FORK;
                dargs.trans = tp;
@@ -1092,7 +1072,7 @@ xfs_bmap_add_attrfork(
        int                     rsvd)           /* xact may use reserved blks */
 {
        xfs_fsblock_t           firstblock;     /* 1st block/ag allocated */
-       xfs_bmap_free_t         flist;          /* freed extent records */
+       struct xfs_defer_ops    dfops;          /* freed extent records */
        xfs_mount_t             *mp;            /* mount structure */
        xfs_trans_t             *tp;            /* transaction pointer */
        int                     blks;           /* space reservation */
@@ -1158,18 +1138,18 @@ xfs_bmap_add_attrfork(
        ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
        ip->i_afp->if_flags = XFS_IFEXTENTS;
        logflags = 0;
-       xfs_bmap_init(&flist, &firstblock);
+       xfs_defer_init(&dfops, &firstblock);
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_LOCAL:
-               error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &flist,
+               error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &dfops,
                        &logflags);
                break;
        case XFS_DINODE_FMT_EXTENTS:
                error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock,
-                       &flist, &logflags);
+                       &dfops, &logflags);
                break;
        case XFS_DINODE_FMT_BTREE:
-               error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &flist,
+               error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &dfops,
                        &logflags);
                break;
        default:
@@ -1198,7 +1178,7 @@ xfs_bmap_add_attrfork(
                        xfs_log_sb(tp);
        }
 
-       error = xfs_bmap_finish(&tp, &flist, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto bmap_cancel;
        error = xfs_trans_commit(tp);
@@ -1206,7 +1186,7 @@ xfs_bmap_add_attrfork(
        return error;
 
 bmap_cancel:
-       xfs_bmap_cancel(&flist);
+       xfs_defer_cancel(&dfops);
 trans_cancel:
        xfs_trans_cancel(tp);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -2003,7 +1983,7 @@ xfs_bmap_add_extent_delay_real(
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
-                                       bma->firstblock, bma->flist,
+                                       bma->firstblock, bma->dfops,
                                        &bma->cur, 1, &tmp_rval, whichfork);
                        rval |= tmp_rval;
                        if (error)
@@ -2087,7 +2067,7 @@ xfs_bmap_add_extent_delay_real(
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
-                               bma->firstblock, bma->flist, &bma->cur, 1,
+                               bma->firstblock, bma->dfops, &bma->cur, 1,
                                &tmp_rval, whichfork);
                        rval |= tmp_rval;
                        if (error)
@@ -2156,7 +2136,7 @@ xfs_bmap_add_extent_delay_real(
 
                if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                        error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
-                                       bma->firstblock, bma->flist, &bma->cur,
+                                       bma->firstblock, bma->dfops, &bma->cur,
                                        1, &tmp_rval, whichfork);
                        rval |= tmp_rval;
                        if (error)
@@ -2199,13 +2179,18 @@ xfs_bmap_add_extent_delay_real(
                ASSERT(0);
        }
 
+       /* add reverse mapping */
+       error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new);
+       if (error)
+               goto done;
+
        /* convert to a btree if necessary */
        if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(bma->cur == NULL);
                error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
-                               bma->firstblock, bma->flist, &bma->cur,
+                               bma->firstblock, bma->dfops, &bma->cur,
                                da_old > 0, &tmp_logflags, whichfork);
                bma->logflags |= tmp_logflags;
                if (error)
@@ -2247,7 +2232,7 @@ xfs_bmap_add_extent_unwritten_real(
        xfs_btree_cur_t         **curp, /* if *curp is null, not a btree */
        xfs_bmbt_irec_t         *new,   /* new data to add to file extents */
        xfs_fsblock_t           *first, /* pointer to firstblock variable */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
+       struct xfs_defer_ops    *dfops, /* list of extents to be freed */
        int                     *logflagsp) /* inode logging flags */
 {
        xfs_btree_cur_t         *cur;   /* btree cursor */
@@ -2735,12 +2720,17 @@ xfs_bmap_add_extent_unwritten_real(
                ASSERT(0);
        }
 
+       /* update reverse mappings */
+       error = xfs_rmap_convert_extent(mp, dfops, ip, XFS_DATA_FORK, new);
+       if (error)
+               goto done;
+
        /* convert to a btree if necessary */
        if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(cur == NULL);
-               error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
+               error = xfs_bmap_extents_to_btree(tp, ip, first, dfops, &cur,
                                0, &tmp_logflags, XFS_DATA_FORK);
                *logflagsp |= tmp_logflags;
                if (error)
@@ -3127,13 +3117,18 @@ xfs_bmap_add_extent_hole_real(
                break;
        }
 
+       /* add reverse mapping */
+       error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new);
+       if (error)
+               goto done;
+
        /* convert to a btree if necessary */
        if (xfs_bmap_needs_btree(bma->ip, whichfork)) {
                int     tmp_logflags;   /* partial log flag return val */
 
                ASSERT(bma->cur == NULL);
                error = xfs_bmap_extents_to_btree(bma->tp, bma->ip,
-                               bma->firstblock, bma->flist, &bma->cur,
+                               bma->firstblock, bma->dfops, &bma->cur,
                                0, &tmp_logflags, whichfork);
                bma->logflags |= tmp_logflags;
                if (error)
@@ -3691,9 +3686,10 @@ xfs_bmap_btalloc(
        args.tp = ap->tp;
        args.mp = mp;
        args.fsbno = ap->blkno;
+       xfs_rmap_skip_owner_update(&args.oinfo);
 
        /* Trim the allocation back to the maximum an AG can fit. */
-       args.maxlen = MIN(ap->length, XFS_ALLOC_AG_MAX_USABLE(mp));
+       args.maxlen = MIN(ap->length, mp->m_ag_max_usable);
        args.firstblock = *ap->firstblock;
        blen = 0;
        if (nullfb) {
@@ -3708,7 +3704,7 @@ xfs_bmap_btalloc(
                        error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
                if (error)
                        return error;
-       } else if (ap->flist->xbf_low) {
+       } else if (ap->dfops->dop_low) {
                if (xfs_inode_is_filestream(ap->ip))
                        args.type = XFS_ALLOCTYPE_FIRST_AG;
                else
@@ -3741,7 +3737,7 @@ xfs_bmap_btalloc(
         * is >= the stripe unit and the allocation offset is
         * at the end of file.
         */
-       if (!ap->flist->xbf_low && ap->aeof) {
+       if (!ap->dfops->dop_low && ap->aeof) {
                if (!ap->offset) {
                        args.alignment = stripe_align;
                        atype = args.type;
@@ -3834,7 +3830,7 @@ xfs_bmap_btalloc(
                args.minleft = 0;
                if ((error = xfs_alloc_vextent(&args)))
                        return error;
-               ap->flist->xbf_low = 1;
+               ap->dfops->dop_low = true;
        }
        if (args.fsbno != NULLFSBLOCK) {
                /*
@@ -3844,7 +3840,7 @@ xfs_bmap_btalloc(
                ASSERT(*ap->firstblock == NULLFSBLOCK ||
                       XFS_FSB_TO_AGNO(mp, *ap->firstblock) ==
                       XFS_FSB_TO_AGNO(mp, args.fsbno) ||
-                      (ap->flist->xbf_low &&
+                      (ap->dfops->dop_low &&
                        XFS_FSB_TO_AGNO(mp, *ap->firstblock) <
                        XFS_FSB_TO_AGNO(mp, args.fsbno)));
 
@@ -3852,7 +3848,7 @@ xfs_bmap_btalloc(
                if (*ap->firstblock == NULLFSBLOCK)
                        *ap->firstblock = args.fsbno;
                ASSERT(nullfb || fb_agno == args.agno ||
-                      (ap->flist->xbf_low && fb_agno < args.agno));
+                      (ap->dfops->dop_low && fb_agno < args.agno));
                ap->length = args.len;
                ap->ip->i_d.di_nblocks += args.len;
                xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
@@ -4319,7 +4315,7 @@ xfs_bmapi_allocate(
        if (error)
                return error;
 
-       if (bma->flist->xbf_low)
+       if (bma->dfops->dop_low)
                bma->minleft = 0;
        if (bma->cur)
                bma->cur->bc_private.b.firstblock = *bma->firstblock;
@@ -4328,7 +4324,7 @@ xfs_bmapi_allocate(
        if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) {
                bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork);
                bma->cur->bc_private.b.firstblock = *bma->firstblock;
-               bma->cur->bc_private.b.flist = bma->flist;
+               bma->cur->bc_private.b.dfops = bma->dfops;
        }
        /*
         * Bump the number of extents we've allocated
@@ -4409,7 +4405,7 @@ xfs_bmapi_convert_unwritten(
                bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp,
                                        bma->ip, whichfork);
                bma->cur->bc_private.b.firstblock = *bma->firstblock;
-               bma->cur->bc_private.b.flist = bma->flist;
+               bma->cur->bc_private.b.dfops = bma->dfops;
        }
        mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
                                ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
@@ -4426,7 +4422,7 @@ xfs_bmapi_convert_unwritten(
        }
 
        error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx,
-                       &bma->cur, mval, bma->firstblock, bma->flist,
+                       &bma->cur, mval, bma->firstblock, bma->dfops,
                        &tmp_logflags);
        /*
         * Log the inode core unconditionally in the unwritten extent conversion
@@ -4480,7 +4476,7 @@ xfs_bmapi_write(
        xfs_extlen_t            total,          /* total blocks needed */
        struct xfs_bmbt_irec    *mval,          /* output: map values */
        int                     *nmap,          /* i/o: mval size/count */
-       struct xfs_bmap_free    *flist)         /* i/o: list extents to free */
+       struct xfs_defer_ops    *dfops)         /* i/o: list extents to free */
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_ifork        *ifp;
@@ -4570,7 +4566,7 @@ xfs_bmapi_write(
        bma.ip = ip;
        bma.total = total;
        bma.userdata = 0;
-       bma.flist = flist;
+       bma.dfops = dfops;
        bma.firstblock = firstblock;
 
        while (bno < end && n < *nmap) {
@@ -4684,7 +4680,7 @@ error0:
                               XFS_FSB_TO_AGNO(mp, *firstblock) ==
                               XFS_FSB_TO_AGNO(mp,
                                       bma.cur->bc_private.b.firstblock) ||
-                              (flist->xbf_low &&
+                              (dfops->dop_low &&
                                XFS_FSB_TO_AGNO(mp, *firstblock) <
                                XFS_FSB_TO_AGNO(mp,
                                        bma.cur->bc_private.b.firstblock)));
@@ -4768,7 +4764,7 @@ xfs_bmap_del_extent(
        xfs_inode_t             *ip,    /* incore inode pointer */
        xfs_trans_t             *tp,    /* current transaction pointer */
        xfs_extnum_t            *idx,   /* extent number to update/delete */
-       xfs_bmap_free_t         *flist, /* list of extents to be freed */
+       struct xfs_defer_ops    *dfops, /* list of extents to be freed */
        xfs_btree_cur_t         *cur,   /* if null, not a btree */
        xfs_bmbt_irec_t         *del,   /* data to remove from extents */
        int                     *logflagsp, /* inode logging flags */
@@ -4870,6 +4866,7 @@ xfs_bmap_del_extent(
                nblks = 0;
                do_fx = 0;
        }
+
        /*
         * Set flag value to use in switch statement.
         * Left-contig is 2, right-contig is 1.
@@ -5052,12 +5049,20 @@ xfs_bmap_del_extent(
                ++*idx;
                break;
        }
+
+       /* remove reverse mapping */
+       if (!delay) {
+               error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, del);
+               if (error)
+                       goto done;
+       }
+
        /*
         * If we need to, add to list of extents to delete.
         */
        if (do_fx)
-               xfs_bmap_add_free(mp, flist, del->br_startblock,
-                       del->br_blockcount);
+               xfs_bmap_add_free(mp, dfops, del->br_startblock,
+                               del->br_blockcount, NULL);
        /*
         * Adjust inode # blocks in the file.
         */
@@ -5097,7 +5102,7 @@ xfs_bunmapi(
        xfs_extnum_t            nexts,          /* number of extents max */
        xfs_fsblock_t           *firstblock,    /* first allocated block
                                                   controls a.g. for allocs */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
+       struct xfs_defer_ops    *dfops,         /* i/o: list extents to free */
        int                     *done)          /* set if not done yet */
 {
        xfs_btree_cur_t         *cur;           /* bmap btree cursor */
@@ -5170,7 +5175,7 @@ xfs_bunmapi(
                ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstblock;
-               cur->bc_private.b.flist = flist;
+               cur->bc_private.b.dfops = dfops;
                cur->bc_private.b.flags = 0;
        } else
                cur = NULL;
@@ -5179,8 +5184,10 @@ xfs_bunmapi(
                /*
                 * Synchronize by locking the bitmap inode.
                 */
-               xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+               xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
                xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+               xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
+               xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
        }
 
        extno = 0;
@@ -5262,7 +5269,7 @@ xfs_bunmapi(
                        }
                        del.br_state = XFS_EXT_UNWRITTEN;
                        error = xfs_bmap_add_extent_unwritten_real(tp, ip,
-                                       &lastx, &cur, &del, firstblock, flist,
+                                       &lastx, &cur, &del, firstblock, dfops,
                                        &logflags);
                        if (error)
                                goto error0;
@@ -5321,7 +5328,7 @@ xfs_bunmapi(
                                lastx--;
                                error = xfs_bmap_add_extent_unwritten_real(tp,
                                                ip, &lastx, &cur, &prev,
-                                               firstblock, flist, &logflags);
+                                               firstblock, dfops, &logflags);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5330,7 +5337,7 @@ xfs_bunmapi(
                                del.br_state = XFS_EXT_UNWRITTEN;
                                error = xfs_bmap_add_extent_unwritten_real(tp,
                                                ip, &lastx, &cur, &del,
-                                               firstblock, flist, &logflags);
+                                               firstblock, dfops, &logflags);
                                if (error)
                                        goto error0;
                                goto nodelete;
@@ -5388,7 +5395,7 @@ xfs_bunmapi(
                } else if (cur)
                        cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL;
 
-               error = xfs_bmap_del_extent(ip, tp, &lastx, flist, cur, &del,
+               error = xfs_bmap_del_extent(ip, tp, &lastx, dfops, cur, &del,
                                &tmp_logflags, whichfork);
                logflags |= tmp_logflags;
                if (error)
@@ -5422,7 +5429,7 @@ nodelete:
         */
        if (xfs_bmap_needs_btree(ip, whichfork)) {
                ASSERT(cur == NULL);
-               error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist,
+               error = xfs_bmap_extents_to_btree(tp, ip, firstblock, dfops,
                        &cur, 0, &tmp_logflags, whichfork);
                logflags |= tmp_logflags;
                if (error)
@@ -5589,7 +5596,8 @@ xfs_bmse_shift_one(
        struct xfs_bmbt_rec_host        *gotp,
        struct xfs_btree_cur            *cur,
        int                             *logflags,
-       enum shift_direction            direction)
+       enum shift_direction            direction,
+       struct xfs_defer_ops            *dfops)
 {
        struct xfs_ifork                *ifp;
        struct xfs_mount                *mp;
@@ -5637,9 +5645,13 @@ xfs_bmse_shift_one(
                /* check whether to merge the extent or shift it down */
                if (xfs_bmse_can_merge(&adj_irec, &got,
                                       offset_shift_fsb)) {
-                       return xfs_bmse_merge(ip, whichfork, offset_shift_fsb,
-                                             *current_ext, gotp, adj_irecp,
-                                             cur, logflags);
+                       error = xfs_bmse_merge(ip, whichfork, offset_shift_fsb,
+                                              *current_ext, gotp, adj_irecp,
+                                              cur, logflags);
+                       if (error)
+                               return error;
+                       adj_irec = got;
+                       goto update_rmap;
                }
        } else {
                startoff = got.br_startoff + offset_shift_fsb;
@@ -5676,9 +5688,10 @@ update_current_ext:
                (*current_ext)--;
        xfs_bmbt_set_startoff(gotp, startoff);
        *logflags |= XFS_ILOG_CORE;
+       adj_irec = got;
        if (!cur) {
                *logflags |= XFS_ILOG_DEXT;
-               return 0;
+               goto update_rmap;
        }
 
        error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock,
@@ -5688,8 +5701,18 @@ update_current_ext:
        XFS_WANT_CORRUPTED_RETURN(mp, i == 1);
 
        got.br_startoff = startoff;
-       return xfs_bmbt_update(cur, got.br_startoff, got.br_startblock,
-                              got.br_blockcount, got.br_state);
+       error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock,
+                       got.br_blockcount, got.br_state);
+       if (error)
+               return error;
+
+update_rmap:
+       /* update reverse mapping */
+       error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, &adj_irec);
+       if (error)
+               return error;
+       adj_irec.br_startoff = startoff;
+       return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &adj_irec);
 }
 
 /*
@@ -5711,7 +5734,7 @@ xfs_bmap_shift_extents(
        int                     *done,
        xfs_fileoff_t           stop_fsb,
        xfs_fsblock_t           *firstblock,
-       struct xfs_bmap_free    *flist,
+       struct xfs_defer_ops    *dfops,
        enum shift_direction    direction,
        int                     num_exts)
 {
@@ -5756,7 +5779,7 @@ xfs_bmap_shift_extents(
        if (ifp->if_flags & XFS_IFBROOT) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstblock;
-               cur->bc_private.b.flist = flist;
+               cur->bc_private.b.dfops = dfops;
                cur->bc_private.b.flags = 0;
        }
 
@@ -5817,7 +5840,7 @@ xfs_bmap_shift_extents(
        while (nexts++ < num_exts) {
                error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
                                           &current_ext, gotp, cur, &logflags,
-                                          direction);
+                                          direction, dfops);
                if (error)
                        goto del_cursor;
                /*
@@ -5865,7 +5888,7 @@ xfs_bmap_split_extent_at(
        struct xfs_inode        *ip,
        xfs_fileoff_t           split_fsb,
        xfs_fsblock_t           *firstfsb,
-       struct xfs_bmap_free    *free_list)
+       struct xfs_defer_ops    *dfops)
 {
        int                             whichfork = XFS_DATA_FORK;
        struct xfs_btree_cur            *cur = NULL;
@@ -5927,7 +5950,7 @@ xfs_bmap_split_extent_at(
        if (ifp->if_flags & XFS_IFBROOT) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstfsb;
-               cur->bc_private.b.flist = free_list;
+               cur->bc_private.b.dfops = dfops;
                cur->bc_private.b.flags = 0;
                error = xfs_bmbt_lookup_eq(cur, got.br_startoff,
                                got.br_startblock,
@@ -5980,7 +6003,7 @@ xfs_bmap_split_extent_at(
                int tmp_logflags; /* partial log flag return val */
 
                ASSERT(cur == NULL);
-               error = xfs_bmap_extents_to_btree(tp, ip, firstfsb, free_list,
+               error = xfs_bmap_extents_to_btree(tp, ip, firstfsb, dfops,
                                &cur, 0, &tmp_logflags, whichfork);
                logflags |= tmp_logflags;
        }
@@ -6004,7 +6027,7 @@ xfs_bmap_split_extent(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           firstfsb;
        int                     error;
 
@@ -6016,21 +6039,21 @@ xfs_bmap_split_extent(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
-       xfs_bmap_init(&free_list, &firstfsb);
+       xfs_defer_init(&dfops, &firstfsb);
 
        error = xfs_bmap_split_extent_at(tp, ip, split_fsb,
-                       &firstfsb, &free_list);
+                       &firstfsb, &dfops);
        if (error)
                goto out;
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out;
 
        return xfs_trans_commit(tp);
 
 out:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_cancel(tp);
        return error;
 }
index f1f3ae6..254034f 100644 (file)
@@ -32,7 +32,7 @@ extern kmem_zone_t    *xfs_bmap_free_item_zone;
  */
 struct xfs_bmalloca {
        xfs_fsblock_t           *firstblock; /* i/o first block allocated */
-       struct xfs_bmap_free    *flist; /* bmap freelist */
+       struct xfs_defer_ops    *dfops; /* bmap freelist */
        struct xfs_trans        *tp;    /* transaction pointer */
        struct xfs_inode        *ip;    /* incore inode pointer */
        struct xfs_bmbt_irec    prev;   /* extent before the new one */
@@ -62,34 +62,14 @@ struct xfs_bmalloca {
  * List of extents to be free "later".
  * The list is kept sorted on xbf_startblock.
  */
-struct xfs_bmap_free_item
+struct xfs_extent_free_item
 {
-       xfs_fsblock_t           xbfi_startblock;/* starting fs block number */
-       xfs_extlen_t            xbfi_blockcount;/* number of blocks in extent */
-       struct list_head        xbfi_list;
+       xfs_fsblock_t           xefi_startblock;/* starting fs block number */
+       xfs_extlen_t            xefi_blockcount;/* number of blocks in extent */
+       struct list_head        xefi_list;
+       struct xfs_owner_info   xefi_oinfo;     /* extent owner */
 };
 
-/*
- * Header for free extent list.
- *
- * xbf_low is used by the allocator to activate the lowspace algorithm -
- * when free space is running low the extent allocator may choose to
- * allocate an extent from an AG without leaving sufficient space for
- * a btree split when inserting the new extent.  In this case the allocator
- * will enable the lowspace algorithm which is supposed to allow further
- * allocations (such as btree splits and newroots) to allocate from
- * sequential AGs.  In order to avoid locking AGs out of order the lowspace
- * algorithm will start searching for free space from AG 0.  If the correct
- * transaction reservations have been made then this algorithm will eventually
- * find all the space it needs.
- */
-typedef        struct xfs_bmap_free
-{
-       struct list_head        xbf_flist;      /* list of to-be-free extents */
-       int                     xbf_count;      /* count of items on list */
-       int                     xbf_low;        /* alloc in low mode */
-} xfs_bmap_free_t;
-
 #define        XFS_BMAP_MAX_NMAP       4
 
 /*
@@ -139,14 +119,6 @@ static inline int xfs_bmapi_aflag(int w)
 #define        DELAYSTARTBLOCK         ((xfs_fsblock_t)-1LL)
 #define        HOLESTARTBLOCK          ((xfs_fsblock_t)-2LL)
 
-static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
-{
-       INIT_LIST_HEAD(&flp->xbf_flist);
-       flp->xbf_count = 0;
-       flp->xbf_low = 0;
-       *fbp = NULLFSBLOCK;
-}
-
 /*
  * Flags for xfs_bmap_add_extent*.
  */
@@ -193,11 +165,9 @@ void       xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
 
 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(struct xfs_mount *mp, struct xfs_bmap_free *flist,
-                         xfs_fsblock_t bno, xfs_filblks_t len);
-void   xfs_bmap_cancel(struct xfs_bmap_free *flist);
-int    xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
-                       struct xfs_inode *ip);
+void   xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+                         xfs_fsblock_t bno, xfs_filblks_t len,
+                         struct xfs_owner_info *oinfo);
 void   xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork);
 int    xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
@@ -218,18 +188,18 @@ int       xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_fileoff_t bno, xfs_filblks_t len, int flags,
                xfs_fsblock_t *firstblock, xfs_extlen_t total,
                struct xfs_bmbt_irec *mval, int *nmap,
-               struct xfs_bmap_free *flist);
+               struct xfs_defer_ops *dfops);
 int    xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_fileoff_t bno, xfs_filblks_t len, int flags,
                xfs_extnum_t nexts, xfs_fsblock_t *firstblock,
-               struct xfs_bmap_free *flist, int *done);
+               struct xfs_defer_ops *dfops, int *done);
 int    xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
                xfs_extnum_t num);
 uint   xfs_default_attroffset(struct xfs_inode *ip);
 int    xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
                xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
                int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
-               struct xfs_bmap_free *flist, enum shift_direction direction,
+               struct xfs_defer_ops *dfops, enum shift_direction direction,
                int num_exts);
 int    xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
 
index db0c71e..cd85274 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
@@ -34,6 +35,7 @@
 #include "xfs_quota.h"
 #include "xfs_trace.h"
 #include "xfs_cksum.h"
+#include "xfs_rmap.h"
 
 /*
  * Determine the extent state.
@@ -406,11 +408,11 @@ xfs_bmbt_dup_cursor(
                        cur->bc_private.b.ip, cur->bc_private.b.whichfork);
 
        /*
-        * Copy the firstblock, flist, and flags values,
+        * Copy the firstblock, dfops, and flags values,
         * since init cursor doesn't get them.
         */
        new->bc_private.b.firstblock = cur->bc_private.b.firstblock;
-       new->bc_private.b.flist = cur->bc_private.b.flist;
+       new->bc_private.b.dfops = cur->bc_private.b.dfops;
        new->bc_private.b.flags = cur->bc_private.b.flags;
 
        return new;
@@ -423,7 +425,7 @@ xfs_bmbt_update_cursor(
 {
        ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) ||
               (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME));
-       ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist);
+       ASSERT(dst->bc_private.b.dfops == src->bc_private.b.dfops);
 
        dst->bc_private.b.allocated += src->bc_private.b.allocated;
        dst->bc_private.b.firstblock = src->bc_private.b.firstblock;
@@ -446,6 +448,8 @@ xfs_bmbt_alloc_block(
        args.mp = cur->bc_mp;
        args.fsbno = cur->bc_private.b.firstblock;
        args.firstblock = args.fsbno;
+       xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_private.b.ip->i_ino,
+                       cur->bc_private.b.whichfork);
 
        if (args.fsbno == NULLFSBLOCK) {
                args.fsbno = be64_to_cpu(start->l);
@@ -462,7 +466,7 @@ xfs_bmbt_alloc_block(
                 * block allocation here and corrupt the filesystem.
                 */
                args.minleft = args.tp->t_blk_res;
-       } else if (cur->bc_private.b.flist->xbf_low) {
+       } else if (cur->bc_private.b.dfops->dop_low) {
                args.type = XFS_ALLOCTYPE_START_BNO;
        } else {
                args.type = XFS_ALLOCTYPE_NEAR_BNO;
@@ -490,7 +494,7 @@ xfs_bmbt_alloc_block(
                error = xfs_alloc_vextent(&args);
                if (error)
                        goto error0;
-               cur->bc_private.b.flist->xbf_low = 1;
+               cur->bc_private.b.dfops->dop_low = true;
        }
        if (args.fsbno == NULLFSBLOCK) {
                XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
@@ -525,8 +529,10 @@ xfs_bmbt_free_block(
        struct xfs_inode        *ip = cur->bc_private.b.ip;
        struct xfs_trans        *tp = cur->bc_tp;
        xfs_fsblock_t           fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
+       struct xfs_owner_info   oinfo;
 
-       xfs_bmap_add_free(mp, cur->bc_private.b.flist, fsbno, 1);
+       xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_private.b.whichfork);
+       xfs_bmap_add_free(mp, cur->bc_private.b.dfops, fsbno, 1, &oinfo);
        ip->i_d.di_nblocks--;
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -599,17 +605,6 @@ xfs_bmbt_init_key_from_rec(
                cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt));
 }
 
-STATIC void
-xfs_bmbt_init_rec_from_key(
-       union xfs_btree_key     *key,
-       union xfs_btree_rec     *rec)
-{
-       ASSERT(key->bmbt.br_startoff != 0);
-
-       xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff),
-                              0, 0, XFS_EXT_NORM);
-}
-
 STATIC void
 xfs_bmbt_init_rec_from_cur(
        struct xfs_btree_cur    *cur,
@@ -760,7 +755,6 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {
        .get_minrecs            = xfs_bmbt_get_minrecs,
        .get_dmaxrecs           = xfs_bmbt_get_dmaxrecs,
        .init_key_from_rec      = xfs_bmbt_init_key_from_rec,
-       .init_rec_from_key      = xfs_bmbt_init_rec_from_key,
        .init_rec_from_cur      = xfs_bmbt_init_rec_from_cur,
        .init_ptr_from_cur      = xfs_bmbt_init_ptr_from_cur,
        .key_diff               = xfs_bmbt_key_diff,
@@ -800,7 +794,7 @@ xfs_bmbt_init_cursor(
        cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
        cur->bc_private.b.ip = ip;
        cur->bc_private.b.firstblock = NULLFSBLOCK;
-       cur->bc_private.b.flist = NULL;
+       cur->bc_private.b.dfops = NULL;
        cur->bc_private.b.allocated = 0;
        cur->bc_private.b.flags = 0;
        cur->bc_private.b.whichfork = whichfork;
index 07eeb0b..b5c213a 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_inode_item.h"
@@ -43,15 +44,14 @@ kmem_zone_t *xfs_btree_cur_zone;
  * Btree magic numbers.
  */
 static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
-       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
+       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, 0, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
          XFS_FIBT_MAGIC },
-       { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
+       { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, XFS_RMAP_CRC_MAGIC,
          XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
 };
 #define xfs_btree_magic(cur) \
        xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
 
-
 STATIC int                             /* error (0 or EFSCORRUPTED) */
 xfs_btree_check_lblock(
        struct xfs_btree_cur    *cur,   /* btree cursor */
@@ -428,6 +428,50 @@ xfs_btree_dup_cursor(
  * into a btree block (xfs_btree_*_offset) or return a pointer to the given
  * record, key or pointer (xfs_btree_*_addr).  Note that all addressing
  * inside the btree block is done using indices starting at one, not zero!
+ *
+ * If XFS_BTREE_OVERLAPPING is set, then this btree supports keys containing
+ * overlapping intervals.  In such a tree, records are still sorted lowest to
+ * highest and indexed by the smallest key value that refers to the record.
+ * However, nodes are different: each pointer has two associated keys -- one
+ * indexing the lowest key available in the block(s) below (the same behavior
+ * as the key in a regular btree) and another indexing the highest key
+ * available in the block(s) below.  Because records are /not/ sorted by the
+ * highest key, all leaf block updates require us to compute the highest key
+ * that matches any record in the leaf and to recursively update the high keys
+ * in the nodes going further up in the tree, if necessary.  Nodes look like
+ * this:
+ *
+ *             +--------+-----+-----+-----+-----+-----+-------+-------+-----+
+ * Non-Leaf:   | header | lo1 | hi1 | lo2 | hi2 | ... | ptr 1 | ptr 2 | ... |
+ *             +--------+-----+-----+-----+-----+-----+-------+-------+-----+
+ *
+ * To perform an interval query on an overlapped tree, perform the usual
+ * depth-first search and use the low and high keys to decide if we can skip
+ * that particular node.  If a leaf node is reached, return the records that
+ * intersect the interval.  Note that an interval query may return numerous
+ * entries.  For a non-overlapped tree, simply search for the record associated
+ * with the lowest key and iterate forward until a non-matching record is
+ * found.  Section 14.3 ("Interval Trees") of _Introduction to Algorithms_ by
+ * Cormen, Leiserson, Rivest, and Stein (2nd or 3rd ed. only) discuss this in
+ * more detail.
+ *
+ * Why do we care about overlapping intervals?  Let's say you have a bunch of
+ * reverse mapping records on a reflink filesystem:
+ *
+ * 1: +- file A startblock B offset C length D -----------+
+ * 2:      +- file E startblock F offset G length H --------------+
+ * 3:      +- file I startblock F offset J length K --+
+ * 4:                                                        +- file L... --+
+ *
+ * Now say we want to map block (B+D) into file A at offset (C+D).  Ideally,
+ * we'd simply increment the length of record 1.  But how do we find the record
+ * that ends at (B+D-1) (i.e. record 1)?  A LE lookup of (B+D-1) would return
+ * record 3 because the keys are ordered first by startblock.  An interval
+ * query would return records 1 and 2 because they both overlap (B+D-1), and
+ * from that we can pick out record 1 as the appropriate left neighbor.
+ *
+ * In the non-overlapped case you can do a LE lookup and decrement the cursor
+ * because a record's interval must end before the next record.
  */
 
 /*
@@ -478,6 +522,18 @@ xfs_btree_key_offset(
                (n - 1) * cur->bc_ops->key_len;
 }
 
+/*
+ * Calculate offset of the n-th high key in a btree block.
+ */
+STATIC size_t
+xfs_btree_high_key_offset(
+       struct xfs_btree_cur    *cur,
+       int                     n)
+{
+       return xfs_btree_block_len(cur) +
+               (n - 1) * cur->bc_ops->key_len + (cur->bc_ops->key_len / 2);
+}
+
 /*
  * Calculate offset of the n-th block pointer in a btree block.
  */
@@ -518,6 +574,19 @@ xfs_btree_key_addr(
                ((char *)block + xfs_btree_key_offset(cur, n));
 }
 
+/*
+ * Return a pointer to the n-th high key in the btree block.
+ */
+STATIC union xfs_btree_key *
+xfs_btree_high_key_addr(
+       struct xfs_btree_cur    *cur,
+       int                     n,
+       struct xfs_btree_block  *block)
+{
+       return (union xfs_btree_key *)
+               ((char *)block + xfs_btree_high_key_offset(cur, n));
+}
+
 /*
  * Return a pointer to the n-th block pointer in the btree block.
  */
@@ -1144,6 +1213,9 @@ xfs_btree_set_refs(
        case XFS_BTNUM_BMAP:
                xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF);
                break;
+       case XFS_BTNUM_RMAP:
+               xfs_buf_set_ref(bp, XFS_RMAP_BTREE_REF);
+               break;
        default:
                ASSERT(0);
        }
@@ -1879,32 +1951,214 @@ error0:
        return error;
 }
 
+/* Find the high key storage area from a regular key. */
+STATIC union xfs_btree_key *
+xfs_btree_high_key_from_key(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *key)
+{
+       ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING);
+       return (union xfs_btree_key *)((char *)key +
+                       (cur->bc_ops->key_len / 2));
+}
+
+/* Determine the low (and high if overlapped) keys of a leaf block */
+STATIC void
+xfs_btree_get_leaf_keys(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       union xfs_btree_key     *key)
+{
+       union xfs_btree_key     max_hkey;
+       union xfs_btree_key     hkey;
+       union xfs_btree_rec     *rec;
+       union xfs_btree_key     *high;
+       int                     n;
+
+       rec = xfs_btree_rec_addr(cur, 1, block);
+       cur->bc_ops->init_key_from_rec(key, rec);
+
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING) {
+
+               cur->bc_ops->init_high_key_from_rec(&max_hkey, rec);
+               for (n = 2; n <= xfs_btree_get_numrecs(block); n++) {
+                       rec = xfs_btree_rec_addr(cur, n, block);
+                       cur->bc_ops->init_high_key_from_rec(&hkey, rec);
+                       if (cur->bc_ops->diff_two_keys(cur, &hkey, &max_hkey)
+                                       > 0)
+                               max_hkey = hkey;
+               }
+
+               high = xfs_btree_high_key_from_key(cur, key);
+               memcpy(high, &max_hkey, cur->bc_ops->key_len / 2);
+       }
+}
+
+/* Determine the low (and high if overlapped) keys of a node block */
+STATIC void
+xfs_btree_get_node_keys(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       union xfs_btree_key     *key)
+{
+       union xfs_btree_key     *hkey;
+       union xfs_btree_key     *max_hkey;
+       union xfs_btree_key     *high;
+       int                     n;
+
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING) {
+               memcpy(key, xfs_btree_key_addr(cur, 1, block),
+                               cur->bc_ops->key_len / 2);
+
+               max_hkey = xfs_btree_high_key_addr(cur, 1, block);
+               for (n = 2; n <= xfs_btree_get_numrecs(block); n++) {
+                       hkey = xfs_btree_high_key_addr(cur, n, block);
+                       if (cur->bc_ops->diff_two_keys(cur, hkey, max_hkey) > 0)
+                               max_hkey = hkey;
+               }
+
+               high = xfs_btree_high_key_from_key(cur, key);
+               memcpy(high, max_hkey, cur->bc_ops->key_len / 2);
+       } else {
+               memcpy(key, xfs_btree_key_addr(cur, 1, block),
+                               cur->bc_ops->key_len);
+       }
+}
+
+/* Derive the keys for any btree block. */
+STATIC void
+xfs_btree_get_keys(
+       struct xfs_btree_cur    *cur,
+       struct xfs_btree_block  *block,
+       union xfs_btree_key     *key)
+{
+       if (be16_to_cpu(block->bb_level) == 0)
+               xfs_btree_get_leaf_keys(cur, block, key);
+       else
+               xfs_btree_get_node_keys(cur, block, key);
+}
+
 /*
- * Update keys at all levels from here to the root along the cursor's path.
+ * Decide if we need to update the parent keys of a btree block.  For
+ * a standard btree this is only necessary if we're updating the first
+ * record/key.  For an overlapping btree, we must always update the
+ * keys because the highest key can be in any of the records or keys
+ * in the block.
+ */
+static inline bool
+xfs_btree_needs_key_update(
+       struct xfs_btree_cur    *cur,
+       int                     ptr)
+{
+       return (cur->bc_flags & XFS_BTREE_OVERLAPPING) || ptr == 1;
+}
+
+/*
+ * Update the low and high parent keys of the given level, progressing
+ * towards the root.  If force_all is false, stop if the keys for a given
+ * level do not need updating.
  */
 STATIC int
-xfs_btree_updkey(
+__xfs_btree_updkeys(
+       struct xfs_btree_cur    *cur,
+       int                     level,
+       struct xfs_btree_block  *block,
+       struct xfs_buf          *bp0,
+       bool                    force_all)
+{
+       union xfs_btree_bigkey  key;    /* keys from current level */
+       union xfs_btree_key     *lkey;  /* keys from the next level up */
+       union xfs_btree_key     *hkey;
+       union xfs_btree_key     *nlkey; /* keys from the next level up */
+       union xfs_btree_key     *nhkey;
+       struct xfs_buf          *bp;
+       int                     ptr;
+
+       ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING);
+
+       /* Exit if there aren't any parent levels to update. */
+       if (level + 1 >= cur->bc_nlevels)
+               return 0;
+
+       trace_xfs_btree_updkeys(cur, level, bp0);
+
+       lkey = (union xfs_btree_key *)&key;
+       hkey = xfs_btree_high_key_from_key(cur, lkey);
+       xfs_btree_get_keys(cur, block, lkey);
+       for (level++; level < cur->bc_nlevels; level++) {
+#ifdef DEBUG
+               int             error;
+#endif
+               block = xfs_btree_get_block(cur, level, &bp);
+               trace_xfs_btree_updkeys(cur, level, bp);
+#ifdef DEBUG
+               error = xfs_btree_check_block(cur, block, level, bp);
+               if (error) {
+                       XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+                       return error;
+               }
+#endif
+               ptr = cur->bc_ptrs[level];
+               nlkey = xfs_btree_key_addr(cur, ptr, block);
+               nhkey = xfs_btree_high_key_addr(cur, ptr, block);
+               if (!force_all &&
+                   !(cur->bc_ops->diff_two_keys(cur, nlkey, lkey) != 0 ||
+                     cur->bc_ops->diff_two_keys(cur, nhkey, hkey) != 0))
+                       break;
+               xfs_btree_copy_keys(cur, nlkey, lkey, 1);
+               xfs_btree_log_keys(cur, bp, ptr, ptr);
+               if (level + 1 >= cur->bc_nlevels)
+                       break;
+               xfs_btree_get_node_keys(cur, block, lkey);
+       }
+
+       return 0;
+}
+
+/* Update all the keys from some level in cursor back to the root. */
+STATIC int
+xfs_btree_updkeys_force(
+       struct xfs_btree_cur    *cur,
+       int                     level)
+{
+       struct xfs_buf          *bp;
+       struct xfs_btree_block  *block;
+
+       block = xfs_btree_get_block(cur, level, &bp);
+       return __xfs_btree_updkeys(cur, level, block, bp, true);
+}
+
+/*
+ * Update the parent keys of the given level, progressing towards the root.
+ */
+STATIC int
+xfs_btree_update_keys(
        struct xfs_btree_cur    *cur,
-       union xfs_btree_key     *keyp,
        int                     level)
 {
        struct xfs_btree_block  *block;
        struct xfs_buf          *bp;
        union xfs_btree_key     *kp;
+       union xfs_btree_key     key;
        int                     ptr;
 
+       ASSERT(level >= 0);
+
+       block = xfs_btree_get_block(cur, level, &bp);
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING)
+               return __xfs_btree_updkeys(cur, level, block, bp, false);
+
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_TRACE_ARGIK(cur, level, keyp);
 
-       ASSERT(!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) || level >= 1);
-
        /*
         * Go up the tree from this level toward the root.
         * At each level, update the key value to the value input.
         * Stop when we reach a level where the cursor isn't pointing
         * at the first entry in the block.
         */
-       for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) {
+       xfs_btree_get_keys(cur, block, &key);
+       for (level++, ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) {
 #ifdef DEBUG
                int             error;
 #endif
@@ -1918,7 +2172,7 @@ xfs_btree_updkey(
 #endif
                ptr = cur->bc_ptrs[level];
                kp = xfs_btree_key_addr(cur, ptr, block);
-               xfs_btree_copy_keys(cur, kp, keyp, 1);
+               xfs_btree_copy_keys(cur, kp, &key, 1);
                xfs_btree_log_keys(cur, bp, ptr, ptr);
        }
 
@@ -1970,12 +2224,9 @@ xfs_btree_update(
                                            ptr, LASTREC_UPDATE);
        }
 
-       /* Updating first rec in leaf. Pass new key value up to our parent. */
-       if (ptr == 1) {
-               union xfs_btree_key     key;
-
-               cur->bc_ops->init_key_from_rec(&key, rec);
-               error = xfs_btree_updkey(cur, &key, 1);
+       /* Pass new key value up to our parent. */
+       if (xfs_btree_needs_key_update(cur, ptr)) {
+               error = xfs_btree_update_keys(cur, 0);
                if (error)
                        goto error0;
        }
@@ -1998,18 +2249,19 @@ xfs_btree_lshift(
        int                     level,
        int                     *stat)          /* success/failure */
 {
-       union xfs_btree_key     key;            /* btree key */
        struct xfs_buf          *lbp;           /* left buffer pointer */
        struct xfs_btree_block  *left;          /* left btree block */
        int                     lrecs;          /* left record count */
        struct xfs_buf          *rbp;           /* right buffer pointer */
        struct xfs_btree_block  *right;         /* right btree block */
+       struct xfs_btree_cur    *tcur;          /* temporary btree cursor */
        int                     rrecs;          /* right record count */
        union xfs_btree_ptr     lptr;           /* left btree pointer */
        union xfs_btree_key     *rkp = NULL;    /* right btree key */
        union xfs_btree_ptr     *rpp = NULL;    /* right address pointer */
        union xfs_btree_rec     *rrp = NULL;    /* right record pointer */
        int                     error;          /* error return value */
+       int                     i;
 
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
        XFS_BTREE_TRACE_ARGI(cur, level);
@@ -2139,18 +2391,33 @@ xfs_btree_lshift(
                        xfs_btree_rec_addr(cur, 2, right),
                        -1, rrecs);
                xfs_btree_log_recs(cur, rbp, 1, rrecs);
+       }
 
-               /*
-                * If it's the first record in the block, we'll need a key
-                * structure to pass up to the next level (updkey).
-                */
-               cur->bc_ops->init_key_from_rec(&key,
-                       xfs_btree_rec_addr(cur, 1, right));
-               rkp = &key;
+       /*
+        * Using a temporary cursor, update the parent key values of the
+        * block on the left.
+        */
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING) {
+               error = xfs_btree_dup_cursor(cur, &tcur);
+               if (error)
+                       goto error0;
+               i = xfs_btree_firstrec(tcur, level);
+               XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0);
+
+               error = xfs_btree_decrement(tcur, level, &i);
+               if (error)
+                       goto error1;
+
+               /* Update the parent high keys of the left block, if needed. */
+               error = xfs_btree_update_keys(tcur, level);
+               if (error)
+                       goto error1;
+
+               xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
        }
 
-       /* Update the parent key values of right. */
-       error = xfs_btree_updkey(cur, rkp, level + 1);
+       /* Update the parent keys of the right block. */
+       error = xfs_btree_update_keys(cur, level);
        if (error)
                goto error0;
 
@@ -2169,6 +2436,11 @@ out0:
 error0:
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
        return error;
+
+error1:
+       XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
+       xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
+       return error;
 }
 
 /*
@@ -2181,7 +2453,6 @@ xfs_btree_rshift(
        int                     level,
        int                     *stat)          /* success/failure */
 {
-       union xfs_btree_key     key;            /* btree key */
        struct xfs_buf          *lbp;           /* left buffer pointer */
        struct xfs_btree_block  *left;          /* left btree block */
        struct xfs_buf          *rbp;           /* right buffer pointer */
@@ -2290,12 +2561,6 @@ xfs_btree_rshift(
                /* Now put the new data in, and log it. */
                xfs_btree_copy_recs(cur, rrp, lrp, 1);
                xfs_btree_log_recs(cur, rbp, 1, rrecs + 1);
-
-               cur->bc_ops->init_key_from_rec(&key, rrp);
-               rkp = &key;
-
-               ASSERT(cur->bc_ops->recs_inorder(cur, rrp,
-                       xfs_btree_rec_addr(cur, 2, right)));
        }
 
        /*
@@ -2315,13 +2580,21 @@ xfs_btree_rshift(
        if (error)
                goto error0;
        i = xfs_btree_lastrec(tcur, level);
-       XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0);
+       XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0);
 
        error = xfs_btree_increment(tcur, level, &i);
        if (error)
                goto error1;
 
-       error = xfs_btree_updkey(tcur, rkp, level + 1);
+       /* Update the parent high keys of the left block, if needed. */
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING) {
+               error = xfs_btree_update_keys(cur, level);
+               if (error)
+                       goto error1;
+       }
+
+       /* Update the parent keys of the right block. */
+       error = xfs_btree_update_keys(tcur, level);
        if (error)
                goto error1;
 
@@ -2422,6 +2695,11 @@ __xfs_btree_split(
 
        XFS_BTREE_STATS_ADD(cur, moves, rrecs);
 
+       /* Adjust numrecs for the later get_*_keys() calls. */
+       lrecs -= rrecs;
+       xfs_btree_set_numrecs(left, lrecs);
+       xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs);
+
        /*
         * Copy btree block entries from the left block over to the
         * new block, the right. Update the right block and log the
@@ -2447,14 +2725,15 @@ __xfs_btree_split(
                }
 #endif
 
+               /* Copy the keys & pointers to the new block. */
                xfs_btree_copy_keys(cur, rkp, lkp, rrecs);
                xfs_btree_copy_ptrs(cur, rpp, lpp, rrecs);
 
                xfs_btree_log_keys(cur, rbp, 1, rrecs);
                xfs_btree_log_ptrs(cur, rbp, 1, rrecs);
 
-               /* Grab the keys to the entries moved to the right block */
-               xfs_btree_copy_keys(cur, key, rkp, 1);
+               /* Stash the keys of the new block for later insertion. */
+               xfs_btree_get_node_keys(cur, right, key);
        } else {
                /* It's a leaf.  Move records.  */
                union xfs_btree_rec     *lrp;   /* left record pointer */
@@ -2463,27 +2742,23 @@ __xfs_btree_split(
                lrp = xfs_btree_rec_addr(cur, src_index, left);
                rrp = xfs_btree_rec_addr(cur, 1, right);
 
+               /* Copy records to the new block. */
                xfs_btree_copy_recs(cur, rrp, lrp, rrecs);
                xfs_btree_log_recs(cur, rbp, 1, rrecs);
 
-               cur->bc_ops->init_key_from_rec(key,
-                       xfs_btree_rec_addr(cur, 1, right));
+               /* Stash the keys of the new block for later insertion. */
+               xfs_btree_get_leaf_keys(cur, right, key);
        }
 
-
        /*
         * Find the left block number by looking in the buffer.
-        * Adjust numrecs, sibling pointers.
+        * Adjust sibling pointers.
         */
        xfs_btree_get_sibling(cur, left, &rrptr, XFS_BB_RIGHTSIB);
        xfs_btree_set_sibling(cur, right, &rrptr, XFS_BB_RIGHTSIB);
        xfs_btree_set_sibling(cur, right, &lptr, XFS_BB_LEFTSIB);
        xfs_btree_set_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB);
 
-       lrecs -= rrecs;
-       xfs_btree_set_numrecs(left, lrecs);
-       xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs);
-
        xfs_btree_log_block(cur, rbp, XFS_BB_ALL_BITS);
        xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB);
 
@@ -2499,6 +2774,14 @@ __xfs_btree_split(
                xfs_btree_set_sibling(cur, rrblock, &rptr, XFS_BB_LEFTSIB);
                xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB);
        }
+
+       /* Update the parent high keys of the left block, if needed. */
+       if (cur->bc_flags & XFS_BTREE_OVERLAPPING) {
+               error = xfs_btree_update_keys(cur, level);
+               if (error)
+                       goto error0;
+       }
+
        /*
         * If the cursor is really in the right block, move it there.
         * If it's just pointing past the last entry in left, then we'll
@@ -2802,6 +3085,7 @@ xfs_btree_new_root(
                bp = lbp;
                nptr = 2;
        }
+
        /* Fill in the new block's btree header and log it. */
        xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2);
        xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS);
@@ -2810,19 +3094,24 @@ xfs_btree_new_root(
 
        /* Fill in the key data in the new root. */
        if (xfs_btree_get_level(left) > 0) {
-               xfs_btree_copy_keys(cur,
-                               xfs_btree_key_addr(cur, 1, new),
-                               xfs_btree_key_addr(cur, 1, left), 1);
-               xfs_btree_copy_keys(cur,
-                               xfs_btree_key_addr(cur, 2, new),
-                               xfs_btree_key_addr(cur, 1, right), 1);
+               /*
+                * Get the keys for the left block's keys and put them directly
+                * in the parent block.  Do the same for the right block.
+                */
+               xfs_btree_get_node_keys(cur, left,
+                               xfs_btree_key_addr(cur, 1, new));
+               xfs_btree_get_node_keys(cur, right,
+                               xfs_btree_key_addr(cur, 2, new));
        } else {
-               cur->bc_ops->init_key_from_rec(
-                               xfs_btree_key_addr(cur, 1, new),
-                               xfs_btree_rec_addr(cur, 1, left));
-               cur->bc_ops->init_key_from_rec(
-                               xfs_btree_key_addr(cur, 2, new),
-                               xfs_btree_rec_addr(cur, 1, right));
+               /*
+                * Get the keys for the left block's records and put them
+                * directly in the parent block.  Do the same for the right
+                * block.
+                */
+               xfs_btree_get_leaf_keys(cur, left,
+                       xfs_btree_key_addr(cur, 1, new));
+               xfs_btree_get_leaf_keys(cur, right,
+                       xfs_btree_key_addr(cur, 2, new));
        }
        xfs_btree_log_keys(cur, nbp, 1, 2);
 
@@ -2858,10 +3147,9 @@ xfs_btree_make_block_unfull(
        int                     *index, /* new tree index */
        union xfs_btree_ptr     *nptr,  /* new btree ptr */
        struct xfs_btree_cur    **ncur, /* new btree cursor */
-       union xfs_btree_rec     *nrec,  /* new record */
+       union xfs_btree_key     *key,   /* key of new block */
        int                     *stat)
 {
-       union xfs_btree_key     key;    /* new btree key value */
        int                     error = 0;
 
        if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
@@ -2871,6 +3159,7 @@ xfs_btree_make_block_unfull(
                if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
                        /* A root block that can be made bigger. */
                        xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork);
+                       *stat = 1;
                } else {
                        /* A root block that needs replacing */
                        int     logflags = 0;
@@ -2906,13 +3195,12 @@ xfs_btree_make_block_unfull(
         * If this works we have to re-set our variables because we
         * could be in a different block now.
         */
-       error = xfs_btree_split(cur, level, nptr, &key, ncur, stat);
+       error = xfs_btree_split(cur, level, nptr, key, ncur, stat);
        if (error || *stat == 0)
                return error;
 
 
        *index = cur->bc_ptrs[level];
-       cur->bc_ops->init_rec_from_key(&key, nrec);
        return 0;
 }
 
@@ -2925,16 +3213,17 @@ xfs_btree_insrec(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        int                     level,  /* level to insert record at */
        union xfs_btree_ptr     *ptrp,  /* i/o: block number inserted */
-       union xfs_btree_rec     *recp,  /* i/o: record data inserted */
+       union xfs_btree_rec     *rec,   /* record to insert */
+       union xfs_btree_key     *key,   /* i/o: block key for ptrp */
        struct xfs_btree_cur    **curp, /* output: new cursor replacing cur */
        int                     *stat)  /* success/failure */
 {
        struct xfs_btree_block  *block; /* btree block */
        struct xfs_buf          *bp;    /* buffer for block */
-       union xfs_btree_key     key;    /* btree key */
        union xfs_btree_ptr     nptr;   /* new block ptr */
        struct xfs_btree_cur    *ncur;  /* new btree cursor */
-       union xfs_btree_rec     nrec;   /* new record count */
+       union xfs_btree_bigkey  nkey;   /* new block key */
+       union xfs_btree_key     *lkey;
        int                     optr;   /* old key/record index */
        int                     ptr;    /* key/record index */
        int                     numrecs;/* number of records */
@@ -2942,11 +3231,13 @@ xfs_btree_insrec(
 #ifdef DEBUG
        int                     i;
 #endif
+       xfs_daddr_t             old_bn;
 
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
-       XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, recp);
+       XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, &rec);
 
        ncur = NULL;
+       lkey = (union xfs_btree_key *)&nkey;
 
        /*
         * If we have an external root pointer, and we've made it to the
@@ -2969,15 +3260,13 @@ xfs_btree_insrec(
                return 0;
        }
 
-       /* Make a key out of the record data to be inserted, and save it. */
-       cur->bc_ops->init_key_from_rec(&key, recp);
-
        optr = ptr;
 
        XFS_BTREE_STATS_INC(cur, insrec);
 
        /* Get pointers to the btree buffer and block. */
        block = xfs_btree_get_block(cur, level, &bp);
+       old_bn = bp ? bp->b_bn : XFS_BUF_DADDR_NULL;
        numrecs = xfs_btree_get_numrecs(block);
 
 #ifdef DEBUG
@@ -2988,10 +3277,10 @@ xfs_btree_insrec(
        /* Check that the new entry is being inserted in the right place. */
        if (ptr <= numrecs) {
                if (level == 0) {
-                       ASSERT(cur->bc_ops->recs_inorder(cur, recp,
+                       ASSERT(cur->bc_ops->recs_inorder(cur, rec,
                                xfs_btree_rec_addr(cur, ptr, block)));
                } else {
-                       ASSERT(cur->bc_ops->keys_inorder(cur, &key,
+                       ASSERT(cur->bc_ops->keys_inorder(cur, key,
                                xfs_btree_key_addr(cur, ptr, block)));
                }
        }
@@ -3004,7 +3293,7 @@ xfs_btree_insrec(
        xfs_btree_set_ptr_null(cur, &nptr);
        if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) {
                error = xfs_btree_make_block_unfull(cur, level, numrecs,
-                                       &optr, &ptr, &nptr, &ncur, &nrec, stat);
+                                       &optr, &ptr, &nptr, &ncur, lkey, stat);
                if (error || *stat == 0)
                        goto error0;
        }
@@ -3054,7 +3343,7 @@ xfs_btree_insrec(
 #endif
 
                /* Now put the new data in, bump numrecs and log it. */
-               xfs_btree_copy_keys(cur, kp, &key, 1);
+               xfs_btree_copy_keys(cur, kp, key, 1);
                xfs_btree_copy_ptrs(cur, pp, ptrp, 1);
                numrecs++;
                xfs_btree_set_numrecs(block, numrecs);
@@ -3075,7 +3364,7 @@ xfs_btree_insrec(
                xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1);
 
                /* Now put the new data in, bump numrecs and log it. */
-               xfs_btree_copy_recs(cur, rp, recp, 1);
+               xfs_btree_copy_recs(cur, rp, rec, 1);
                xfs_btree_set_numrecs(block, ++numrecs);
                xfs_btree_log_recs(cur, bp, ptr, numrecs);
 #ifdef DEBUG
@@ -3089,9 +3378,18 @@ xfs_btree_insrec(
        /* Log the new number of records in the btree header. */
        xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS);
 
-       /* If we inserted at the start of a block, update the parents' keys. */
-       if (optr == 1) {
-               error = xfs_btree_updkey(cur, &key, level + 1);
+       /*
+        * If we just inserted into a new tree block, we have to
+        * recalculate nkey here because nkey is out of date.
+        *
+        * Otherwise we're just updating an existing block (having shoved
+        * some records into the new tree block), so use the regular key
+        * update mechanism.
+        */
+       if (bp && bp->b_bn != old_bn) {
+               xfs_btree_get_keys(cur, block, lkey);
+       } else if (xfs_btree_needs_key_update(cur, optr)) {
+               error = xfs_btree_update_keys(cur, level);
                if (error)
                        goto error0;
        }
@@ -3101,7 +3399,7 @@ xfs_btree_insrec(
         * we are at the far right edge of the tree, update it.
         */
        if (xfs_btree_is_lastrec(cur, block, level)) {
-               cur->bc_ops->update_lastrec(cur, block, recp,
+               cur->bc_ops->update_lastrec(cur, block, rec,
                                            ptr, LASTREC_INSREC);
        }
 
@@ -3111,7 +3409,7 @@ xfs_btree_insrec(
         */
        *ptrp = nptr;
        if (!xfs_btree_ptr_is_null(cur, &nptr)) {
-               *recp = nrec;
+               xfs_btree_copy_keys(cur, key, lkey, 1);
                *curp = ncur;
        }
 
@@ -3142,14 +3440,20 @@ xfs_btree_insert(
        union xfs_btree_ptr     nptr;   /* new block number (split result) */
        struct xfs_btree_cur    *ncur;  /* new cursor (split result) */
        struct xfs_btree_cur    *pcur;  /* previous level's cursor */
+       union xfs_btree_bigkey  bkey;   /* key of block to insert */
+       union xfs_btree_key     *key;
        union xfs_btree_rec     rec;    /* record to insert */
 
        level = 0;
        ncur = NULL;
        pcur = cur;
+       key = (union xfs_btree_key *)&bkey;
 
        xfs_btree_set_ptr_null(cur, &nptr);
+
+       /* Make a key out of the record data to be inserted, and save it. */
        cur->bc_ops->init_rec_from_cur(cur, &rec);
+       cur->bc_ops->init_key_from_rec(key, &rec);
 
        /*
         * Loop going up the tree, starting at the leaf level.
@@ -3161,7 +3465,8 @@ xfs_btree_insert(
                 * Insert nrec/nptr into this level of the tree.
                 * Note if we fail, nptr will be null.
                 */
-               error = xfs_btree_insrec(pcur, level, &nptr, &rec, &ncur, &i);
+               error = xfs_btree_insrec(pcur, level, &nptr, &rec, key,
+                               &ncur, &i);
                if (error) {
                        if (pcur != cur)
                                xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
@@ -3385,8 +3690,6 @@ xfs_btree_delrec(
        struct xfs_buf          *bp;            /* buffer for block */
        int                     error;          /* error return value */
        int                     i;              /* loop counter */
-       union xfs_btree_key     key;            /* storage for keyp */
-       union xfs_btree_key     *keyp = &key;   /* passed to the next level */
        union xfs_btree_ptr     lptr;           /* left sibling block ptr */
        struct xfs_buf          *lbp;           /* left buffer pointer */
        struct xfs_btree_block  *left;          /* left btree block */
@@ -3457,13 +3760,6 @@ xfs_btree_delrec(
                        xfs_btree_log_keys(cur, bp, ptr, numrecs - 1);
                        xfs_btree_log_ptrs(cur, bp, ptr, numrecs - 1);
                }
-
-               /*
-                * If it's the first record in the block, we'll need to pass a
-                * key up to the next level (updkey).
-                */
-               if (ptr == 1)
-                       keyp = xfs_btree_key_addr(cur, 1, block);
        } else {
                /* It's a leaf. operate on records */
                if (ptr < numrecs) {
@@ -3472,16 +3768,6 @@ xfs_btree_delrec(
                                -1, numrecs - ptr);
                        xfs_btree_log_recs(cur, bp, ptr, numrecs - 1);
                }
-
-               /*
-                * If it's the first record in the block, we'll need a key
-                * structure to pass up to the next level (updkey).
-                */
-               if (ptr == 1) {
-                       cur->bc_ops->init_key_from_rec(&key,
-                                       xfs_btree_rec_addr(cur, 1, block));
-                       keyp = &key;
-               }
        }
 
        /*
@@ -3548,8 +3834,8 @@ xfs_btree_delrec(
         * If we deleted the leftmost entry in the block, update the
         * key values above us in the tree.
         */
-       if (ptr == 1) {
-               error = xfs_btree_updkey(cur, keyp, level + 1);
+       if (xfs_btree_needs_key_update(cur, ptr)) {
+               error = xfs_btree_update_keys(cur, level);
                if (error)
                        goto error0;
        }
@@ -3878,6 +4164,16 @@ xfs_btree_delrec(
        if (level > 0)
                cur->bc_ptrs[level]--;
 
+       /*
+        * We combined blocks, so we have to update the parent keys if the
+        * btree supports overlapped intervals.  However, bc_ptrs[level + 1]
+        * points to the old block so that the caller knows which record to
+        * delete.  Therefore, the caller must be savvy enough to call updkeys
+        * for us if we return stat == 2.  The other exit points from this
+        * function don't require deletions further up the tree, so they can
+        * call updkeys directly.
+        */
+
        XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
        /* Return value means the next level up has something to do. */
        *stat = 2;
@@ -3903,6 +4199,7 @@ xfs_btree_delete(
        int                     error;  /* error return value */
        int                     level;
        int                     i;
+       bool                    joined = false;
 
        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
 
@@ -3916,6 +4213,18 @@ xfs_btree_delete(
                error = xfs_btree_delrec(cur, level, &i);
                if (error)
                        goto error0;
+               if (i == 2)
+                       joined = true;
+       }
+
+       /*
+        * If we combined blocks as part of deleting the record, delrec won't
+        * have updated the parent high keys so we have to do that here.
+        */
+       if (joined && (cur->bc_flags & XFS_BTREE_OVERLAPPING)) {
+               error = xfs_btree_updkeys_force(cur, 0);
+               if (error)
+                       goto error0;
        }
 
        if (i == 0) {
@@ -3978,6 +4287,81 @@ xfs_btree_get_rec(
        return 0;
 }
 
+/* Visit a block in a btree. */
+STATIC int
+xfs_btree_visit_block(
+       struct xfs_btree_cur            *cur,
+       int                             level,
+       xfs_btree_visit_blocks_fn       fn,
+       void                            *data)
+{
+       struct xfs_btree_block          *block;
+       struct xfs_buf                  *bp;
+       union xfs_btree_ptr             rptr;
+       int                             error;
+
+       /* do right sibling readahead */
+       xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
+       block = xfs_btree_get_block(cur, level, &bp);
+
+       /* process the block */
+       error = fn(cur, level, data);
+       if (error)
+               return error;
+
+       /* now read rh sibling block for next iteration */
+       xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
+       if (xfs_btree_ptr_is_null(cur, &rptr))
+               return -ENOENT;
+
+       return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
+}
+
+
+/* Visit every block in a btree. */
+int
+xfs_btree_visit_blocks(
+       struct xfs_btree_cur            *cur,
+       xfs_btree_visit_blocks_fn       fn,
+       void                            *data)
+{
+       union xfs_btree_ptr             lptr;
+       int                             level;
+       struct xfs_btree_block          *block = NULL;
+       int                             error = 0;
+
+       cur->bc_ops->init_ptr_from_cur(cur, &lptr);
+
+       /* for each level */
+       for (level = cur->bc_nlevels - 1; level >= 0; level--) {
+               /* grab the left hand block */
+               error = xfs_btree_lookup_get_block(cur, level, &lptr, &block);
+               if (error)
+                       return error;
+
+               /* readahead the left most block for the next level down */
+               if (level > 0) {
+                       union xfs_btree_ptr     *ptr;
+
+                       ptr = xfs_btree_ptr_addr(cur, 1, block);
+                       xfs_btree_readahead_ptr(cur, ptr, 1);
+
+                       /* save for the next iteration of the loop */
+                       lptr = *ptr;
+               }
+
+               /* for each buffer in the level */
+               do {
+                       error = xfs_btree_visit_block(cur, level, fn, data);
+               } while (!error);
+
+               if (error != -ENOENT)
+                       return error;
+       }
+
+       return 0;
+}
+
 /*
  * Change the owner of a btree.
  *
@@ -4002,26 +4386,27 @@ xfs_btree_get_rec(
  * just queue the modified buffer as delayed write buffer so the transaction
  * recovery completion writes the changes to disk.
  */
+struct xfs_btree_block_change_owner_info {
+       __uint64_t              new_owner;
+       struct list_head        *buffer_list;
+};
+
 static int
 xfs_btree_block_change_owner(
        struct xfs_btree_cur    *cur,
        int                     level,
-       __uint64_t              new_owner,
-       struct list_head        *buffer_list)
+       void                    *data)
 {
+       struct xfs_btree_block_change_owner_info        *bbcoi = data;
        struct xfs_btree_block  *block;
        struct xfs_buf          *bp;
-       union xfs_btree_ptr     rptr;
-
-       /* do right sibling readahead */
-       xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
 
        /* modify the owner */
        block = xfs_btree_get_block(cur, level, &bp);
        if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
-               block->bb_u.l.bb_owner = cpu_to_be64(new_owner);
+               block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner);
        else
-               block->bb_u.s.bb_owner = cpu_to_be32(new_owner);
+               block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner);
 
        /*
         * If the block is a root block hosted in an inode, we might not have a
@@ -4035,19 +4420,14 @@ xfs_btree_block_change_owner(
                        xfs_trans_ordered_buf(cur->bc_tp, bp);
                        xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
                } else {
-                       xfs_buf_delwri_queue(bp, buffer_list);
+                       xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
                }
        } else {
                ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
                ASSERT(level == cur->bc_nlevels - 1);
        }
 
-       /* now read rh sibling block for next iteration */
-       xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
-       if (xfs_btree_ptr_is_null(cur, &rptr))
-               return -ENOENT;
-
-       return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
+       return 0;
 }
 
 int
@@ -4056,43 +4436,13 @@ xfs_btree_change_owner(
        __uint64_t              new_owner,
        struct list_head        *buffer_list)
 {
-       union xfs_btree_ptr     lptr;
-       int                     level;
-       struct xfs_btree_block  *block = NULL;
-       int                     error = 0;
-
-       cur->bc_ops->init_ptr_from_cur(cur, &lptr);
-
-       /* for each level */
-       for (level = cur->bc_nlevels - 1; level >= 0; level--) {
-               /* grab the left hand block */
-               error = xfs_btree_lookup_get_block(cur, level, &lptr, &block);
-               if (error)
-                       return error;
-
-               /* readahead the left most block for the next level down */
-               if (level > 0) {
-                       union xfs_btree_ptr     *ptr;
-
-                       ptr = xfs_btree_ptr_addr(cur, 1, block);
-                       xfs_btree_readahead_ptr(cur, ptr, 1);
-
-                       /* save for the next iteration of the loop */
-                       lptr = *ptr;
-               }
-
-               /* for each buffer in the level */
-               do {
-                       error = xfs_btree_block_change_owner(cur, level,
-                                                            new_owner,
-                                                            buffer_list);
-               } while (!error);
+       struct xfs_btree_block_change_owner_info        bbcoi;
 
-               if (error != -ENOENT)
-                       return error;
-       }
+       bbcoi.new_owner = new_owner;
+       bbcoi.buffer_list = buffer_list;
 
-       return 0;
+       return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner,
+                       &bbcoi);
 }
 
 /**
@@ -4171,3 +4521,267 @@ xfs_btree_compute_maxlevels(
                maxblocks = (maxblocks + limits[1] - 1) / limits[1];
        return level;
 }
+
+/*
+ * Query a regular btree for all records overlapping a given interval.
+ * Start with a LE lookup of the key of low_rec and return all records
+ * until we find a record with a key greater than the key of high_rec.
+ */
+STATIC int
+xfs_btree_simple_query_range(
+       struct xfs_btree_cur            *cur,
+       union xfs_btree_key             *low_key,
+       union xfs_btree_key             *high_key,
+       xfs_btree_query_range_fn        fn,
+       void                            *priv)
+{
+       union xfs_btree_rec             *recp;
+       union xfs_btree_key             rec_key;
+       __int64_t                       diff;
+       int                             stat;
+       bool                            firstrec = true;
+       int                             error;
+
+       ASSERT(cur->bc_ops->init_high_key_from_rec);
+       ASSERT(cur->bc_ops->diff_two_keys);
+
+       /*
+        * Find the leftmost record.  The btree cursor must be set
+        * to the low record used to generate low_key.
+        */
+       stat = 0;
+       error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, &stat);
+       if (error)
+               goto out;
+
+       while (stat) {
+               /* Find the record. */
+               error = xfs_btree_get_rec(cur, &recp, &stat);
+               if (error || !stat)
+                       break;
+               cur->bc_ops->init_high_key_from_rec(&rec_key, recp);
+
+               /* Skip if high_key(rec) < low_key. */
+               if (firstrec) {
+                       firstrec = false;
+                       diff = cur->bc_ops->diff_two_keys(cur, low_key,
+                                       &rec_key);
+                       if (diff > 0)
+                               goto advloop;
+               }
+
+               /* Stop if high_key < low_key(rec). */
+               diff = cur->bc_ops->diff_two_keys(cur, &rec_key, high_key);
+               if (diff > 0)
+                       break;
+
+               /* Callback */
+               error = fn(cur, recp, priv);
+               if (error < 0 || error == XFS_BTREE_QUERY_RANGE_ABORT)
+                       break;
+
+advloop:
+               /* Move on to the next record. */
+               error = xfs_btree_increment(cur, 0, &stat);
+               if (error)
+                       break;
+       }
+
+out:
+       return error;
+}
+
+/*
+ * Query an overlapped interval btree for all records overlapping a given
+ * interval.  This function roughly follows the algorithm given in
+ * "Interval Trees" of _Introduction to Algorithms_, which is section
+ * 14.3 in the 2nd and 3rd editions.
+ *
+ * First, generate keys for the low and high records passed in.
+ *
+ * For any leaf node, generate the high and low keys for the record.
+ * If the record keys overlap with the query low/high keys, pass the
+ * record to the function iterator.
+ *
+ * For any internal node, compare the low and high keys of each
+ * pointer against the query low/high keys.  If there's an overlap,
+ * follow the pointer.
+ *
+ * As an optimization, we stop scanning a block when we find a low key
+ * that is greater than the query's high key.
+ */
+STATIC int
+xfs_btree_overlapped_query_range(
+       struct xfs_btree_cur            *cur,
+       union xfs_btree_key             *low_key,
+       union xfs_btree_key             *high_key,
+       xfs_btree_query_range_fn        fn,
+       void                            *priv)
+{
+       union xfs_btree_ptr             ptr;
+       union xfs_btree_ptr             *pp;
+       union xfs_btree_key             rec_key;
+       union xfs_btree_key             rec_hkey;
+       union xfs_btree_key             *lkp;
+       union xfs_btree_key             *hkp;
+       union xfs_btree_rec             *recp;
+       struct xfs_btree_block          *block;
+       __int64_t                       ldiff;
+       __int64_t                       hdiff;
+       int                             level;
+       struct xfs_buf                  *bp;
+       int                             i;
+       int                             error;
+
+       /* Load the root of the btree. */
+       level = cur->bc_nlevels - 1;
+       cur->bc_ops->init_ptr_from_cur(cur, &ptr);
+       error = xfs_btree_lookup_get_block(cur, level, &ptr, &block);
+       if (error)
+               return error;
+       xfs_btree_get_block(cur, level, &bp);
+       trace_xfs_btree_overlapped_query_range(cur, level, bp);
+#ifdef DEBUG
+       error = xfs_btree_check_block(cur, block, level, bp);
+       if (error)
+               goto out;
+#endif
+       cur->bc_ptrs[level] = 1;
+
+       while (level < cur->bc_nlevels) {
+               block = xfs_btree_get_block(cur, level, &bp);
+
+               /* End of node, pop back towards the root. */
+               if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) {
+pop_up:
+                       if (level < cur->bc_nlevels - 1)
+                               cur->bc_ptrs[level + 1]++;
+                       level++;
+                       continue;
+               }
+
+               if (level == 0) {
+                       /* Handle a leaf node. */
+                       recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
+
+                       cur->bc_ops->init_high_key_from_rec(&rec_hkey, recp);
+                       ldiff = cur->bc_ops->diff_two_keys(cur, &rec_hkey,
+                                       low_key);
+
+                       cur->bc_ops->init_key_from_rec(&rec_key, recp);
+                       hdiff = cur->bc_ops->diff_two_keys(cur, high_key,
+                                       &rec_key);
+
+                       /*
+                        * If (record's high key >= query's low key) and
+                        *    (query's high key >= record's low key), then
+                        * this record overlaps the query range; callback.
+                        */
+                       if (ldiff >= 0 && hdiff >= 0) {
+                               error = fn(cur, recp, priv);
+                               if (error < 0 ||
+                                   error == XFS_BTREE_QUERY_RANGE_ABORT)
+                                       break;
+                       } else if (hdiff < 0) {
+                               /* Record is larger than high key; pop. */
+                               goto pop_up;
+                       }
+                       cur->bc_ptrs[level]++;
+                       continue;
+               }
+
+               /* Handle an internal node. */
+               lkp = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block);
+               hkp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block);
+               pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block);
+
+               ldiff = cur->bc_ops->diff_two_keys(cur, hkp, low_key);
+               hdiff = cur->bc_ops->diff_two_keys(cur, high_key, lkp);
+
+               /*
+                * If (pointer's high key >= query's low key) and
+                *    (query's high key >= pointer's low key), then
+                * this record overlaps the query range; follow pointer.
+                */
+               if (ldiff >= 0 && hdiff >= 0) {
+                       level--;
+                       error = xfs_btree_lookup_get_block(cur, level, pp,
+                                       &block);
+                       if (error)
+                               goto out;
+                       xfs_btree_get_block(cur, level, &bp);
+                       trace_xfs_btree_overlapped_query_range(cur, level, bp);
+#ifdef DEBUG
+                       error = xfs_btree_check_block(cur, block, level, bp);
+                       if (error)
+                               goto out;
+#endif
+                       cur->bc_ptrs[level] = 1;
+                       continue;
+               } else if (hdiff < 0) {
+                       /* The low key is larger than the upper range; pop. */
+                       goto pop_up;
+               }
+               cur->bc_ptrs[level]++;
+       }
+
+out:
+       /*
+        * If we don't end this function with the cursor pointing at a record
+        * block, a subsequent non-error cursor deletion will not release
+        * node-level buffers, causing a buffer leak.  This is quite possible
+        * with a zero-results range query, so release the buffers if we
+        * failed to return any results.
+        */
+       if (cur->bc_bufs[0] == NULL) {
+               for (i = 0; i < cur->bc_nlevels; i++) {
+                       if (cur->bc_bufs[i]) {
+                               xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]);
+                               cur->bc_bufs[i] = NULL;
+                               cur->bc_ptrs[i] = 0;
+                               cur->bc_ra[i] = 0;
+                       }
+               }
+       }
+
+       return error;
+}
+
+/*
+ * Query a btree for all records overlapping a given interval of keys.  The
+ * supplied function will be called with each record found; return one of the
+ * XFS_BTREE_QUERY_RANGE_{CONTINUE,ABORT} values or the usual negative error
+ * code.  This function returns XFS_BTREE_QUERY_RANGE_ABORT, zero, or a
+ * negative error code.
+ */
+int
+xfs_btree_query_range(
+       struct xfs_btree_cur            *cur,
+       union xfs_btree_irec            *low_rec,
+       union xfs_btree_irec            *high_rec,
+       xfs_btree_query_range_fn        fn,
+       void                            *priv)
+{
+       union xfs_btree_rec             rec;
+       union xfs_btree_key             low_key;
+       union xfs_btree_key             high_key;
+
+       /* Find the keys of both ends of the interval. */
+       cur->bc_rec = *high_rec;
+       cur->bc_ops->init_rec_from_cur(cur, &rec);
+       cur->bc_ops->init_key_from_rec(&high_key, &rec);
+
+       cur->bc_rec = *low_rec;
+       cur->bc_ops->init_rec_from_cur(cur, &rec);
+       cur->bc_ops->init_key_from_rec(&low_key, &rec);
+
+       /* Enforce low key < high key. */
+       if (cur->bc_ops->diff_two_keys(cur, &low_key, &high_key) > 0)
+               return -EINVAL;
+
+       if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
+               return xfs_btree_simple_query_range(cur, &low_key,
+                               &high_key, fn, priv);
+       return xfs_btree_overlapped_query_range(cur, &low_key, &high_key,
+                       fn, priv);
+}
index 785a996..04d0865 100644 (file)
@@ -19,7 +19,7 @@
 #define        __XFS_BTREE_H__
 
 struct xfs_buf;
-struct xfs_bmap_free;
+struct xfs_defer_ops;
 struct xfs_inode;
 struct xfs_mount;
 struct xfs_trans;
@@ -38,17 +38,37 @@ union xfs_btree_ptr {
 };
 
 union xfs_btree_key {
-       xfs_bmbt_key_t          bmbt;
-       xfs_bmdr_key_t          bmbr;   /* bmbt root block */
-       xfs_alloc_key_t         alloc;
-       xfs_inobt_key_t         inobt;
+       struct xfs_bmbt_key             bmbt;
+       xfs_bmdr_key_t                  bmbr;   /* bmbt root block */
+       xfs_alloc_key_t                 alloc;
+       struct xfs_inobt_key            inobt;
+       struct xfs_rmap_key             rmap;
+};
+
+/*
+ * In-core key that holds both low and high keys for overlapped btrees.
+ * The two keys are packed next to each other on disk, so do the same
+ * in memory.  Preserve the existing xfs_btree_key as a single key to
+ * avoid the mental model breakage that would happen if we passed a
+ * bigkey into a function that operates on a single key.
+ */
+union xfs_btree_bigkey {
+       struct xfs_bmbt_key             bmbt;
+       xfs_bmdr_key_t                  bmbr;   /* bmbt root block */
+       xfs_alloc_key_t                 alloc;
+       struct xfs_inobt_key            inobt;
+       struct {
+               struct xfs_rmap_key     rmap;
+               struct xfs_rmap_key     rmap_hi;
+       };
 };
 
 union xfs_btree_rec {
-       xfs_bmbt_rec_t          bmbt;
-       xfs_bmdr_rec_t          bmbr;   /* bmbt root block */
-       xfs_alloc_rec_t         alloc;
-       xfs_inobt_rec_t         inobt;
+       struct xfs_bmbt_rec             bmbt;
+       xfs_bmdr_rec_t                  bmbr;   /* bmbt root block */
+       struct xfs_alloc_rec            alloc;
+       struct xfs_inobt_rec            inobt;
+       struct xfs_rmap_rec             rmap;
 };
 
 /*
@@ -63,6 +83,7 @@ union xfs_btree_rec {
 #define        XFS_BTNUM_BMAP  ((xfs_btnum_t)XFS_BTNUM_BMAPi)
 #define        XFS_BTNUM_INO   ((xfs_btnum_t)XFS_BTNUM_INOi)
 #define        XFS_BTNUM_FINO  ((xfs_btnum_t)XFS_BTNUM_FINOi)
+#define        XFS_BTNUM_RMAP  ((xfs_btnum_t)XFS_BTNUM_RMAPi)
 
 /*
  * For logging record fields.
@@ -95,6 +116,7 @@ do {    \
        case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(__mp, bmbt, stat); break; \
        case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(__mp, ibt, stat); break; \
        case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(__mp, fibt, stat); break; \
+       case XFS_BTNUM_RMAP: __XFS_BTREE_STATS_INC(__mp, rmap, stat); break; \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;       \
        }       \
 } while (0)
@@ -115,11 +137,13 @@ do {    \
                __XFS_BTREE_STATS_ADD(__mp, ibt, stat, val); break; \
        case XFS_BTNUM_FINO:    \
                __XFS_BTREE_STATS_ADD(__mp, fibt, stat, val); break; \
+       case XFS_BTNUM_RMAP:    \
+               __XFS_BTREE_STATS_ADD(__mp, rmap, stat, val); break; \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
        }       \
 } while (0)
 
-#define        XFS_BTREE_MAXLEVELS     8       /* max of all btrees */
+#define        XFS_BTREE_MAXLEVELS     9       /* max of all btrees */
 
 struct xfs_btree_ops {
        /* size of the key and record structures */
@@ -158,17 +182,25 @@ struct xfs_btree_ops {
        /* init values of btree structures */
        void    (*init_key_from_rec)(union xfs_btree_key *key,
                                     union xfs_btree_rec *rec);
-       void    (*init_rec_from_key)(union xfs_btree_key *key,
-                                    union xfs_btree_rec *rec);
        void    (*init_rec_from_cur)(struct xfs_btree_cur *cur,
                                     union xfs_btree_rec *rec);
        void    (*init_ptr_from_cur)(struct xfs_btree_cur *cur,
                                     union xfs_btree_ptr *ptr);
+       void    (*init_high_key_from_rec)(union xfs_btree_key *key,
+                                         union xfs_btree_rec *rec);
 
        /* difference between key value and cursor value */
        __int64_t (*key_diff)(struct xfs_btree_cur *cur,
                              union xfs_btree_key *key);
 
+       /*
+        * Difference between key2 and key1 -- positive if key1 > key2,
+        * negative if key1 < key2, and zero if equal.
+        */
+       __int64_t (*diff_two_keys)(struct xfs_btree_cur *cur,
+                                  union xfs_btree_key *key1,
+                                  union xfs_btree_key *key2);
+
        const struct xfs_buf_ops        *buf_ops;
 
 #if defined(DEBUG) || defined(XFS_WARN)
@@ -192,6 +224,13 @@ struct xfs_btree_ops {
 #define LASTREC_DELREC 2
 
 
+union xfs_btree_irec {
+       struct xfs_alloc_rec_incore     a;
+       struct xfs_bmbt_irec            b;
+       struct xfs_inobt_rec_incore     i;
+       struct xfs_rmap_irec            r;
+};
+
 /*
  * Btree cursor structure.
  * This collects all information needed by the btree code in one place.
@@ -202,11 +241,7 @@ typedef struct xfs_btree_cur
        struct xfs_mount        *bc_mp; /* file system mount struct */
        const struct xfs_btree_ops *bc_ops;
        uint                    bc_flags; /* btree features - below */
-       union {
-               xfs_alloc_rec_incore_t  a;
-               xfs_bmbt_irec_t         b;
-               xfs_inobt_rec_incore_t  i;
-       }               bc_rec;         /* current insert/search record value */
+       union xfs_btree_irec    bc_rec; /* current insert/search record value */
        struct xfs_buf  *bc_bufs[XFS_BTREE_MAXLEVELS];  /* buf ptr per level */
        int             bc_ptrs[XFS_BTREE_MAXLEVELS];   /* key/record # */
        __uint8_t       bc_ra[XFS_BTREE_MAXLEVELS];     /* readahead bits */
@@ -218,11 +253,12 @@ typedef struct xfs_btree_cur
        union {
                struct {                        /* needed for BNO, CNT, INO */
                        struct xfs_buf  *agbp;  /* agf/agi buffer pointer */
+                       struct xfs_defer_ops *dfops;    /* deferred updates */
                        xfs_agnumber_t  agno;   /* ag number */
                } a;
                struct {                        /* needed for BMAP */
                        struct xfs_inode *ip;   /* pointer to our inode */
-                       struct xfs_bmap_free *flist;    /* list to free after */
+                       struct xfs_defer_ops *dfops;    /* deferred updates */
                        xfs_fsblock_t   firstblock;     /* 1st blk allocated */
                        int             allocated;      /* count of alloced */
                        short           forksize;       /* fork's inode space */
@@ -238,6 +274,7 @@ typedef struct xfs_btree_cur
 #define XFS_BTREE_ROOT_IN_INODE                (1<<1)  /* root may be variable size */
 #define XFS_BTREE_LASTREC_UPDATE       (1<<2)  /* track last rec externally */
 #define XFS_BTREE_CRC_BLOCKS           (1<<3)  /* uses extended btree blocks */
+#define XFS_BTREE_OVERLAPPING          (1<<4)  /* overlapping intervals */
 
 
 #define        XFS_BTREE_NOERROR       0
@@ -477,4 +514,19 @@ bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs);
 uint xfs_btree_compute_maxlevels(struct xfs_mount *mp, uint *limits,
                                 unsigned long len);
 
+/* return codes */
+#define XFS_BTREE_QUERY_RANGE_CONTINUE 0       /* keep iterating */
+#define XFS_BTREE_QUERY_RANGE_ABORT    1       /* stop iterating */
+typedef int (*xfs_btree_query_range_fn)(struct xfs_btree_cur *cur,
+               union xfs_btree_rec *rec, void *priv);
+
+int xfs_btree_query_range(struct xfs_btree_cur *cur,
+               union xfs_btree_irec *low_rec, union xfs_btree_irec *high_rec,
+               xfs_btree_query_range_fn fn, void *priv);
+
+typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
+               void *data);
+int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
+               xfs_btree_visit_blocks_fn fn, void *data);
+
 #endif /* __XFS_BTREE_H__ */
index 0f1f165..f2dc1a9 100644 (file)
@@ -2029,7 +2029,7 @@ xfs_da_grow_inode_int(
        error = xfs_bmapi_write(tp, dp, *bno, count,
                        xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
                        args->firstblock, args->total, &map, &nmap,
-                       args->flist);
+                       args->dfops);
        if (error)
                return error;
 
@@ -2052,7 +2052,7 @@ xfs_da_grow_inode_int(
                        error = xfs_bmapi_write(tp, dp, b, c,
                                        xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA,
                                        args->firstblock, args->total,
-                                       &mapp[mapi], &nmap, args->flist);
+                                       &mapp[mapi], &nmap, args->dfops);
                        if (error)
                                goto out_free_map;
                        if (nmap < 1)
@@ -2362,7 +2362,7 @@ xfs_da_shrink_inode(
                 */
                error = xfs_bunmapi(tp, dp, dead_blkno, count,
                                    xfs_bmapi_aflag(w), 0, args->firstblock,
-                                   args->flist, &done);
+                                   args->dfops, &done);
                if (error == -ENOSPC) {
                        if (w != XFS_DATA_FORK)
                                break;
index 6e153e3..98c75cb 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef __XFS_DA_BTREE_H__
 #define        __XFS_DA_BTREE_H__
 
-struct xfs_bmap_free;
+struct xfs_defer_ops;
 struct xfs_inode;
 struct xfs_trans;
 struct zone;
@@ -70,7 +70,7 @@ typedef struct xfs_da_args {
        xfs_ino_t       inumber;        /* input/output inode number */
        struct xfs_inode *dp;           /* directory inode to manipulate */
        xfs_fsblock_t   *firstblock;    /* ptr to firstblock for bmap calls */
-       struct xfs_bmap_free *flist;    /* ptr to freelist for bmap_finish */
+       struct xfs_defer_ops *dfops;    /* ptr to freelist for bmap_finish */
        struct xfs_trans *trans;        /* current trans (changes over time) */
        xfs_extlen_t    total;          /* total blocks needed, for 1st bmap */
        int             whichfork;      /* data or attribute fork */
index 685f23b..9a492a9 100644 (file)
@@ -629,6 +629,7 @@ typedef struct xfs_attr_shortform {
        struct xfs_attr_sf_hdr {        /* constant-structure header block */
                __be16  totsize;        /* total bytes in shortform list */
                __u8    count;  /* count of active entries */
+               __u8    padding;
        } hdr;
        struct xfs_attr_sf_entry {
                __uint8_t namelen;      /* actual length of name (no NULL) */
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
new file mode 100644 (file)
index 0000000..054a203
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trace.h"
+
+/*
+ * Deferred Operations in XFS
+ *
+ * Due to the way locking rules work in XFS, certain transactions (block
+ * mapping and unmapping, typically) have permanent reservations so that
+ * we can roll the transaction to adhere to AG locking order rules and
+ * to unlock buffers between metadata updates.  Prior to rmap/reflink,
+ * the mapping code had a mechanism to perform these deferrals for
+ * extents that were going to be freed; this code makes that facility
+ * more generic.
+ *
+ * When adding the reverse mapping and reflink features, it became
+ * necessary to perform complex remapping multi-transactions to comply
+ * with AG locking order rules, and to be able to spread a single
+ * refcount update operation (an operation on an n-block extent can
+ * update as many as n records!) among multiple transactions.  XFS can
+ * roll a transaction to facilitate this, but using this facility
+ * requires us to log "intent" items in case log recovery needs to
+ * redo the operation, and to log "done" items to indicate that redo
+ * is not necessary.
+ *
+ * Deferred work is tracked in xfs_defer_pending items.  Each pending
+ * item tracks one type of deferred work.  Incoming work items (which
+ * have not yet had an intent logged) are attached to a pending item
+ * on the dop_intake list, where they wait for the caller to finish
+ * the deferred operations.
+ *
+ * Finishing a set of deferred operations is an involved process.  To
+ * start, we define "rolling a deferred-op transaction" as follows:
+ *
+ * > For each xfs_defer_pending item on the dop_intake list,
+ *   - Sort the work items in AG order.  XFS locking
+ *     order rules require us to lock buffers in AG order.
+ *   - Create a log intent item for that type.
+ *   - Attach it to the pending item.
+ *   - Move the pending item from the dop_intake list to the
+ *     dop_pending list.
+ * > Roll the transaction.
+ *
+ * NOTE: To avoid exceeding the transaction reservation, we limit the
+ * number of items that we attach to a given xfs_defer_pending.
+ *
+ * The actual finishing process looks like this:
+ *
+ * > For each xfs_defer_pending in the dop_pending list,
+ *   - Roll the deferred-op transaction as above.
+ *   - Create a log done item for that type, and attach it to the
+ *     log intent item.
+ *   - For each work item attached to the log intent item,
+ *     * Perform the described action.
+ *     * Attach the work item to the log done item.
+ *
+ * The key here is that we must log an intent item for all pending
+ * work items every time we roll the transaction, and that we must log
+ * a done item as soon as the work is completed.  With this mechanism
+ * we can perform complex remapping operations, chaining intent items
+ * as needed.
+ *
+ * This is an example of remapping the extent (E, E+B) into file X at
+ * offset A and dealing with the extent (C, C+B) already being mapped
+ * there:
+ * +-------------------------------------------------+
+ * | Unmap file X startblock C offset A length B     | t0
+ * | Intent to reduce refcount for extent (C, B)     |
+ * | Intent to remove rmap (X, C, A, B)              |
+ * | Intent to free extent (D, 1) (bmbt block)       |
+ * | Intent to map (X, A, B) at startblock E         |
+ * +-------------------------------------------------+
+ * | Map file X startblock E offset A length B       | t1
+ * | Done mapping (X, E, A, B)                       |
+ * | Intent to increase refcount for extent (E, B)   |
+ * | Intent to add rmap (X, E, A, B)                 |
+ * +-------------------------------------------------+
+ * | Reduce refcount for extent (C, B)               | t2
+ * | Done reducing refcount for extent (C, B)        |
+ * | Increase refcount for extent (E, B)             |
+ * | Done increasing refcount for extent (E, B)      |
+ * | Intent to free extent (C, B)                    |
+ * | Intent to free extent (F, 1) (refcountbt block) |
+ * | Intent to remove rmap (F, 1, REFC)              |
+ * +-------------------------------------------------+
+ * | Remove rmap (X, C, A, B)                        | t3
+ * | Done removing rmap (X, C, A, B)                 |
+ * | Add rmap (X, E, A, B)                           |
+ * | Done adding rmap (X, E, A, B)                   |
+ * | Remove rmap (F, 1, REFC)                        |
+ * | Done removing rmap (F, 1, REFC)                 |
+ * +-------------------------------------------------+
+ * | Free extent (C, B)                              | t4
+ * | Done freeing extent (C, B)                      |
+ * | Free extent (D, 1)                              |
+ * | Done freeing extent (D, 1)                      |
+ * | Free extent (F, 1)                              |
+ * | Done freeing extent (F, 1)                      |
+ * +-------------------------------------------------+
+ *
+ * If we should crash before t2 commits, log recovery replays
+ * the following intent items:
+ *
+ * - Intent to reduce refcount for extent (C, B)
+ * - Intent to remove rmap (X, C, A, B)
+ * - Intent to free extent (D, 1) (bmbt block)
+ * - Intent to increase refcount for extent (E, B)
+ * - Intent to add rmap (X, E, A, B)
+ *
+ * In the process of recovering, it should also generate and take care
+ * of these intent items:
+ *
+ * - Intent to free extent (C, B)
+ * - Intent to free extent (F, 1) (refcountbt block)
+ * - Intent to remove rmap (F, 1, REFC)
+ */
+
+static const struct xfs_defer_op_type *defer_op_types[XFS_DEFER_OPS_TYPE_MAX];
+
+/*
+ * For each pending item in the intake list, log its intent item and the
+ * associated extents, then add the entire intake list to the end of
+ * the pending list.
+ */
+STATIC void
+xfs_defer_intake_work(
+       struct xfs_trans                *tp,
+       struct xfs_defer_ops            *dop)
+{
+       struct list_head                *li;
+       struct xfs_defer_pending        *dfp;
+
+       list_for_each_entry(dfp, &dop->dop_intake, dfp_list) {
+               trace_xfs_defer_intake_work(tp->t_mountp, dfp);
+               dfp->dfp_intent = dfp->dfp_type->create_intent(tp,
+                               dfp->dfp_count);
+               list_sort(tp->t_mountp, &dfp->dfp_work,
+                               dfp->dfp_type->diff_items);
+               list_for_each(li, &dfp->dfp_work)
+                       dfp->dfp_type->log_item(tp, dfp->dfp_intent, li);
+       }
+
+       list_splice_tail_init(&dop->dop_intake, &dop->dop_pending);
+}
+
+/* Abort all the intents that were committed. */
+STATIC void
+xfs_defer_trans_abort(
+       struct xfs_trans                *tp,
+       struct xfs_defer_ops            *dop,
+       int                             error)
+{
+       struct xfs_defer_pending        *dfp;
+
+       trace_xfs_defer_trans_abort(tp->t_mountp, dop);
+       /*
+        * If the transaction was committed, drop the intent reference
+        * since we're bailing out of here. The other reference is
+        * dropped when the intent hits the AIL.  If the transaction
+        * was not committed, the intent is freed by the intent item
+        * unlock handler on abort.
+        */
+       if (!dop->dop_committed)
+               return;
+
+       /* Abort intent items. */
+       list_for_each_entry(dfp, &dop->dop_pending, dfp_list) {
+               trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
+               if (dfp->dfp_committed)
+                       dfp->dfp_type->abort_intent(dfp->dfp_intent);
+       }
+
+       /* Shut down FS. */
+       xfs_force_shutdown(tp->t_mountp, (error == -EFSCORRUPTED) ?
+                       SHUTDOWN_CORRUPT_INCORE : SHUTDOWN_META_IO_ERROR);
+}
+
+/* Roll a transaction so we can do some deferred op processing. */
+STATIC int
+xfs_defer_trans_roll(
+       struct xfs_trans                **tp,
+       struct xfs_defer_ops            *dop,
+       struct xfs_inode                *ip)
+{
+       int                             i;
+       int                             error;
+
+       /* Log all the joined inodes except the one we passed in. */
+       for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) {
+               if (dop->dop_inodes[i] == ip)
+                       continue;
+               xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE);
+       }
+
+       trace_xfs_defer_trans_roll((*tp)->t_mountp, dop);
+
+       /* Roll the transaction. */
+       error = xfs_trans_roll(tp, ip);
+       if (error) {
+               trace_xfs_defer_trans_roll_error((*tp)->t_mountp, dop, error);
+               xfs_defer_trans_abort(*tp, dop, error);
+               return error;
+       }
+       dop->dop_committed = true;
+
+       /* Rejoin the joined inodes except the one we passed in. */
+       for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) {
+               if (dop->dop_inodes[i] == ip)
+                       continue;
+               xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0);
+       }
+
+       return error;
+}
+
+/* Do we have any work items to finish? */
+bool
+xfs_defer_has_unfinished_work(
+       struct xfs_defer_ops            *dop)
+{
+       return !list_empty(&dop->dop_pending) || !list_empty(&dop->dop_intake);
+}
+
+/*
+ * Add this inode to the deferred op.  Each joined inode is relogged
+ * each time we roll the transaction, in addition to any inode passed
+ * to xfs_defer_finish().
+ */
+int
+xfs_defer_join(
+       struct xfs_defer_ops            *dop,
+       struct xfs_inode                *ip)
+{
+       int                             i;
+
+       for (i = 0; i < XFS_DEFER_OPS_NR_INODES; i++) {
+               if (dop->dop_inodes[i] == ip)
+                       return 0;
+               else if (dop->dop_inodes[i] == NULL) {
+                       dop->dop_inodes[i] = ip;
+                       return 0;
+               }
+       }
+
+       return -EFSCORRUPTED;
+}
+
+/*
+ * Finish all the pending work.  This involves logging intent items for
+ * any work items that wandered in since the last transaction roll (if
+ * one has even happened), rolling the transaction, and finishing the
+ * work items in the first item on the logged-and-pending list.
+ *
+ * If an inode is provided, relog it to the new transaction.
+ */
+int
+xfs_defer_finish(
+       struct xfs_trans                **tp,
+       struct xfs_defer_ops            *dop,
+       struct xfs_inode                *ip)
+{
+       struct xfs_defer_pending        *dfp;
+       struct list_head                *li;
+       struct list_head                *n;
+       void                            *done_item = NULL;
+       void                            *state;
+       int                             error = 0;
+       void                            (*cleanup_fn)(struct xfs_trans *, void *, int);
+
+       ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
+
+       trace_xfs_defer_finish((*tp)->t_mountp, dop);
+
+       /* Until we run out of pending work to finish... */
+       while (xfs_defer_has_unfinished_work(dop)) {
+               /* Log intents for work items sitting in the intake. */
+               xfs_defer_intake_work(*tp, dop);
+
+               /* Roll the transaction. */
+               error = xfs_defer_trans_roll(tp, dop, ip);
+               if (error)
+                       goto out;
+
+               /* Mark all pending intents as committed. */
+               list_for_each_entry_reverse(dfp, &dop->dop_pending, dfp_list) {
+                       if (dfp->dfp_committed)
+                               break;
+                       trace_xfs_defer_pending_commit((*tp)->t_mountp, dfp);
+                       dfp->dfp_committed = true;
+               }
+
+               /* Log an intent-done item for the first pending item. */
+               dfp = list_first_entry(&dop->dop_pending,
+                               struct xfs_defer_pending, dfp_list);
+               trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp);
+               done_item = dfp->dfp_type->create_done(*tp, dfp->dfp_intent,
+                               dfp->dfp_count);
+               cleanup_fn = dfp->dfp_type->finish_cleanup;
+
+               /* Finish the work items. */
+               state = NULL;
+               list_for_each_safe(li, n, &dfp->dfp_work) {
+                       list_del(li);
+                       dfp->dfp_count--;
+                       error = dfp->dfp_type->finish_item(*tp, dop, li,
+                                       done_item, &state);
+                       if (error) {
+                               /*
+                                * Clean up after ourselves and jump out.
+                                * xfs_defer_cancel will take care of freeing
+                                * all these lists and stuff.
+                                */
+                               if (cleanup_fn)
+                                       cleanup_fn(*tp, state, error);
+                               xfs_defer_trans_abort(*tp, dop, error);
+                               goto out;
+                       }
+               }
+               /* Done with the dfp, free it. */
+               list_del(&dfp->dfp_list);
+               kmem_free(dfp);
+
+               if (cleanup_fn)
+                       cleanup_fn(*tp, state, error);
+       }
+
+out:
+       if (error)
+               trace_xfs_defer_finish_error((*tp)->t_mountp, dop, error);
+       else
+               trace_xfs_defer_finish_done((*tp)->t_mountp, dop);
+       return error;
+}
+
+/*
+ * Free up any items left in the list.
+ */
+void
+xfs_defer_cancel(
+       struct xfs_defer_ops            *dop)
+{
+       struct xfs_defer_pending        *dfp;
+       struct xfs_defer_pending        *pli;
+       struct list_head                *pwi;
+       struct list_head                *n;
+
+       trace_xfs_defer_cancel(NULL, dop);
+
+       /*
+        * Free the pending items.  Caller should already have arranged
+        * for the intent items to be released.
+        */
+       list_for_each_entry_safe(dfp, pli, &dop->dop_intake, dfp_list) {
+               trace_xfs_defer_intake_cancel(NULL, dfp);
+               list_del(&dfp->dfp_list);
+               list_for_each_safe(pwi, n, &dfp->dfp_work) {
+                       list_del(pwi);
+                       dfp->dfp_count--;
+                       dfp->dfp_type->cancel_item(pwi);
+               }
+               ASSERT(dfp->dfp_count == 0);
+               kmem_free(dfp);
+       }
+       list_for_each_entry_safe(dfp, pli, &dop->dop_pending, dfp_list) {
+               trace_xfs_defer_pending_cancel(NULL, dfp);
+               list_del(&dfp->dfp_list);
+               list_for_each_safe(pwi, n, &dfp->dfp_work) {
+                       list_del(pwi);
+                       dfp->dfp_count--;
+                       dfp->dfp_type->cancel_item(pwi);
+               }
+               ASSERT(dfp->dfp_count == 0);
+               kmem_free(dfp);
+       }
+}
+
+/* Add an item for later deferred processing. */
+void
+xfs_defer_add(
+       struct xfs_defer_ops            *dop,
+       enum xfs_defer_ops_type         type,
+       struct list_head                *li)
+{
+       struct xfs_defer_pending        *dfp = NULL;
+
+       /*
+        * Add the item to a pending item at the end of the intake list.
+        * If the last pending item has the same type, reuse it.  Else,
+        * create a new pending item at the end of the intake list.
+        */
+       if (!list_empty(&dop->dop_intake)) {
+               dfp = list_last_entry(&dop->dop_intake,
+                               struct xfs_defer_pending, dfp_list);
+               if (dfp->dfp_type->type != type ||
+                   (dfp->dfp_type->max_items &&
+                    dfp->dfp_count >= dfp->dfp_type->max_items))
+                       dfp = NULL;
+       }
+       if (!dfp) {
+               dfp = kmem_alloc(sizeof(struct xfs_defer_pending),
+                               KM_SLEEP | KM_NOFS);
+               dfp->dfp_type = defer_op_types[type];
+               dfp->dfp_committed = false;
+               dfp->dfp_intent = NULL;
+               dfp->dfp_count = 0;
+               INIT_LIST_HEAD(&dfp->dfp_work);
+               list_add_tail(&dfp->dfp_list, &dop->dop_intake);
+       }
+
+       list_add_tail(li, &dfp->dfp_work);
+       dfp->dfp_count++;
+}
+
+/* Initialize a deferred operation list. */
+void
+xfs_defer_init_op_type(
+       const struct xfs_defer_op_type  *type)
+{
+       defer_op_types[type->type] = type;
+}
+
+/* Initialize a deferred operation. */
+void
+xfs_defer_init(
+       struct xfs_defer_ops            *dop,
+       xfs_fsblock_t                   *fbp)
+{
+       dop->dop_committed = false;
+       dop->dop_low = false;
+       memset(&dop->dop_inodes, 0, sizeof(dop->dop_inodes));
+       *fbp = NULLFSBLOCK;
+       INIT_LIST_HEAD(&dop->dop_intake);
+       INIT_LIST_HEAD(&dop->dop_pending);
+       trace_xfs_defer_init(NULL, dop);
+}
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
new file mode 100644 (file)
index 0000000..cc3981c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#ifndef __XFS_DEFER_H__
+#define        __XFS_DEFER_H__
+
+struct xfs_defer_op_type;
+
+/*
+ * Save a log intent item and a list of extents, so that we can replay
+ * whatever action had to happen to the extent list and file the log done
+ * item.
+ */
+struct xfs_defer_pending {
+       const struct xfs_defer_op_type  *dfp_type;      /* function pointers */
+       struct list_head                dfp_list;       /* pending items */
+       bool                            dfp_committed;  /* committed trans? */
+       void                            *dfp_intent;    /* log intent item */
+       struct list_head                dfp_work;       /* work items */
+       unsigned int                    dfp_count;      /* # extent items */
+};
+
+/*
+ * Header for deferred operation list.
+ *
+ * dop_low is used by the allocator to activate the lowspace algorithm -
+ * when free space is running low the extent allocator may choose to
+ * allocate an extent from an AG without leaving sufficient space for
+ * a btree split when inserting the new extent.  In this case the allocator
+ * will enable the lowspace algorithm which is supposed to allow further
+ * allocations (such as btree splits and newroots) to allocate from
+ * sequential AGs.  In order to avoid locking AGs out of order the lowspace
+ * algorithm will start searching for free space from AG 0.  If the correct
+ * transaction reservations have been made then this algorithm will eventually
+ * find all the space it needs.
+ */
+enum xfs_defer_ops_type {
+       XFS_DEFER_OPS_TYPE_RMAP,
+       XFS_DEFER_OPS_TYPE_FREE,
+       XFS_DEFER_OPS_TYPE_MAX,
+};
+
+#define XFS_DEFER_OPS_NR_INODES        2       /* join up to two inodes */
+
+struct xfs_defer_ops {
+       bool                    dop_committed;  /* did any trans commit? */
+       bool                    dop_low;        /* alloc in low mode */
+       struct list_head        dop_intake;     /* unlogged pending work */
+       struct list_head        dop_pending;    /* logged pending work */
+
+       /* relog these inodes with each roll */
+       struct xfs_inode        *dop_inodes[XFS_DEFER_OPS_NR_INODES];
+};
+
+void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type,
+               struct list_head *h);
+int xfs_defer_finish(struct xfs_trans **tp, struct xfs_defer_ops *dop,
+               struct xfs_inode *ip);
+void xfs_defer_cancel(struct xfs_defer_ops *dop);
+void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp);
+bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop);
+int xfs_defer_join(struct xfs_defer_ops *dop, struct xfs_inode *ip);
+
+/* Description of a deferred type. */
+struct xfs_defer_op_type {
+       enum xfs_defer_ops_type type;
+       unsigned int            max_items;
+       void (*abort_intent)(void *);
+       void *(*create_done)(struct xfs_trans *, void *, unsigned int);
+       int (*finish_item)(struct xfs_trans *, struct xfs_defer_ops *,
+                       struct list_head *, void *, void **);
+       void (*finish_cleanup)(struct xfs_trans *, void *, int);
+       void (*cancel_item)(struct list_head *);
+       int (*diff_items)(void *, struct list_head *, struct list_head *);
+       void *(*create_intent)(struct xfs_trans *, uint);
+       void (*log_item)(struct xfs_trans *, void *, struct list_head *);
+};
+
+void xfs_defer_init_op_type(const struct xfs_defer_op_type *type);
+
+#endif /* __XFS_DEFER_H__ */
index af0f9d1..20a96dd 100644 (file)
@@ -21,6 +21,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
@@ -259,7 +260,7 @@ xfs_dir_createname(
        struct xfs_name         *name,
        xfs_ino_t               inum,           /* new entry inode number */
        xfs_fsblock_t           *first,         /* bmap's firstblock */
-       xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
+       struct xfs_defer_ops    *dfops,         /* bmap's freeblock list */
        xfs_extlen_t            total)          /* bmap's total block count */
 {
        struct xfs_da_args      *args;
@@ -286,7 +287,7 @@ xfs_dir_createname(
        args->inumber = inum;
        args->dp = dp;
        args->firstblock = first;
-       args->flist = flist;
+       args->dfops = dfops;
        args->total = total;
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
@@ -436,7 +437,7 @@ xfs_dir_removename(
        struct xfs_name *name,
        xfs_ino_t       ino,
        xfs_fsblock_t   *first,         /* bmap's firstblock */
-       xfs_bmap_free_t *flist,         /* bmap's freeblock list */
+       struct xfs_defer_ops    *dfops,         /* bmap's freeblock list */
        xfs_extlen_t    total)          /* bmap's total block count */
 {
        struct xfs_da_args *args;
@@ -458,7 +459,7 @@ xfs_dir_removename(
        args->inumber = ino;
        args->dp = dp;
        args->firstblock = first;
-       args->flist = flist;
+       args->dfops = dfops;
        args->total = total;
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
@@ -498,7 +499,7 @@ xfs_dir_replace(
        struct xfs_name *name,          /* name of entry to replace */
        xfs_ino_t       inum,           /* new inode number */
        xfs_fsblock_t   *first,         /* bmap's firstblock */
-       xfs_bmap_free_t *flist,         /* bmap's freeblock list */
+       struct xfs_defer_ops    *dfops,         /* bmap's freeblock list */
        xfs_extlen_t    total)          /* bmap's total block count */
 {
        struct xfs_da_args *args;
@@ -523,7 +524,7 @@ xfs_dir_replace(
        args->inumber = inum;
        args->dp = dp;
        args->firstblock = first;
-       args->flist = flist;
+       args->dfops = dfops;
        args->total = total;
        args->whichfork = XFS_DATA_FORK;
        args->trans = tp;
@@ -680,7 +681,7 @@ xfs_dir2_shrink_inode(
 
        /* Unmap the fsblock(s). */
        error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0,
-                           args->firstblock, args->flist, &done);
+                           args->firstblock, args->dfops, &done);
        if (error) {
                /*
                 * ENOSPC actually can happen if we're in a removename with no
index e553536..becc926 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef __XFS_DIR2_H__
 #define __XFS_DIR2_H__
 
-struct xfs_bmap_free;
+struct xfs_defer_ops;
 struct xfs_da_args;
 struct xfs_inode;
 struct xfs_mount;
@@ -129,18 +129,18 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t inum,
                                xfs_fsblock_t *first,
-                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+                               struct xfs_defer_ops *dfops, xfs_extlen_t tot);
 extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t *inum,
                                struct xfs_name *ci_name);
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t ino,
                                xfs_fsblock_t *first,
-                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+                               struct xfs_defer_ops *dfops, xfs_extlen_t tot);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name, xfs_ino_t inum,
                                xfs_fsblock_t *first,
-                               struct xfs_bmap_free *flist, xfs_extlen_t tot);
+                               struct xfs_defer_ops *dfops, xfs_extlen_t tot);
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
                                struct xfs_name *name);
 
index adb204d..f814d42 100644 (file)
@@ -455,8 +455,10 @@ xfs_sb_has_compat_feature(
 }
 
 #define XFS_SB_FEAT_RO_COMPAT_FINOBT   (1 << 0)                /* free inode btree */
+#define XFS_SB_FEAT_RO_COMPAT_RMAPBT   (1 << 1)                /* reverse map btree */
 #define XFS_SB_FEAT_RO_COMPAT_ALL \
-               (XFS_SB_FEAT_RO_COMPAT_FINOBT)
+               (XFS_SB_FEAT_RO_COMPAT_FINOBT | \
+                XFS_SB_FEAT_RO_COMPAT_RMAPBT)
 #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN  ~XFS_SB_FEAT_RO_COMPAT_ALL
 static inline bool
 xfs_sb_has_ro_compat_feature(
@@ -538,6 +540,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
                (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
 }
 
+static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp)
+{
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+               (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_RMAPBT);
+}
+
 /*
  * end of superblock version macros
  */
@@ -598,10 +606,10 @@ xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
 #define        XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION)
 
 /*
- * Btree number 0 is bno, 1 is cnt This value gives the size of the
+ * Btree number 0 is bno, 1 is cnt, 2 is rmap. This value gives the size of the
  * arrays below.
  */
-#define        XFS_BTNUM_AGF   ((int)XFS_BTNUM_CNTi + 1)
+#define        XFS_BTNUM_AGF   ((int)XFS_BTNUM_RMAPi + 1)
 
 /*
  * The second word of agf_levels in the first a.g. overlaps the EFS
@@ -618,12 +626,10 @@ typedef struct xfs_agf {
        __be32          agf_seqno;      /* sequence # starting from 0 */
        __be32          agf_length;     /* size in blocks of a.g. */
        /*
-        * Freespace information
+        * Freespace and rmap information
         */
        __be32          agf_roots[XFS_BTNUM_AGF];       /* root blocks */
-       __be32          agf_spare0;     /* spare field */
        __be32          agf_levels[XFS_BTNUM_AGF];      /* btree levels */
-       __be32          agf_spare1;     /* spare field */
 
        __be32          agf_flfirst;    /* first freelist block's index */
        __be32          agf_fllast;     /* last freelist block's index */
@@ -1308,17 +1314,118 @@ typedef __be32 xfs_inobt_ptr_t;
 #define        XFS_FIBT_BLOCK(mp)              ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
 
 /*
- * The first data block of an AG depends on whether the filesystem was formatted
- * with the finobt feature. If so, account for the finobt reserved root btree
- * block.
+ * Reverse mapping btree format definitions
+ *
+ * There is a btree for the reverse map per allocation group
+ */
+#define        XFS_RMAP_CRC_MAGIC      0x524d4233      /* 'RMB3' */
+
+/*
+ * Ownership info for an extent.  This is used to create reverse-mapping
+ * entries.
  */
-#define XFS_PREALLOC_BLOCKS(mp) \
+#define XFS_OWNER_INFO_ATTR_FORK       (1 << 0)
+#define XFS_OWNER_INFO_BMBT_BLOCK      (1 << 1)
+struct xfs_owner_info {
+       uint64_t                oi_owner;
+       xfs_fileoff_t           oi_offset;
+       unsigned int            oi_flags;
+};
+
+/*
+ * Special owner types.
+ *
+ * Seeing as we only support up to 8EB, we have the upper bit of the owner field
+ * to tell us we have a special owner value. We use these for static metadata
+ * allocated at mkfs/growfs time, as well as for freespace management metadata.
+ */
+#define XFS_RMAP_OWN_NULL      (-1ULL) /* No owner, for growfs */
+#define XFS_RMAP_OWN_UNKNOWN   (-2ULL) /* Unknown owner, for EFI recovery */
+#define XFS_RMAP_OWN_FS                (-3ULL) /* static fs metadata */
+#define XFS_RMAP_OWN_LOG       (-4ULL) /* static fs metadata */
+#define XFS_RMAP_OWN_AG                (-5ULL) /* AG freespace btree blocks */
+#define XFS_RMAP_OWN_INOBT     (-6ULL) /* Inode btree blocks */
+#define XFS_RMAP_OWN_INODES    (-7ULL) /* Inode chunk */
+#define XFS_RMAP_OWN_MIN       (-8ULL) /* guard */
+
+#define XFS_RMAP_NON_INODE_OWNER(owner)        (!!((owner) & (1ULL << 63)))
+
+/*
+ * Data record structure
+ */
+struct xfs_rmap_rec {
+       __be32          rm_startblock;  /* extent start block */
+       __be32          rm_blockcount;  /* extent length */
+       __be64          rm_owner;       /* extent owner */
+       __be64          rm_offset;      /* offset within the owner */
+};
+
+/*
+ * rmap btree record
+ *  rm_offset:63 is the attribute fork flag
+ *  rm_offset:62 is the bmbt block flag
+ *  rm_offset:61 is the unwritten extent flag (same as l0:63 in bmbt)
+ *  rm_offset:54-60 aren't used and should be zero
+ *  rm_offset:0-53 is the block offset within the inode
+ */
+#define XFS_RMAP_OFF_ATTR_FORK ((__uint64_t)1ULL << 63)
+#define XFS_RMAP_OFF_BMBT_BLOCK        ((__uint64_t)1ULL << 62)
+#define XFS_RMAP_OFF_UNWRITTEN ((__uint64_t)1ULL << 61)
+
+#define XFS_RMAP_LEN_MAX       ((__uint32_t)~0U)
+#define XFS_RMAP_OFF_FLAGS     (XFS_RMAP_OFF_ATTR_FORK | \
+                                XFS_RMAP_OFF_BMBT_BLOCK | \
+                                XFS_RMAP_OFF_UNWRITTEN)
+#define XFS_RMAP_OFF_MASK      ((__uint64_t)0x3FFFFFFFFFFFFFULL)
+
+#define XFS_RMAP_OFF(off)              ((off) & XFS_RMAP_OFF_MASK)
+
+#define XFS_RMAP_IS_BMBT_BLOCK(off)    (!!((off) & XFS_RMAP_OFF_BMBT_BLOCK))
+#define XFS_RMAP_IS_ATTR_FORK(off)     (!!((off) & XFS_RMAP_OFF_ATTR_FORK))
+#define XFS_RMAP_IS_UNWRITTEN(len)     (!!((off) & XFS_RMAP_OFF_UNWRITTEN))
+
+#define RMAPBT_STARTBLOCK_BITLEN       32
+#define RMAPBT_BLOCKCOUNT_BITLEN       32
+#define RMAPBT_OWNER_BITLEN            64
+#define RMAPBT_ATTRFLAG_BITLEN         1
+#define RMAPBT_BMBTFLAG_BITLEN         1
+#define RMAPBT_EXNTFLAG_BITLEN         1
+#define RMAPBT_UNUSED_OFFSET_BITLEN    7
+#define RMAPBT_OFFSET_BITLEN           54
+
+#define XFS_RMAP_ATTR_FORK             (1 << 0)
+#define XFS_RMAP_BMBT_BLOCK            (1 << 1)
+#define XFS_RMAP_UNWRITTEN             (1 << 2)
+#define XFS_RMAP_KEY_FLAGS             (XFS_RMAP_ATTR_FORK | \
+                                        XFS_RMAP_BMBT_BLOCK)
+#define XFS_RMAP_REC_FLAGS             (XFS_RMAP_UNWRITTEN)
+struct xfs_rmap_irec {
+       xfs_agblock_t   rm_startblock;  /* extent start block */
+       xfs_extlen_t    rm_blockcount;  /* extent length */
+       __uint64_t      rm_owner;       /* extent owner */
+       __uint64_t      rm_offset;      /* offset within the owner */
+       unsigned int    rm_flags;       /* state flags */
+};
+
+/*
+ * Key structure
+ *
+ * We don't use the length for lookups
+ */
+struct xfs_rmap_key {
+       __be32          rm_startblock;  /* extent start block */
+       __be64          rm_owner;       /* extent owner */
+       __be64          rm_offset;      /* offset within the owner */
+} __attribute__((packed));
+
+/* btree pointer type */
+typedef __be32 xfs_rmap_ptr_t;
+
+#define        XFS_RMAP_BLOCK(mp) \
        (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
         XFS_FIBT_BLOCK(mp) + 1 : \
         XFS_IBT_BLOCK(mp) + 1)
 
-
-
 /*
  * BMAP Btree format definitions
  *
index f5ec9c5..7945505 100644 (file)
@@ -206,6 +206,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_FTYPE      0x10000 /* inode directory types */
 #define XFS_FSOP_GEOM_FLAGS_FINOBT     0x20000 /* free inode btree */
 #define XFS_FSOP_GEOM_FLAGS_SPINODES   0x40000 /* sparse inode chunks  */
+#define XFS_FSOP_GEOM_FLAGS_RMAPBT     0x80000 /* Reverse mapping btree */
 
 /*
  * Minimum and maximum sizes need for growth checks.
index 4b1e408..51b4e0d 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_ialloc.h"
@@ -39,6 +40,7 @@
 #include "xfs_icache.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
+#include "xfs_rmap.h"
 
 
 /*
@@ -614,6 +616,7 @@ xfs_ialloc_ag_alloc(
        args.tp = tp;
        args.mp = tp->t_mountp;
        args.fsbno = NULLFSBLOCK;
+       xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_INODES);
 
 #ifdef DEBUG
        /* randomly do sparse inode allocations */
@@ -1817,19 +1820,21 @@ xfs_difree_inode_chunk(
        struct xfs_mount                *mp,
        xfs_agnumber_t                  agno,
        struct xfs_inobt_rec_incore     *rec,
-       struct xfs_bmap_free            *flist)
+       struct xfs_defer_ops            *dfops)
 {
        xfs_agblock_t   sagbno = XFS_AGINO_TO_AGBNO(mp, rec->ir_startino);
        int             startidx, endidx;
        int             nextbit;
        xfs_agblock_t   agbno;
        int             contigblk;
+       struct xfs_owner_info   oinfo;
        DECLARE_BITMAP(holemask, XFS_INOBT_HOLEMASK_BITS);
+       xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_INODES);
 
        if (!xfs_inobt_issparse(rec->ir_holemask)) {
                /* not sparse, calculate extent info directly */
-               xfs_bmap_add_free(mp, flist, XFS_AGB_TO_FSB(mp, agno, sagbno),
-                                 mp->m_ialloc_blks);
+               xfs_bmap_add_free(mp, dfops, XFS_AGB_TO_FSB(mp, agno, sagbno),
+                                 mp->m_ialloc_blks, &oinfo);
                return;
        }
 
@@ -1872,8 +1877,8 @@ xfs_difree_inode_chunk(
 
                ASSERT(agbno % mp->m_sb.sb_spino_align == 0);
                ASSERT(contigblk % mp->m_sb.sb_spino_align == 0);
-               xfs_bmap_add_free(mp, flist, XFS_AGB_TO_FSB(mp, agno, agbno),
-                                 contigblk);
+               xfs_bmap_add_free(mp, dfops, XFS_AGB_TO_FSB(mp, agno, agbno),
+                                 contigblk, &oinfo);
 
                /* reset range to current bit and carry on... */
                startidx = endidx = nextbit;
@@ -1889,7 +1894,7 @@ xfs_difree_inobt(
        struct xfs_trans                *tp,
        struct xfs_buf                  *agbp,
        xfs_agino_t                     agino,
-       struct xfs_bmap_free            *flist,
+       struct xfs_defer_ops            *dfops,
        struct xfs_icluster             *xic,
        struct xfs_inobt_rec_incore     *orec)
 {
@@ -1976,7 +1981,7 @@ xfs_difree_inobt(
                        goto error0;
                }
 
-               xfs_difree_inode_chunk(mp, agno, &rec, flist);
+               xfs_difree_inode_chunk(mp, agno, &rec, dfops);
        } else {
                xic->deleted = 0;
 
@@ -2121,7 +2126,7 @@ int
 xfs_difree(
        struct xfs_trans        *tp,            /* transaction pointer */
        xfs_ino_t               inode,          /* inode to be freed */
-       struct xfs_bmap_free    *flist,         /* extents to free */
+       struct xfs_defer_ops    *dfops,         /* extents to free */
        struct xfs_icluster     *xic)   /* cluster info if deleted */
 {
        /* REFERENCED */
@@ -2173,7 +2178,7 @@ xfs_difree(
        /*
         * Fix up the inode allocation btree.
         */
-       error = xfs_difree_inobt(mp, tp, agbp, agino, flist, xic, &rec);
+       error = xfs_difree_inobt(mp, tp, agbp, agino, dfops, xic, &rec);
        if (error)
                goto error0;
 
index 6e450df..0bb8966 100644 (file)
@@ -95,7 +95,7 @@ int                                   /* error */
 xfs_difree(
        struct xfs_trans *tp,           /* transaction pointer */
        xfs_ino_t       inode,          /* inode to be freed */
-       struct xfs_bmap_free *flist,    /* extents to free */
+       struct xfs_defer_ops *dfops,    /* extents to free */
        struct xfs_icluster *ifree);    /* cluster info if deleted */
 
 /*
index 89c21d7..31ca220 100644 (file)
@@ -32,6 +32,7 @@
 #include "xfs_trace.h"
 #include "xfs_cksum.h"
 #include "xfs_trans.h"
+#include "xfs_rmap.h"
 
 
 STATIC int
@@ -96,6 +97,7 @@ xfs_inobt_alloc_block(
        memset(&args, 0, sizeof(args));
        args.tp = cur->bc_tp;
        args.mp = cur->bc_mp;
+       xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_INOBT);
        args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno);
        args.minlen = 1;
        args.maxlen = 1;
@@ -125,8 +127,12 @@ xfs_inobt_free_block(
        struct xfs_btree_cur    *cur,
        struct xfs_buf          *bp)
 {
+       struct xfs_owner_info   oinfo;
+
+       xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_INOBT);
        return xfs_free_extent(cur->bc_tp,
-                       XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)), 1);
+                       XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)), 1,
+                       &oinfo);
 }
 
 STATIC int
@@ -145,14 +151,6 @@ xfs_inobt_init_key_from_rec(
        key->inobt.ir_startino = rec->inobt.ir_startino;
 }
 
-STATIC void
-xfs_inobt_init_rec_from_key(
-       union xfs_btree_key     *key,
-       union xfs_btree_rec     *rec)
-{
-       rec->inobt.ir_startino = key->inobt.ir_startino;
-}
-
 STATIC void
 xfs_inobt_init_rec_from_cur(
        struct xfs_btree_cur    *cur,
@@ -314,7 +312,6 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
        .get_minrecs            = xfs_inobt_get_minrecs,
        .get_maxrecs            = xfs_inobt_get_maxrecs,
        .init_key_from_rec      = xfs_inobt_init_key_from_rec,
-       .init_rec_from_key      = xfs_inobt_init_rec_from_key,
        .init_rec_from_cur      = xfs_inobt_init_rec_from_cur,
        .init_ptr_from_cur      = xfs_inobt_init_ptr_from_cur,
        .key_diff               = xfs_inobt_key_diff,
@@ -336,7 +333,6 @@ static const struct xfs_btree_ops xfs_finobt_ops = {
        .get_minrecs            = xfs_inobt_get_minrecs,
        .get_maxrecs            = xfs_inobt_get_maxrecs,
        .init_key_from_rec      = xfs_inobt_init_key_from_rec,
-       .init_rec_from_key      = xfs_inobt_init_rec_from_key,
        .init_rec_from_cur      = xfs_inobt_init_rec_from_cur,
        .init_ptr_from_cur      = xfs_finobt_init_ptr_from_cur,
        .key_diff               = xfs_inobt_key_diff,
index 9d9559e..4b9769e 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_error.h"
 #include "xfs_cksum.h"
index e8f49c0..a6eed43 100644 (file)
@@ -110,7 +110,9 @@ static inline uint xlog_get_cycle(char *ptr)
 #define XLOG_REG_TYPE_COMMIT           18
 #define XLOG_REG_TYPE_TRANSHDR         19
 #define XLOG_REG_TYPE_ICREATE          20
-#define XLOG_REG_TYPE_MAX              20
+#define XLOG_REG_TYPE_RUI_FORMAT       21
+#define XLOG_REG_TYPE_RUD_FORMAT       22
+#define XLOG_REG_TYPE_MAX              22
 
 /*
  * Flags to log operation header
@@ -227,6 +229,8 @@ typedef struct xfs_trans_header {
 #define        XFS_LI_DQUOT            0x123d
 #define        XFS_LI_QUOTAOFF         0x123e
 #define        XFS_LI_ICREATE          0x123f
+#define        XFS_LI_RUI              0x1240  /* rmap update intent */
+#define        XFS_LI_RUD              0x1241
 
 #define XFS_LI_TYPE_DESC \
        { XFS_LI_EFI,           "XFS_LI_EFI" }, \
@@ -236,7 +240,9 @@ typedef struct xfs_trans_header {
        { XFS_LI_BUF,           "XFS_LI_BUF" }, \
        { XFS_LI_DQUOT,         "XFS_LI_DQUOT" }, \
        { XFS_LI_QUOTAOFF,      "XFS_LI_QUOTAOFF" }, \
-       { XFS_LI_ICREATE,       "XFS_LI_ICREATE" }
+       { XFS_LI_ICREATE,       "XFS_LI_ICREATE" }, \
+       { XFS_LI_RUI,           "XFS_LI_RUI" }, \
+       { XFS_LI_RUD,           "XFS_LI_RUD" }
 
 /*
  * Inode Log Item Format definitions.
@@ -603,6 +609,59 @@ typedef struct xfs_efd_log_format_64 {
        xfs_extent_64_t         efd_extents[1]; /* array of extents freed */
 } xfs_efd_log_format_64_t;
 
+/*
+ * RUI/RUD (reverse mapping) log format definitions
+ */
+struct xfs_map_extent {
+       __uint64_t              me_owner;
+       __uint64_t              me_startblock;
+       __uint64_t              me_startoff;
+       __uint32_t              me_len;
+       __uint32_t              me_flags;
+};
+
+/* rmap me_flags: upper bits are flags, lower byte is type code */
+#define XFS_RMAP_EXTENT_MAP            1
+#define XFS_RMAP_EXTENT_UNMAP          3
+#define XFS_RMAP_EXTENT_CONVERT                5
+#define XFS_RMAP_EXTENT_ALLOC          7
+#define XFS_RMAP_EXTENT_FREE           8
+#define XFS_RMAP_EXTENT_TYPE_MASK      0xFF
+
+#define XFS_RMAP_EXTENT_ATTR_FORK      (1U << 31)
+#define XFS_RMAP_EXTENT_BMBT_BLOCK     (1U << 30)
+#define XFS_RMAP_EXTENT_UNWRITTEN      (1U << 29)
+
+#define XFS_RMAP_EXTENT_FLAGS          (XFS_RMAP_EXTENT_TYPE_MASK | \
+                                        XFS_RMAP_EXTENT_ATTR_FORK | \
+                                        XFS_RMAP_EXTENT_BMBT_BLOCK | \
+                                        XFS_RMAP_EXTENT_UNWRITTEN)
+
+/*
+ * This is the structure used to lay out an rui log item in the
+ * log.  The rui_extents field is a variable size array whose
+ * size is given by rui_nextents.
+ */
+struct xfs_rui_log_format {
+       __uint16_t              rui_type;       /* rui log item type */
+       __uint16_t              rui_size;       /* size of this item */
+       __uint32_t              rui_nextents;   /* # extents to free */
+       __uint64_t              rui_id;         /* rui identifier */
+       struct xfs_map_extent   rui_extents[1]; /* array of extents to rmap */
+};
+
+/*
+ * This is the structure used to lay out an rud log item in the
+ * log.  The rud_extents array is a variable size array whose
+ * size is given by rud_nextents;
+ */
+struct xfs_rud_log_format {
+       __uint16_t              rud_type;       /* rud log item type */
+       __uint16_t              rud_size;       /* size of this item */
+       __uint32_t              __pad;
+       __uint64_t              rud_rui_id;     /* id of corresponding rui */
+};
+
 /*
  * Dquot Log format definitions.
  *
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
new file mode 100644 (file)
index 0000000..73d0540
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ * 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.
+ *
+ * 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.  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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_btree.h"
+#include "xfs_trans.h"
+#include "xfs_alloc.h"
+#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
+#include "xfs_trans_space.h"
+#include "xfs_trace.h"
+#include "xfs_error.h"
+#include "xfs_extent_busy.h"
+#include "xfs_bmap.h"
+#include "xfs_inode.h"
+
+/*
+ * Lookup the first record less than or equal to [bno, len, owner, offset]
+ * in the btree given by cur.
+ */
+int
+xfs_rmap_lookup_le(
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       uint64_t                owner,
+       uint64_t                offset,
+       unsigned int            flags,
+       int                     *stat)
+{
+       cur->bc_rec.r.rm_startblock = bno;
+       cur->bc_rec.r.rm_blockcount = len;
+       cur->bc_rec.r.rm_owner = owner;
+       cur->bc_rec.r.rm_offset = offset;
+       cur->bc_rec.r.rm_flags = flags;
+       return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
+}
+
+/*
+ * Lookup the record exactly matching [bno, len, owner, offset]
+ * in the btree given by cur.
+ */
+int
+xfs_rmap_lookup_eq(
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       uint64_t                owner,
+       uint64_t                offset,
+       unsigned int            flags,
+       int                     *stat)
+{
+       cur->bc_rec.r.rm_startblock = bno;
+       cur->bc_rec.r.rm_blockcount = len;
+       cur->bc_rec.r.rm_owner = owner;
+       cur->bc_rec.r.rm_offset = offset;
+       cur->bc_rec.r.rm_flags = flags;
+       return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
+}
+
+/*
+ * Update the record referred to by cur to the value given
+ * by [bno, len, owner, offset].
+ * This either works (return 0) or gets an EFSCORRUPTED error.
+ */
+STATIC int
+xfs_rmap_update(
+       struct xfs_btree_cur    *cur,
+       struct xfs_rmap_irec    *irec)
+{
+       union xfs_btree_rec     rec;
+       int                     error;
+
+       trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno,
+                       irec->rm_startblock, irec->rm_blockcount,
+                       irec->rm_owner, irec->rm_offset, irec->rm_flags);
+
+       rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
+       rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
+       rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
+       rec.rmap.rm_offset = cpu_to_be64(
+                       xfs_rmap_irec_offset_pack(irec));
+       error = xfs_btree_update(cur, &rec);
+       if (error)
+               trace_xfs_rmap_update_error(cur->bc_mp,
+                               cur->bc_private.a.agno, error, _RET_IP_);
+       return error;
+}
+
+int
+xfs_rmap_insert(
+       struct xfs_btree_cur    *rcur,
+       xfs_agblock_t           agbno,
+       xfs_extlen_t            len,
+       uint64_t                owner,
+       uint64_t                offset,
+       unsigned int            flags)
+{
+       int                     i;
+       int                     error;
+
+       trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
+                       len, owner, offset, flags);
+
+       error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done);
+
+       rcur->bc_rec.r.rm_startblock = agbno;
+       rcur->bc_rec.r.rm_blockcount = len;
+       rcur->bc_rec.r.rm_owner = owner;
+       rcur->bc_rec.r.rm_offset = offset;
+       rcur->bc_rec.r.rm_flags = flags;
+       error = xfs_btree_insert(rcur, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
+done:
+       if (error)
+               trace_xfs_rmap_insert_error(rcur->bc_mp,
+                               rcur->bc_private.a.agno, error, _RET_IP_);
+       return error;
+}
+
+static int
+xfs_rmap_btrec_to_irec(
+       union xfs_btree_rec     *rec,
+       struct xfs_rmap_irec    *irec)
+{
+       irec->rm_flags = 0;
+       irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
+       irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
+       irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
+       return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
+                       irec);
+}
+
+/*
+ * Get the data from the pointed-to record.
+ */
+int
+xfs_rmap_get_rec(
+       struct xfs_btree_cur    *cur,
+       struct xfs_rmap_irec    *irec,
+       int                     *stat)
+{
+       union xfs_btree_rec     *rec;
+       int                     error;
+
+       error = xfs_btree_get_rec(cur, &rec, stat);
+       if (error || !*stat)
+               return error;
+
+       return xfs_rmap_btrec_to_irec(rec, irec);
+}
+
+/*
+ * Find the extent in the rmap btree and remove it.
+ *
+ * The record we find should always be an exact match for the extent that we're
+ * looking for, since we insert them into the btree without modification.
+ *
+ * Special Case #1: when growing the filesystem, we "free" an extent when
+ * growing the last AG. This extent is new space and so it is not tracked as
+ * used space in the btree. The growfs code will pass in an owner of
+ * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
+ * extent. We verify that - the extent lookup result in a record that does not
+ * overlap.
+ *
+ * Special Case #2: EFIs do not record the owner of the extent, so when
+ * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
+ * btree to ignore the owner (i.e. wildcard match) so we don't trigger
+ * corruption checks during log recovery.
+ */
+STATIC int
+xfs_rmap_unmap(
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       bool                    unwritten,
+       struct xfs_owner_info   *oinfo)
+{
+       struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_rmap_irec    ltrec;
+       uint64_t                ltoff;
+       int                     error = 0;
+       int                     i;
+       uint64_t                owner;
+       uint64_t                offset;
+       unsigned int            flags;
+       bool                    ignore_off;
+
+       xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
+       ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
+                       (flags & XFS_RMAP_BMBT_BLOCK);
+       if (unwritten)
+               flags |= XFS_RMAP_UNWRITTEN;
+       trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+
+       /*
+        * We should always have a left record because there's a static record
+        * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
+        * will not ever be removed from the tree.
+        */
+       error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+
+       error = xfs_rmap_get_rec(cur, &ltrec, &i);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
+                       cur->bc_private.a.agno, ltrec.rm_startblock,
+                       ltrec.rm_blockcount, ltrec.rm_owner,
+                       ltrec.rm_offset, ltrec.rm_flags);
+       ltoff = ltrec.rm_offset;
+
+       /*
+        * For growfs, the incoming extent must be beyond the left record we
+        * just found as it is new space and won't be used by anyone. This is
+        * just a corruption check as we don't actually do anything with this
+        * extent.  Note that we need to use >= instead of > because it might
+        * be the case that the "left" extent goes all the way to EOFS.
+        */
+       if (owner == XFS_RMAP_OWN_NULL) {
+               XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock +
+                                               ltrec.rm_blockcount, out_error);
+               goto out_done;
+       }
+
+       /* Make sure the unwritten flag matches. */
+       XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
+                       (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
+
+       /* Make sure the extent we found covers the entire freeing range. */
+       XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
+               ltrec.rm_startblock + ltrec.rm_blockcount >=
+               bno + len, out_error);
+
+       /* Make sure the owner matches what we expect to find in the tree. */
+       XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner ||
+                                   XFS_RMAP_NON_INODE_OWNER(owner), out_error);
+
+       /* Check the offset, if necessary. */
+       if (!XFS_RMAP_NON_INODE_OWNER(owner)) {
+               if (flags & XFS_RMAP_BMBT_BLOCK) {
+                       XFS_WANT_CORRUPTED_GOTO(mp,
+                                       ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK,
+                                       out_error);
+               } else {
+                       XFS_WANT_CORRUPTED_GOTO(mp,
+                                       ltrec.rm_offset <= offset, out_error);
+                       XFS_WANT_CORRUPTED_GOTO(mp,
+                                       ltoff + ltrec.rm_blockcount >= offset + len,
+                                       out_error);
+               }
+       }
+
+       if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
+               /* exact match, simply remove the record from rmap tree */
+               trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                               ltrec.rm_startblock, ltrec.rm_blockcount,
+                               ltrec.rm_owner, ltrec.rm_offset,
+                               ltrec.rm_flags);
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto out_error;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       } else if (ltrec.rm_startblock == bno) {
+               /*
+                * overlap left hand side of extent: move the start, trim the
+                * length and update the current record.
+                *
+                *       ltbno                ltlen
+                * Orig:    |oooooooooooooooooooo|
+                * Freeing: |fffffffff|
+                * Result:            |rrrrrrrrrr|
+                *         bno       len
+                */
+               ltrec.rm_startblock += len;
+               ltrec.rm_blockcount -= len;
+               if (!ignore_off)
+                       ltrec.rm_offset += len;
+               error = xfs_rmap_update(cur, &ltrec);
+               if (error)
+                       goto out_error;
+       } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
+               /*
+                * overlap right hand side of extent: trim the length and update
+                * the current record.
+                *
+                *       ltbno                ltlen
+                * Orig:    |oooooooooooooooooooo|
+                * Freeing:            |fffffffff|
+                * Result:  |rrrrrrrrrr|
+                *                    bno       len
+                */
+               ltrec.rm_blockcount -= len;
+               error = xfs_rmap_update(cur, &ltrec);
+               if (error)
+                       goto out_error;
+       } else {
+
+               /*
+                * overlap middle of extent: trim the length of the existing
+                * record to the length of the new left-extent size, increment
+                * the insertion position so we can insert a new record
+                * containing the remaining right-extent space.
+                *
+                *       ltbno                ltlen
+                * Orig:    |oooooooooooooooooooo|
+                * Freeing:       |fffffffff|
+                * Result:  |rrrrr|         |rrrr|
+                *               bno       len
+                */
+               xfs_extlen_t    orig_len = ltrec.rm_blockcount;
+
+               ltrec.rm_blockcount = bno - ltrec.rm_startblock;
+               error = xfs_rmap_update(cur, &ltrec);
+               if (error)
+                       goto out_error;
+
+               error = xfs_btree_increment(cur, 0, &i);
+               if (error)
+                       goto out_error;
+
+               cur->bc_rec.r.rm_startblock = bno + len;
+               cur->bc_rec.r.rm_blockcount = orig_len - len -
+                                                    ltrec.rm_blockcount;
+               cur->bc_rec.r.rm_owner = ltrec.rm_owner;
+               if (ignore_off)
+                       cur->bc_rec.r.rm_offset = 0;
+               else
+                       cur->bc_rec.r.rm_offset = offset + len;
+               cur->bc_rec.r.rm_flags = flags;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
+                               cur->bc_rec.r.rm_startblock,
+                               cur->bc_rec.r.rm_blockcount,
+                               cur->bc_rec.r.rm_owner,
+                               cur->bc_rec.r.rm_offset,
+                               cur->bc_rec.r.rm_flags);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto out_error;
+       }
+
+out_done:
+       trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+out_error:
+       if (error)
+               trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno,
+                               error, _RET_IP_);
+       return error;
+}
+
+/*
+ * Remove a reference to an extent in the rmap btree.
+ */
+int
+xfs_rmap_free(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       struct xfs_owner_info   *oinfo)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return 0;
+
+       cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+
+       error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
+       if (error)
+               goto out_error;
+
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+       return 0;
+
+out_error:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       return error;
+}
+
+/*
+ * A mergeable rmap must have the same owner and the same values for
+ * the unwritten, attr_fork, and bmbt flags.  The startblock and
+ * offset are checked separately.
+ */
+static bool
+xfs_rmap_is_mergeable(
+       struct xfs_rmap_irec    *irec,
+       uint64_t                owner,
+       unsigned int            flags)
+{
+       if (irec->rm_owner == XFS_RMAP_OWN_NULL)
+               return false;
+       if (irec->rm_owner != owner)
+               return false;
+       if ((flags & XFS_RMAP_UNWRITTEN) ^
+           (irec->rm_flags & XFS_RMAP_UNWRITTEN))
+               return false;
+       if ((flags & XFS_RMAP_ATTR_FORK) ^
+           (irec->rm_flags & XFS_RMAP_ATTR_FORK))
+               return false;
+       if ((flags & XFS_RMAP_BMBT_BLOCK) ^
+           (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
+               return false;
+       return true;
+}
+
+/*
+ * When we allocate a new block, the first thing we do is add a reference to
+ * the extent in the rmap btree. This takes the form of a [agbno, length,
+ * owner, offset] record.  Flags are encoded in the high bits of the offset
+ * field.
+ */
+STATIC int
+xfs_rmap_map(
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       bool                    unwritten,
+       struct xfs_owner_info   *oinfo)
+{
+       struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_rmap_irec    ltrec;
+       struct xfs_rmap_irec    gtrec;
+       int                     have_gt;
+       int                     have_lt;
+       int                     error = 0;
+       int                     i;
+       uint64_t                owner;
+       uint64_t                offset;
+       unsigned int            flags = 0;
+       bool                    ignore_off;
+
+       xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
+       ASSERT(owner != 0);
+       ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
+                       (flags & XFS_RMAP_BMBT_BLOCK);
+       if (unwritten)
+               flags |= XFS_RMAP_UNWRITTEN;
+       trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+
+       /*
+        * For the initial lookup, look for an exact match or the left-adjacent
+        * record for our insertion point. This will also give us the record for
+        * start block contiguity tests.
+        */
+       error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
+                       &have_lt);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
+
+       error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
+       if (error)
+               goto out_error;
+       XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
+       trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
+                       cur->bc_private.a.agno, ltrec.rm_startblock,
+                       ltrec.rm_blockcount, ltrec.rm_owner,
+                       ltrec.rm_offset, ltrec.rm_flags);
+
+       if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
+               have_lt = 0;
+
+       XFS_WANT_CORRUPTED_GOTO(mp,
+               have_lt == 0 ||
+               ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
+
+       /*
+        * Increment the cursor to see if we have a right-adjacent record to our
+        * insertion point. This will give us the record for end block
+        * contiguity tests.
+        */
+       error = xfs_btree_increment(cur, 0, &have_gt);
+       if (error)
+               goto out_error;
+       if (have_gt) {
+               error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
+               if (error)
+                       goto out_error;
+               XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
+               XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
+                                       out_error);
+               trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
+                       cur->bc_private.a.agno, gtrec.rm_startblock,
+                       gtrec.rm_blockcount, gtrec.rm_owner,
+                       gtrec.rm_offset, gtrec.rm_flags);
+               if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
+                       have_gt = 0;
+       }
+
+       /*
+        * Note: cursor currently points one record to the right of ltrec, even
+        * if there is no record in the tree to the right.
+        */
+       if (have_lt &&
+           ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
+           (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
+               /*
+                * left edge contiguous, merge into left record.
+                *
+                *       ltbno     ltlen
+                * orig:   |ooooooooo|
+                * adding:           |aaaaaaaaa|
+                * result: |rrrrrrrrrrrrrrrrrrr|
+                *                  bno       len
+                */
+               ltrec.rm_blockcount += len;
+               if (have_gt &&
+                   bno + len == gtrec.rm_startblock &&
+                   (ignore_off || offset + len == gtrec.rm_offset) &&
+                   (unsigned long)ltrec.rm_blockcount + len +
+                               gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
+                       /*
+                        * right edge also contiguous, delete right record
+                        * and merge into left record.
+                        *
+                        *       ltbno     ltlen    gtbno     gtlen
+                        * orig:   |ooooooooo|         |ooooooooo|
+                        * adding:           |aaaaaaaaa|
+                        * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
+                        */
+                       ltrec.rm_blockcount += gtrec.rm_blockcount;
+                       trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                                       gtrec.rm_startblock,
+                                       gtrec.rm_blockcount,
+                                       gtrec.rm_owner,
+                                       gtrec.rm_offset,
+                                       gtrec.rm_flags);
+                       error = xfs_btree_delete(cur, &i);
+                       if (error)
+                               goto out_error;
+                       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+               }
+
+               /* point the cursor back to the left record and update */
+               error = xfs_btree_decrement(cur, 0, &have_gt);
+               if (error)
+                       goto out_error;
+               error = xfs_rmap_update(cur, &ltrec);
+               if (error)
+                       goto out_error;
+       } else if (have_gt &&
+                  bno + len == gtrec.rm_startblock &&
+                  (ignore_off || offset + len == gtrec.rm_offset)) {
+               /*
+                * right edge contiguous, merge into right record.
+                *
+                *                 gtbno     gtlen
+                * Orig:             |ooooooooo|
+                * adding: |aaaaaaaaa|
+                * Result: |rrrrrrrrrrrrrrrrrrr|
+                *        bno       len
+                */
+               gtrec.rm_startblock = bno;
+               gtrec.rm_blockcount += len;
+               if (!ignore_off)
+                       gtrec.rm_offset = offset;
+               error = xfs_rmap_update(cur, &gtrec);
+               if (error)
+                       goto out_error;
+       } else {
+               /*
+                * no contiguous edge with identical owner, insert
+                * new record at current cursor position.
+                */
+               cur->bc_rec.r.rm_startblock = bno;
+               cur->bc_rec.r.rm_blockcount = len;
+               cur->bc_rec.r.rm_owner = owner;
+               cur->bc_rec.r.rm_offset = offset;
+               cur->bc_rec.r.rm_flags = flags;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
+                       owner, offset, flags);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto out_error;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
+       }
+
+       trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+out_error:
+       if (error)
+               trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
+                               error, _RET_IP_);
+       return error;
+}
+
+/*
+ * Add a reference to an extent in the rmap btree.
+ */
+int
+xfs_rmap_alloc(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       struct xfs_owner_info   *oinfo)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return 0;
+
+       cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+       error = xfs_rmap_map(cur, bno, len, false, oinfo);
+       if (error)
+               goto out_error;
+
+       xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+       return 0;
+
+out_error:
+       xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
+       return error;
+}
+
+#define RMAP_LEFT_CONTIG       (1 << 0)
+#define RMAP_RIGHT_CONTIG      (1 << 1)
+#define RMAP_LEFT_FILLING      (1 << 2)
+#define RMAP_RIGHT_FILLING     (1 << 3)
+#define RMAP_LEFT_VALID                (1 << 6)
+#define RMAP_RIGHT_VALID       (1 << 7)
+
+#define LEFT           r[0]
+#define RIGHT          r[1]
+#define PREV           r[2]
+#define NEW            r[3]
+
+/*
+ * Convert an unwritten extent to a real extent or vice versa.
+ * Does not handle overlapping extents.
+ */
+STATIC int
+xfs_rmap_convert(
+       struct xfs_btree_cur    *cur,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       bool                    unwritten,
+       struct xfs_owner_info   *oinfo)
+{
+       struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_rmap_irec    r[4];   /* neighbor extent entries */
+                                       /* left is 0, right is 1, prev is 2 */
+                                       /* new is 3 */
+       uint64_t                owner;
+       uint64_t                offset;
+       uint64_t                new_endoff;
+       unsigned int            oldext;
+       unsigned int            newext;
+       unsigned int            flags = 0;
+       int                     i;
+       int                     state = 0;
+       int                     error;
+
+       xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
+       ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
+                       (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
+       oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
+       new_endoff = offset + len;
+       trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+
+       /*
+        * For the initial lookup, look for an exact match or the left-adjacent
+        * record for our insertion point. This will also give us the record for
+        * start block contiguity tests.
+        */
+       error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+
+       error = xfs_rmap_get_rec(cur, &PREV, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
+                       cur->bc_private.a.agno, PREV.rm_startblock,
+                       PREV.rm_blockcount, PREV.rm_owner,
+                       PREV.rm_offset, PREV.rm_flags);
+
+       ASSERT(PREV.rm_offset <= offset);
+       ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
+       ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
+       newext = ~oldext & XFS_RMAP_UNWRITTEN;
+
+       /*
+        * Set flags determining what part of the previous oldext allocation
+        * extent is being replaced by a newext allocation.
+        */
+       if (PREV.rm_offset == offset)
+               state |= RMAP_LEFT_FILLING;
+       if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
+               state |= RMAP_RIGHT_FILLING;
+
+       /*
+        * Decrement the cursor to see if we have a left-adjacent record to our
+        * insertion point. This will give us the record for end block
+        * contiguity tests.
+        */
+       error = xfs_btree_decrement(cur, 0, &i);
+       if (error)
+               goto done;
+       if (i) {
+               state |= RMAP_LEFT_VALID;
+               error = xfs_rmap_get_rec(cur, &LEFT, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               XFS_WANT_CORRUPTED_GOTO(mp,
+                               LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
+                               done);
+               trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
+                               cur->bc_private.a.agno, LEFT.rm_startblock,
+                               LEFT.rm_blockcount, LEFT.rm_owner,
+                               LEFT.rm_offset, LEFT.rm_flags);
+               if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
+                   LEFT.rm_offset + LEFT.rm_blockcount == offset &&
+                   xfs_rmap_is_mergeable(&LEFT, owner, newext))
+                       state |= RMAP_LEFT_CONTIG;
+       }
+
+       /*
+        * Increment the cursor to see if we have a right-adjacent record to our
+        * insertion point. This will give us the record for end block
+        * contiguity tests.
+        */
+       error = xfs_btree_increment(cur, 0, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+       error = xfs_btree_increment(cur, 0, &i);
+       if (error)
+               goto done;
+       if (i) {
+               state |= RMAP_RIGHT_VALID;
+               error = xfs_rmap_get_rec(cur, &RIGHT, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
+                                       done);
+               trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
+                               cur->bc_private.a.agno, RIGHT.rm_startblock,
+                               RIGHT.rm_blockcount, RIGHT.rm_owner,
+                               RIGHT.rm_offset, RIGHT.rm_flags);
+               if (bno + len == RIGHT.rm_startblock &&
+                   offset + len == RIGHT.rm_offset &&
+                   xfs_rmap_is_mergeable(&RIGHT, owner, newext))
+                       state |= RMAP_RIGHT_CONTIG;
+       }
+
+       /* check that left + prev + right is not too long */
+       if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
+                        RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
+           (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
+            RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
+           (unsigned long)LEFT.rm_blockcount + len +
+            RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
+               state &= ~RMAP_RIGHT_CONTIG;
+
+       trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
+                       _RET_IP_);
+
+       /* reset the cursor back to PREV */
+       error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
+       if (error)
+               goto done;
+       XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+
+       /*
+        * Switch out based on the FILLING and CONTIG state bits.
+        */
+       switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
+                        RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
+       case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
+            RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
+               /*
+                * Setting all of a previous oldext extent to newext.
+                * The left and right neighbors are both contiguous with new.
+                */
+               error = xfs_btree_increment(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                               RIGHT.rm_startblock, RIGHT.rm_blockcount,
+                               RIGHT.rm_owner, RIGHT.rm_offset,
+                               RIGHT.rm_flags);
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                               PREV.rm_startblock, PREV.rm_blockcount,
+                               PREV.rm_owner, PREV.rm_offset,
+                               PREV.rm_flags);
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               NEW = LEFT;
+               NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
+               /*
+                * Setting all of a previous oldext extent to newext.
+                * The left neighbor is contiguous, the right is not.
+                */
+               trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                               PREV.rm_startblock, PREV.rm_blockcount,
+                               PREV.rm_owner, PREV.rm_offset,
+                               PREV.rm_flags);
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               NEW = LEFT;
+               NEW.rm_blockcount += PREV.rm_blockcount;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
+               /*
+                * Setting all of a previous oldext extent to newext.
+                * The right neighbor is contiguous, the left is not.
+                */
+               error = xfs_btree_increment(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
+                               RIGHT.rm_startblock, RIGHT.rm_blockcount,
+                               RIGHT.rm_owner, RIGHT.rm_offset,
+                               RIGHT.rm_flags);
+               error = xfs_btree_delete(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               NEW = PREV;
+               NEW.rm_blockcount = len + RIGHT.rm_blockcount;
+               NEW.rm_flags = newext;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
+               /*
+                * Setting all of a previous oldext extent to newext.
+                * Neither the left nor right neighbors are contiguous with
+                * the new one.
+                */
+               NEW = PREV;
+               NEW.rm_flags = newext;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
+               /*
+                * Setting the first part of a previous oldext extent to newext.
+                * The left neighbor is contiguous.
+                */
+               NEW = PREV;
+               NEW.rm_offset += len;
+               NEW.rm_startblock += len;
+               NEW.rm_blockcount -= len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               error = xfs_btree_decrement(cur, 0, &i);
+               if (error)
+                       goto done;
+               NEW = LEFT;
+               NEW.rm_blockcount += len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_LEFT_FILLING:
+               /*
+                * Setting the first part of a previous oldext extent to newext.
+                * The left neighbor is not contiguous.
+                */
+               NEW = PREV;
+               NEW.rm_startblock += len;
+               NEW.rm_offset += len;
+               NEW.rm_blockcount -= len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               NEW.rm_startblock = bno;
+               NEW.rm_owner = owner;
+               NEW.rm_offset = offset;
+               NEW.rm_blockcount = len;
+               NEW.rm_flags = newext;
+               cur->bc_rec.r = NEW;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
+                               len, owner, offset, newext);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               break;
+
+       case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
+               /*
+                * Setting the last part of a previous oldext extent to newext.
+                * The right neighbor is contiguous with the new allocation.
+                */
+               NEW = PREV;
+               NEW.rm_blockcount -= len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               error = xfs_btree_increment(cur, 0, &i);
+               if (error)
+                       goto done;
+               NEW = RIGHT;
+               NEW.rm_offset = offset;
+               NEW.rm_startblock = bno;
+               NEW.rm_blockcount += len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               break;
+
+       case RMAP_RIGHT_FILLING:
+               /*
+                * Setting the last part of a previous oldext extent to newext.
+                * The right neighbor is not contiguous.
+                */
+               NEW = PREV;
+               NEW.rm_blockcount -= len;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
+                               oldext, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+               NEW.rm_startblock = bno;
+               NEW.rm_owner = owner;
+               NEW.rm_offset = offset;
+               NEW.rm_blockcount = len;
+               NEW.rm_flags = newext;
+               cur->bc_rec.r = NEW;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
+                               len, owner, offset, newext);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               break;
+
+       case 0:
+               /*
+                * Setting the middle part of a previous oldext extent to
+                * newext.  Contiguity is impossible here.
+                * One extent becomes three extents.
+                */
+               /* new right extent - oldext */
+               NEW.rm_startblock = bno + len;
+               NEW.rm_owner = owner;
+               NEW.rm_offset = new_endoff;
+               NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
+                               new_endoff;
+               NEW.rm_flags = PREV.rm_flags;
+               error = xfs_rmap_update(cur, &NEW);
+               if (error)
+                       goto done;
+               /* new left extent - oldext */
+               NEW = PREV;
+               NEW.rm_blockcount = offset - PREV.rm_offset;
+               cur->bc_rec.r = NEW;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
+                               NEW.rm_startblock, NEW.rm_blockcount,
+                               NEW.rm_owner, NEW.rm_offset,
+                               NEW.rm_flags);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               /*
+                * Reset the cursor to the position of the new extent
+                * we are about to insert as we can't trust it after
+                * the previous insert.
+                */
+               error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
+                               oldext, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
+               /* new middle extent - newext */
+               cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
+               cur->bc_rec.r.rm_flags |= newext;
+               trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
+                               owner, offset, newext);
+               error = xfs_btree_insert(cur, &i);
+               if (error)
+                       goto done;
+               XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
+               break;
+
+       case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
+       case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
+       case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
+       case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
+       case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
+       case RMAP_LEFT_CONTIG:
+       case RMAP_RIGHT_CONTIG:
+               /*
+                * These cases are all impossible.
+                */
+               ASSERT(0);
+       }
+
+       trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
+                       unwritten, oinfo);
+done:
+       if (error)
+               trace_xfs_rmap_convert_error(cur->bc_mp,
+                               cur->bc_private.a.agno, error, _RET_IP_);
+       return error;
+}
+
+#undef NEW
+#undef LEFT
+#undef RIGHT
+#undef PREV
+
+struct xfs_rmap_query_range_info {
+       xfs_rmap_query_range_fn fn;
+       void                            *priv;
+};
+
+/* Format btree record and pass to our callback. */
+STATIC int
+xfs_rmap_query_range_helper(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_rec     *rec,
+       void                    *priv)
+{
+       struct xfs_rmap_query_range_info        *query = priv;
+       struct xfs_rmap_irec                    irec;
+       int                                     error;
+
+       error = xfs_rmap_btrec_to_irec(rec, &irec);
+       if (error)
+               return error;
+       return query->fn(cur, &irec, query->priv);
+}
+
+/* Find all rmaps between two keys. */
+int
+xfs_rmap_query_range(
+       struct xfs_btree_cur            *cur,
+       struct xfs_rmap_irec            *low_rec,
+       struct xfs_rmap_irec            *high_rec,
+       xfs_rmap_query_range_fn fn,
+       void                            *priv)
+{
+       union xfs_btree_irec            low_brec;
+       union xfs_btree_irec            high_brec;
+       struct xfs_rmap_query_range_info        query;
+
+       low_brec.r = *low_rec;
+       high_brec.r = *high_rec;
+       query.priv = priv;
+       query.fn = fn;
+       return xfs_btree_query_range(cur, &low_brec, &high_brec,
+                       xfs_rmap_query_range_helper, &query);
+}
+
+/* Clean up after calling xfs_rmap_finish_one. */
+void
+xfs_rmap_finish_one_cleanup(
+       struct xfs_trans        *tp,
+       struct xfs_btree_cur    *rcur,
+       int                     error)
+{
+       struct xfs_buf          *agbp;
+
+       if (rcur == NULL)
+               return;
+       agbp = rcur->bc_private.a.agbp;
+       xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+       if (error)
+               xfs_trans_brelse(tp, agbp);
+}
+
+/*
+ * Process one of the deferred rmap operations.  We pass back the
+ * btree cursor to maintain our lock on the rmapbt between calls.
+ * This saves time and eliminates a buffer deadlock between the
+ * superblock and the AGF because we'll always grab them in the same
+ * order.
+ */
+int
+xfs_rmap_finish_one(
+       struct xfs_trans                *tp,
+       enum xfs_rmap_intent_type       type,
+       __uint64_t                      owner,
+       int                             whichfork,
+       xfs_fileoff_t                   startoff,
+       xfs_fsblock_t                   startblock,
+       xfs_filblks_t                   blockcount,
+       xfs_exntst_t                    state,
+       struct xfs_btree_cur            **pcur)
+{
+       struct xfs_mount                *mp = tp->t_mountp;
+       struct xfs_btree_cur            *rcur;
+       struct xfs_buf                  *agbp = NULL;
+       int                             error = 0;
+       xfs_agnumber_t                  agno;
+       struct xfs_owner_info           oinfo;
+       xfs_agblock_t                   bno;
+       bool                            unwritten;
+
+       agno = XFS_FSB_TO_AGNO(mp, startblock);
+       ASSERT(agno != NULLAGNUMBER);
+       bno = XFS_FSB_TO_AGBNO(mp, startblock);
+
+       trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
+                       startoff, blockcount, state);
+
+       if (XFS_TEST_ERROR(false, mp,
+                       XFS_ERRTAG_RMAP_FINISH_ONE,
+                       XFS_RANDOM_RMAP_FINISH_ONE))
+               return -EIO;
+
+       /*
+        * If we haven't gotten a cursor or the cursor AG doesn't match
+        * the startblock, get one now.
+        */
+       rcur = *pcur;
+       if (rcur != NULL && rcur->bc_private.a.agno != agno) {
+               xfs_rmap_finish_one_cleanup(tp, rcur, 0);
+               rcur = NULL;
+               *pcur = NULL;
+       }
+       if (rcur == NULL) {
+               /*
+                * Refresh the freelist before we start changing the
+                * rmapbt, because a shape change could cause us to
+                * allocate blocks.
+                */
+               error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
+               if (error)
+                       return error;
+               if (!agbp)
+                       return -EFSCORRUPTED;
+
+               rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+               if (!rcur) {
+                       error = -ENOMEM;
+                       goto out_cur;
+               }
+       }
+       *pcur = rcur;
+
+       xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff);
+       unwritten = state == XFS_EXT_UNWRITTEN;
+       bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock);
+
+       switch (type) {
+       case XFS_RMAP_ALLOC:
+       case XFS_RMAP_MAP:
+               error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo);
+               break;
+       case XFS_RMAP_FREE:
+       case XFS_RMAP_UNMAP:
+               error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten,
+                               &oinfo);
+               break;
+       case XFS_RMAP_CONVERT:
+               error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
+                               &oinfo);
+               break;
+       default:
+               ASSERT(0);
+               error = -EFSCORRUPTED;
+       }
+       return error;
+
+out_cur:
+       xfs_trans_brelse(tp, agbp);
+
+       return error;
+}
+
+/*
+ * Don't defer an rmap if we aren't an rmap filesystem.
+ */
+static bool
+xfs_rmap_update_is_needed(
+       struct xfs_mount        *mp)
+{
+       return xfs_sb_version_hasrmapbt(&mp->m_sb);
+}
+
+/*
+ * Record a rmap intent; the list is kept sorted first by AG and then by
+ * increasing age.
+ */
+static int
+__xfs_rmap_add(
+       struct xfs_mount                *mp,
+       struct xfs_defer_ops            *dfops,
+       enum xfs_rmap_intent_type       type,
+       __uint64_t                      owner,
+       int                             whichfork,
+       struct xfs_bmbt_irec            *bmap)
+{
+       struct xfs_rmap_intent  *ri;
+
+       trace_xfs_rmap_defer(mp, XFS_FSB_TO_AGNO(mp, bmap->br_startblock),
+                       type,
+                       XFS_FSB_TO_AGBNO(mp, bmap->br_startblock),
+                       owner, whichfork,
+                       bmap->br_startoff,
+                       bmap->br_blockcount,
+                       bmap->br_state);
+
+       ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_SLEEP | KM_NOFS);
+       INIT_LIST_HEAD(&ri->ri_list);
+       ri->ri_type = type;
+       ri->ri_owner = owner;
+       ri->ri_whichfork = whichfork;
+       ri->ri_bmap = *bmap;
+
+       xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list);
+       return 0;
+}
+
+/* Map an extent into a file. */
+int
+xfs_rmap_map_extent(
+       struct xfs_mount        *mp,
+       struct xfs_defer_ops    *dfops,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       struct xfs_bmbt_irec    *PREV)
+{
+       if (!xfs_rmap_update_is_needed(mp))
+               return 0;
+
+       return __xfs_rmap_add(mp, dfops, XFS_RMAP_MAP, ip->i_ino,
+                       whichfork, PREV);
+}
+
+/* Unmap an extent out of a file. */
+int
+xfs_rmap_unmap_extent(
+       struct xfs_mount        *mp,
+       struct xfs_defer_ops    *dfops,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       struct xfs_bmbt_irec    *PREV)
+{
+       if (!xfs_rmap_update_is_needed(mp))
+               return 0;
+
+       return __xfs_rmap_add(mp, dfops, XFS_RMAP_UNMAP, ip->i_ino,
+                       whichfork, PREV);
+}
+
+/* Convert a data fork extent from unwritten to real or vice versa. */
+int
+xfs_rmap_convert_extent(
+       struct xfs_mount        *mp,
+       struct xfs_defer_ops    *dfops,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       struct xfs_bmbt_irec    *PREV)
+{
+       if (!xfs_rmap_update_is_needed(mp))
+               return 0;
+
+       return __xfs_rmap_add(mp, dfops, XFS_RMAP_CONVERT, ip->i_ino,
+                       whichfork, PREV);
+}
+
+/* Schedule the creation of an rmap for non-file data. */
+int
+xfs_rmap_alloc_extent(
+       struct xfs_mount        *mp,
+       struct xfs_defer_ops    *dfops,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       __uint64_t              owner)
+{
+       struct xfs_bmbt_irec    bmap;
+
+       if (!xfs_rmap_update_is_needed(mp))
+               return 0;
+
+       bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno);
+       bmap.br_blockcount = len;
+       bmap.br_startoff = 0;
+       bmap.br_state = XFS_EXT_NORM;
+
+       return __xfs_rmap_add(mp, dfops, XFS_RMAP_ALLOC, owner,
+                       XFS_DATA_FORK, &bmap);
+}
+
+/* Schedule the deletion of an rmap for non-file data. */
+int
+xfs_rmap_free_extent(
+       struct xfs_mount        *mp,
+       struct xfs_defer_ops    *dfops,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           bno,
+       xfs_extlen_t            len,
+       __uint64_t              owner)
+{
+       struct xfs_bmbt_irec    bmap;
+
+       if (!xfs_rmap_update_is_needed(mp))
+               return 0;
+
+       bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno);
+       bmap.br_blockcount = len;
+       bmap.br_startoff = 0;
+       bmap.br_state = XFS_EXT_NORM;
+
+       return __xfs_rmap_add(mp, dfops, XFS_RMAP_FREE, owner,
+                       XFS_DATA_FORK, &bmap);
+}
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
new file mode 100644 (file)
index 0000000..71cf99a
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#ifndef __XFS_RMAP_H__
+#define __XFS_RMAP_H__
+
+static inline void
+xfs_rmap_ag_owner(
+       struct xfs_owner_info   *oi,
+       uint64_t                owner)
+{
+       oi->oi_owner = owner;
+       oi->oi_offset = 0;
+       oi->oi_flags = 0;
+}
+
+static inline void
+xfs_rmap_ino_bmbt_owner(
+       struct xfs_owner_info   *oi,
+       xfs_ino_t               ino,
+       int                     whichfork)
+{
+       oi->oi_owner = ino;
+       oi->oi_offset = 0;
+       oi->oi_flags = XFS_OWNER_INFO_BMBT_BLOCK;
+       if (whichfork == XFS_ATTR_FORK)
+               oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
+}
+
+static inline void
+xfs_rmap_ino_owner(
+       struct xfs_owner_info   *oi,
+       xfs_ino_t               ino,
+       int                     whichfork,
+       xfs_fileoff_t           offset)
+{
+       oi->oi_owner = ino;
+       oi->oi_offset = offset;
+       oi->oi_flags = 0;
+       if (whichfork == XFS_ATTR_FORK)
+               oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
+}
+
+static inline void
+xfs_rmap_skip_owner_update(
+       struct xfs_owner_info   *oi)
+{
+       oi->oi_owner = XFS_RMAP_OWN_UNKNOWN;
+}
+
+/* Reverse mapping functions. */
+
+struct xfs_buf;
+
+static inline __u64
+xfs_rmap_irec_offset_pack(
+       const struct xfs_rmap_irec      *irec)
+{
+       __u64                   x;
+
+       x = XFS_RMAP_OFF(irec->rm_offset);
+       if (irec->rm_flags & XFS_RMAP_ATTR_FORK)
+               x |= XFS_RMAP_OFF_ATTR_FORK;
+       if (irec->rm_flags & XFS_RMAP_BMBT_BLOCK)
+               x |= XFS_RMAP_OFF_BMBT_BLOCK;
+       if (irec->rm_flags & XFS_RMAP_UNWRITTEN)
+               x |= XFS_RMAP_OFF_UNWRITTEN;
+       return x;
+}
+
+static inline int
+xfs_rmap_irec_offset_unpack(
+       __u64                   offset,
+       struct xfs_rmap_irec    *irec)
+{
+       if (offset & ~(XFS_RMAP_OFF_MASK | XFS_RMAP_OFF_FLAGS))
+               return -EFSCORRUPTED;
+       irec->rm_offset = XFS_RMAP_OFF(offset);
+       if (offset & XFS_RMAP_OFF_ATTR_FORK)
+               irec->rm_flags |= XFS_RMAP_ATTR_FORK;
+       if (offset & XFS_RMAP_OFF_BMBT_BLOCK)
+               irec->rm_flags |= XFS_RMAP_BMBT_BLOCK;
+       if (offset & XFS_RMAP_OFF_UNWRITTEN)
+               irec->rm_flags |= XFS_RMAP_UNWRITTEN;
+       return 0;
+}
+
+static inline void
+xfs_owner_info_unpack(
+       struct xfs_owner_info   *oinfo,
+       uint64_t                *owner,
+       uint64_t                *offset,
+       unsigned int            *flags)
+{
+       unsigned int            r = 0;
+
+       *owner = oinfo->oi_owner;
+       *offset = oinfo->oi_offset;
+       if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK)
+               r |= XFS_RMAP_ATTR_FORK;
+       if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK)
+               r |= XFS_RMAP_BMBT_BLOCK;
+       *flags = r;
+}
+
+static inline void
+xfs_owner_info_pack(
+       struct xfs_owner_info   *oinfo,
+       uint64_t                owner,
+       uint64_t                offset,
+       unsigned int            flags)
+{
+       oinfo->oi_owner = owner;
+       oinfo->oi_offset = XFS_RMAP_OFF(offset);
+       oinfo->oi_flags = 0;
+       if (flags & XFS_RMAP_ATTR_FORK)
+               oinfo->oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
+       if (flags & XFS_RMAP_BMBT_BLOCK)
+               oinfo->oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
+}
+
+int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
+                  xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+                  struct xfs_owner_info *oinfo);
+int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
+                 xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+                 struct xfs_owner_info *oinfo);
+
+int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
+               xfs_extlen_t len, uint64_t owner, uint64_t offset,
+               unsigned int flags, int *stat);
+int xfs_rmap_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno,
+               xfs_extlen_t len, uint64_t owner, uint64_t offset,
+               unsigned int flags, int *stat);
+int xfs_rmap_insert(struct xfs_btree_cur *rcur, xfs_agblock_t agbno,
+               xfs_extlen_t len, uint64_t owner, uint64_t offset,
+               unsigned int flags);
+int xfs_rmap_get_rec(struct xfs_btree_cur *cur, struct xfs_rmap_irec *irec,
+               int *stat);
+
+typedef int (*xfs_rmap_query_range_fn)(
+       struct xfs_btree_cur    *cur,
+       struct xfs_rmap_irec    *rec,
+       void                    *priv);
+
+int xfs_rmap_query_range(struct xfs_btree_cur *cur,
+               struct xfs_rmap_irec *low_rec, struct xfs_rmap_irec *high_rec,
+               xfs_rmap_query_range_fn fn, void *priv);
+
+enum xfs_rmap_intent_type {
+       XFS_RMAP_MAP,
+       XFS_RMAP_MAP_SHARED,
+       XFS_RMAP_UNMAP,
+       XFS_RMAP_UNMAP_SHARED,
+       XFS_RMAP_CONVERT,
+       XFS_RMAP_CONVERT_SHARED,
+       XFS_RMAP_ALLOC,
+       XFS_RMAP_FREE,
+};
+
+struct xfs_rmap_intent {
+       struct list_head                        ri_list;
+       enum xfs_rmap_intent_type               ri_type;
+       __uint64_t                              ri_owner;
+       int                                     ri_whichfork;
+       struct xfs_bmbt_irec                    ri_bmap;
+};
+
+/* functions for updating the rmapbt based on bmbt map/unmap operations */
+int xfs_rmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+               struct xfs_inode *ip, int whichfork,
+               struct xfs_bmbt_irec *imap);
+int xfs_rmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+               struct xfs_inode *ip, int whichfork,
+               struct xfs_bmbt_irec *imap);
+int xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+               struct xfs_inode *ip, int whichfork,
+               struct xfs_bmbt_irec *imap);
+int xfs_rmap_alloc_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+               xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+               __uint64_t owner);
+int xfs_rmap_free_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
+               xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+               __uint64_t owner);
+
+void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp,
+               struct xfs_btree_cur *rcur, int error);
+int xfs_rmap_finish_one(struct xfs_trans *tp, enum xfs_rmap_intent_type type,
+               __uint64_t owner, int whichfork, xfs_fileoff_t startoff,
+               xfs_fsblock_t startblock, xfs_filblks_t blockcount,
+               xfs_exntst_t state, struct xfs_btree_cur **pcur);
+
+#endif /* __XFS_RMAP_H__ */
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
new file mode 100644 (file)
index 0000000..bc1faeb
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ * 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.
+ *
+ * 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.  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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
+#include "xfs_error.h"
+#include "xfs_extent_busy.h"
+
+/*
+ * Reverse map btree.
+ *
+ * This is a per-ag tree used to track the owner(s) of a given extent. With
+ * reflink it is possible for there to be multiple owners, which is a departure
+ * from classic XFS. Owner records for data extents are inserted when the
+ * extent is mapped and removed when an extent is unmapped.  Owner records for
+ * all other block types (i.e. metadata) are inserted when an extent is
+ * allocated and removed when an extent is freed. There can only be one owner
+ * of a metadata extent, usually an inode or some other metadata structure like
+ * an AG btree.
+ *
+ * The rmap btree is part of the free space management, so blocks for the tree
+ * are sourced from the agfl. Hence we need transaction reservation support for
+ * this tree so that the freelist is always large enough. This also impacts on
+ * the minimum space we need to leave free in the AG.
+ *
+ * The tree is ordered by [ag block, owner, offset]. This is a large key size,
+ * but it is the only way to enforce unique keys when a block can be owned by
+ * multiple files at any offset. There's no need to order/search by extent
+ * size for online updating/management of the tree. It is intended that most
+ * reverse lookups will be to find the owner(s) of a particular block, or to
+ * try to recover tree and file data from corrupt primary metadata.
+ */
+
+static struct xfs_btree_cur *
+xfs_rmapbt_dup_cursor(
+       struct xfs_btree_cur    *cur)
+{
+       return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
+                       cur->bc_private.a.agbp, cur->bc_private.a.agno);
+}
+
+STATIC void
+xfs_rmapbt_set_root(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr,
+       int                     inc)
+{
+       struct xfs_buf          *agbp = cur->bc_private.a.agbp;
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(agbp);
+       xfs_agnumber_t          seqno = be32_to_cpu(agf->agf_seqno);
+       int                     btnum = cur->bc_btnum;
+       struct xfs_perag        *pag = xfs_perag_get(cur->bc_mp, seqno);
+
+       ASSERT(ptr->s != 0);
+
+       agf->agf_roots[btnum] = ptr->s;
+       be32_add_cpu(&agf->agf_levels[btnum], inc);
+       pag->pagf_levels[btnum] += inc;
+       xfs_perag_put(pag);
+
+       xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
+}
+
+STATIC int
+xfs_rmapbt_alloc_block(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *start,
+       union xfs_btree_ptr     *new,
+       int                     *stat)
+{
+       int                     error;
+       xfs_agblock_t           bno;
+
+       XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
+
+       /* Allocate the new block from the freelist. If we can't, give up.  */
+       error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
+                                      &bno, 1);
+       if (error) {
+               XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
+               return error;
+       }
+
+       trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno,
+                       bno, 1);
+       if (bno == NULLAGBLOCK) {
+               XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+               *stat = 0;
+               return 0;
+       }
+
+       xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1,
+                       false);
+
+       xfs_trans_agbtree_delta(cur->bc_tp, 1);
+       new->s = cpu_to_be32(bno);
+
+       XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
+       *stat = 1;
+       return 0;
+}
+
+STATIC int
+xfs_rmapbt_free_block(
+       struct xfs_btree_cur    *cur,
+       struct xfs_buf          *bp)
+{
+       struct xfs_buf          *agbp = cur->bc_private.a.agbp;
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(agbp);
+       xfs_agblock_t           bno;
+       int                     error;
+
+       bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
+       trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_private.a.agno,
+                       bno, 1);
+       error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1);
+       if (error)
+               return error;
+
+       xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
+                             XFS_EXTENT_BUSY_SKIP_DISCARD);
+       xfs_trans_agbtree_delta(cur->bc_tp, -1);
+
+       return 0;
+}
+
+STATIC int
+xfs_rmapbt_get_minrecs(
+       struct xfs_btree_cur    *cur,
+       int                     level)
+{
+       return cur->bc_mp->m_rmap_mnr[level != 0];
+}
+
+STATIC int
+xfs_rmapbt_get_maxrecs(
+       struct xfs_btree_cur    *cur,
+       int                     level)
+{
+       return cur->bc_mp->m_rmap_mxr[level != 0];
+}
+
+STATIC void
+xfs_rmapbt_init_key_from_rec(
+       union xfs_btree_key     *key,
+       union xfs_btree_rec     *rec)
+{
+       key->rmap.rm_startblock = rec->rmap.rm_startblock;
+       key->rmap.rm_owner = rec->rmap.rm_owner;
+       key->rmap.rm_offset = rec->rmap.rm_offset;
+}
+
+/*
+ * The high key for a reverse mapping record can be computed by shifting
+ * the startblock and offset to the highest value that would still map
+ * to that record.  In practice this means that we add blockcount-1 to
+ * the startblock for all records, and if the record is for a data/attr
+ * fork mapping, we add blockcount-1 to the offset too.
+ */
+STATIC void
+xfs_rmapbt_init_high_key_from_rec(
+       union xfs_btree_key     *key,
+       union xfs_btree_rec     *rec)
+{
+       __uint64_t              off;
+       int                     adj;
+
+       adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
+
+       key->rmap.rm_startblock = rec->rmap.rm_startblock;
+       be32_add_cpu(&key->rmap.rm_startblock, adj);
+       key->rmap.rm_owner = rec->rmap.rm_owner;
+       key->rmap.rm_offset = rec->rmap.rm_offset;
+       if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
+           XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
+               return;
+       off = be64_to_cpu(key->rmap.rm_offset);
+       off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
+       key->rmap.rm_offset = cpu_to_be64(off);
+}
+
+STATIC void
+xfs_rmapbt_init_rec_from_cur(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_rec     *rec)
+{
+       rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
+       rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
+       rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
+       rec->rmap.rm_offset = cpu_to_be64(
+                       xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
+}
+
+STATIC void
+xfs_rmapbt_init_ptr_from_cur(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr)
+{
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
+
+       ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno));
+       ASSERT(agf->agf_roots[cur->bc_btnum] != 0);
+
+       ptr->s = agf->agf_roots[cur->bc_btnum];
+}
+
+STATIC __int64_t
+xfs_rmapbt_key_diff(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *key)
+{
+       struct xfs_rmap_irec    *rec = &cur->bc_rec.r;
+       struct xfs_rmap_key     *kp = &key->rmap;
+       __u64                   x, y;
+       __int64_t               d;
+
+       d = (__int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock;
+       if (d)
+               return d;
+
+       x = be64_to_cpu(kp->rm_owner);
+       y = rec->rm_owner;
+       if (x > y)
+               return 1;
+       else if (y > x)
+               return -1;
+
+       x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset));
+       y = rec->rm_offset;
+       if (x > y)
+               return 1;
+       else if (y > x)
+               return -1;
+       return 0;
+}
+
+STATIC __int64_t
+xfs_rmapbt_diff_two_keys(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *k1,
+       union xfs_btree_key     *k2)
+{
+       struct xfs_rmap_key     *kp1 = &k1->rmap;
+       struct xfs_rmap_key     *kp2 = &k2->rmap;
+       __int64_t               d;
+       __u64                   x, y;
+
+       d = (__int64_t)be32_to_cpu(kp1->rm_startblock) -
+                      be32_to_cpu(kp2->rm_startblock);
+       if (d)
+               return d;
+
+       x = be64_to_cpu(kp1->rm_owner);
+       y = be64_to_cpu(kp2->rm_owner);
+       if (x > y)
+               return 1;
+       else if (y > x)
+               return -1;
+
+       x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset));
+       y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset));
+       if (x > y)
+               return 1;
+       else if (y > x)
+               return -1;
+       return 0;
+}
+
+static bool
+xfs_rmapbt_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       struct xfs_perag        *pag = bp->b_pag;
+       unsigned int            level;
+
+       /*
+        * magic number and level verification
+        *
+        * During growfs operations, we can't verify the exact level or owner as
+        * the perag is not fully initialised and hence not attached to the
+        * buffer.  In this case, check against the maximum tree depth.
+        *
+        * Similarly, during log recovery we will have a perag structure
+        * attached, but the agf information will not yet have been initialised
+        * from the on disk AGF. Again, we can only check against maximum limits
+        * in this case.
+        */
+       if (block->bb_magic != cpu_to_be32(XFS_RMAP_CRC_MAGIC))
+               return false;
+
+       if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return false;
+       if (!xfs_btree_sblock_v5hdr_verify(bp))
+               return false;
+
+       level = be16_to_cpu(block->bb_level);
+       if (pag && pag->pagf_init) {
+               if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi])
+                       return false;
+       } else if (level >= mp->m_rmap_maxlevels)
+               return false;
+
+       return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]);
+}
+
+static void
+xfs_rmapbt_read_verify(
+       struct xfs_buf  *bp)
+{
+       if (!xfs_btree_sblock_verify_crc(bp))
+               xfs_buf_ioerror(bp, -EFSBADCRC);
+       else if (!xfs_rmapbt_verify(bp))
+               xfs_buf_ioerror(bp, -EFSCORRUPTED);
+
+       if (bp->b_error) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               xfs_verifier_error(bp);
+       }
+}
+
+static void
+xfs_rmapbt_write_verify(
+       struct xfs_buf  *bp)
+{
+       if (!xfs_rmapbt_verify(bp)) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               xfs_buf_ioerror(bp, -EFSCORRUPTED);
+               xfs_verifier_error(bp);
+               return;
+       }
+       xfs_btree_sblock_calc_crc(bp);
+
+}
+
+const struct xfs_buf_ops xfs_rmapbt_buf_ops = {
+       .name                   = "xfs_rmapbt",
+       .verify_read            = xfs_rmapbt_read_verify,
+       .verify_write           = xfs_rmapbt_write_verify,
+};
+
+#if defined(DEBUG) || defined(XFS_WARN)
+STATIC int
+xfs_rmapbt_keys_inorder(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *k1,
+       union xfs_btree_key     *k2)
+{
+       __uint32_t              x;
+       __uint32_t              y;
+       __uint64_t              a;
+       __uint64_t              b;
+
+       x = be32_to_cpu(k1->rmap.rm_startblock);
+       y = be32_to_cpu(k2->rmap.rm_startblock);
+       if (x < y)
+               return 1;
+       else if (x > y)
+               return 0;
+       a = be64_to_cpu(k1->rmap.rm_owner);
+       b = be64_to_cpu(k2->rmap.rm_owner);
+       if (a < b)
+               return 1;
+       else if (a > b)
+               return 0;
+       a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset));
+       b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset));
+       if (a <= b)
+               return 1;
+       return 0;
+}
+
+STATIC int
+xfs_rmapbt_recs_inorder(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_rec     *r1,
+       union xfs_btree_rec     *r2)
+{
+       __uint32_t              x;
+       __uint32_t              y;
+       __uint64_t              a;
+       __uint64_t              b;
+
+       x = be32_to_cpu(r1->rmap.rm_startblock);
+       y = be32_to_cpu(r2->rmap.rm_startblock);
+       if (x < y)
+               return 1;
+       else if (x > y)
+               return 0;
+       a = be64_to_cpu(r1->rmap.rm_owner);
+       b = be64_to_cpu(r2->rmap.rm_owner);
+       if (a < b)
+               return 1;
+       else if (a > b)
+               return 0;
+       a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset));
+       b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset));
+       if (a <= b)
+               return 1;
+       return 0;
+}
+#endif /* DEBUG */
+
+static const struct xfs_btree_ops xfs_rmapbt_ops = {
+       .rec_len                = sizeof(struct xfs_rmap_rec),
+       .key_len                = 2 * sizeof(struct xfs_rmap_key),
+
+       .dup_cursor             = xfs_rmapbt_dup_cursor,
+       .set_root               = xfs_rmapbt_set_root,
+       .alloc_block            = xfs_rmapbt_alloc_block,
+       .free_block             = xfs_rmapbt_free_block,
+       .get_minrecs            = xfs_rmapbt_get_minrecs,
+       .get_maxrecs            = xfs_rmapbt_get_maxrecs,
+       .init_key_from_rec      = xfs_rmapbt_init_key_from_rec,
+       .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec,
+       .init_rec_from_cur      = xfs_rmapbt_init_rec_from_cur,
+       .init_ptr_from_cur      = xfs_rmapbt_init_ptr_from_cur,
+       .key_diff               = xfs_rmapbt_key_diff,
+       .buf_ops                = &xfs_rmapbt_buf_ops,
+       .diff_two_keys          = xfs_rmapbt_diff_two_keys,
+#if defined(DEBUG) || defined(XFS_WARN)
+       .keys_inorder           = xfs_rmapbt_keys_inorder,
+       .recs_inorder           = xfs_rmapbt_recs_inorder,
+#endif
+};
+
+/*
+ * Allocate a new allocation btree cursor.
+ */
+struct xfs_btree_cur *
+xfs_rmapbt_init_cursor(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_buf          *agbp,
+       xfs_agnumber_t          agno)
+{
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(agbp);
+       struct xfs_btree_cur    *cur;
+
+       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
+       cur->bc_tp = tp;
+       cur->bc_mp = mp;
+       /* Overlapping btree; 2 keys per pointer. */
+       cur->bc_btnum = XFS_BTNUM_RMAP;
+       cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
+       cur->bc_blocklog = mp->m_sb.sb_blocklog;
+       cur->bc_ops = &xfs_rmapbt_ops;
+       cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
+
+       cur->bc_private.a.agbp = agbp;
+       cur->bc_private.a.agno = agno;
+
+       return cur;
+}
+
+/*
+ * Calculate number of records in an rmap btree block.
+ */
+int
+xfs_rmapbt_maxrecs(
+       struct xfs_mount        *mp,
+       int                     blocklen,
+       int                     leaf)
+{
+       blocklen -= XFS_RMAP_BLOCK_LEN;
+
+       if (leaf)
+               return blocklen / sizeof(struct xfs_rmap_rec);
+       return blocklen /
+               (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t));
+}
+
+/* Compute the maximum height of an rmap btree. */
+void
+xfs_rmapbt_compute_maxlevels(
+       struct xfs_mount                *mp)
+{
+       mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(mp,
+                       mp->m_rmap_mnr, mp->m_sb.sb_agblocks);
+}
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
new file mode 100644 (file)
index 0000000..e73a553
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ * 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.
+ *
+ * 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.  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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef __XFS_RMAP_BTREE_H__
+#define __XFS_RMAP_BTREE_H__
+
+struct xfs_buf;
+struct xfs_btree_cur;
+struct xfs_mount;
+
+/* rmaps only exist on crc enabled filesystems */
+#define XFS_RMAP_BLOCK_LEN     XFS_BTREE_SBLOCK_CRC_LEN
+
+/*
+ * Record, key, and pointer address macros for btree blocks.
+ *
+ * (note that some of these may appear unused, but they are used in userspace)
+ */
+#define XFS_RMAP_REC_ADDR(block, index) \
+       ((struct xfs_rmap_rec *) \
+               ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
+                (((index) - 1) * sizeof(struct xfs_rmap_rec))))
+
+#define XFS_RMAP_KEY_ADDR(block, index) \
+       ((struct xfs_rmap_key *) \
+               ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
+                ((index) - 1) * 2 * sizeof(struct xfs_rmap_key)))
+
+#define XFS_RMAP_HIGH_KEY_ADDR(block, index) \
+       ((struct xfs_rmap_key *) \
+               ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
+                sizeof(struct xfs_rmap_key) + \
+                ((index) - 1) * 2 * sizeof(struct xfs_rmap_key)))
+
+#define XFS_RMAP_PTR_ADDR(block, index, maxrecs) \
+       ((xfs_rmap_ptr_t *) \
+               ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
+                (maxrecs) * 2 * sizeof(struct xfs_rmap_key) + \
+                ((index) - 1) * sizeof(xfs_rmap_ptr_t)))
+
+struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
+                               struct xfs_trans *tp, struct xfs_buf *bp,
+                               xfs_agnumber_t agno);
+int xfs_rmapbt_maxrecs(struct xfs_mount *mp, int blocklen, int leaf);
+extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp);
+
+#endif /* __XFS_RMAP_BTREE_H__ */
index 12ca867..0e3d4f5 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
@@ -36,6 +37,7 @@
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_log.h"
+#include "xfs_rmap_btree.h"
 
 /*
  * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -729,6 +731,11 @@ xfs_sb_mount_common(
        mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
        mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
 
+       mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 1);
+       mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 0);
+       mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
+       mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
+
        mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
        mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
                                        sbp->sb_inopblock);
@@ -738,6 +745,8 @@ xfs_sb_mount_common(
                mp->m_ialloc_min_blks = sbp->sb_spino_align;
        else
                mp->m_ialloc_min_blks = mp->m_ialloc_blks;
+       mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
+       mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
 }
 
 /*
index 16002b5..0c5b30b 100644 (file)
@@ -38,6 +38,7 @@ extern const struct xfs_buf_ops xfs_agi_buf_ops;
 extern const struct xfs_buf_ops xfs_agf_buf_ops;
 extern const struct xfs_buf_ops xfs_agfl_buf_ops;
 extern const struct xfs_buf_ops xfs_allocbt_buf_ops;
+extern const struct xfs_buf_ops xfs_rmapbt_buf_ops;
 extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops;
 extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops;
 extern const struct xfs_buf_ops xfs_bmbt_buf_ops;
@@ -116,6 +117,7 @@ int xfs_log_calc_minimum_size(struct xfs_mount *);
 #define        XFS_INO_BTREE_REF       3
 #define        XFS_ALLOC_BTREE_REF     2
 #define        XFS_BMAP_BTREE_REF      2
+#define        XFS_RMAP_BTREE_REF      2
 #define        XFS_DIR_BTREE_REF       2
 #define        XFS_INO_REF             2
 #define        XFS_ATTR_BTREE_REF      1
index 68cb1e7..301ef2f 100644 (file)
@@ -63,6 +63,30 @@ xfs_calc_buf_res(
        return nbufs * (size + xfs_buf_log_overhead());
 }
 
+/*
+ * Per-extent log reservation for the btree changes involved in freeing or
+ * allocating an extent.  In classic XFS there were two trees that will be
+ * modified (bnobt + cntbt).  With rmap enabled, there are three trees
+ * (rmapbt).  The number of blocks reserved is based on the formula:
+ *
+ * num trees * ((2 blocks/level * max depth) - 1)
+ *
+ * Keep in mind that max depth is calculated separately for each type of tree.
+ */
+static uint
+xfs_allocfree_log_count(
+       struct xfs_mount *mp,
+       uint            num_ops)
+{
+       uint            blocks;
+
+       blocks = num_ops * 2 * (2 * mp->m_ag_maxlevels - 1);
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               blocks += num_ops * (2 * mp->m_rmap_maxlevels - 1);
+
+       return blocks;
+}
+
 /*
  * Logging inodes is really tricksy. They are logged in memory format,
  * which means that what we write into the log doesn't directly translate into
@@ -126,7 +150,7 @@ xfs_calc_inode_res(
  */
 STATIC uint
 xfs_calc_finobt_res(
-       struct xfs_mount        *mp,
+       struct xfs_mount        *mp,
        int                     alloc,
        int                     modify)
 {
@@ -137,7 +161,7 @@ xfs_calc_finobt_res(
 
        res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
        if (alloc)
-               res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), 
+               res += xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                        XFS_FSB_TO_B(mp, 1));
        if (modify)
                res += (uint)XFS_FSB_TO_B(mp, 1);
@@ -153,9 +177,9 @@ xfs_calc_finobt_res(
  * item logged to try to account for the overhead of the transaction mechanism.
  *
  * Note:  Most of the reservations underestimate the number of allocation
- * groups into which they could free extents in the xfs_bmap_finish() call.
+ * groups into which they could free extents in the xfs_defer_finish() call.
  * This is because the number in the worst case is quite high and quite
- * unusual.  In order to fix this we need to change xfs_bmap_finish() to free
+ * unusual.  In order to fix this we need to change xfs_defer_finish() to free
  * extents in only a single AG at a time.  This will require changes to the
  * EFI code as well, however, so that the EFI for the extents not freed is
  * logged again in each transaction.  See SGI PV #261917.
@@ -188,10 +212,10 @@ xfs_calc_write_reservation(
                     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
                                      XFS_FSB_TO_B(mp, 1)) +
                     xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2),
                                      XFS_FSB_TO_B(mp, 1))),
                    (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2),
                                      XFS_FSB_TO_B(mp, 1))));
 }
 
@@ -217,10 +241,10 @@ xfs_calc_itruncate_reservation(
                     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1,
                                      XFS_FSB_TO_B(mp, 1))),
                    (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4),
                                      XFS_FSB_TO_B(mp, 1)) +
                    xfs_calc_buf_res(5, 0) +
-                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                   xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                     XFS_FSB_TO_B(mp, 1)) +
                    xfs_calc_buf_res(2 + mp->m_ialloc_blks +
                                     mp->m_in_maxlevels, 0)));
@@ -247,7 +271,7 @@ xfs_calc_rename_reservation(
                     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
                                      XFS_FSB_TO_B(mp, 1))),
                    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 3),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 3),
                                      XFS_FSB_TO_B(mp, 1))));
 }
 
@@ -286,7 +310,7 @@ xfs_calc_link_reservation(
                     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
                                      XFS_FSB_TO_B(mp, 1))),
                    (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                      XFS_FSB_TO_B(mp, 1))));
 }
 
@@ -324,7 +348,7 @@ xfs_calc_remove_reservation(
                     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
                                      XFS_FSB_TO_B(mp, 1))),
                    (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2),
                                      XFS_FSB_TO_B(mp, 1))));
 }
 
@@ -371,7 +395,7 @@ xfs_calc_create_resv_alloc(
                mp->m_sb.sb_sectsize +
                xfs_calc_buf_res(mp->m_ialloc_blks, XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
 }
 
@@ -399,7 +423,7 @@ xfs_calc_icreate_resv_alloc(
        return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
                mp->m_sb.sb_sectsize +
                xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_finobt_res(mp, 0, 0);
 }
@@ -483,7 +507,7 @@ xfs_calc_ifree_reservation(
                xfs_calc_buf_res(1, 0) +
                xfs_calc_buf_res(2 + mp->m_ialloc_blks +
                                 mp->m_in_maxlevels, 0) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_finobt_res(mp, 0, 1);
 }
@@ -513,7 +537,7 @@ xfs_calc_growdata_reservation(
        struct xfs_mount        *mp)
 {
        return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
 }
 
@@ -535,7 +559,7 @@ xfs_calc_growrtalloc_reservation(
                xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
                                 XFS_FSB_TO_B(mp, 1)) +
                xfs_calc_inode_res(mp, 1) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
 }
 
@@ -611,7 +635,7 @@ xfs_calc_addafork_reservation(
                xfs_calc_buf_res(1, mp->m_dir_geo->blksize) +
                xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1,
                                 XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+               xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
                                 XFS_FSB_TO_B(mp, 1));
 }
 
@@ -634,7 +658,7 @@ xfs_calc_attrinval_reservation(
                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
                                     XFS_FSB_TO_B(mp, 1))),
                   (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
-                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
+                   xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4),
                                     XFS_FSB_TO_B(mp, 1))));
 }
 
@@ -701,7 +725,7 @@ xfs_calc_attrrm_reservation(
                                        XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
                     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)),
                    (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2),
                                      XFS_FSB_TO_B(mp, 1))));
 }
 
index 7978150..0eb46ed 100644 (file)
@@ -67,16 +67,6 @@ struct xfs_trans_resv {
 /* shorthand way of accessing reservation structure */
 #define M_RES(mp)      (&(mp)->m_resv)
 
-/*
- * Per-extent log reservation for the allocation btree changes
- * involved in freeing or allocating an extent.
- * 2 trees * (2 blocks/level * max depth - 1) * block size
- */
-#define        XFS_ALLOCFREE_LOG_RES(mp,nx) \
-       ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * (mp)->m_ag_maxlevels - 1)))
-#define        XFS_ALLOCFREE_LOG_COUNT(mp,nx) \
-       ((nx) * (2 * (2 * (mp)->m_ag_maxlevels - 1)))
-
 /*
  * Per-directory log reservation for any directory change.
  * dir blocks: (1 btree block per level + data block + free block) * dblock size
index b79dc66..3d50364 100644 (file)
@@ -108,8 +108,8 @@ typedef enum {
 } xfs_lookup_t;
 
 typedef enum {
-       XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
-       XFS_BTNUM_FINOi, XFS_BTNUM_MAX
+       XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_RMAPi, XFS_BTNUM_BMAPi,
+       XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_MAX
 } xfs_btnum_t;
 
 struct xfs_name {
index cd4a850..4ece4f2 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_bit.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
@@ -40,6 +41,7 @@
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_log.h"
+#include "xfs_rmap_btree.h"
 
 /* Kernel only BMAP related definitions and functions */
 
@@ -79,95 +81,6 @@ xfs_zero_extent(
                GFP_NOFS, true);
 }
 
-/* Sort bmap items by AG. */
-static int
-xfs_bmap_free_list_cmp(
-       void                    *priv,
-       struct list_head        *a,
-       struct list_head        *b)
-{
-       struct xfs_mount        *mp = priv;
-       struct xfs_bmap_free_item       *ra;
-       struct xfs_bmap_free_item       *rb;
-
-       ra = container_of(a, struct xfs_bmap_free_item, xbfi_list);
-       rb = container_of(b, struct xfs_bmap_free_item, xbfi_list);
-       return  XFS_FSB_TO_AGNO(mp, ra->xbfi_startblock) -
-               XFS_FSB_TO_AGNO(mp, rb->xbfi_startblock);
-}
-
-/*
- * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
- * caller.  Frees all the extents that need freeing, which must be done
- * last due to locking considerations.  We never free any extents in
- * the first transaction.
- *
- * If an inode *ip is provided, rejoin it to the transaction if
- * the transaction was committed.
- */
-int                                            /* error */
-xfs_bmap_finish(
-       struct xfs_trans                **tp,   /* transaction pointer addr */
-       struct xfs_bmap_free            *flist, /* i/o: list extents to free */
-       struct xfs_inode                *ip)
-{
-       struct xfs_efd_log_item         *efd;   /* extent free data */
-       struct xfs_efi_log_item         *efi;   /* extent free intention */
-       int                             error;  /* error return value */
-       int                             committed;/* xact committed or not */
-       struct xfs_bmap_free_item       *free;  /* free extent item */
-
-       ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
-       if (flist->xbf_count == 0)
-               return 0;
-
-       list_sort((*tp)->t_mountp, &flist->xbf_flist, xfs_bmap_free_list_cmp);
-
-       efi = xfs_trans_get_efi(*tp, flist->xbf_count);
-       list_for_each_entry(free, &flist->xbf_flist, xbfi_list)
-               xfs_trans_log_efi_extent(*tp, efi, free->xbfi_startblock,
-                       free->xbfi_blockcount);
-
-       error = __xfs_trans_roll(tp, ip, &committed);
-       if (error) {
-               /*
-                * If the transaction was committed, drop the EFD reference
-                * since we're bailing out of here. The other reference is
-                * dropped when the EFI hits the AIL.
-                *
-                * If the transaction was not committed, the EFI is freed by the
-                * EFI item unlock handler on abort. Also, we have a new
-                * transaction so we should return committed=1 even though we're
-                * returning an error.
-                */
-               if (committed) {
-                       xfs_efi_release(efi);
-                       xfs_force_shutdown((*tp)->t_mountp,
-                                          SHUTDOWN_META_IO_ERROR);
-               }
-               return error;
-       }
-
-       /*
-        * Get an EFD and free each extent in the list, logging to the EFD in
-        * the process. The remaining bmap free list is cleaned up by the caller
-        * on error.
-        */
-       efd = xfs_trans_get_efd(*tp, efi, flist->xbf_count);
-       while (!list_empty(&flist->xbf_flist)) {
-               free = list_first_entry(&flist->xbf_flist,
-                               struct xfs_bmap_free_item, xbfi_list);
-               error = xfs_trans_free_extent(*tp, efd, free->xbfi_startblock,
-                                             free->xbfi_blockcount);
-               if (error)
-                       return error;
-
-               xfs_bmap_del_free(flist, free);
-       }
-
-       return 0;
-}
-
 int
 xfs_bmap_rtalloc(
        struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
@@ -214,9 +127,9 @@ xfs_bmap_rtalloc(
        /*
         * Lock out modifications to both the RT bitmap and summary inodes
         */
-       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP);
        xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
+       xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM);
        xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL);
 
        /*
@@ -773,7 +686,7 @@ xfs_bmap_punch_delalloc_range(
                xfs_bmbt_irec_t imap;
                int             nimaps = 1;
                xfs_fsblock_t   firstblock;
-               xfs_bmap_free_t flist;
+               struct xfs_defer_ops dfops;
 
                /*
                 * Map the range first and check that it is a delalloc extent
@@ -804,18 +717,18 @@ xfs_bmap_punch_delalloc_range(
                WARN_ON(imap.br_blockcount == 0);
 
                /*
-                * Note: while we initialise the firstblock/flist pair, they
+                * Note: while we initialise the firstblock/dfops pair, they
                 * should never be used because blocks should never be
                 * allocated or freed for a delalloc extent and hence we need
                 * don't cancel or finish them after the xfs_bunmapi() call.
                 */
-               xfs_bmap_init(&flist, &firstblock);
+               xfs_defer_init(&dfops, &firstblock);
                error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
-                                       &flist, &done);
+                                       &dfops, &done);
                if (error)
                        break;
 
-               ASSERT(!flist.xbf_count && list_empty(&flist.xbf_flist));
+               ASSERT(!xfs_defer_has_unfinished_work(&dfops));
 next_block:
                start_fsb++;
                remaining--;
@@ -972,7 +885,7 @@ xfs_alloc_file_space(
        int                     rt;
        xfs_trans_t             *tp;
        xfs_bmbt_irec_t         imaps[1], *imapp;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        uint                    qblocks, resblks, resrtextents;
        int                     error;
 
@@ -1063,17 +976,17 @@ xfs_alloc_file_space(
 
                xfs_trans_ijoin(tp, ip, 0);
 
-               xfs_bmap_init(&free_list, &firstfsb);
+               xfs_defer_init(&dfops, &firstfsb);
                error = xfs_bmapi_write(tp, ip, startoffset_fsb,
                                        allocatesize_fsb, alloc_type, &firstfsb,
-                                       resblks, imapp, &nimaps, &free_list);
+                                       resblks, imapp, &nimaps, &dfops);
                if (error)
                        goto error0;
 
                /*
                 * Complete the transaction
                 */
-               error = xfs_bmap_finish(&tp, &free_list, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto error0;
 
@@ -1096,7 +1009,7 @@ xfs_alloc_file_space(
        return error;
 
 error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
 
 error1:        /* Just cancel transaction */
@@ -1114,7 +1027,7 @@ xfs_unmap_extent(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           firstfsb;
        uint                    resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
        int                     error;
@@ -1133,13 +1046,13 @@ xfs_unmap_extent(
 
        xfs_trans_ijoin(tp, ip, 0);
 
-       xfs_bmap_init(&free_list, &firstfsb);
+       xfs_defer_init(&dfops, &firstfsb);
        error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb,
-                       &free_list, done);
+                       &dfops, done);
        if (error)
                goto out_bmap_cancel;
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, ip);
        if (error)
                goto out_bmap_cancel;
 
@@ -1149,7 +1062,7 @@ out_unlock:
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
        goto out_unlock;
@@ -1338,7 +1251,7 @@ xfs_shift_file_space(
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
        int                     error;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        xfs_fileoff_t           stop_fsb;
        xfs_fileoff_t           next_fsb;
@@ -1416,19 +1329,19 @@ xfs_shift_file_space(
 
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
-               xfs_bmap_init(&free_list, &first_block);
+               xfs_defer_init(&dfops, &first_block);
 
                /*
                 * We are using the write transaction in which max 2 bmbt
                 * updates are allowed
                 */
                error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
-                               &done, stop_fsb, &first_block, &free_list,
+                               &done, stop_fsb, &first_block, &dfops,
                                direction, XFS_BMAP_MAX_SHIFT_EXTENTS);
                if (error)
                        goto out_bmap_cancel;
 
-               error = xfs_bmap_finish(&tp, &free_list, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto out_bmap_cancel;
 
@@ -1438,7 +1351,7 @@ xfs_shift_file_space(
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
        return error;
@@ -1622,6 +1535,10 @@ xfs_swap_extents(
        __uint64_t      tmp;
        int             lock_flags;
 
+       /* XXX: we can't do this with rmap, will fix later */
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return -EOPNOTSUPP;
+
        tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
        if (!tempifp) {
                error = -ENOMEM;
index f200714..68a621a 100644 (file)
@@ -21,7 +21,7 @@
 /* Kernel only BMAP related definitions and functions */
 
 struct xfs_bmbt_irec;
-struct xfs_bmap_free_item;
+struct xfs_extent_free_item;
 struct xfs_ifork;
 struct xfs_inode;
 struct xfs_mount;
@@ -40,8 +40,6 @@ int   xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
                xfs_bmap_format_t formatter, void *arg);
 
 /* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */
-void   xfs_bmap_del_free(struct xfs_bmap_free *flist,
-                         struct xfs_bmap_free_item *free);
 int    xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp,
                               struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz,
                               int rt, int eof, int delay, int convert,
index 272c3f8..4ff499a 100644 (file)
@@ -179,7 +179,7 @@ xfs_ioc_trim(
         * matter as trimming blocks is an advisory interface.
         */
        if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) ||
-           range.minlen > XFS_FSB_TO_B(mp, XFS_ALLOC_AG_MAX_USABLE(mp)) ||
+           range.minlen > XFS_FSB_TO_B(mp, mp->m_ag_max_usable) ||
            range.len < mp->m_sb.sb_blocksize)
                return -EINVAL;
 
index ccb0811..7a30b8f 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
@@ -307,7 +308,7 @@ xfs_qm_dqalloc(
        xfs_buf_t       **O_bpp)
 {
        xfs_fsblock_t   firstblock;
-       xfs_bmap_free_t flist;
+       struct xfs_defer_ops dfops;
        xfs_bmbt_irec_t map;
        int             nmaps, error;
        xfs_buf_t       *bp;
@@ -320,7 +321,7 @@ xfs_qm_dqalloc(
        /*
         * Initialize the bmap freelist prior to calling bmapi code.
         */
-       xfs_bmap_init(&flist, &firstblock);
+       xfs_defer_init(&dfops, &firstblock);
        xfs_ilock(quotip, XFS_ILOCK_EXCL);
        /*
         * Return if this type of quotas is turned off while we didn't
@@ -336,7 +337,7 @@ xfs_qm_dqalloc(
        error = xfs_bmapi_write(tp, quotip, offset_fsb,
                                XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA,
                                &firstblock, XFS_QM_DQALLOC_SPACE_RES(mp),
-                               &map, &nmaps, &flist);
+                               &map, &nmaps, &dfops);
        if (error)
                goto error0;
        ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB);
@@ -368,7 +369,7 @@ xfs_qm_dqalloc(
                              dqp->dq_flags & XFS_DQ_ALLTYPES, bp);
 
        /*
-        * xfs_bmap_finish() may commit the current transaction and
+        * xfs_defer_finish() may commit the current transaction and
         * start a second transaction if the freelist is not empty.
         *
         * Since we still want to modify this buffer, we need to
@@ -382,7 +383,7 @@ xfs_qm_dqalloc(
 
        xfs_trans_bhold(tp, bp);
 
-       error = xfs_bmap_finish(tpp, &flist, NULL);
+       error = xfs_defer_finish(tpp, &dfops, NULL);
        if (error)
                goto error1;
 
@@ -398,7 +399,7 @@ xfs_qm_dqalloc(
        return 0;
 
 error1:
-       xfs_bmap_cancel(&flist);
+       xfs_defer_cancel(&dfops);
 error0:
        xfs_iunlock(quotip, XFS_ILOCK_EXCL);
 
index 2e4f67f..3d22470 100644 (file)
@@ -90,7 +90,9 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
 #define XFS_ERRTAG_STRATCMPL_IOERR                     19
 #define XFS_ERRTAG_DIOWRITE_IOERR                      20
 #define XFS_ERRTAG_BMAPIFORMAT                         21
-#define XFS_ERRTAG_MAX                                 22
+#define XFS_ERRTAG_FREE_EXTENT                         22
+#define XFS_ERRTAG_RMAP_FINISH_ONE                     23
+#define XFS_ERRTAG_MAX                                 24
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -117,6 +119,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
 #define XFS_RANDOM_STRATCMPL_IOERR                     (XFS_RANDOM_DEFAULT/10)
 #define XFS_RANDOM_DIOWRITE_IOERR                      (XFS_RANDOM_DEFAULT/10)
 #define        XFS_RANDOM_BMAPIFORMAT                          XFS_RANDOM_DEFAULT
+#define XFS_RANDOM_FREE_EXTENT                         1
+#define XFS_RANDOM_RMAP_FINISH_ONE                     1
 
 #ifdef DEBUG
 extern int xfs_error_test_active;
index a1b2dd8..fe1bfee 100644 (file)
@@ -246,7 +246,7 @@ const struct export_operations xfs_export_operations = {
        .fh_to_parent           = xfs_fs_fh_to_parent,
        .get_parent             = xfs_fs_get_parent,
        .commit_metadata        = xfs_fs_nfs_commit_metadata,
-#ifdef CONFIG_NFSD_BLOCKLAYOUT
+#ifdef CONFIG_EXPORTFS_BLOCK_OPS
        .get_uuid               = xfs_fs_get_uuid,
        .map_blocks             = xfs_fs_map_blocks,
        .commit_blocks          = xfs_fs_commit_blocks,
index ab77946..d7bc149 100644 (file)
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
+#include "xfs_bit.h"
 #include "xfs_mount.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_buf_item.h"
 #include "xfs_extfree_item.h"
 #include "xfs_log.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
 
 
 kmem_zone_t    *xfs_efi_zone;
@@ -486,3 +489,69 @@ xfs_efd_init(
 
        return efdp;
 }
+
+/*
+ * Process an extent free intent item that was recovered from
+ * the log.  We need to free the extents that it describes.
+ */
+int
+xfs_efi_recover(
+       struct xfs_mount        *mp,
+       struct xfs_efi_log_item *efip)
+{
+       struct xfs_efd_log_item *efdp;
+       struct xfs_trans        *tp;
+       int                     i;
+       int                     error = 0;
+       xfs_extent_t            *extp;
+       xfs_fsblock_t           startblock_fsb;
+       struct xfs_owner_info   oinfo;
+
+       ASSERT(!test_bit(XFS_EFI_RECOVERED, &efip->efi_flags));
+
+       /*
+        * First check the validity of the extents described by the
+        * EFI.  If any are bad, then assume that all are bad and
+        * just toss the EFI.
+        */
+       for (i = 0; i < efip->efi_format.efi_nextents; i++) {
+               extp = &efip->efi_format.efi_extents[i];
+               startblock_fsb = XFS_BB_TO_FSB(mp,
+                                  XFS_FSB_TO_DADDR(mp, extp->ext_start));
+               if (startblock_fsb == 0 ||
+                   extp->ext_len == 0 ||
+                   startblock_fsb >= mp->m_sb.sb_dblocks ||
+                   extp->ext_len >= mp->m_sb.sb_agblocks) {
+                       /*
+                        * This will pull the EFI from the AIL and
+                        * free the memory associated with it.
+                        */
+                       set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
+                       xfs_efi_release(efip);
+                       return -EIO;
+               }
+       }
+
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+       if (error)
+               return error;
+       efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
+
+       xfs_rmap_skip_owner_update(&oinfo);
+       for (i = 0; i < efip->efi_format.efi_nextents; i++) {
+               extp = &efip->efi_format.efi_extents[i];
+               error = xfs_trans_free_extent(tp, efdp, extp->ext_start,
+                                             extp->ext_len, &oinfo);
+               if (error)
+                       goto abort_error;
+
+       }
+
+       set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
+       error = xfs_trans_commit(tp);
+       return error;
+
+abort_error:
+       xfs_trans_cancel(tp);
+       return error;
+}
index 8fa8651..a32c794 100644 (file)
@@ -98,4 +98,7 @@ int                   xfs_efi_copy_format(xfs_log_iovec_t *buf,
 void                   xfs_efi_item_free(xfs_efi_log_item_t *);
 void                   xfs_efi_release(struct xfs_efi_log_item *);
 
+int                    xfs_efi_recover(struct xfs_mount *mp,
+                                       struct xfs_efi_log_item *efip);
+
 #endif /* __XFS_EXTFREE_ITEM_H__ */
index a51353a..4a33a33 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
@@ -385,7 +386,7 @@ xfs_filestream_new_ag(
        }
 
        flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
-               (ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0);
+               (ap->dfops->dop_low ? XFS_PICK_LOWSPACE : 0);
 
        err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
 
index 7191c38..0f96847 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
@@ -32,6 +33,7 @@
 #include "xfs_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_alloc.h"
+#include "xfs_rmap_btree.h"
 #include "xfs_ialloc.h"
 #include "xfs_fsops.h"
 #include "xfs_itable.h"
@@ -40,6 +42,7 @@
 #include "xfs_trace.h"
 #include "xfs_log.h"
 #include "xfs_filestream.h"
+#include "xfs_rmap.h"
 
 /*
  * File system operations
@@ -103,7 +106,9 @@ xfs_fs_geometry(
                        (xfs_sb_version_hasfinobt(&mp->m_sb) ?
                                XFS_FSOP_GEOM_FLAGS_FINOBT : 0) |
                        (xfs_sb_version_hassparseinodes(&mp->m_sb) ?
-                               XFS_FSOP_GEOM_FLAGS_SPINODES : 0);
+                               XFS_FSOP_GEOM_FLAGS_SPINODES : 0) |
+                       (xfs_sb_version_hasrmapbt(&mp->m_sb) ?
+                               XFS_FSOP_GEOM_FLAGS_RMAPBT : 0);
                geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
                                mp->m_sb.sb_logsectsize : BBSIZE;
                geo->rtsectsize = mp->m_sb.sb_blocksize;
@@ -239,10 +244,16 @@ xfs_growfs_data_private(
                agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
                agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
                agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
+               if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+                       agf->agf_roots[XFS_BTNUM_RMAPi] =
+                                               cpu_to_be32(XFS_RMAP_BLOCK(mp));
+                       agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1);
+               }
+
                agf->agf_flfirst = cpu_to_be32(1);
                agf->agf_fllast = 0;
                agf->agf_flcount = 0;
-               tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
+               tmpsize = agsize - mp->m_ag_prealloc_blocks;
                agf->agf_freeblks = cpu_to_be32(tmpsize);
                agf->agf_longest = cpu_to_be32(tmpsize);
                if (xfs_sb_version_hascrc(&mp->m_sb))
@@ -339,7 +350,7 @@ xfs_growfs_data_private(
                                                agno, 0);
 
                arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
-               arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
+               arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
 
@@ -368,7 +379,7 @@ xfs_growfs_data_private(
                                                agno, 0);
 
                arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
-               arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
+               arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
                arec->ar_blockcount = cpu_to_be32(
                        agsize - be32_to_cpu(arec->ar_startblock));
                nfree += be32_to_cpu(arec->ar_blockcount);
@@ -378,6 +389,72 @@ xfs_growfs_data_private(
                if (error)
                        goto error0;
 
+               /* RMAP btree root block */
+               if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+                       struct xfs_rmap_rec     *rrec;
+                       struct xfs_btree_block  *block;
+
+                       bp = xfs_growfs_get_hdr_buf(mp,
+                               XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)),
+                               BTOBB(mp->m_sb.sb_blocksize), 0,
+                               &xfs_rmapbt_buf_ops);
+                       if (!bp) {
+                               error = -ENOMEM;
+                               goto error0;
+                       }
+
+                       xfs_btree_init_block(mp, bp, XFS_RMAP_CRC_MAGIC, 0, 0,
+                                               agno, XFS_BTREE_CRC_BLOCKS);
+                       block = XFS_BUF_TO_BLOCK(bp);
+
+
+                       /*
+                        * mark the AG header regions as static metadata The BNO
+                        * btree block is the first block after the headers, so
+                        * it's location defines the size of region the static
+                        * metadata consumes.
+                        *
+                        * Note: unlike mkfs, we never have to account for log
+                        * space when growing the data regions
+                        */
+                       rrec = XFS_RMAP_REC_ADDR(block, 1);
+                       rrec->rm_startblock = 0;
+                       rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp));
+                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS);
+                       rrec->rm_offset = 0;
+                       be16_add_cpu(&block->bb_numrecs, 1);
+
+                       /* account freespace btree root blocks */
+                       rrec = XFS_RMAP_REC_ADDR(block, 2);
+                       rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp));
+                       rrec->rm_blockcount = cpu_to_be32(2);
+                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
+                       rrec->rm_offset = 0;
+                       be16_add_cpu(&block->bb_numrecs, 1);
+
+                       /* account inode btree root blocks */
+                       rrec = XFS_RMAP_REC_ADDR(block, 3);
+                       rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp));
+                       rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) -
+                                                       XFS_IBT_BLOCK(mp));
+                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT);
+                       rrec->rm_offset = 0;
+                       be16_add_cpu(&block->bb_numrecs, 1);
+
+                       /* account for rmap btree root */
+                       rrec = XFS_RMAP_REC_ADDR(block, 4);
+                       rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp));
+                       rrec->rm_blockcount = cpu_to_be32(1);
+                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
+                       rrec->rm_offset = 0;
+                       be16_add_cpu(&block->bb_numrecs, 1);
+
+                       error = xfs_bwrite(bp);
+                       xfs_buf_relse(bp);
+                       if (error)
+                               goto error0;
+               }
+
                /*
                 * INO btree root block
                 */
@@ -435,6 +512,8 @@ xfs_growfs_data_private(
         * There are new blocks in the old last a.g.
         */
        if (new) {
+               struct xfs_owner_info   oinfo;
+
                /*
                 * Change the agi length.
                 */
@@ -462,14 +541,20 @@ xfs_growfs_data_private(
                       be32_to_cpu(agi->agi_length));
 
                xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
+
                /*
                 * Free the new space.
+                *
+                * XFS_RMAP_OWN_NULL is used here to tell the rmap btree that
+                * this doesn't actually exist in the rmap btree.
                 */
-               error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno,
-                       be32_to_cpu(agf->agf_length) - new), new);
-               if (error) {
+               xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL);
+               error = xfs_free_extent(tp,
+                               XFS_AGB_TO_FSB(mp, agno,
+                                       be32_to_cpu(agf->agf_length) - new),
+                               new, &oinfo);
+               if (error)
                        goto error0;
-               }
        }
 
        /*
@@ -501,6 +586,7 @@ xfs_growfs_data_private(
        } else
                mp->m_maxicount = 0;
        xfs_set_low_space_thresholds(mp);
+       mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
 
        /* update secondary superblocks. */
        for (agno = 1; agno < nagcount; agno++) {
@@ -638,7 +724,7 @@ xfs_fs_counts(
        cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
        cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
        cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
-                                                       XFS_ALLOC_SET_ASIDE(mp);
+                                               mp->m_alloc_set_aside;
 
        spin_lock(&mp->m_sb_lock);
        cnt->freertx = mp->m_sb.sb_frextents;
@@ -726,7 +812,7 @@ xfs_reserve_blocks(
        error = -ENOSPC;
        do {
                free = percpu_counter_sum(&mp->m_fdblocks) -
-                                                       XFS_ALLOC_SET_ASIDE(mp);
+                                               mp->m_alloc_set_aside;
                if (!free)
                        break;
 
index 8825bcf..e08eaea 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
@@ -1122,7 +1123,7 @@ xfs_create(
        struct xfs_inode        *ip = NULL;
        struct xfs_trans        *tp = NULL;
        int                     error;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        bool                    unlock_dp_on_error = false;
        prid_t                  prid;
@@ -1182,7 +1183,7 @@ xfs_create(
                      XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT);
        unlock_dp_on_error = true;
 
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
 
        /*
         * Reserve disk quota and the inode.
@@ -1219,7 +1220,7 @@ xfs_create(
        unlock_dp_on_error = false;
 
        error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-                                       &first_block, &free_list, resblks ?
+                                       &first_block, &dfops, resblks ?
                                        resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
        if (error) {
                ASSERT(error != -ENOSPC);
@@ -1253,7 +1254,7 @@ xfs_create(
         */
        xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out_bmap_cancel;
 
@@ -1269,7 +1270,7 @@ xfs_create(
        return 0;
 
  out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
  out_trans_cancel:
        xfs_trans_cancel(tp);
  out_release_inode:
@@ -1401,7 +1402,7 @@ xfs_link(
        xfs_mount_t             *mp = tdp->i_mount;
        xfs_trans_t             *tp;
        int                     error;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        int                     resblks;
 
@@ -1452,7 +1453,7 @@ xfs_link(
                        goto error_return;
        }
 
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
 
        /*
         * Handle initial link state of O_TMPFILE inode
@@ -1464,7 +1465,7 @@ xfs_link(
        }
 
        error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-                                       &first_block, &free_list, resblks);
+                                       &first_block, &dfops, resblks);
        if (error)
                goto error_return;
        xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
@@ -1482,9 +1483,9 @@ xfs_link(
        if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
                xfs_trans_set_sync(tp);
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error) {
-               xfs_bmap_cancel(&free_list);
+               xfs_defer_cancel(&dfops);
                goto error_return;
        }
 
@@ -1526,7 +1527,7 @@ xfs_itruncate_extents(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp = *tpp;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        xfs_fileoff_t           first_unmap_block;
        xfs_fileoff_t           last_block;
@@ -1562,12 +1563,12 @@ xfs_itruncate_extents(
        ASSERT(first_unmap_block < last_block);
        unmap_len = last_block - first_unmap_block + 1;
        while (!done) {
-               xfs_bmap_init(&free_list, &first_block);
+               xfs_defer_init(&dfops, &first_block);
                error = xfs_bunmapi(tp, ip,
                                    first_unmap_block, unmap_len,
                                    xfs_bmapi_aflag(whichfork),
                                    XFS_ITRUNC_MAX_EXTENTS,
-                                   &first_block, &free_list,
+                                   &first_block, &dfops,
                                    &done);
                if (error)
                        goto out_bmap_cancel;
@@ -1576,7 +1577,7 @@ xfs_itruncate_extents(
                 * Duplicate the transaction that has the permanent
                 * reservation and commit the old transaction.
                 */
-               error = xfs_bmap_finish(&tp, &free_list, ip);
+               error = xfs_defer_finish(&tp, &dfops, ip);
                if (error)
                        goto out_bmap_cancel;
 
@@ -1602,7 +1603,7 @@ out_bmap_cancel:
         * the transaction can be properly aborted.  We just need to make sure
         * we're not holding any resources that we were not when we came in.
         */
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        goto out;
 }
 
@@ -1743,7 +1744,7 @@ STATIC int
 xfs_inactive_ifree(
        struct xfs_inode *ip)
 {
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_trans        *tp;
@@ -1780,8 +1781,8 @@ xfs_inactive_ifree(
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_trans_ijoin(tp, ip, 0);
 
-       xfs_bmap_init(&free_list, &first_block);
-       error = xfs_ifree(tp, ip, &free_list);
+       xfs_defer_init(&dfops, &first_block);
+       error = xfs_ifree(tp, ip, &dfops);
        if (error) {
                /*
                 * If we fail to free the inode, shut down.  The cancel
@@ -1807,11 +1808,11 @@ xfs_inactive_ifree(
         * Just ignore errors at this point.  There is nothing we can do except
         * to try to keep going. Make sure it's not a silent error.
         */
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error) {
-               xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
+               xfs_notice(mp, "%s: xfs_defer_finish returned error %d",
                        __func__, error);
-               xfs_bmap_cancel(&free_list);
+               xfs_defer_cancel(&dfops);
        }
        error = xfs_trans_commit(tp);
        if (error)
@@ -2367,7 +2368,7 @@ int
 xfs_ifree(
        xfs_trans_t     *tp,
        xfs_inode_t     *ip,
-       xfs_bmap_free_t *flist)
+       struct xfs_defer_ops    *dfops)
 {
        int                     error;
        struct xfs_icluster     xic = { 0 };
@@ -2386,7 +2387,7 @@ xfs_ifree(
        if (error)
                return error;
 
-       error = xfs_difree(tp, ip->i_ino, flist, &xic);
+       error = xfs_difree(tp, ip->i_ino, dfops, &xic);
        if (error)
                return error;
 
@@ -2474,7 +2475,7 @@ xfs_iunpin_wait(
  * directory entry.
  *
  * This is still safe from a transactional point of view - it is not until we
- * get to xfs_bmap_finish() that we have the possibility of multiple
+ * get to xfs_defer_finish() that we have the possibility of multiple
  * transactions in this operation. Hence as long as we remove the directory
  * entry and drop the link count in the first transaction of the remove
  * operation, there are no transactional constraints on the ordering here.
@@ -2489,7 +2490,7 @@ xfs_remove(
        xfs_trans_t             *tp = NULL;
        int                     is_dir = S_ISDIR(VFS_I(ip)->i_mode);
        int                     error = 0;
-       xfs_bmap_free_t         free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        uint                    resblks;
 
@@ -2571,9 +2572,9 @@ xfs_remove(
        if (error)
                goto out_trans_cancel;
 
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
        error = xfs_dir_removename(tp, dp, name, ip->i_ino,
-                                       &first_block, &free_list, resblks);
+                                       &first_block, &dfops, resblks);
        if (error) {
                ASSERT(error != -ENOENT);
                goto out_bmap_cancel;
@@ -2587,7 +2588,7 @@ xfs_remove(
        if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
                xfs_trans_set_sync(tp);
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out_bmap_cancel;
 
@@ -2601,7 +2602,7 @@ xfs_remove(
        return 0;
 
  out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
  out_trans_cancel:
        xfs_trans_cancel(tp);
  std_return:
@@ -2662,7 +2663,7 @@ xfs_sort_for_rename(
 static int
 xfs_finish_rename(
        struct xfs_trans        *tp,
-       struct xfs_bmap_free    *free_list)
+       struct xfs_defer_ops    *dfops)
 {
        int                     error;
 
@@ -2673,9 +2674,9 @@ xfs_finish_rename(
        if (tp->t_mountp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
                xfs_trans_set_sync(tp);
 
-       error = xfs_bmap_finish(&tp, free_list, NULL);
+       error = xfs_defer_finish(&tp, dfops, NULL);
        if (error) {
-               xfs_bmap_cancel(free_list);
+               xfs_defer_cancel(dfops);
                xfs_trans_cancel(tp);
                return error;
        }
@@ -2697,7 +2698,7 @@ xfs_cross_rename(
        struct xfs_inode        *dp2,
        struct xfs_name         *name2,
        struct xfs_inode        *ip2,
-       struct xfs_bmap_free    *free_list,
+       struct xfs_defer_ops    *dfops,
        xfs_fsblock_t           *first_block,
        int                     spaceres)
 {
@@ -2709,14 +2710,14 @@ xfs_cross_rename(
        /* Swap inode number for dirent in first parent */
        error = xfs_dir_replace(tp, dp1, name1,
                                ip2->i_ino,
-                               first_block, free_list, spaceres);
+                               first_block, dfops, spaceres);
        if (error)
                goto out_trans_abort;
 
        /* Swap inode number for dirent in second parent */
        error = xfs_dir_replace(tp, dp2, name2,
                                ip1->i_ino,
-                               first_block, free_list, spaceres);
+                               first_block, dfops, spaceres);
        if (error)
                goto out_trans_abort;
 
@@ -2731,7 +2732,7 @@ xfs_cross_rename(
                if (S_ISDIR(VFS_I(ip2)->i_mode)) {
                        error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
                                                dp1->i_ino, first_block,
-                                               free_list, spaceres);
+                                               dfops, spaceres);
                        if (error)
                                goto out_trans_abort;
 
@@ -2758,7 +2759,7 @@ xfs_cross_rename(
                if (S_ISDIR(VFS_I(ip1)->i_mode)) {
                        error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
                                                dp2->i_ino, first_block,
-                                               free_list, spaceres);
+                                               dfops, spaceres);
                        if (error)
                                goto out_trans_abort;
 
@@ -2797,10 +2798,10 @@ xfs_cross_rename(
        }
        xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
-       return xfs_finish_rename(tp, free_list);
+       return xfs_finish_rename(tp, dfops);
 
 out_trans_abort:
-       xfs_bmap_cancel(free_list);
+       xfs_defer_cancel(dfops);
        xfs_trans_cancel(tp);
        return error;
 }
@@ -2855,7 +2856,7 @@ xfs_rename(
 {
        struct xfs_mount        *mp = src_dp->i_mount;
        struct xfs_trans        *tp;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        struct xfs_inode        *wip = NULL;            /* whiteout inode */
        struct xfs_inode        *inodes[__XFS_SORT_INODES];
@@ -2944,13 +2945,13 @@ xfs_rename(
                goto out_trans_cancel;
        }
 
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
 
        /* RENAME_EXCHANGE is unique from here on. */
        if (flags & RENAME_EXCHANGE)
                return xfs_cross_rename(tp, src_dp, src_name, src_ip,
                                        target_dp, target_name, target_ip,
-                                       &free_list, &first_block, spaceres);
+                                       &dfops, &first_block, spaceres);
 
        /*
         * Set up the target.
@@ -2972,7 +2973,7 @@ xfs_rename(
                 */
                error = xfs_dir_createname(tp, target_dp, target_name,
                                                src_ip->i_ino, &first_block,
-                                               &free_list, spaceres);
+                                               &dfops, spaceres);
                if (error)
                        goto out_bmap_cancel;
 
@@ -3012,7 +3013,7 @@ xfs_rename(
                 */
                error = xfs_dir_replace(tp, target_dp, target_name,
                                        src_ip->i_ino,
-                                       &first_block, &free_list, spaceres);
+                                       &first_block, &dfops, spaceres);
                if (error)
                        goto out_bmap_cancel;
 
@@ -3047,7 +3048,7 @@ xfs_rename(
                 */
                error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
                                        target_dp->i_ino,
-                                       &first_block, &free_list, spaceres);
+                                       &first_block, &dfops, spaceres);
                ASSERT(error != -EEXIST);
                if (error)
                        goto out_bmap_cancel;
@@ -3086,10 +3087,10 @@ xfs_rename(
         */
        if (wip) {
                error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
-                                       &first_block, &free_list, spaceres);
+                                       &first_block, &dfops, spaceres);
        } else
                error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
-                                          &first_block, &free_list, spaceres);
+                                          &first_block, &dfops, spaceres);
        if (error)
                goto out_bmap_cancel;
 
@@ -3124,13 +3125,13 @@ xfs_rename(
        if (new_parent)
                xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
 
-       error = xfs_finish_rename(tp, &free_list);
+       error = xfs_finish_rename(tp, &dfops);
        if (wip)
                IRELE(wip);
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
 out_release_wip:
index 8eb78ec..e1a411e 100644 (file)
@@ -27,7 +27,7 @@
 struct xfs_dinode;
 struct xfs_inode;
 struct xfs_buf;
-struct xfs_bmap_free;
+struct xfs_defer_ops;
 struct xfs_bmbt_irec;
 struct xfs_inode_log_item;
 struct xfs_mount;
@@ -398,7 +398,7 @@ uint                xfs_ilock_attr_map_shared(struct xfs_inode *);
 
 uint           xfs_ip2xflags(struct xfs_inode *);
 int            xfs_ifree(struct xfs_trans *, xfs_inode_t *,
-                          struct xfs_bmap_free *);
+                          struct xfs_defer_ops *);
 int            xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *,
                                      int, xfs_fsize_t);
 void           xfs_iext_realloc(xfs_inode_t *, int, int);
index 9a7c878..96a70fd 100644 (file)
@@ -232,7 +232,7 @@ xfs_open_by_handle(
        }
 
        if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
-               error = -EACCES;
+               error = -EPERM;
                goto out_dput;
        }
 
@@ -387,6 +387,7 @@ xfs_attrlist_by_handle(
 {
        int                     error = -ENOMEM;
        attrlist_cursor_kern_t  *cursor;
+       struct xfs_fsop_attrlist_handlereq __user       *p = arg;
        xfs_fsop_attrlist_handlereq_t al_hreq;
        struct dentry           *dentry;
        char                    *kbuf;
@@ -419,6 +420,11 @@ xfs_attrlist_by_handle(
        if (error)
                goto out_kfree;
 
+       if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) {
+               error = -EFAULT;
+               goto out_kfree;
+       }
+
        if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
                error = -EFAULT;
 
index 620fc91..2114d53 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_bmap_btree.h"
@@ -128,7 +129,7 @@ xfs_iomap_write_direct(
        int             quota_flag;
        int             rt;
        xfs_trans_t     *tp;
-       xfs_bmap_free_t free_list;
+       struct xfs_defer_ops dfops;
        uint            qblocks, resblks, resrtextents;
        int             error;
        int             lockmode;
@@ -231,18 +232,18 @@ xfs_iomap_write_direct(
         * From this point onwards we overwrite the imap pointer that the
         * caller gave to us.
         */
-       xfs_bmap_init(&free_list, &firstfsb);
+       xfs_defer_init(&dfops, &firstfsb);
        nimaps = 1;
        error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
                                bmapi_flags, &firstfsb, resblks, imap,
-                               &nimaps, &free_list);
+                               &nimaps, &dfops);
        if (error)
                goto out_bmap_cancel;
 
        /*
         * Complete the transaction
         */
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out_bmap_cancel;
 
@@ -266,7 +267,7 @@ out_unlock:
        return error;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
 out_trans_cancel:
        xfs_trans_cancel(tp);
@@ -685,7 +686,7 @@ xfs_iomap_write_allocate(
        xfs_fileoff_t   offset_fsb, last_block;
        xfs_fileoff_t   end_fsb, map_start_fsb;
        xfs_fsblock_t   first_block;
-       xfs_bmap_free_t free_list;
+       struct xfs_defer_ops    dfops;
        xfs_filblks_t   count_fsb;
        xfs_trans_t     *tp;
        int             nimaps;
@@ -727,7 +728,7 @@ xfs_iomap_write_allocate(
                        xfs_ilock(ip, XFS_ILOCK_EXCL);
                        xfs_trans_ijoin(tp, ip, 0);
 
-                       xfs_bmap_init(&free_list, &first_block);
+                       xfs_defer_init(&dfops, &first_block);
 
                        /*
                         * it is possible that the extents have changed since
@@ -783,11 +784,11 @@ xfs_iomap_write_allocate(
                        error = xfs_bmapi_write(tp, ip, map_start_fsb,
                                                count_fsb, 0, &first_block,
                                                nres, imap, &nimaps,
-                                               &free_list);
+                                               &dfops);
                        if (error)
                                goto trans_cancel;
 
-                       error = xfs_bmap_finish(&tp, &free_list, NULL);
+                       error = xfs_defer_finish(&tp, &dfops, NULL);
                        if (error)
                                goto trans_cancel;
 
@@ -821,7 +822,7 @@ xfs_iomap_write_allocate(
        }
 
 trans_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_cancel(tp);
 error0:
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -842,7 +843,7 @@ xfs_iomap_write_unwritten(
        int             nimaps;
        xfs_trans_t     *tp;
        xfs_bmbt_irec_t imap;
-       xfs_bmap_free_t free_list;
+       struct xfs_defer_ops dfops;
        xfs_fsize_t     i_size;
        uint            resblks;
        int             error;
@@ -886,11 +887,11 @@ xfs_iomap_write_unwritten(
                /*
                 * Modify the unwritten extent state of the buffer.
                 */
-               xfs_bmap_init(&free_list, &firstfsb);
+               xfs_defer_init(&dfops, &firstfsb);
                nimaps = 1;
                error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
                                        XFS_BMAPI_CONVERT, &firstfsb, resblks,
-                                       &imap, &nimaps, &free_list);
+                                       &imap, &nimaps, &dfops);
                if (error)
                        goto error_on_bmapi_transaction;
 
@@ -909,7 +910,7 @@ xfs_iomap_write_unwritten(
                        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
                }
 
-               error = xfs_bmap_finish(&tp, &free_list, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto error_on_bmapi_transaction;
 
@@ -936,7 +937,7 @@ xfs_iomap_write_unwritten(
        return 0;
 
 error_on_bmapi_transaction:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
        xfs_trans_cancel(tp);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return error;
index 8359978..e8638fd 100644 (file)
@@ -43,6 +43,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_error.h"
 #include "xfs_dir2.h"
+#include "xfs_rmap_item.h"
 
 #define BLK_AVG(blk1, blk2)    ((blk1+blk2) >> 1)
 
@@ -1911,6 +1912,8 @@ xlog_recover_reorder_trans(
                case XFS_LI_QUOTAOFF:
                case XFS_LI_EFD:
                case XFS_LI_EFI:
+               case XFS_LI_RUI:
+               case XFS_LI_RUD:
                        trace_xfs_log_recover_item_reorder_tail(log,
                                                        trans, item, pass);
                        list_move_tail(&item->ri_list, &inode_list);
@@ -2228,6 +2231,7 @@ xlog_recover_get_buf_lsn(
        case XFS_ABTC_CRC_MAGIC:
        case XFS_ABTB_MAGIC:
        case XFS_ABTC_MAGIC:
+       case XFS_RMAP_CRC_MAGIC:
        case XFS_IBT_CRC_MAGIC:
        case XFS_IBT_MAGIC: {
                struct xfs_btree_block *btb = blk;
@@ -2396,6 +2400,9 @@ xlog_recover_validate_buf_type(
                case XFS_BMAP_MAGIC:
                        bp->b_ops = &xfs_bmbt_buf_ops;
                        break;
+               case XFS_RMAP_CRC_MAGIC:
+                       bp->b_ops = &xfs_rmapbt_buf_ops;
+                       break;
                default:
                        xfs_warn(mp, "Bad btree block magic!");
                        ASSERT(0);
@@ -3414,6 +3421,99 @@ xlog_recover_efd_pass2(
        return 0;
 }
 
+/*
+ * This routine is called to create an in-core extent rmap update
+ * item from the rui format structure which was logged on disk.
+ * It allocates an in-core rui, copies the extents from the format
+ * structure into it, and adds the rui to the AIL with the given
+ * LSN.
+ */
+STATIC int
+xlog_recover_rui_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       lsn)
+{
+       int                             error;
+       struct xfs_mount                *mp = log->l_mp;
+       struct xfs_rui_log_item         *ruip;
+       struct xfs_rui_log_format       *rui_formatp;
+
+       rui_formatp = item->ri_buf[0].i_addr;
+
+       ruip = xfs_rui_init(mp, rui_formatp->rui_nextents);
+       error = xfs_rui_copy_format(&item->ri_buf[0], &ruip->rui_format);
+       if (error) {
+               xfs_rui_item_free(ruip);
+               return error;
+       }
+       atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents);
+
+       spin_lock(&log->l_ailp->xa_lock);
+       /*
+        * The RUI has two references. One for the RUD and one for RUI to ensure
+        * it makes it into the AIL. Insert the RUI into the AIL directly and
+        * drop the RUI reference. Note that xfs_trans_ail_update() drops the
+        * AIL lock.
+        */
+       xfs_trans_ail_update(log->l_ailp, &ruip->rui_item, lsn);
+       xfs_rui_release(ruip);
+       return 0;
+}
+
+
+/*
+ * This routine is called when an RUD format structure is found in a committed
+ * transaction in the log. Its purpose is to cancel the corresponding RUI if it
+ * was still in the log. To do this it searches the AIL for the RUI with an id
+ * equal to that in the RUD format structure. If we find it we drop the RUD
+ * reference, which removes the RUI from the AIL and frees it.
+ */
+STATIC int
+xlog_recover_rud_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
+{
+       struct xfs_rud_log_format       *rud_formatp;
+       struct xfs_rui_log_item         *ruip = NULL;
+       struct xfs_log_item             *lip;
+       __uint64_t                      rui_id;
+       struct xfs_ail_cursor           cur;
+       struct xfs_ail                  *ailp = log->l_ailp;
+
+       rud_formatp = item->ri_buf[0].i_addr;
+       ASSERT(item->ri_buf[0].i_len == sizeof(struct xfs_rud_log_format));
+       rui_id = rud_formatp->rud_rui_id;
+
+       /*
+        * Search for the RUI with the id in the RUD format structure in the
+        * AIL.
+        */
+       spin_lock(&ailp->xa_lock);
+       lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+       while (lip != NULL) {
+               if (lip->li_type == XFS_LI_RUI) {
+                       ruip = (struct xfs_rui_log_item *)lip;
+                       if (ruip->rui_format.rui_id == rui_id) {
+                               /*
+                                * Drop the RUD reference to the RUI. This
+                                * removes the RUI from the AIL and frees it.
+                                */
+                               spin_unlock(&ailp->xa_lock);
+                               xfs_rui_release(ruip);
+                               spin_lock(&ailp->xa_lock);
+                               break;
+                       }
+               }
+               lip = xfs_trans_ail_cursor_next(ailp, &cur);
+       }
+
+       xfs_trans_ail_cursor_done(&cur);
+       spin_unlock(&ailp->xa_lock);
+
+       return 0;
+}
+
 /*
  * This routine is called when an inode create format structure is found in a
  * committed transaction in the log.  It's purpose is to initialise the inodes
@@ -3639,6 +3739,8 @@ xlog_recover_ra_pass2(
        case XFS_LI_EFI:
        case XFS_LI_EFD:
        case XFS_LI_QUOTAOFF:
+       case XFS_LI_RUI:
+       case XFS_LI_RUD:
        default:
                break;
        }
@@ -3662,6 +3764,8 @@ xlog_recover_commit_pass1(
        case XFS_LI_EFD:
        case XFS_LI_DQUOT:
        case XFS_LI_ICREATE:
+       case XFS_LI_RUI:
+       case XFS_LI_RUD:
                /* nothing to do in pass 1 */
                return 0;
        default:
@@ -3692,6 +3796,10 @@ xlog_recover_commit_pass2(
                return xlog_recover_efi_pass2(log, item, trans->r_lsn);
        case XFS_LI_EFD:
                return xlog_recover_efd_pass2(log, item);
+       case XFS_LI_RUI:
+               return xlog_recover_rui_pass2(log, item, trans->r_lsn);
+       case XFS_LI_RUD:
+               return xlog_recover_rud_pass2(log, item);
        case XFS_LI_DQUOT:
                return xlog_recover_dquot_pass2(log, buffer_list, item,
                                                trans->r_lsn);
@@ -4164,126 +4272,156 @@ xlog_recover_process_data(
        return 0;
 }
 
-/*
- * Process an extent free intent item that was recovered from
- * the log.  We need to free the extents that it describes.
- */
+/* Recover the EFI if necessary. */
 STATIC int
 xlog_recover_process_efi(
-       xfs_mount_t             *mp,
-       xfs_efi_log_item_t      *efip)
+       struct xfs_mount                *mp,
+       struct xfs_ail                  *ailp,
+       struct xfs_log_item             *lip)
 {
-       xfs_efd_log_item_t      *efdp;
-       xfs_trans_t             *tp;
-       int                     i;
-       int                     error = 0;
-       xfs_extent_t            *extp;
-       xfs_fsblock_t           startblock_fsb;
-
-       ASSERT(!test_bit(XFS_EFI_RECOVERED, &efip->efi_flags));
+       struct xfs_efi_log_item         *efip;
+       int                             error;
 
        /*
-        * First check the validity of the extents described by the
-        * EFI.  If any are bad, then assume that all are bad and
-        * just toss the EFI.
+        * Skip EFIs that we've already processed.
         */
-       for (i = 0; i < efip->efi_format.efi_nextents; i++) {
-               extp = &(efip->efi_format.efi_extents[i]);
-               startblock_fsb = XFS_BB_TO_FSB(mp,
-                                  XFS_FSB_TO_DADDR(mp, extp->ext_start));
-               if ((startblock_fsb == 0) ||
-                   (extp->ext_len == 0) ||
-                   (startblock_fsb >= mp->m_sb.sb_dblocks) ||
-                   (extp->ext_len >= mp->m_sb.sb_agblocks)) {
-                       /*
-                        * This will pull the EFI from the AIL and
-                        * free the memory associated with it.
-                        */
-                       set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
-                       xfs_efi_release(efip);
-                       return -EIO;
-               }
-       }
+       efip = container_of(lip, struct xfs_efi_log_item, efi_item);
+       if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags))
+               return 0;
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
-       if (error)
-               return error;
-       efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
+       spin_unlock(&ailp->xa_lock);
+       error = xfs_efi_recover(mp, efip);
+       spin_lock(&ailp->xa_lock);
 
-       for (i = 0; i < efip->efi_format.efi_nextents; i++) {
-               extp = &(efip->efi_format.efi_extents[i]);
-               error = xfs_trans_free_extent(tp, efdp, extp->ext_start,
-                                             extp->ext_len);
-               if (error)
-                       goto abort_error;
+       return error;
+}
 
-       }
+/* Release the EFI since we're cancelling everything. */
+STATIC void
+xlog_recover_cancel_efi(
+       struct xfs_mount                *mp,
+       struct xfs_ail                  *ailp,
+       struct xfs_log_item             *lip)
+{
+       struct xfs_efi_log_item         *efip;
 
-       set_bit(XFS_EFI_RECOVERED, &efip->efi_flags);
-       error = xfs_trans_commit(tp);
-       return error;
+       efip = container_of(lip, struct xfs_efi_log_item, efi_item);
+
+       spin_unlock(&ailp->xa_lock);
+       xfs_efi_release(efip);
+       spin_lock(&ailp->xa_lock);
+}
+
+/* Recover the RUI if necessary. */
+STATIC int
+xlog_recover_process_rui(
+       struct xfs_mount                *mp,
+       struct xfs_ail                  *ailp,
+       struct xfs_log_item             *lip)
+{
+       struct xfs_rui_log_item         *ruip;
+       int                             error;
+
+       /*
+        * Skip RUIs that we've already processed.
+        */
+       ruip = container_of(lip, struct xfs_rui_log_item, rui_item);
+       if (test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags))
+               return 0;
+
+       spin_unlock(&ailp->xa_lock);
+       error = xfs_rui_recover(mp, ruip);
+       spin_lock(&ailp->xa_lock);
 
-abort_error:
-       xfs_trans_cancel(tp);
        return error;
 }
 
+/* Release the RUI since we're cancelling everything. */
+STATIC void
+xlog_recover_cancel_rui(
+       struct xfs_mount                *mp,
+       struct xfs_ail                  *ailp,
+       struct xfs_log_item             *lip)
+{
+       struct xfs_rui_log_item         *ruip;
+
+       ruip = container_of(lip, struct xfs_rui_log_item, rui_item);
+
+       spin_unlock(&ailp->xa_lock);
+       xfs_rui_release(ruip);
+       spin_lock(&ailp->xa_lock);
+}
+
+/* Is this log item a deferred action intent? */
+static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
+{
+       switch (lip->li_type) {
+       case XFS_LI_EFI:
+       case XFS_LI_RUI:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /*
- * When this is called, all of the EFIs which did not have
- * corresponding EFDs should be in the AIL.  What we do now
- * is free the extents associated with each one.
+ * When this is called, all of the log intent items which did not have
+ * corresponding log done items should be in the AIL.  What we do now
+ * is update the data structures associated with each one.
  *
- * Since we process the EFIs in normal transactions, they
- * will be removed at some point after the commit.  This prevents
- * us from just walking down the list processing each one.
- * We'll use a flag in the EFI to skip those that we've already
- * processed and use the AIL iteration mechanism's generation
- * count to try to speed this up at least a bit.
+ * Since we process the log intent items in normal transactions, they
+ * will be removed at some point after the commit.  This prevents us
+ * from just walking down the list processing each one.  We'll use a
+ * flag in the intent item to skip those that we've already processed
+ * and use the AIL iteration mechanism's generation count to try to
+ * speed this up at least a bit.
  *
- * When we start, we know that the EFIs are the only things in
- * the AIL.  As we process them, however, other items are added
- * to the AIL.  Since everything added to the AIL must come after
- * everything already in the AIL, we stop processing as soon as
- * we see something other than an EFI in the AIL.
+ * When we start, we know that the intents are the only things in the
+ * AIL.  As we process them, however, other items are added to the
+ * AIL.
  */
 STATIC int
-xlog_recover_process_efis(
+xlog_recover_process_intents(
        struct xlog             *log)
 {
        struct xfs_log_item     *lip;
-       struct xfs_efi_log_item *efip;
        int                     error = 0;
        struct xfs_ail_cursor   cur;
        struct xfs_ail          *ailp;
+       xfs_lsn_t               last_lsn;
 
        ailp = log->l_ailp;
        spin_lock(&ailp->xa_lock);
        lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+       last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block);
        while (lip != NULL) {
                /*
-                * We're done when we see something other than an EFI.
-                * There should be no EFIs left in the AIL now.
+                * We're done when we see something other than an intent.
+                * There should be no intents left in the AIL now.
                 */
-               if (lip->li_type != XFS_LI_EFI) {
+               if (!xlog_item_is_intent(lip)) {
 #ifdef DEBUG
                        for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur))
-                               ASSERT(lip->li_type != XFS_LI_EFI);
+                               ASSERT(!xlog_item_is_intent(lip));
 #endif
                        break;
                }
 
                /*
-                * Skip EFIs that we've already processed.
+                * We should never see a redo item with a LSN higher than
+                * the last transaction we found in the log at the start
+                * of recovery.
                 */
-               efip = container_of(lip, struct xfs_efi_log_item, efi_item);
-               if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) {
-                       lip = xfs_trans_ail_cursor_next(ailp, &cur);
-                       continue;
-               }
+               ASSERT(XFS_LSN_CMP(last_lsn, lip->li_lsn) >= 0);
 
-               spin_unlock(&ailp->xa_lock);
-               error = xlog_recover_process_efi(log->l_mp, efip);
-               spin_lock(&ailp->xa_lock);
+               switch (lip->li_type) {
+               case XFS_LI_EFI:
+                       error = xlog_recover_process_efi(log->l_mp, ailp, lip);
+                       break;
+               case XFS_LI_RUI:
+                       error = xlog_recover_process_rui(log->l_mp, ailp, lip);
+                       break;
+               }
                if (error)
                        goto out;
                lip = xfs_trans_ail_cursor_next(ailp, &cur);
@@ -4295,15 +4433,14 @@ out:
 }
 
 /*
- * A cancel occurs when the mount has failed and we're bailing out. Release all
- * pending EFIs so they don't pin the AIL.
+ * A cancel occurs when the mount has failed and we're bailing out.
+ * Release all pending log intent items so they don't pin the AIL.
  */
 STATIC int
-xlog_recover_cancel_efis(
+xlog_recover_cancel_intents(
        struct xlog             *log)
 {
        struct xfs_log_item     *lip;
-       struct xfs_efi_log_item *efip;
        int                     error = 0;
        struct xfs_ail_cursor   cur;
        struct xfs_ail          *ailp;
@@ -4313,22 +4450,25 @@ xlog_recover_cancel_efis(
        lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
        while (lip != NULL) {
                /*
-                * We're done when we see something other than an EFI.
-                * There should be no EFIs left in the AIL now.
+                * We're done when we see something other than an intent.
+                * There should be no intents left in the AIL now.
                 */
-               if (lip->li_type != XFS_LI_EFI) {
+               if (!xlog_item_is_intent(lip)) {
 #ifdef DEBUG
                        for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur))
-                               ASSERT(lip->li_type != XFS_LI_EFI);
+                               ASSERT(!xlog_item_is_intent(lip));
 #endif
                        break;
                }
 
-               efip = container_of(lip, struct xfs_efi_log_item, efi_item);
-
-               spin_unlock(&ailp->xa_lock);
-               xfs_efi_release(efip);
-               spin_lock(&ailp->xa_lock);
+               switch (lip->li_type) {
+               case XFS_LI_EFI:
+                       xlog_recover_cancel_efi(log->l_mp, ailp, lip);
+                       break;
+               case XFS_LI_RUI:
+                       xlog_recover_cancel_rui(log->l_mp, ailp, lip);
+                       break;
+               }
 
                lip = xfs_trans_ail_cursor_next(ailp, &cur);
        }
@@ -5023,6 +5163,7 @@ xlog_do_recover(
                xfs_warn(mp, "Failed post-recovery per-ag init: %d", error);
                return error;
        }
+       mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
 
        xlog_recover_check_summary(log);
 
@@ -5139,16 +5280,17 @@ xlog_recover_finish(
         */
        if (log->l_flags & XLOG_RECOVERY_NEEDED) {
                int     error;
-               error = xlog_recover_process_efis(log);
+               error = xlog_recover_process_intents(log);
                if (error) {
-                       xfs_alert(log->l_mp, "Failed to recover EFIs");
+                       xfs_alert(log->l_mp, "Failed to recover intents");
                        return error;
                }
+
                /*
-                * Sync the log to get all the EFIs out of the AIL.
+                * Sync the log to get all the intents out of the AIL.
                 * This isn't absolutely necessary, but it helps in
                 * case the unlink transactions would have problems
-                * pushing the EFIs out of the way.
+                * pushing the intents out of the way.
                 */
                xfs_log_force(log->l_mp, XFS_LOG_SYNC);
 
@@ -5173,7 +5315,7 @@ xlog_recover_cancel(
        int             error = 0;
 
        if (log->l_flags & XLOG_RECOVERY_NEEDED)
-               error = xlog_recover_cancel_efis(log);
+               error = xlog_recover_cancel_intents(log);
 
        return error;
 }
index 970c19b..faeead6 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_bit.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_inode.h"
@@ -41,6 +42,7 @@
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_sysfs.h"
+#include "xfs_rmap_btree.h"
 
 
 static DEFINE_MUTEX(xfs_uuid_table_mutex);
@@ -230,6 +232,8 @@ xfs_initialize_perag(
 
        if (maxagi)
                *maxagi = index;
+
+       mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
        return 0;
 
 out_unwind:
@@ -679,6 +683,7 @@ xfs_mountfs(
        xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);
        xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK);
        xfs_ialloc_compute_maxlevels(mp);
+       xfs_rmapbt_compute_maxlevels(mp);
 
        xfs_set_maxicount(mp);
 
@@ -1216,7 +1221,7 @@ xfs_mod_fdblocks(
                batch = XFS_FDBLOCKS_BATCH;
 
        __percpu_counter_add(&mp->m_fdblocks, delta, batch);
-       if (__percpu_counter_compare(&mp->m_fdblocks, XFS_ALLOC_SET_ASIDE(mp),
+       if (__percpu_counter_compare(&mp->m_fdblocks, mp->m_alloc_set_aside,
                                     XFS_FDBLOCKS_BATCH) >= 0) {
                /* we had space! */
                return 0;
index c1b798c..b36676c 100644 (file)
@@ -116,9 +116,15 @@ typedef struct xfs_mount {
        uint                    m_bmap_dmnr[2]; /* min bmap btree records */
        uint                    m_inobt_mxr[2]; /* max inobt btree records */
        uint                    m_inobt_mnr[2]; /* min inobt btree records */
+       uint                    m_rmap_mxr[2];  /* max rmap btree records */
+       uint                    m_rmap_mnr[2];  /* min rmap btree records */
        uint                    m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
        uint                    m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
        uint                    m_in_maxlevels; /* max inobt btree levels. */
+       uint                    m_rmap_maxlevels; /* max rmap btree levels */
+       xfs_extlen_t            m_ag_prealloc_blocks; /* reserved ag blocks */
+       uint                    m_alloc_set_aside; /* space we can't use */
+       uint                    m_ag_max_usable; /* max space per AG */
        struct radix_tree_root  m_perag_tree;   /* per-ag accounting info */
        spinlock_t              m_perag_lock;   /* lock for m_perag_tree */
        struct mutex            m_growlock;     /* growfs mutex */
index 0cc8d8f..69e2986 100644 (file)
@@ -49,11 +49,14 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_STRUCT_SIZE(struct xfs_dsymlink_hdr,          56);
        XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_key,             4);
        XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_rec,             16);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_key,              20);
+       XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_rec,              24);
        XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp,             8);
        XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t,                  8);
        XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t,                  4);
        XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t,                  8);
        XFS_CHECK_STRUCT_SIZE(xfs_inobt_ptr_t,                  4);
+       XFS_CHECK_STRUCT_SIZE(xfs_rmap_ptr_t,                   4);
 
        /* dir/attr trees */
        XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_leaf_hdr,        80);
index 93f7485..e8339f7 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _XFS_PNFS_H
 #define _XFS_PNFS_H 1
 
-#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
+#ifdef CONFIG_EXPORTFS_BLOCK_OPS
 int xfs_fs_get_uuid(struct super_block *sb, u8 *buf, u32 *len, u64 *offset);
 int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length,
                struct iomap *iomap, bool write, u32 *device_generation);
@@ -15,5 +15,5 @@ xfs_break_layouts(struct inode *inode, uint *iolock, bool with_imutex)
 {
        return 0;
 }
-#endif /* CONFIG_NFSD_PNFS */
+#endif /* CONFIG_EXPORTFS_BLOCK_OPS */
 #endif /* _XFS_PNFS_H */
diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c
new file mode 100644 (file)
index 0000000..2500f28
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
+#include "xfs_rmap_item.h"
+#include "xfs_log.h"
+#include "xfs_rmap.h"
+
+
+kmem_zone_t    *xfs_rui_zone;
+kmem_zone_t    *xfs_rud_zone;
+
+static inline struct xfs_rui_log_item *RUI_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_rui_log_item, rui_item);
+}
+
+void
+xfs_rui_item_free(
+       struct xfs_rui_log_item *ruip)
+{
+       if (ruip->rui_format.rui_nextents > XFS_RUI_MAX_FAST_EXTENTS)
+               kmem_free(ruip);
+       else
+               kmem_zone_free(xfs_rui_zone, ruip);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given rui item.
+ * We only need 1 iovec for an rui item.  It just logs the rui_log_format
+ * structure.
+ */
+static inline int
+xfs_rui_item_sizeof(
+       struct xfs_rui_log_item *ruip)
+{
+       return sizeof(struct xfs_rui_log_format) +
+                       (ruip->rui_format.rui_nextents - 1) *
+                       sizeof(struct xfs_map_extent);
+}
+
+STATIC void
+xfs_rui_item_size(
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
+{
+       *nvecs += 1;
+       *nbytes += xfs_rui_item_sizeof(RUI_ITEM(lip));
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given rui log item. We use only 1 iovec, and we point that
+ * at the rui_log_format structure embedded in the rui item.
+ * It is at this point that we assert that all of the extent
+ * slots in the rui item have been filled.
+ */
+STATIC void
+xfs_rui_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_vec      *lv)
+{
+       struct xfs_rui_log_item *ruip = RUI_ITEM(lip);
+       struct xfs_log_iovec    *vecp = NULL;
+
+       ASSERT(atomic_read(&ruip->rui_next_extent) ==
+                       ruip->rui_format.rui_nextents);
+
+       ruip->rui_format.rui_type = XFS_LI_RUI;
+       ruip->rui_format.rui_size = 1;
+
+       xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format,
+                       xfs_rui_item_sizeof(ruip));
+}
+
+/*
+ * Pinning has no meaning for an rui item, so just return.
+ */
+STATIC void
+xfs_rui_item_pin(
+       struct xfs_log_item     *lip)
+{
+}
+
+/*
+ * The unpin operation is the last place an RUI is manipulated in the log. It is
+ * either inserted in the AIL or aborted in the event of a log I/O error. In
+ * either case, the RUI transaction has been successfully committed to make it
+ * this far. Therefore, we expect whoever committed the RUI to either construct
+ * and commit the RUD or drop the RUD's reference in the event of error. Simply
+ * drop the log's RUI reference now that the log is done with it.
+ */
+STATIC void
+xfs_rui_item_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
+{
+       struct xfs_rui_log_item *ruip = RUI_ITEM(lip);
+
+       xfs_rui_release(ruip);
+}
+
+/*
+ * RUI items have no locking or pushing.  However, since RUIs are pulled from
+ * the AIL when their corresponding RUDs are committed to disk, their situation
+ * is very similar to being pinned.  Return XFS_ITEM_PINNED so that the caller
+ * will eventually flush the log.  This should help in getting the RUI out of
+ * the AIL.
+ */
+STATIC uint
+xfs_rui_item_push(
+       struct xfs_log_item     *lip,
+       struct list_head        *buffer_list)
+{
+       return XFS_ITEM_PINNED;
+}
+
+/*
+ * The RUI has been either committed or aborted if the transaction has been
+ * cancelled. If the transaction was cancelled, an RUD isn't going to be
+ * constructed and thus we free the RUI here directly.
+ */
+STATIC void
+xfs_rui_item_unlock(
+       struct xfs_log_item     *lip)
+{
+       if (lip->li_flags & XFS_LI_ABORTED)
+               xfs_rui_item_free(RUI_ITEM(lip));
+}
+
+/*
+ * The RUI is logged only once and cannot be moved in the log, so simply return
+ * the lsn at which it's been logged.
+ */
+STATIC xfs_lsn_t
+xfs_rui_item_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+       return lsn;
+}
+
+/*
+ * The RUI dependency tracking op doesn't do squat.  It can't because
+ * it doesn't know where the free extent is coming from.  The dependency
+ * tracking has to be handled by the "enclosing" metadata object.  For
+ * example, for inodes, the inode is locked throughout the extent freeing
+ * so the dependency should be recorded there.
+ */
+STATIC void
+xfs_rui_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all rui log items.
+ */
+static const struct xfs_item_ops xfs_rui_item_ops = {
+       .iop_size       = xfs_rui_item_size,
+       .iop_format     = xfs_rui_item_format,
+       .iop_pin        = xfs_rui_item_pin,
+       .iop_unpin      = xfs_rui_item_unpin,
+       .iop_unlock     = xfs_rui_item_unlock,
+       .iop_committed  = xfs_rui_item_committed,
+       .iop_push       = xfs_rui_item_push,
+       .iop_committing = xfs_rui_item_committing,
+};
+
+/*
+ * Allocate and initialize an rui item with the given number of extents.
+ */
+struct xfs_rui_log_item *
+xfs_rui_init(
+       struct xfs_mount                *mp,
+       uint                            nextents)
+
+{
+       struct xfs_rui_log_item         *ruip;
+       uint                            size;
+
+       ASSERT(nextents > 0);
+       if (nextents > XFS_RUI_MAX_FAST_EXTENTS) {
+               size = (uint)(sizeof(struct xfs_rui_log_item) +
+                       ((nextents - 1) * sizeof(struct xfs_map_extent)));
+               ruip = kmem_zalloc(size, KM_SLEEP);
+       } else {
+               ruip = kmem_zone_zalloc(xfs_rui_zone, KM_SLEEP);
+       }
+
+       xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops);
+       ruip->rui_format.rui_nextents = nextents;
+       ruip->rui_format.rui_id = (uintptr_t)(void *)ruip;
+       atomic_set(&ruip->rui_next_extent, 0);
+       atomic_set(&ruip->rui_refcount, 2);
+
+       return ruip;
+}
+
+/*
+ * Copy an RUI format buffer from the given buf, and into the destination
+ * RUI format structure.  The RUI/RUD items were designed not to need any
+ * special alignment handling.
+ */
+int
+xfs_rui_copy_format(
+       struct xfs_log_iovec            *buf,
+       struct xfs_rui_log_format       *dst_rui_fmt)
+{
+       struct xfs_rui_log_format       *src_rui_fmt;
+       uint                            len;
+
+       src_rui_fmt = buf->i_addr;
+       len = sizeof(struct xfs_rui_log_format) +
+                       (src_rui_fmt->rui_nextents - 1) *
+                       sizeof(struct xfs_map_extent);
+
+       if (buf->i_len != len)
+               return -EFSCORRUPTED;
+
+       memcpy((char *)dst_rui_fmt, (char *)src_rui_fmt, len);
+       return 0;
+}
+
+/*
+ * Freeing the RUI requires that we remove it from the AIL if it has already
+ * been placed there. However, the RUI may not yet have been placed in the AIL
+ * when called by xfs_rui_release() from RUD processing due to the ordering of
+ * committed vs unpin operations in bulk insert operations. Hence the reference
+ * count to ensure only the last caller frees the RUI.
+ */
+void
+xfs_rui_release(
+       struct xfs_rui_log_item *ruip)
+{
+       if (atomic_dec_and_test(&ruip->rui_refcount)) {
+               xfs_trans_ail_remove(&ruip->rui_item, SHUTDOWN_LOG_IO_ERROR);
+               xfs_rui_item_free(ruip);
+       }
+}
+
+static inline struct xfs_rud_log_item *RUD_ITEM(struct xfs_log_item *lip)
+{
+       return container_of(lip, struct xfs_rud_log_item, rud_item);
+}
+
+STATIC void
+xfs_rud_item_size(
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
+{
+       *nvecs += 1;
+       *nbytes += sizeof(struct xfs_rud_log_format);
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given rud log item. We use only 1 iovec, and we point that
+ * at the rud_log_format structure embedded in the rud item.
+ * It is at this point that we assert that all of the extent
+ * slots in the rud item have been filled.
+ */
+STATIC void
+xfs_rud_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_vec      *lv)
+{
+       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+       struct xfs_log_iovec    *vecp = NULL;
+
+       rudp->rud_format.rud_type = XFS_LI_RUD;
+       rudp->rud_format.rud_size = 1;
+
+       xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format,
+                       sizeof(struct xfs_rud_log_format));
+}
+
+/*
+ * Pinning has no meaning for an rud item, so just return.
+ */
+STATIC void
+xfs_rud_item_pin(
+       struct xfs_log_item     *lip)
+{
+}
+
+/*
+ * Since pinning has no meaning for an rud item, unpinning does
+ * not either.
+ */
+STATIC void
+xfs_rud_item_unpin(
+       struct xfs_log_item     *lip,
+       int                     remove)
+{
+}
+
+/*
+ * There isn't much you can do to push on an rud item.  It is simply stuck
+ * waiting for the log to be flushed to disk.
+ */
+STATIC uint
+xfs_rud_item_push(
+       struct xfs_log_item     *lip,
+       struct list_head        *buffer_list)
+{
+       return XFS_ITEM_PINNED;
+}
+
+/*
+ * The RUD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the RUI and free the
+ * RUD.
+ */
+STATIC void
+xfs_rud_item_unlock(
+       struct xfs_log_item     *lip)
+{
+       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+
+       if (lip->li_flags & XFS_LI_ABORTED) {
+               xfs_rui_release(rudp->rud_ruip);
+               kmem_zone_free(xfs_rud_zone, rudp);
+       }
+}
+
+/*
+ * When the rud item is committed to disk, all we need to do is delete our
+ * reference to our partner rui item and then free ourselves. Since we're
+ * freeing ourselves we must return -1 to keep the transaction code from
+ * further referencing this item.
+ */
+STATIC xfs_lsn_t
+xfs_rud_item_committed(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+       struct xfs_rud_log_item *rudp = RUD_ITEM(lip);
+
+       /*
+        * Drop the RUI reference regardless of whether the RUD has been
+        * aborted. Once the RUD transaction is constructed, it is the sole
+        * responsibility of the RUD to release the RUI (even if the RUI is
+        * aborted due to log I/O error).
+        */
+       xfs_rui_release(rudp->rud_ruip);
+       kmem_zone_free(xfs_rud_zone, rudp);
+
+       return (xfs_lsn_t)-1;
+}
+
+/*
+ * The RUD dependency tracking op doesn't do squat.  It can't because
+ * it doesn't know where the free extent is coming from.  The dependency
+ * tracking has to be handled by the "enclosing" metadata object.  For
+ * example, for inodes, the inode is locked throughout the extent freeing
+ * so the dependency should be recorded there.
+ */
+STATIC void
+xfs_rud_item_committing(
+       struct xfs_log_item     *lip,
+       xfs_lsn_t               lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all rud log items.
+ */
+static const struct xfs_item_ops xfs_rud_item_ops = {
+       .iop_size       = xfs_rud_item_size,
+       .iop_format     = xfs_rud_item_format,
+       .iop_pin        = xfs_rud_item_pin,
+       .iop_unpin      = xfs_rud_item_unpin,
+       .iop_unlock     = xfs_rud_item_unlock,
+       .iop_committed  = xfs_rud_item_committed,
+       .iop_push       = xfs_rud_item_push,
+       .iop_committing = xfs_rud_item_committing,
+};
+
+/*
+ * Allocate and initialize an rud item with the given number of extents.
+ */
+struct xfs_rud_log_item *
+xfs_rud_init(
+       struct xfs_mount                *mp,
+       struct xfs_rui_log_item         *ruip)
+
+{
+       struct xfs_rud_log_item *rudp;
+
+       rudp = kmem_zone_zalloc(xfs_rud_zone, KM_SLEEP);
+       xfs_log_item_init(mp, &rudp->rud_item, XFS_LI_RUD, &xfs_rud_item_ops);
+       rudp->rud_ruip = ruip;
+       rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
+
+       return rudp;
+}
+
+/*
+ * Process an rmap update intent item that was recovered from the log.
+ * We need to update the rmapbt.
+ */
+int
+xfs_rui_recover(
+       struct xfs_mount                *mp,
+       struct xfs_rui_log_item         *ruip)
+{
+       int                             i;
+       int                             error = 0;
+       struct xfs_map_extent           *rmap;
+       xfs_fsblock_t                   startblock_fsb;
+       bool                            op_ok;
+       struct xfs_rud_log_item         *rudp;
+       enum xfs_rmap_intent_type       type;
+       int                             whichfork;
+       xfs_exntst_t                    state;
+       struct xfs_trans                *tp;
+       struct xfs_btree_cur            *rcur = NULL;
+
+       ASSERT(!test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags));
+
+       /*
+        * First check the validity of the extents described by the
+        * RUI.  If any are bad, then assume that all are bad and
+        * just toss the RUI.
+        */
+       for (i = 0; i < ruip->rui_format.rui_nextents; i++) {
+               rmap = &ruip->rui_format.rui_extents[i];
+               startblock_fsb = XFS_BB_TO_FSB(mp,
+                                  XFS_FSB_TO_DADDR(mp, rmap->me_startblock));
+               switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) {
+               case XFS_RMAP_EXTENT_MAP:
+               case XFS_RMAP_EXTENT_UNMAP:
+               case XFS_RMAP_EXTENT_CONVERT:
+               case XFS_RMAP_EXTENT_ALLOC:
+               case XFS_RMAP_EXTENT_FREE:
+                       op_ok = true;
+                       break;
+               default:
+                       op_ok = false;
+                       break;
+               }
+               if (!op_ok || startblock_fsb == 0 ||
+                   rmap->me_len == 0 ||
+                   startblock_fsb >= mp->m_sb.sb_dblocks ||
+                   rmap->me_len >= mp->m_sb.sb_agblocks ||
+                   (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS)) {
+                       /*
+                        * This will pull the RUI from the AIL and
+                        * free the memory associated with it.
+                        */
+                       set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags);
+                       xfs_rui_release(ruip);
+                       return -EIO;
+               }
+       }
+
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+       if (error)
+               return error;
+       rudp = xfs_trans_get_rud(tp, ruip);
+
+       for (i = 0; i < ruip->rui_format.rui_nextents; i++) {
+               rmap = &ruip->rui_format.rui_extents[i];
+               state = (rmap->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ?
+                               XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
+               whichfork = (rmap->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ?
+                               XFS_ATTR_FORK : XFS_DATA_FORK;
+               switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) {
+               case XFS_RMAP_EXTENT_MAP:
+                       type = XFS_RMAP_MAP;
+                       break;
+               case XFS_RMAP_EXTENT_UNMAP:
+                       type = XFS_RMAP_UNMAP;
+                       break;
+               case XFS_RMAP_EXTENT_CONVERT:
+                       type = XFS_RMAP_CONVERT;
+                       break;
+               case XFS_RMAP_EXTENT_ALLOC:
+                       type = XFS_RMAP_ALLOC;
+                       break;
+               case XFS_RMAP_EXTENT_FREE:
+                       type = XFS_RMAP_FREE;
+                       break;
+               default:
+                       error = -EFSCORRUPTED;
+                       goto abort_error;
+               }
+               error = xfs_trans_log_finish_rmap_update(tp, rudp, type,
+                               rmap->me_owner, whichfork,
+                               rmap->me_startoff, rmap->me_startblock,
+                               rmap->me_len, state, &rcur);
+               if (error)
+                       goto abort_error;
+
+       }
+
+       xfs_rmap_finish_one_cleanup(tp, rcur, error);
+       set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags);
+       error = xfs_trans_commit(tp);
+       return error;
+
+abort_error:
+       xfs_rmap_finish_one_cleanup(tp, rcur, error);
+       xfs_trans_cancel(tp);
+       return error;
+}
diff --git a/fs/xfs/xfs_rmap_item.h b/fs/xfs/xfs_rmap_item.h
new file mode 100644 (file)
index 0000000..aefcc3a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#ifndef        __XFS_RMAP_ITEM_H__
+#define        __XFS_RMAP_ITEM_H__
+
+/*
+ * There are (currently) three pairs of rmap btree redo item types: map, unmap,
+ * and convert.  The common abbreviations for these are RUI (rmap update
+ * intent) and RUD (rmap update done).  The redo item type is encoded in the
+ * flags field of each xfs_map_extent.
+ *
+ * *I items should be recorded in the *first* of a series of rolled
+ * transactions, and the *D items should be recorded in the same transaction
+ * that records the associated rmapbt updates.  Typically, the first
+ * transaction will record a bmbt update, followed by some number of
+ * transactions containing rmapbt updates, and finally transactions with any
+ * bnobt/cntbt updates.
+ *
+ * Should the system crash after the commit of the first transaction but
+ * before the commit of the final transaction in a series, log recovery will
+ * use the redo information recorded by the intent items to replay the
+ * (rmapbt/bnobt/cntbt) metadata updates in the non-first transaction.
+ */
+
+/* kernel only RUI/RUD definitions */
+
+struct xfs_mount;
+struct kmem_zone;
+
+/*
+ * Max number of extents in fast allocation path.
+ */
+#define        XFS_RUI_MAX_FAST_EXTENTS        16
+
+/*
+ * Define RUI flag bits. Manipulated by set/clear/test_bit operators.
+ */
+#define        XFS_RUI_RECOVERED               1
+
+/*
+ * This is the "rmap update intent" log item.  It is used to log the fact that
+ * some reverse mappings need to change.  It is used in conjunction with the
+ * "rmap update done" log item described below.
+ *
+ * These log items follow the same rules as struct xfs_efi_log_item; see the
+ * comments about that structure (in xfs_extfree_item.h) for more details.
+ */
+struct xfs_rui_log_item {
+       struct xfs_log_item             rui_item;
+       atomic_t                        rui_refcount;
+       atomic_t                        rui_next_extent;
+       unsigned long                   rui_flags;      /* misc flags */
+       struct xfs_rui_log_format       rui_format;
+};
+
+/*
+ * This is the "rmap update done" log item.  It is used to log the fact that
+ * some rmapbt updates mentioned in an earlier rui item have been performed.
+ */
+struct xfs_rud_log_item {
+       struct xfs_log_item             rud_item;
+       struct xfs_rui_log_item         *rud_ruip;
+       struct xfs_rud_log_format       rud_format;
+};
+
+extern struct kmem_zone        *xfs_rui_zone;
+extern struct kmem_zone        *xfs_rud_zone;
+
+struct xfs_rui_log_item *xfs_rui_init(struct xfs_mount *, uint);
+struct xfs_rud_log_item *xfs_rud_init(struct xfs_mount *,
+               struct xfs_rui_log_item *);
+int xfs_rui_copy_format(struct xfs_log_iovec *buf,
+               struct xfs_rui_log_format *dst_rui_fmt);
+void xfs_rui_item_free(struct xfs_rui_log_item *);
+void xfs_rui_release(struct xfs_rui_log_item *);
+int xfs_rui_recover(struct xfs_mount *mp, struct xfs_rui_log_item *ruip);
+
+#endif /* __XFS_RMAP_ITEM_H__ */
index 3938b37..802bcc3 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
@@ -769,7 +770,7 @@ xfs_growfs_rt_alloc(
        xfs_daddr_t             d;              /* disk block address */
        int                     error;          /* error return value */
        xfs_fsblock_t           firstblock;/* first block allocated in xaction */
-       struct xfs_bmap_free    flist;          /* list of freed blocks */
+       struct xfs_defer_ops    dfops;          /* list of freed blocks */
        xfs_fsblock_t           fsbno;          /* filesystem block for bno */
        struct xfs_bmbt_irec    map;            /* block map output */
        int                     nmap;           /* number of block maps */
@@ -794,14 +795,14 @@ xfs_growfs_rt_alloc(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
-               xfs_bmap_init(&flist, &firstblock);
+               xfs_defer_init(&dfops, &firstblock);
                /*
                 * Allocate blocks to the bitmap file.
                 */
                nmap = 1;
                error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
                                        XFS_BMAPI_METADATA, &firstblock,
-                                       resblks, &map, &nmap, &flist);
+                                       resblks, &map, &nmap, &dfops);
                if (!error && nmap < 1)
                        error = -ENOSPC;
                if (error)
@@ -809,7 +810,7 @@ xfs_growfs_rt_alloc(
                /*
                 * Free any blocks freed up in the transaction, then commit.
                 */
-               error = xfs_bmap_finish(&tp, &flist, NULL);
+               error = xfs_defer_finish(&tp, &dfops, NULL);
                if (error)
                        goto out_bmap_cancel;
                error = xfs_trans_commit(tp);
@@ -862,7 +863,7 @@ xfs_growfs_rt_alloc(
        return 0;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&flist);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
        return error;
index d266e83..6e812fe 100644 (file)
@@ -61,6 +61,7 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
                { "bmbt2",              XFSSTAT_END_BMBT_V2             },
                { "ibt2",               XFSSTAT_END_IBT_V2              },
                { "fibt2",              XFSSTAT_END_FIBT_V2             },
+               { "rmapbt",             XFSSTAT_END_RMAP_V2             },
                /* we print both series of quota information together */
                { "qm",                 XFSSTAT_END_QM                  },
        };
index 483b0ef..657865f 100644 (file)
@@ -197,7 +197,23 @@ struct xfsstats {
        __uint32_t              xs_fibt_2_alloc;
        __uint32_t              xs_fibt_2_free;
        __uint32_t              xs_fibt_2_moves;
-#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_FIBT_V2+6)
+#define XFSSTAT_END_RMAP_V2            (XFSSTAT_END_FIBT_V2+15)
+       __uint32_t              xs_rmap_2_lookup;
+       __uint32_t              xs_rmap_2_compare;
+       __uint32_t              xs_rmap_2_insrec;
+       __uint32_t              xs_rmap_2_delrec;
+       __uint32_t              xs_rmap_2_newroot;
+       __uint32_t              xs_rmap_2_killroot;
+       __uint32_t              xs_rmap_2_increment;
+       __uint32_t              xs_rmap_2_decrement;
+       __uint32_t              xs_rmap_2_lshift;
+       __uint32_t              xs_rmap_2_rshift;
+       __uint32_t              xs_rmap_2_split;
+       __uint32_t              xs_rmap_2_join;
+       __uint32_t              xs_rmap_2_alloc;
+       __uint32_t              xs_rmap_2_free;
+       __uint32_t              xs_rmap_2_moves;
+#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_RMAP_V2+6)
        __uint32_t              xs_qm_dqreclaims;
        __uint32_t              xs_qm_dqreclaim_misses;
        __uint32_t              xs_qm_dquot_dups;
index 0303f10..24ef83e 100644 (file)
@@ -46,6 +46,7 @@
 #include "xfs_quota.h"
 #include "xfs_sysfs.h"
 #include "xfs_ondisk.h"
+#include "xfs_rmap_item.h"
 
 #include <linux/namei.h>
 #include <linux/init.h>
@@ -1075,7 +1076,7 @@ xfs_fs_statfs(
        statp->f_blocks = sbp->sb_dblocks - lsize;
        spin_unlock(&mp->m_sb_lock);
 
-       statp->f_bfree = fdblocks - XFS_ALLOC_SET_ASIDE(mp);
+       statp->f_bfree = fdblocks - mp->m_alloc_set_aside;
        statp->f_bavail = statp->f_bfree;
 
        fakeinos = statp->f_bfree << sbp->sb_inopblog;
@@ -1573,6 +1574,10 @@ xfs_fs_fill_super(
                }
        }
 
+       if (xfs_sb_version_hasrmapbt(&mp->m_sb))
+               xfs_alert(mp,
+       "EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!");
+
        error = xfs_mountfs(mp);
        if (error)
                goto out_filestream_unmount;
@@ -1697,7 +1702,7 @@ xfs_init_zones(void)
                goto out_free_ioend_bioset;
 
        xfs_bmap_free_item_zone = kmem_zone_init(
-                       sizeof(struct xfs_bmap_free_item),
+                       sizeof(struct xfs_extent_free_item),
                        "xfs_bmap_free_item");
        if (!xfs_bmap_free_item_zone)
                goto out_destroy_log_ticket_zone;
@@ -1765,8 +1770,24 @@ xfs_init_zones(void)
        if (!xfs_icreate_zone)
                goto out_destroy_ili_zone;
 
+       xfs_rud_zone = kmem_zone_init(sizeof(struct xfs_rud_log_item),
+                       "xfs_rud_item");
+       if (!xfs_rud_zone)
+               goto out_destroy_icreate_zone;
+
+       xfs_rui_zone = kmem_zone_init((sizeof(struct xfs_rui_log_item) +
+                       ((XFS_RUI_MAX_FAST_EXTENTS - 1) *
+                               sizeof(struct xfs_map_extent))),
+                       "xfs_rui_item");
+       if (!xfs_rui_zone)
+               goto out_destroy_rud_zone;
+
        return 0;
 
+ out_destroy_rud_zone:
+       kmem_zone_destroy(xfs_rud_zone);
+ out_destroy_icreate_zone:
+       kmem_zone_destroy(xfs_icreate_zone);
  out_destroy_ili_zone:
        kmem_zone_destroy(xfs_ili_zone);
  out_destroy_inode_zone:
@@ -1805,6 +1826,8 @@ xfs_destroy_zones(void)
         * destroy caches.
         */
        rcu_barrier();
+       kmem_zone_destroy(xfs_rui_zone);
+       kmem_zone_destroy(xfs_rud_zone);
        kmem_zone_destroy(xfs_icreate_zone);
        kmem_zone_destroy(xfs_ili_zone);
        kmem_zone_destroy(xfs_inode_zone);
@@ -1854,6 +1877,9 @@ init_xfs_fs(void)
        printk(KERN_INFO XFS_VERSION_STRING " with "
                         XFS_BUILD_OPTIONS " enabled\n");
 
+       xfs_extent_free_init_defer_op();
+       xfs_rmap_update_init_defer_op();
+
        xfs_dir_startup();
 
        error = xfs_init_zones();
index 08a46c6..58142ae 100644 (file)
@@ -26,6 +26,7 @@
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
+#include "xfs_defer.h"
 #include "xfs_dir2.h"
 #include "xfs_inode.h"
 #include "xfs_ialloc.h"
@@ -172,7 +173,7 @@ xfs_symlink(
        struct xfs_inode        *ip = NULL;
        int                     error = 0;
        int                     pathlen;
-       struct xfs_bmap_free    free_list;
+       struct xfs_defer_ops    dfops;
        xfs_fsblock_t           first_block;
        bool                    unlock_dp_on_error = false;
        xfs_fileoff_t           first_fsb;
@@ -269,7 +270,7 @@ xfs_symlink(
         * Initialize the bmap freelist prior to calling either
         * bmapi or the directory create code.
         */
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
 
        /*
         * Allocate an inode for the symlink.
@@ -313,7 +314,7 @@ xfs_symlink(
 
                error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
                                  XFS_BMAPI_METADATA, &first_block, resblks,
-                                 mval, &nmaps, &free_list);
+                                 mval, &nmaps, &dfops);
                if (error)
                        goto out_bmap_cancel;
 
@@ -361,7 +362,7 @@ xfs_symlink(
         * Create the directory entry for the symlink.
         */
        error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
-                                       &first_block, &free_list, resblks);
+                                       &first_block, &dfops, resblks);
        if (error)
                goto out_bmap_cancel;
        xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
@@ -376,7 +377,7 @@ xfs_symlink(
                xfs_trans_set_sync(tp);
        }
 
-       error = xfs_bmap_finish(&tp, &free_list, NULL);
+       error = xfs_defer_finish(&tp, &dfops, NULL);
        if (error)
                goto out_bmap_cancel;
 
@@ -392,7 +393,7 @@ xfs_symlink(
        return 0;
 
 out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 out_trans_cancel:
        xfs_trans_cancel(tp);
 out_release_inode:
@@ -426,7 +427,7 @@ xfs_inactive_symlink_rmt(
        int             done;
        int             error;
        xfs_fsblock_t   first_block;
-       xfs_bmap_free_t free_list;
+       struct xfs_defer_ops    dfops;
        int             i;
        xfs_mount_t     *mp;
        xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS];
@@ -465,7 +466,7 @@ xfs_inactive_symlink_rmt(
         * Find the block(s) so we can inval and unmap them.
         */
        done = 0;
-       xfs_bmap_init(&free_list, &first_block);
+       xfs_defer_init(&dfops, &first_block);
        nmaps = ARRAY_SIZE(mval);
        error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size),
                                mval, &nmaps, 0);
@@ -485,17 +486,17 @@ xfs_inactive_symlink_rmt(
                xfs_trans_binval(tp, bp);
        }
        /*
-        * Unmap the dead block(s) to the free_list.
+        * Unmap the dead block(s) to the dfops.
         */
        error = xfs_bunmapi(tp, ip, 0, size, 0, nmaps,
-                           &first_block, &free_list, &done);
+                           &first_block, &dfops, &done);
        if (error)
                goto error_bmap_cancel;
        ASSERT(done);
        /*
         * Commit the first transaction.  This logs the EFI and the inode.
         */
-       error = xfs_bmap_finish(&tp, &free_list, ip);
+       error = xfs_defer_finish(&tp, &dfops, ip);
        if (error)
                goto error_bmap_cancel;
        /*
@@ -525,7 +526,7 @@ xfs_inactive_symlink_rmt(
        return 0;
 
 error_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
+       xfs_defer_cancel(&dfops);
 error_trans_cancel:
        xfs_trans_cancel(tp);
 error_unlock:
index 13a0298..7f17ae6 100644 (file)
@@ -22,7 +22,9 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_da_format.h"
+#include "xfs_defer.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_da_btree.h"
index 1451690..551b7e2 100644 (file)
@@ -38,6 +38,7 @@ struct xlog_recover_item;
 struct xfs_buf_log_format;
 struct xfs_inode_log_format;
 struct xfs_bmbt_irec;
+struct xfs_btree_cur;
 
 DECLARE_EVENT_CLASS(xfs_attr_list_class,
        TP_PROTO(struct xfs_attr_list_context *ctx),
@@ -2185,6 +2186,379 @@ DEFINE_DISCARD_EVENT(xfs_discard_toosmall);
 DEFINE_DISCARD_EVENT(xfs_discard_exclude);
 DEFINE_DISCARD_EVENT(xfs_discard_busy);
 
+/* btree cursor events */
+DECLARE_EVENT_CLASS(xfs_btree_cur_class,
+       TP_PROTO(struct xfs_btree_cur *cur, int level, struct xfs_buf *bp),
+       TP_ARGS(cur, level, bp),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_btnum_t, btnum)
+               __field(int, level)
+               __field(int, nlevels)
+               __field(int, ptr)
+               __field(xfs_daddr_t, daddr)
+       ),
+       TP_fast_assign(
+               __entry->dev = cur->bc_mp->m_super->s_dev;
+               __entry->btnum = cur->bc_btnum;
+               __entry->level = level;
+               __entry->nlevels = cur->bc_nlevels;
+               __entry->ptr = cur->bc_ptrs[level];
+               __entry->daddr = bp ? bp->b_bn : -1;
+       ),
+       TP_printk("dev %d:%d btnum %d level %d/%d ptr %d daddr 0x%llx",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->btnum,
+                 __entry->level,
+                 __entry->nlevels,
+                 __entry->ptr,
+                 (unsigned long long)__entry->daddr)
+)
+
+#define DEFINE_BTREE_CUR_EVENT(name) \
+DEFINE_EVENT(xfs_btree_cur_class, name, \
+       TP_PROTO(struct xfs_btree_cur *cur, int level, struct xfs_buf *bp), \
+       TP_ARGS(cur, level, bp))
+DEFINE_BTREE_CUR_EVENT(xfs_btree_updkeys);
+DEFINE_BTREE_CUR_EVENT(xfs_btree_overlapped_query_range);
+
+/* deferred ops */
+struct xfs_defer_pending;
+struct xfs_defer_intake;
+struct xfs_defer_ops;
+
+DECLARE_EVENT_CLASS(xfs_defer_class,
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop),
+       TP_ARGS(mp, dop),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(void *, dop)
+               __field(bool, committed)
+               __field(bool, low)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp ? mp->m_super->s_dev : 0;
+               __entry->dop = dop;
+               __entry->committed = dop->dop_committed;
+               __entry->low = dop->dop_low;
+       ),
+       TP_printk("dev %d:%d ops %p committed %d low %d\n",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->dop,
+                 __entry->committed,
+                 __entry->low)
+)
+#define DEFINE_DEFER_EVENT(name) \
+DEFINE_EVENT(xfs_defer_class, name, \
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop), \
+       TP_ARGS(mp, dop))
+
+DECLARE_EVENT_CLASS(xfs_defer_error_class,
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop, int error),
+       TP_ARGS(mp, dop, error),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(void *, dop)
+               __field(bool, committed)
+               __field(bool, low)
+               __field(int, error)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp ? mp->m_super->s_dev : 0;
+               __entry->dop = dop;
+               __entry->committed = dop->dop_committed;
+               __entry->low = dop->dop_low;
+               __entry->error = error;
+       ),
+       TP_printk("dev %d:%d ops %p committed %d low %d err %d\n",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->dop,
+                 __entry->committed,
+                 __entry->low,
+                 __entry->error)
+)
+#define DEFINE_DEFER_ERROR_EVENT(name) \
+DEFINE_EVENT(xfs_defer_error_class, name, \
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop, int error), \
+       TP_ARGS(mp, dop, error))
+
+DECLARE_EVENT_CLASS(xfs_defer_pending_class,
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_pending *dfp),
+       TP_ARGS(mp, dfp),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(int, type)
+               __field(void *, intent)
+               __field(bool, committed)
+               __field(int, nr)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp ? mp->m_super->s_dev : 0;
+               __entry->type = dfp->dfp_type->type;
+               __entry->intent = dfp->dfp_intent;
+               __entry->committed = dfp->dfp_committed;
+               __entry->nr = dfp->dfp_count;
+       ),
+       TP_printk("dev %d:%d optype %d intent %p committed %d nr %d\n",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->type,
+                 __entry->intent,
+                 __entry->committed,
+                 __entry->nr)
+)
+#define DEFINE_DEFER_PENDING_EVENT(name) \
+DEFINE_EVENT(xfs_defer_pending_class, name, \
+       TP_PROTO(struct xfs_mount *mp, struct xfs_defer_pending *dfp), \
+       TP_ARGS(mp, dfp))
+
+DECLARE_EVENT_CLASS(xfs_phys_extent_deferred_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                int type, xfs_agblock_t agbno, xfs_extlen_t len),
+       TP_ARGS(mp, agno, type, agbno, len),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(int, type)
+               __field(xfs_agblock_t, agbno)
+               __field(xfs_extlen_t, len)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->type = type;
+               __entry->agbno = agbno;
+               __entry->len = len;
+       ),
+       TP_printk("dev %d:%d op %d agno %u agbno %u len %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->type,
+                 __entry->agno,
+                 __entry->agbno,
+                 __entry->len)
+);
+#define DEFINE_PHYS_EXTENT_DEFERRED_EVENT(name) \
+DEFINE_EVENT(xfs_phys_extent_deferred_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+                int type, \
+                xfs_agblock_t bno, \
+                xfs_extlen_t len), \
+       TP_ARGS(mp, agno, type, bno, len))
+
+DECLARE_EVENT_CLASS(xfs_map_extent_deferred_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                int op,
+                xfs_agblock_t agbno,
+                xfs_ino_t ino,
+                int whichfork,
+                xfs_fileoff_t offset,
+                xfs_filblks_t len,
+                xfs_exntst_t state),
+       TP_ARGS(mp, agno, op, agbno, ino, whichfork, offset, len, state),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_ino_t, ino)
+               __field(xfs_agblock_t, agbno)
+               __field(int, whichfork)
+               __field(xfs_fileoff_t, l_loff)
+               __field(xfs_filblks_t, l_len)
+               __field(xfs_exntst_t, l_state)
+               __field(int, op)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->ino = ino;
+               __entry->agbno = agbno;
+               __entry->whichfork = whichfork;
+               __entry->l_loff = offset;
+               __entry->l_len = len;
+               __entry->l_state = state;
+               __entry->op = op;
+       ),
+       TP_printk("dev %d:%d op %d agno %u agbno %u owner %lld %s offset %llu len %llu state %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->op,
+                 __entry->agno,
+                 __entry->agbno,
+                 __entry->ino,
+                 __entry->whichfork == XFS_ATTR_FORK ? "attr" : "data",
+                 __entry->l_loff,
+                 __entry->l_len,
+                 __entry->l_state)
+);
+#define DEFINE_MAP_EXTENT_DEFERRED_EVENT(name) \
+DEFINE_EVENT(xfs_map_extent_deferred_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+                int op, \
+                xfs_agblock_t agbno, \
+                xfs_ino_t ino, \
+                int whichfork, \
+                xfs_fileoff_t offset, \
+                xfs_filblks_t len, \
+                xfs_exntst_t state), \
+       TP_ARGS(mp, agno, op, agbno, ino, whichfork, offset, len, state))
+
+DEFINE_DEFER_EVENT(xfs_defer_init);
+DEFINE_DEFER_EVENT(xfs_defer_cancel);
+DEFINE_DEFER_EVENT(xfs_defer_trans_roll);
+DEFINE_DEFER_EVENT(xfs_defer_trans_abort);
+DEFINE_DEFER_EVENT(xfs_defer_finish);
+DEFINE_DEFER_EVENT(xfs_defer_finish_done);
+
+DEFINE_DEFER_ERROR_EVENT(xfs_defer_trans_roll_error);
+DEFINE_DEFER_ERROR_EVENT(xfs_defer_finish_error);
+DEFINE_DEFER_ERROR_EVENT(xfs_defer_op_finish_error);
+
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_work);
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_cancel);
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_commit);
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_cancel);
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish);
+DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort);
+
+#define DEFINE_BMAP_FREE_DEFERRED_EVENT DEFINE_PHYS_EXTENT_DEFERRED_EVENT
+DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_defer);
+DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_deferred);
+
+/* rmap tracepoints */
+DECLARE_EVENT_CLASS(xfs_rmap_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                xfs_agblock_t agbno, xfs_extlen_t len, bool unwritten,
+                struct xfs_owner_info *oinfo),
+       TP_ARGS(mp, agno, agbno, len, unwritten, oinfo),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agblock_t, agbno)
+               __field(xfs_extlen_t, len)
+               __field(uint64_t, owner)
+               __field(uint64_t, offset)
+               __field(unsigned long, flags)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->agbno = agbno;
+               __entry->len = len;
+               __entry->owner = oinfo->oi_owner;
+               __entry->offset = oinfo->oi_offset;
+               __entry->flags = oinfo->oi_flags;
+               if (unwritten)
+                       __entry->flags |= XFS_RMAP_UNWRITTEN;
+       ),
+       TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%lx",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->agbno,
+                 __entry->len,
+                 __entry->owner,
+                 __entry->offset,
+                 __entry->flags)
+);
+#define DEFINE_RMAP_EVENT(name) \
+DEFINE_EVENT(xfs_rmap_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+                xfs_agblock_t agbno, xfs_extlen_t len, bool unwritten, \
+                struct xfs_owner_info *oinfo), \
+       TP_ARGS(mp, agno, agbno, len, unwritten, oinfo))
+
+/* simple AG-based error/%ip tracepoint class */
+DECLARE_EVENT_CLASS(xfs_ag_error_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int error,
+                unsigned long caller_ip),
+       TP_ARGS(mp, agno, error, caller_ip),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(int, error)
+               __field(unsigned long, caller_ip)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->error = error;
+               __entry->caller_ip = caller_ip;
+       ),
+       TP_printk("dev %d:%d agno %u error %d caller %ps",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->error,
+                 (char *)__entry->caller_ip)
+);
+
+#define DEFINE_AG_ERROR_EVENT(name) \
+DEFINE_EVENT(xfs_ag_error_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int error, \
+                unsigned long caller_ip), \
+       TP_ARGS(mp, agno, error, caller_ip))
+
+DEFINE_RMAP_EVENT(xfs_rmap_unmap);
+DEFINE_RMAP_EVENT(xfs_rmap_unmap_done);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_unmap_error);
+DEFINE_RMAP_EVENT(xfs_rmap_map);
+DEFINE_RMAP_EVENT(xfs_rmap_map_done);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_map_error);
+DEFINE_RMAP_EVENT(xfs_rmap_convert);
+DEFINE_RMAP_EVENT(xfs_rmap_convert_done);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_convert_error);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_convert_state);
+
+DECLARE_EVENT_CLASS(xfs_rmapbt_class,
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+                xfs_agblock_t agbno, xfs_extlen_t len,
+                uint64_t owner, uint64_t offset, unsigned int flags),
+       TP_ARGS(mp, agno, agbno, len, owner, offset, flags),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+               __field(xfs_agnumber_t, agno)
+               __field(xfs_agblock_t, agbno)
+               __field(xfs_extlen_t, len)
+               __field(uint64_t, owner)
+               __field(uint64_t, offset)
+               __field(unsigned int, flags)
+       ),
+       TP_fast_assign(
+               __entry->dev = mp->m_super->s_dev;
+               __entry->agno = agno;
+               __entry->agbno = agbno;
+               __entry->len = len;
+               __entry->owner = owner;
+               __entry->offset = offset;
+               __entry->flags = flags;
+       ),
+       TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%x",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->agno,
+                 __entry->agbno,
+                 __entry->len,
+                 __entry->owner,
+                 __entry->offset,
+                 __entry->flags)
+);
+#define DEFINE_RMAPBT_EVENT(name) \
+DEFINE_EVENT(xfs_rmapbt_class, name, \
+       TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+                xfs_agblock_t agbno, xfs_extlen_t len, \
+                uint64_t owner, uint64_t offset, unsigned int flags), \
+       TP_ARGS(mp, agno, agbno, len, owner, offset, flags))
+
+#define DEFINE_RMAP_DEFERRED_EVENT DEFINE_MAP_EXTENT_DEFERRED_EVENT
+DEFINE_RMAP_DEFERRED_EVENT(xfs_rmap_defer);
+DEFINE_RMAP_DEFERRED_EVENT(xfs_rmap_deferred);
+
+DEFINE_BUSY_EVENT(xfs_rmapbt_alloc_block);
+DEFINE_BUSY_EVENT(xfs_rmapbt_free_block);
+DEFINE_RMAPBT_EVENT(xfs_rmap_update);
+DEFINE_RMAPBT_EVENT(xfs_rmap_insert);
+DEFINE_RMAPBT_EVENT(xfs_rmap_delete);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error);
+DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error);
+DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result);
+DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result);
+DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_result);
+
 #endif /* _TRACE_XFS_H */
 
 #undef TRACE_INCLUDE_PATH
index 9b2b9fa..e2bf86a 100644 (file)
@@ -33,6 +33,9 @@ struct xfs_trans;
 struct xfs_trans_res;
 struct xfs_dquot_acct;
 struct xfs_busy_extent;
+struct xfs_rud_log_item;
+struct xfs_rui_log_item;
+struct xfs_btree_cur;
 
 typedef struct xfs_log_item {
        struct list_head                li_ail;         /* AIL pointers */
@@ -210,17 +213,14 @@ void              xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
 void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
 void           xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
 void           xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
-struct xfs_efi_log_item        *xfs_trans_get_efi(xfs_trans_t *, uint);
-void           xfs_trans_log_efi_extent(xfs_trans_t *,
-                                        struct xfs_efi_log_item *,
-                                        xfs_fsblock_t,
-                                        xfs_extlen_t);
-struct xfs_efd_log_item        *xfs_trans_get_efd(xfs_trans_t *,
+
+void           xfs_extent_free_init_defer_op(void);
+struct xfs_efd_log_item        *xfs_trans_get_efd(struct xfs_trans *,
                                  struct xfs_efi_log_item *,
                                  uint);
 int            xfs_trans_free_extent(struct xfs_trans *,
                                      struct xfs_efd_log_item *, xfs_fsblock_t,
-                                     xfs_extlen_t);
+                                     xfs_extlen_t, struct xfs_owner_info *);
 int            xfs_trans_commit(struct xfs_trans *);
 int            __xfs_trans_roll(struct xfs_trans **, struct xfs_inode *, int *);
 int            xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
@@ -236,4 +236,16 @@ void               xfs_trans_buf_copy_type(struct xfs_buf *dst_bp,
 extern kmem_zone_t     *xfs_trans_zone;
 extern kmem_zone_t     *xfs_log_item_desc_zone;
 
+/* rmap updates */
+enum xfs_rmap_intent_type;
+
+void xfs_rmap_update_init_defer_op(void);
+struct xfs_rud_log_item *xfs_trans_get_rud(struct xfs_trans *tp,
+               struct xfs_rui_log_item *ruip);
+int xfs_trans_log_finish_rmap_update(struct xfs_trans *tp,
+               struct xfs_rud_log_item *rudp, enum xfs_rmap_intent_type type,
+               __uint64_t owner, int whichfork, xfs_fileoff_t startoff,
+               xfs_fsblock_t startblock, xfs_filblks_t blockcount,
+               xfs_exntst_t state, struct xfs_btree_cur **pcur);
+
 #endif /* __XFS_TRANS_H__ */
index a96ae54..459ddec 100644 (file)
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
+#include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_defer.h"
 #include "xfs_trans.h"
 #include "xfs_trans_priv.h"
 #include "xfs_extfree_item.h"
 #include "xfs_alloc.h"
-
-/*
- * This routine is called to allocate an "extent free intention"
- * log item that will hold nextents worth of extents.  The
- * caller must use all nextents extents, because we are not
- * flexible about this at all.
- */
-xfs_efi_log_item_t *
-xfs_trans_get_efi(xfs_trans_t  *tp,
-                 uint          nextents)
-{
-       xfs_efi_log_item_t      *efip;
-
-       ASSERT(tp != NULL);
-       ASSERT(nextents > 0);
-
-       efip = xfs_efi_init(tp->t_mountp, nextents);
-       ASSERT(efip != NULL);
-
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
-       xfs_trans_add_item(tp, &efip->efi_item);
-       return efip;
-}
-
-/*
- * This routine is called to indicate that the described
- * extent is to be logged as needing to be freed.  It should
- * be called once for each extent to be freed.
- */
-void
-xfs_trans_log_efi_extent(xfs_trans_t           *tp,
-                        xfs_efi_log_item_t     *efip,
-                        xfs_fsblock_t          start_block,
-                        xfs_extlen_t           ext_len)
-{
-       uint                    next_extent;
-       xfs_extent_t            *extp;
-
-       tp->t_flags |= XFS_TRANS_DIRTY;
-       efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
-
-       /*
-        * atomic_inc_return gives us the value after the increment;
-        * we want to use it as an array index so we need to subtract 1 from
-        * it.
-        */
-       next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
-       ASSERT(next_extent < efip->efi_format.efi_nextents);
-       extp = &(efip->efi_format.efi_extents[next_extent]);
-       extp->ext_start = start_block;
-       extp->ext_len = ext_len;
-}
-
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
 
 /*
  * This routine is called to allocate an "extent free done"
@@ -88,12 +37,12 @@ xfs_trans_log_efi_extent(xfs_trans_t                *tp,
  * caller must use all nextents extents, because we are not
  * flexible about this at all.
  */
-xfs_efd_log_item_t *
-xfs_trans_get_efd(xfs_trans_t          *tp,
-                 xfs_efi_log_item_t    *efip,
-                 uint                  nextents)
+struct xfs_efd_log_item *
+xfs_trans_get_efd(struct xfs_trans             *tp,
+                 struct xfs_efi_log_item       *efip,
+                 uint                          nextents)
 {
-       xfs_efd_log_item_t      *efdp;
+       struct xfs_efd_log_item                 *efdp;
 
        ASSERT(tp != NULL);
        ASSERT(nextents > 0);
@@ -118,13 +67,19 @@ xfs_trans_free_extent(
        struct xfs_trans        *tp,
        struct xfs_efd_log_item *efdp,
        xfs_fsblock_t           start_block,
-       xfs_extlen_t            ext_len)
+       xfs_extlen_t            ext_len,
+       struct xfs_owner_info   *oinfo)
 {
+       struct xfs_mount        *mp = tp->t_mountp;
        uint                    next_extent;
+       xfs_agnumber_t          agno = XFS_FSB_TO_AGNO(mp, start_block);
+       xfs_agblock_t           agbno = XFS_FSB_TO_AGBNO(mp, start_block);
        struct xfs_extent       *extp;
        int                     error;
 
-       error = xfs_free_extent(tp, start_block, ext_len);
+       trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno, ext_len);
+
+       error = xfs_free_extent(tp, start_block, ext_len, oinfo);
 
        /*
         * Mark the transaction dirty, even on error. This ensures the
@@ -145,3 +100,139 @@ xfs_trans_free_extent(
 
        return error;
 }
+
+/* Sort bmap items by AG. */
+static int
+xfs_extent_free_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
+{
+       struct xfs_mount                *mp = priv;
+       struct xfs_extent_free_item     *ra;
+       struct xfs_extent_free_item     *rb;
+
+       ra = container_of(a, struct xfs_extent_free_item, xefi_list);
+       rb = container_of(b, struct xfs_extent_free_item, xefi_list);
+       return  XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) -
+               XFS_FSB_TO_AGNO(mp, rb->xefi_startblock);
+}
+
+/* Get an EFI. */
+STATIC void *
+xfs_extent_free_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
+{
+       struct xfs_efi_log_item         *efip;
+
+       ASSERT(tp != NULL);
+       ASSERT(count > 0);
+
+       efip = xfs_efi_init(tp->t_mountp, count);
+       ASSERT(efip != NULL);
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       xfs_trans_add_item(tp, &efip->efi_item);
+       return efip;
+}
+
+/* Log a free extent to the intent item. */
+STATIC void
+xfs_extent_free_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
+{
+       struct xfs_efi_log_item         *efip = intent;
+       struct xfs_extent_free_item     *free;
+       uint                            next_extent;
+       struct xfs_extent               *extp;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+       /*
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
+        */
+       next_extent = atomic_inc_return(&efip->efi_next_extent) - 1;
+       ASSERT(next_extent < efip->efi_format.efi_nextents);
+       extp = &efip->efi_format.efi_extents[next_extent];
+       extp->ext_start = free->xefi_startblock;
+       extp->ext_len = free->xefi_blockcount;
+}
+
+/* Get an EFD so we can process all the free extents. */
+STATIC void *
+xfs_extent_free_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_efd(tp, intent, count);
+}
+
+/* Process a free extent. */
+STATIC int
+xfs_extent_free_finish_item(
+       struct xfs_trans                *tp,
+       struct xfs_defer_ops            *dop,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
+{
+       struct xfs_extent_free_item     *free;
+       int                             error;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+       error = xfs_trans_free_extent(tp, done_item,
+                       free->xefi_startblock,
+                       free->xefi_blockcount,
+                       &free->xefi_oinfo);
+       kmem_free(free);
+       return error;
+}
+
+/* Abort all pending EFIs. */
+STATIC void
+xfs_extent_free_abort_intent(
+       void                            *intent)
+{
+       xfs_efi_release(intent);
+}
+
+/* Cancel a free extent. */
+STATIC void
+xfs_extent_free_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_extent_free_item     *free;
+
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+       kmem_free(free);
+}
+
+static const struct xfs_defer_op_type xfs_extent_free_defer_type = {
+       .type           = XFS_DEFER_OPS_TYPE_FREE,
+       .max_items      = XFS_EFI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_extent_free_diff_items,
+       .create_intent  = xfs_extent_free_create_intent,
+       .abort_intent   = xfs_extent_free_abort_intent,
+       .log_item       = xfs_extent_free_log_item,
+       .create_done    = xfs_extent_free_create_done,
+       .finish_item    = xfs_extent_free_finish_item,
+       .cancel_item    = xfs_extent_free_cancel_item,
+};
+
+/* Register the deferred op type. */
+void
+xfs_extent_free_init_defer_op(void)
+{
+       xfs_defer_init_op_type(&xfs_extent_free_defer_type);
+}
diff --git a/fs/xfs/xfs_trans_rmap.c b/fs/xfs/xfs_trans_rmap.c
new file mode 100644 (file)
index 0000000..5a50ef8
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.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 would 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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_rmap_item.h"
+#include "xfs_alloc.h"
+#include "xfs_rmap.h"
+
+/* Set the map extent flags for this reverse mapping. */
+static void
+xfs_trans_set_rmap_flags(
+       struct xfs_map_extent           *rmap,
+       enum xfs_rmap_intent_type       type,
+       int                             whichfork,
+       xfs_exntst_t                    state)
+{
+       rmap->me_flags = 0;
+       if (state == XFS_EXT_UNWRITTEN)
+               rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
+       if (whichfork == XFS_ATTR_FORK)
+               rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
+       switch (type) {
+       case XFS_RMAP_MAP:
+               rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
+               break;
+       case XFS_RMAP_UNMAP:
+               rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
+               break;
+       case XFS_RMAP_CONVERT:
+               rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
+               break;
+       case XFS_RMAP_ALLOC:
+               rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
+               break;
+       case XFS_RMAP_FREE:
+               rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
+               break;
+       default:
+               ASSERT(0);
+       }
+}
+
+struct xfs_rud_log_item *
+xfs_trans_get_rud(
+       struct xfs_trans                *tp,
+       struct xfs_rui_log_item         *ruip)
+{
+       struct xfs_rud_log_item         *rudp;
+
+       rudp = xfs_rud_init(tp->t_mountp, ruip);
+       xfs_trans_add_item(tp, &rudp->rud_item);
+       return rudp;
+}
+
+/*
+ * Finish an rmap update and log it to the RUD. Note that the transaction is
+ * marked dirty regardless of whether the rmap update succeeds or fails to
+ * support the RUI/RUD lifecycle rules.
+ */
+int
+xfs_trans_log_finish_rmap_update(
+       struct xfs_trans                *tp,
+       struct xfs_rud_log_item         *rudp,
+       enum xfs_rmap_intent_type       type,
+       __uint64_t                      owner,
+       int                             whichfork,
+       xfs_fileoff_t                   startoff,
+       xfs_fsblock_t                   startblock,
+       xfs_filblks_t                   blockcount,
+       xfs_exntst_t                    state,
+       struct xfs_btree_cur            **pcur)
+{
+       int                             error;
+
+       error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff,
+                       startblock, blockcount, state, pcur);
+
+       /*
+        * Mark the transaction dirty, even on error. This ensures the
+        * transaction is aborted, which:
+        *
+        * 1.) releases the RUI and frees the RUD
+        * 2.) shuts down the filesystem
+        */
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       rudp->rud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+       return error;
+}
+
+/* Sort rmap intents by AG. */
+static int
+xfs_rmap_update_diff_items(
+       void                            *priv,
+       struct list_head                *a,
+       struct list_head                *b)
+{
+       struct xfs_mount                *mp = priv;
+       struct xfs_rmap_intent          *ra;
+       struct xfs_rmap_intent          *rb;
+
+       ra = container_of(a, struct xfs_rmap_intent, ri_list);
+       rb = container_of(b, struct xfs_rmap_intent, ri_list);
+       return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
+               XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
+}
+
+/* Get an RUI. */
+STATIC void *
+xfs_rmap_update_create_intent(
+       struct xfs_trans                *tp,
+       unsigned int                    count)
+{
+       struct xfs_rui_log_item         *ruip;
+
+       ASSERT(tp != NULL);
+       ASSERT(count > 0);
+
+       ruip = xfs_rui_init(tp->t_mountp, count);
+       ASSERT(ruip != NULL);
+
+       /*
+        * Get a log_item_desc to point at the new item.
+        */
+       xfs_trans_add_item(tp, &ruip->rui_item);
+       return ruip;
+}
+
+/* Log rmap updates in the intent item. */
+STATIC void
+xfs_rmap_update_log_item(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       struct list_head                *item)
+{
+       struct xfs_rui_log_item         *ruip = intent;
+       struct xfs_rmap_intent          *rmap;
+       uint                            next_extent;
+       struct xfs_map_extent           *map;
+
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+
+       tp->t_flags |= XFS_TRANS_DIRTY;
+       ruip->rui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+       /*
+        * atomic_inc_return gives us the value after the increment;
+        * we want to use it as an array index so we need to subtract 1 from
+        * it.
+        */
+       next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
+       ASSERT(next_extent < ruip->rui_format.rui_nextents);
+       map = &ruip->rui_format.rui_extents[next_extent];
+       map->me_owner = rmap->ri_owner;
+       map->me_startblock = rmap->ri_bmap.br_startblock;
+       map->me_startoff = rmap->ri_bmap.br_startoff;
+       map->me_len = rmap->ri_bmap.br_blockcount;
+       xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork,
+                       rmap->ri_bmap.br_state);
+}
+
+/* Get an RUD so we can process all the deferred rmap updates. */
+STATIC void *
+xfs_rmap_update_create_done(
+       struct xfs_trans                *tp,
+       void                            *intent,
+       unsigned int                    count)
+{
+       return xfs_trans_get_rud(tp, intent);
+}
+
+/* Process a deferred rmap update. */
+STATIC int
+xfs_rmap_update_finish_item(
+       struct xfs_trans                *tp,
+       struct xfs_defer_ops            *dop,
+       struct list_head                *item,
+       void                            *done_item,
+       void                            **state)
+{
+       struct xfs_rmap_intent          *rmap;
+       int                             error;
+
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+       error = xfs_trans_log_finish_rmap_update(tp, done_item,
+                       rmap->ri_type,
+                       rmap->ri_owner, rmap->ri_whichfork,
+                       rmap->ri_bmap.br_startoff,
+                       rmap->ri_bmap.br_startblock,
+                       rmap->ri_bmap.br_blockcount,
+                       rmap->ri_bmap.br_state,
+                       (struct xfs_btree_cur **)state);
+       kmem_free(rmap);
+       return error;
+}
+
+/* Clean up after processing deferred rmaps. */
+STATIC void
+xfs_rmap_update_finish_cleanup(
+       struct xfs_trans        *tp,
+       void                    *state,
+       int                     error)
+{
+       struct xfs_btree_cur    *rcur = state;
+
+       xfs_rmap_finish_one_cleanup(tp, rcur, error);
+}
+
+/* Abort all pending RUIs. */
+STATIC void
+xfs_rmap_update_abort_intent(
+       void                            *intent)
+{
+       xfs_rui_release(intent);
+}
+
+/* Cancel a deferred rmap update. */
+STATIC void
+xfs_rmap_update_cancel_item(
+       struct list_head                *item)
+{
+       struct xfs_rmap_intent          *rmap;
+
+       rmap = container_of(item, struct xfs_rmap_intent, ri_list);
+       kmem_free(rmap);
+}
+
+static const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
+       .type           = XFS_DEFER_OPS_TYPE_RMAP,
+       .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
+       .diff_items     = xfs_rmap_update_diff_items,
+       .create_intent  = xfs_rmap_update_create_intent,
+       .abort_intent   = xfs_rmap_update_abort_intent,
+       .log_item       = xfs_rmap_update_log_item,
+       .create_done    = xfs_rmap_update_create_done,
+       .finish_item    = xfs_rmap_update_finish_item,
+       .finish_cleanup = xfs_rmap_update_finish_cleanup,
+       .cancel_item    = xfs_rmap_update_cancel_item,
+};
+
+/* Register the deferred op type. */
+void
+xfs_rmap_update_init_defer_op(void)
+{
+       xfs_defer_init_op_type(&xfs_rmap_update_defer_type);
+}
index dd86c5f..d7d0f49 100644 (file)
@@ -13,7 +13,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
 }
 #endif
 
-void __iomem *__init_refok
+void __iomem *__ref
 acpi_os_map_iomem(acpi_physical_address phys, acpi_size size);
 void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size);
 void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size);
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
deleted file mode 100644 (file)
index 4e3b655..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* 
- * include/asm-generic/rtc.h
- *
- * Author: Tom Rini <trini@mvista.com>
- *
- * Based on:
- * drivers/char/rtc.c
- *
- * Please read the COPYING file for all license details.
- */
-
-#ifndef __ASM_RTC_H__
-#define __ASM_RTC_H__
-
-#include <linux/mc146818rtc.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/delay.h>
-#ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#endif
-
-#define RTC_PIE 0x40           /* periodic interrupt enable */
-#define RTC_AIE 0x20           /* alarm interrupt enable */
-#define RTC_UIE 0x10           /* update-finished interrupt enable */
-
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100     /* battery bad */
-#define RTC_SQWE 0x08          /* enable square-wave output */
-#define RTC_DM_BINARY 0x04     /* all time/date values are BCD if clear */
-#define RTC_24H 0x02           /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01                /* auto switch DST - works f. USA only */
-
-/*
- * Returns true if a clock update is in progress
- */
-static inline unsigned char rtc_is_updating(void)
-{
-       unsigned char uip;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-       return uip;
-}
-
-static inline unsigned int __get_rtc_time(struct rtc_time *time)
-{
-       unsigned char ctrl;
-       unsigned long flags;
-       unsigned char century = 0;
-
-#ifdef CONFIG_MACH_DECSTATION
-       unsigned int real_year;
-#endif
-
-       /*
-        * read RTC once any update in progress is done. The update
-        * can take just over 2ms. We wait 20ms. There is no need to
-        * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
-        * If you need to know *exactly* when a second has started, enable
-        * periodic update complete interrupts, (via ioctl) and then 
-        * immediately read /dev/rtc which will block until you get the IRQ.
-        * Once the read clears, read the RTC time (again via ioctl). Easy.
-        */
-       if (rtc_is_updating())
-               mdelay(20);
-
-       /*
-        * Only the values that we read from the RTC are set. We leave
-        * tm_wday, tm_yday and tm_isdst untouched. Even though the
-        * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
-        * by the RTC when initially set to a non-zero value.
-        */
-       spin_lock_irqsave(&rtc_lock, flags);
-       time->tm_sec = CMOS_READ(RTC_SECONDS);
-       time->tm_min = CMOS_READ(RTC_MINUTES);
-       time->tm_hour = CMOS_READ(RTC_HOURS);
-       time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
-       time->tm_mon = CMOS_READ(RTC_MONTH);
-       time->tm_year = CMOS_READ(RTC_YEAR);
-#ifdef CONFIG_MACH_DECSTATION
-       real_year = CMOS_READ(RTC_DEC_YEAR);
-#endif
-#ifdef CONFIG_ACPI
-       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
-           acpi_gbl_FADT.century)
-               century = CMOS_READ(acpi_gbl_FADT.century);
-#endif
-       ctrl = CMOS_READ(RTC_CONTROL);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-       {
-               time->tm_sec = bcd2bin(time->tm_sec);
-               time->tm_min = bcd2bin(time->tm_min);
-               time->tm_hour = bcd2bin(time->tm_hour);
-               time->tm_mday = bcd2bin(time->tm_mday);
-               time->tm_mon = bcd2bin(time->tm_mon);
-               time->tm_year = bcd2bin(time->tm_year);
-               century = bcd2bin(century);
-       }
-
-#ifdef CONFIG_MACH_DECSTATION
-       time->tm_year += real_year - 72;
-#endif
-
-       if (century)
-               time->tm_year += (century - 19) * 100;
-
-       /*
-        * Account for differences between how the RTC uses the values
-        * and how they are defined in a struct rtc_time;
-        */
-       if (time->tm_year <= 69)
-               time->tm_year += 100;
-
-       time->tm_mon--;
-
-       return RTC_24H;
-}
-
-#ifndef get_rtc_time
-#define get_rtc_time   __get_rtc_time
-#endif
-
-/* Set the current date and time in the real time clock. */
-static inline int __set_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-       unsigned char mon, day, hrs, min, sec;
-       unsigned char save_control, save_freq_select;
-       unsigned int yrs;
-#ifdef CONFIG_MACH_DECSTATION
-       unsigned int real_yrs, leap_yr;
-#endif
-       unsigned char century = 0;
-
-       yrs = time->tm_year;
-       mon = time->tm_mon + 1;   /* tm_mon starts at zero */
-       day = time->tm_mday;
-       hrs = time->tm_hour;
-       min = time->tm_min;
-       sec = time->tm_sec;
-
-       if (yrs > 255)  /* They are unsigned */
-               return -EINVAL;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-#ifdef CONFIG_MACH_DECSTATION
-       real_yrs = yrs;
-       leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
-                       !((yrs + 1900) % 400));
-       yrs = 72;
-
-       /*
-        * We want to keep the year set to 73 until March
-        * for non-leap years, so that Feb, 29th is handled
-        * correctly.
-        */
-       if (!leap_yr && mon < 3) {
-               real_yrs--;
-               yrs = 73;
-       }
-#endif
-
-#ifdef CONFIG_ACPI
-       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
-           acpi_gbl_FADT.century) {
-               century = (yrs + 1900) / 100;
-               yrs %= 100;
-       }
-#endif
-
-       /* These limits and adjustments are independent of
-        * whether the chip is in binary mode or not.
-        */
-       if (yrs > 169) {
-               spin_unlock_irqrestore(&rtc_lock, flags);
-               return -EINVAL;
-       }
-
-       if (yrs >= 100)
-               yrs -= 100;
-
-       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
-           || RTC_ALWAYS_BCD) {
-               sec = bin2bcd(sec);
-               min = bin2bcd(min);
-               hrs = bin2bcd(hrs);
-               day = bin2bcd(day);
-               mon = bin2bcd(mon);
-               yrs = bin2bcd(yrs);
-               century = bin2bcd(century);
-       }
-
-       save_control = CMOS_READ(RTC_CONTROL);
-       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-#ifdef CONFIG_MACH_DECSTATION
-       CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
-#endif
-       CMOS_WRITE(yrs, RTC_YEAR);
-       CMOS_WRITE(mon, RTC_MONTH);
-       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
-       CMOS_WRITE(hrs, RTC_HOURS);
-       CMOS_WRITE(min, RTC_MINUTES);
-       CMOS_WRITE(sec, RTC_SECONDS);
-#ifdef CONFIG_ACPI
-       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
-           acpi_gbl_FADT.century)
-               CMOS_WRITE(century, acpi_gbl_FADT.century);
-#endif
-
-       CMOS_WRITE(save_control, RTC_CONTROL);
-       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return 0;
-}
-
-#ifndef set_rtc_time
-#define set_rtc_time   __set_rtc_time
-#endif
-
-static inline unsigned int get_rtc_ss(void)
-{
-       struct rtc_time h;
-
-       get_rtc_time(&h);
-       return h.tm_sec;
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
-       return -EINVAL;
-}
-
-#endif /* __ASM_RTC_H__ */
index 54643d1..2456397 100644 (file)
 
 #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name)
 #define __OF_TABLE(cfg, name)  ___OF_TABLE(cfg, name)
-#define OF_TABLE(cfg, name)    __OF_TABLE(config_enabled(cfg), name)
+#define OF_TABLE(cfg, name)    __OF_TABLE(IS_ENABLED(cfg), name)
 #define _OF_TABLE_0(name)
 #define _OF_TABLE_1(name)                                              \
        . = ALIGN(8);                                                   \
index 3edeaf8..44e0708 100644 (file)
@@ -308,6 +308,7 @@ struct drm_plane_helper_funcs;
  * @mode_changed: crtc_state->mode or crtc_state->enable has been changed
  * @active_changed: crtc_state->active has been toggled.
  * @connectors_changed: connectors to this crtc have been updated
+ * @zpos_changed: zpos values of planes on this crtc have been updated
  * @color_mgmt_changed: color management properties have changed (degamma or
  *     gamma LUT or CSC matrix)
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
@@ -344,6 +345,7 @@ struct drm_crtc_state {
        bool mode_changed : 1;
        bool active_changed : 1;
        bool connectors_changed : 1;
+       bool zpos_changed : 1;
        bool color_mgmt_changed : 1;
 
        /* attached planes bitmask:
@@ -1409,6 +1411,9 @@ struct drm_connector {
  * @src_w: width of visible portion of plane (in 16.16)
  * @src_h: height of visible portion of plane (in 16.16)
  * @rotation: rotation of the plane
+ * @zpos: priority of the given plane on crtc (optional)
+ * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
+ *     where N is the number of active planes for given crtc
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_plane_state {
@@ -1429,6 +1434,10 @@ struct drm_plane_state {
        /* Plane rotation */
        unsigned int rotation;
 
+       /* Plane zpos */
+       unsigned int zpos;
+       unsigned int normalized_zpos;
+
        struct drm_atomic_state *state;
 };
 
@@ -1688,6 +1697,7 @@ enum drm_plane_type {
  * @properties: property tracking for this plane
  * @type: type of plane (overlay, primary, cursor)
  * @state: current atomic state for this plane
+ * @zpos_property: zpos property for this plane
  * @helper_private: mid-layer private data
  */
 struct drm_plane {
@@ -1732,6 +1742,8 @@ struct drm_plane {
        const struct drm_plane_helper_funcs *helper_private;
 
        struct drm_plane_state *state;
+
+       struct drm_property *zpos_property;
 };
 
 /**
@@ -2958,6 +2970,14 @@ extern void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
                                       uint degamma_lut_size,
                                       bool has_ctm,
                                       uint gamma_lut_size);
+
+int drm_plane_create_zpos_property(struct drm_plane *plane,
+                                  unsigned int zpos,
+                                  unsigned int min, unsigned int max);
+
+int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
+                                            unsigned int zpos);
+
 /* Helpers */
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
                                             uint32_t id, uint32_t type);
index 72dee12..63b8bd5 100644 (file)
@@ -657,6 +657,8 @@ struct edp_vsc_psr {
 #define EDP_VSC_PSR_UPDATE_RFB         (1<<1)
 #define EDP_VSC_PSR_CRC_VALUES_VALID   (1<<2)
 
+int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]);
+
 static inline int
 drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
index 4348d6d..99c6d01 100644 (file)
@@ -962,6 +962,7 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
  *
  * @bo: A pointer to a struct ttm_buffer_object.
  * @evict: 1: This is an eviction. Don't try to pipeline.
+ * @interruptible: Sleep interruptible if waiting.
  * @no_wait_gpu: Return immediately if the GPU is busy.
  * @new_mem: struct ttm_mem_reg indicating where to move.
  *
@@ -976,7 +977,7 @@ void ttm_mem_io_free(struct ttm_bo_device *bdev,
  */
 
 extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
-                          bool evict, bool no_wait_gpu,
+                          bool evict, bool interruptible, bool no_wait_gpu,
                           struct ttm_mem_reg *new_mem);
 
 /**
index da0a524..19b698e 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
+ * Copyright (C) 2015, 2016 ARM 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
  * 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
-#ifndef __ASM_ARM_KVM_VGIC_H
-#define __ASM_ARM_KVM_VGIC_H
-
-#ifdef CONFIG_KVM_NEW_VGIC
-#include <kvm/vgic/vgic.h>
-#else
+#ifndef __KVM_ARM_VGIC_H
+#define __KVM_ARM_VGIC_H
 
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <kvm/iodev.h>
-#include <linux/irqchip/arm-gic-common.h>
+#include <linux/list.h>
 
-#define VGIC_NR_IRQS_LEGACY    256
+#define VGIC_V3_MAX_CPUS       255
+#define VGIC_V2_MAX_CPUS       8
+#define VGIC_NR_IRQS_LEGACY     256
 #define VGIC_NR_SGIS           16
 #define VGIC_NR_PPIS           16
 #define VGIC_NR_PRIVATE_IRQS   (VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE       (VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI           1019
+#define VGIC_MAX_RESERVED      1023
+#define VGIC_MIN_LPI           8192
+#define KVM_IRQCHIP_NUM_PINS   (1020 - 32)
 
-#define VGIC_V2_MAX_LRS                (1 << 6)
-#define VGIC_V3_MAX_LRS                16
-#define VGIC_MAX_IRQS          1024
-#define VGIC_V2_MAX_CPUS       8
-#define VGIC_V3_MAX_CPUS       255
+enum vgic_type {
+       VGIC_V2,                /* Good ol' GICv2 */
+       VGIC_V3,                /* New fancy GICv3 */
+};
 
-#if (VGIC_NR_IRQS_LEGACY & 31)
-#error "VGIC_NR_IRQS must be a multiple of 32"
-#endif
+/* same for all guests, as depending only on the _host's_ GIC model */
+struct vgic_global {
+       /* type of the host GIC */
+       enum vgic_type          type;
 
-#if (VGIC_NR_IRQS_LEGACY > VGIC_MAX_IRQS)
-#error "VGIC_NR_IRQS must be <= 1024"
-#endif
+       /* Physical address of vgic virtual cpu interface */
+       phys_addr_t             vcpu_base;
 
-/*
- * The GIC distributor registers describing interrupts have two parts:
- * - 32 per-CPU interrupts (SGI + PPI)
- * - a bunch of shared interrupts (SPI)
- */
-struct vgic_bitmap {
-       /*
-        * - One UL per VCPU for private interrupts (assumes UL is at
-        *   least 32 bits)
-        * - As many UL as necessary for shared interrupts.
-        *
-        * The private interrupts are accessed via the "private"
-        * field, one UL per vcpu (the state for vcpu n is in
-        * private[n]). The shared interrupts are accessed via the
-        * "shared" pointer (IRQn state is at bit n-32 in the bitmap).
-        */
-       unsigned long *private;
-       unsigned long *shared;
-};
+       /* virtual control interface mapping */
+       void __iomem            *vctrl_base;
 
-struct vgic_bytemap {
-       /*
-        * - 8 u32 per VCPU for private interrupts
-        * - As many u32 as necessary for shared interrupts.
-        *
-        * The private interrupts are accessed via the "private"
-        * field, (the state for vcpu n is in private[n*8] to
-        * private[n*8 + 7]). The shared interrupts are accessed via
-        * the "shared" pointer (IRQn state is at byte (n-32)%4 of the
-        * shared[(n-32)/4] word).
-        */
-       u32 *private;
-       u32 *shared;
-};
+       /* Number of implemented list registers */
+       int                     nr_lr;
 
-struct kvm_vcpu;
+       /* Maintenance IRQ number */
+       unsigned int            maint_irq;
 
-enum vgic_type {
-       VGIC_V2,                /* Good ol' GICv2 */
-       VGIC_V3,                /* New fancy GICv3 */
+       /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
+       int                     max_gic_vcpus;
+
+       /* Only needed for the legacy KVM_CREATE_IRQCHIP */
+       bool                    can_emulate_gicv2;
 };
 
-#define LR_STATE_PENDING       (1 << 0)
-#define LR_STATE_ACTIVE                (1 << 1)
-#define LR_STATE_MASK          (3 << 0)
-#define LR_EOI_INT             (1 << 2)
-#define LR_HW                  (1 << 3)
+extern struct vgic_global kvm_vgic_global_state;
 
-struct vgic_lr {
-       unsigned irq:10;
-       union {
-               unsigned hwirq:10;
-               unsigned source:3;
-       };
-       unsigned state:4;
-};
+#define VGIC_V2_MAX_LRS                (1 << 6)
+#define VGIC_V3_MAX_LRS                16
+#define VGIC_V3_LR_INDEX(lr)   (VGIC_V3_MAX_LRS - 1 - lr)
 
-struct vgic_vmcr {
-       u32     ctlr;
-       u32     abpr;
-       u32     bpr;
-       u32     pmr;
+enum vgic_irq_config {
+       VGIC_CONFIG_EDGE = 0,
+       VGIC_CONFIG_LEVEL
 };
 
-struct vgic_ops {
-       struct vgic_lr  (*get_lr)(const struct kvm_vcpu *, int);
-       void    (*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
-       u64     (*get_elrsr)(const struct kvm_vcpu *vcpu);
-       u64     (*get_eisr)(const struct kvm_vcpu *vcpu);
-       void    (*clear_eisr)(struct kvm_vcpu *vcpu);
-       u32     (*get_interrupt_status)(const struct kvm_vcpu *vcpu);
-       void    (*enable_underflow)(struct kvm_vcpu *vcpu);
-       void    (*disable_underflow)(struct kvm_vcpu *vcpu);
-       void    (*get_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-       void    (*set_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-       void    (*enable)(struct kvm_vcpu *vcpu);
+struct vgic_irq {
+       spinlock_t irq_lock;            /* Protects the content of the struct */
+       struct list_head lpi_list;      /* Used to link all LPIs together */
+       struct list_head ap_list;
+
+       struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
+                                        * SPIs and LPIs: The VCPU whose ap_list
+                                        * this is queued on.
+                                        */
+
+       struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
+                                        * be sent to, as a result of the
+                                        * targets reg (v2) or the
+                                        * affinity reg (v3).
+                                        */
+
+       u32 intid;                      /* Guest visible INTID */
+       bool pending;
+       bool line_level;                /* Level only */
+       bool soft_pending;              /* Level only */
+       bool active;                    /* not used for LPIs */
+       bool enabled;
+       bool hw;                        /* Tied to HW IRQ */
+       struct kref refcount;           /* Used for LPIs */
+       u32 hwintid;                    /* HW INTID number */
+       union {
+               u8 targets;                     /* GICv2 target VCPUs mask */
+               u32 mpidr;                      /* GICv3 target VCPU */
+       };
+       u8 source;                      /* GICv2 SGIs only */
+       u8 priority;
+       enum vgic_irq_config config;    /* Level or edge */
 };
 
-struct vgic_params {
-       /* vgic type */
-       enum vgic_type  type;
-       /* Physical address of vgic virtual cpu interface */
-       phys_addr_t     vcpu_base;
-       /* Number of list registers */
-       u32             nr_lr;
-       /* Interrupt number */
-       unsigned int    maint_irq;
-       /* Virtual control interface base address */
-       void __iomem    *vctrl_base;
-       int             max_gic_vcpus;
-       /* Only needed for the legacy KVM_CREATE_IRQCHIP */
-       bool            can_emulate_gicv2;
-};
+struct vgic_register_region;
+struct vgic_its;
 
-struct vgic_vm_ops {
-       bool    (*queue_sgi)(struct kvm_vcpu *, int irq);
-       void    (*add_sgi_source)(struct kvm_vcpu *, int irq, int source);
-       int     (*init_model)(struct kvm *);
-       int     (*map_resources)(struct kvm *, const struct vgic_params *);
+enum iodev_type {
+       IODEV_CPUIF,
+       IODEV_DIST,
+       IODEV_REDIST,
+       IODEV_ITS
 };
 
 struct vgic_io_device {
-       gpa_t addr;
-       int len;
-       const struct vgic_io_range *reg_ranges;
-       struct kvm_vcpu *redist_vcpu;
+       gpa_t base_addr;
+       union {
+               struct kvm_vcpu *redist_vcpu;
+               struct vgic_its *its;
+       };
+       const struct vgic_register_region *regions;
+       enum iodev_type iodev_type;
+       int nr_regions;
        struct kvm_io_device dev;
 };
 
-struct irq_phys_map {
-       u32                     virt_irq;
-       u32                     phys_irq;
-};
-
-struct irq_phys_map_entry {
-       struct list_head        entry;
-       struct rcu_head         rcu;
-       struct irq_phys_map     map;
+struct vgic_its {
+       /* The base address of the ITS control register frame */
+       gpa_t                   vgic_its_base;
+
+       bool                    enabled;
+       bool                    initialized;
+       struct vgic_io_device   iodev;
+       struct kvm_device       *dev;
+
+       /* These registers correspond to GITS_BASER{0,1} */
+       u64                     baser_device_table;
+       u64                     baser_coll_table;
+
+       /* Protects the command queue */
+       struct mutex            cmd_lock;
+       u64                     cbaser;
+       u32                     creadr;
+       u32                     cwriter;
+
+       /* Protects the device and collection lists */
+       struct mutex            its_lock;
+       struct list_head        device_list;
+       struct list_head        collection_list;
 };
 
 struct vgic_dist {
-       spinlock_t              lock;
        bool                    in_kernel;
        bool                    ready;
+       bool                    initialized;
 
        /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
        u32                     vgic_model;
 
-       int                     nr_cpus;
-       int                     nr_irqs;
+       /* Do injected MSIs require an additional device ID? */
+       bool                    msis_require_devid;
 
+       int                     nr_spis;
+
+       /* TODO: Consider moving to global state */
        /* Virtual control interface mapping */
        void __iomem            *vctrl_base;
 
-       /* Distributor and vcpu interface mapping in the guest */
-       phys_addr_t             vgic_dist_base;
-       /* GICv2 and GICv3 use different mapped register blocks */
+       /* base addresses in guest physical address space: */
+       gpa_t                   vgic_dist_base;         /* distributor */
        union {
-               phys_addr_t             vgic_cpu_base;
-               phys_addr_t             vgic_redist_base;
+               /* either a GICv2 CPU interface */
+               gpa_t                   vgic_cpu_base;
+               /* or a number of GICv3 redistributor regions */
+               gpa_t                   vgic_redist_base;
        };
 
-       /* Distributor enabled */
-       u32                     enabled;
-
-       /* Interrupt enabled (one bit per IRQ) */
-       struct vgic_bitmap      irq_enabled;
-
-       /* Level-triggered interrupt external input is asserted */
-       struct vgic_bitmap      irq_level;
-
-       /*
-        * Interrupt state is pending on the distributor
-        */
-       struct vgic_bitmap      irq_pending;
-
-       /*
-        * Tracks writes to GICD_ISPENDRn and GICD_ICPENDRn for level-triggered
-        * interrupts.  Essentially holds the state of the flip-flop in
-        * Figure 4-10 on page 4-101 in ARM IHI 0048B.b.
-        * Once set, it is only cleared for level-triggered interrupts on
-        * guest ACKs (when we queue it) or writes to GICD_ICPENDRn.
-        */
-       struct vgic_bitmap      irq_soft_pend;
-
-       /* Level-triggered interrupt queued on VCPU interface */
-       struct vgic_bitmap      irq_queued;
+       /* distributor enabled */
+       bool                    enabled;
 
-       /* Interrupt was active when unqueue from VCPU interface */
-       struct vgic_bitmap      irq_active;
+       struct vgic_irq         *spis;
 
-       /* Interrupt priority. Not used yet. */
-       struct vgic_bytemap     irq_priority;
-
-       /* Level/edge triggered */
-       struct vgic_bitmap      irq_cfg;
-
-       /*
-        * Source CPU per SGI and target CPU:
-        *
-        * Each byte represent a SGI observable on a VCPU, each bit of
-        * this byte indicating if the corresponding VCPU has
-        * generated this interrupt. This is a GICv2 feature only.
-        *
-        * For VCPUn (n < 8), irq_sgi_sources[n*16] to [n*16 + 15] are
-        * the SGIs observable on VCPUn.
-        */
-       u8                      *irq_sgi_sources;
+       struct vgic_io_device   dist_iodev;
 
-       /*
-        * Target CPU for each SPI:
-        *
-        * Array of available SPI, each byte indicating the target
-        * VCPU for SPI. IRQn (n >=32) is at irq_spi_cpu[n-32].
-        */
-       u8                      *irq_spi_cpu;
+       bool                    has_its;
 
        /*
-        * Reverse lookup of irq_spi_cpu for faster compute pending:
-        *
-        * Array of bitmaps, one per VCPU, describing if IRQn is
-        * routed to a particular VCPU.
+        * Contains the attributes and gpa of the LPI configuration table.
+        * Since we report GICR_TYPER.CommonLPIAff as 0b00, we can share
+        * one address across all redistributors.
+        * GICv3 spec: 6.1.2 "LPI Configuration tables"
         */
-       struct vgic_bitmap      *irq_spi_target;
-
-       /* Target MPIDR for each IRQ (needed for GICv3 IROUTERn) only */
-       u32                     *irq_spi_mpidr;
-
-       /* Bitmap indicating which CPU has something pending */
-       unsigned long           *irq_pending_on_cpu;
+       u64                     propbaser;
 
-       /* Bitmap indicating which CPU has active IRQs */
-       unsigned long           *irq_active_on_cpu;
-
-       struct vgic_vm_ops      vm_ops;
-       struct vgic_io_device   dist_iodev;
-       struct vgic_io_device   *redist_iodevs;
-
-       /* Virtual irq to hwirq mapping */
-       spinlock_t              irq_phys_map_lock;
-       struct list_head        irq_phys_map_list;
+       /* Protects the lpi_list and the count value below. */
+       spinlock_t              lpi_list_lock;
+       struct list_head        lpi_list_head;
+       int                     lpi_list_count;
 };
 
 struct vgic_v2_cpu_if {
@@ -298,78 +231,94 @@ struct vgic_v3_cpu_if {
 };
 
 struct vgic_cpu {
-       /* Pending/active/both interrupts on this VCPU */
-       DECLARE_BITMAP(pending_percpu, VGIC_NR_PRIVATE_IRQS);
-       DECLARE_BITMAP(active_percpu, VGIC_NR_PRIVATE_IRQS);
-       DECLARE_BITMAP(pend_act_percpu, VGIC_NR_PRIVATE_IRQS);
-
-       /* Pending/active/both shared interrupts, dynamically sized */
-       unsigned long   *pending_shared;
-       unsigned long   *active_shared;
-       unsigned long   *pend_act_shared;
-
        /* CPU vif control registers for world switch */
        union {
                struct vgic_v2_cpu_if   vgic_v2;
                struct vgic_v3_cpu_if   vgic_v3;
        };
 
-       /* Protected by the distributor's irq_phys_map_lock */
-       struct list_head        irq_phys_map_list;
+       unsigned int used_lrs;
+       struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
 
-       u64             live_lrs;
-};
+       spinlock_t ap_list_lock;        /* Protects the ap_list */
 
-#define LR_EMPTY       0xff
+       /*
+        * List of IRQs that this VCPU should consider because they are either
+        * Active or Pending (hence the name; AP list), or because they recently
+        * were one of the two and need to be migrated off this list to another
+        * VCPU.
+        */
+       struct list_head ap_list_head;
+
+       u64 live_lrs;
+
+       /*
+        * Members below are used with GICv3 emulation only and represent
+        * parts of the redistributor.
+        */
+       struct vgic_io_device   rd_iodev;
+       struct vgic_io_device   sgi_iodev;
 
-#define INT_STATUS_EOI         (1 << 0)
-#define INT_STATUS_UNDERFLOW   (1 << 1)
+       /* Contains the attributes and gpa of the LPI pending tables. */
+       u64 pendbaser;
 
-struct kvm;
-struct kvm_vcpu;
+       bool lpis_enabled;
+};
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
-int kvm_vgic_hyp_init(void);
-int kvm_vgic_map_resources(struct kvm *kvm);
-int kvm_vgic_get_max_vcpus(void);
 void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
-void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
-void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
-int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
+int kvm_vgic_map_resources(struct kvm *kvm);
+int kvm_vgic_hyp_init(void);
+
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
                        bool level);
-int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-                              unsigned int virt_irq, bool level);
-void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
-int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq);
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+                              bool level);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)   (!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)    (!!((k)->arch.vgic.nr_cpus))
+#define vgic_initialized(k)    ((k)->arch.vgic.initialized)
 #define vgic_ready(k)          ((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)   (((i) >= VGIC_NR_PRIVATE_IRQS) && \
-                                ((i) < (k)->arch.vgic.nr_irqs))
+                       ((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+
+bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 
-int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info,
-                 const struct vgic_ops **ops,
-                 const struct vgic_params **params);
 #ifdef CONFIG_KVM_ARM_VGIC_V3
-int vgic_v3_probe(const struct gic_kvm_info *gic_kvm_info,
-                 const struct vgic_ops **ops,
-                 const struct vgic_params **params);
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 #else
-static inline int vgic_v3_probe(const struct gic_kvm_info *gic_kvm_info,
-                               const struct vgic_ops **ops,
-                               const struct vgic_params **params)
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 {
-       return -ENODEV;
 }
 #endif
 
-#endif /* old VGIC include */
-#endif
+/**
+ * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
+ *
+ * The host's GIC naturally limits the maximum amount of VCPUs a guest
+ * can use.
+ */
+static inline int kvm_vgic_get_max_vcpus(void)
+{
+       return kvm_vgic_global_state.max_gic_vcpus;
+}
+
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
+
+/**
+ * kvm_vgic_setup_default_irq_routing:
+ * Setup a default flat gsi routing table mapping all SPIs
+ */
+int kvm_vgic_setup_default_irq_routing(struct kvm *kvm);
+
+#endif /* __KVM_ARM_VGIC_H */
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
deleted file mode 100644 (file)
index 3fbd175..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2015, 2016 ARM 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
-#define __ASM_ARM_KVM_VGIC_VGIC_H
-
-#include <linux/kernel.h>
-#include <linux/kvm.h>
-#include <linux/irqreturn.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <kvm/iodev.h>
-
-#define VGIC_V3_MAX_CPUS       255
-#define VGIC_V2_MAX_CPUS       8
-#define VGIC_NR_IRQS_LEGACY     256
-#define VGIC_NR_SGIS           16
-#define VGIC_NR_PPIS           16
-#define VGIC_NR_PRIVATE_IRQS   (VGIC_NR_SGIS + VGIC_NR_PPIS)
-#define VGIC_MAX_PRIVATE       (VGIC_NR_PRIVATE_IRQS - 1)
-#define VGIC_MAX_SPI           1019
-#define VGIC_MAX_RESERVED      1023
-#define VGIC_MIN_LPI           8192
-
-enum vgic_type {
-       VGIC_V2,                /* Good ol' GICv2 */
-       VGIC_V3,                /* New fancy GICv3 */
-};
-
-/* same for all guests, as depending only on the _host's_ GIC model */
-struct vgic_global {
-       /* type of the host GIC */
-       enum vgic_type          type;
-
-       /* Physical address of vgic virtual cpu interface */
-       phys_addr_t             vcpu_base;
-
-       /* virtual control interface mapping */
-       void __iomem            *vctrl_base;
-
-       /* Number of implemented list registers */
-       int                     nr_lr;
-
-       /* Maintenance IRQ number */
-       unsigned int            maint_irq;
-
-       /* maximum number of VCPUs allowed (GICv2 limits us to 8) */
-       int                     max_gic_vcpus;
-
-       /* Only needed for the legacy KVM_CREATE_IRQCHIP */
-       bool                    can_emulate_gicv2;
-};
-
-extern struct vgic_global kvm_vgic_global_state;
-
-#define VGIC_V2_MAX_LRS                (1 << 6)
-#define VGIC_V3_MAX_LRS                16
-#define VGIC_V3_LR_INDEX(lr)   (VGIC_V3_MAX_LRS - 1 - lr)
-
-enum vgic_irq_config {
-       VGIC_CONFIG_EDGE = 0,
-       VGIC_CONFIG_LEVEL
-};
-
-struct vgic_irq {
-       spinlock_t irq_lock;            /* Protects the content of the struct */
-       struct list_head ap_list;
-
-       struct kvm_vcpu *vcpu;          /* SGIs and PPIs: The VCPU
-                                        * SPIs and LPIs: The VCPU whose ap_list
-                                        * this is queued on.
-                                        */
-
-       struct kvm_vcpu *target_vcpu;   /* The VCPU that this interrupt should
-                                        * be sent to, as a result of the
-                                        * targets reg (v2) or the
-                                        * affinity reg (v3).
-                                        */
-
-       u32 intid;                      /* Guest visible INTID */
-       bool pending;
-       bool line_level;                /* Level only */
-       bool soft_pending;              /* Level only */
-       bool active;                    /* not used for LPIs */
-       bool enabled;
-       bool hw;                        /* Tied to HW IRQ */
-       u32 hwintid;                    /* HW INTID number */
-       union {
-               u8 targets;                     /* GICv2 target VCPUs mask */
-               u32 mpidr;                      /* GICv3 target VCPU */
-       };
-       u8 source;                      /* GICv2 SGIs only */
-       u8 priority;
-       enum vgic_irq_config config;    /* Level or edge */
-};
-
-struct vgic_register_region;
-
-struct vgic_io_device {
-       gpa_t base_addr;
-       struct kvm_vcpu *redist_vcpu;
-       const struct vgic_register_region *regions;
-       int nr_regions;
-       struct kvm_io_device dev;
-};
-
-struct vgic_dist {
-       bool                    in_kernel;
-       bool                    ready;
-       bool                    initialized;
-
-       /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
-       u32                     vgic_model;
-
-       int                     nr_spis;
-
-       /* TODO: Consider moving to global state */
-       /* Virtual control interface mapping */
-       void __iomem            *vctrl_base;
-
-       /* base addresses in guest physical address space: */
-       gpa_t                   vgic_dist_base;         /* distributor */
-       union {
-               /* either a GICv2 CPU interface */
-               gpa_t                   vgic_cpu_base;
-               /* or a number of GICv3 redistributor regions */
-               gpa_t                   vgic_redist_base;
-       };
-
-       /* distributor enabled */
-       bool                    enabled;
-
-       struct vgic_irq         *spis;
-
-       struct vgic_io_device   dist_iodev;
-       struct vgic_io_device   *redist_iodevs;
-};
-
-struct vgic_v2_cpu_if {
-       u32             vgic_hcr;
-       u32             vgic_vmcr;
-       u32             vgic_misr;      /* Saved only */
-       u64             vgic_eisr;      /* Saved only */
-       u64             vgic_elrsr;     /* Saved only */
-       u32             vgic_apr;
-       u32             vgic_lr[VGIC_V2_MAX_LRS];
-};
-
-struct vgic_v3_cpu_if {
-#ifdef CONFIG_KVM_ARM_VGIC_V3
-       u32             vgic_hcr;
-       u32             vgic_vmcr;
-       u32             vgic_sre;       /* Restored only, change ignored */
-       u32             vgic_misr;      /* Saved only */
-       u32             vgic_eisr;      /* Saved only */
-       u32             vgic_elrsr;     /* Saved only */
-       u32             vgic_ap0r[4];
-       u32             vgic_ap1r[4];
-       u64             vgic_lr[VGIC_V3_MAX_LRS];
-#endif
-};
-
-struct vgic_cpu {
-       /* CPU vif control registers for world switch */
-       union {
-               struct vgic_v2_cpu_if   vgic_v2;
-               struct vgic_v3_cpu_if   vgic_v3;
-       };
-
-       unsigned int used_lrs;
-       struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
-
-       spinlock_t ap_list_lock;        /* Protects the ap_list */
-
-       /*
-        * List of IRQs that this VCPU should consider because they are either
-        * Active or Pending (hence the name; AP list), or because they recently
-        * were one of the two and need to be migrated off this list to another
-        * VCPU.
-        */
-       struct list_head ap_list_head;
-
-       u64 live_lrs;
-};
-
-int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
-void kvm_vgic_early_init(struct kvm *kvm);
-int kvm_vgic_create(struct kvm *kvm, u32 type);
-void kvm_vgic_destroy(struct kvm *kvm);
-void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
-void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
-int kvm_vgic_map_resources(struct kvm *kvm);
-int kvm_vgic_hyp_init(void);
-
-int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
-                       bool level);
-int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
-                              bool level);
-int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
-
-int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-
-#define irqchip_in_kernel(k)   (!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)    ((k)->arch.vgic.initialized)
-#define vgic_ready(k)          ((k)->arch.vgic.ready)
-#define vgic_valid_spi(k, i)   (((i) >= VGIC_NR_PRIVATE_IRQS) && \
-                       ((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
-
-bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
-void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
-void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
-
-#ifdef CONFIG_KVM_ARM_VGIC_V3
-void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
-#else
-static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
-{
-}
-#endif
-
-/**
- * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
- *
- * The host's GIC naturally limits the maximum amount of VCPUs a guest
- * can use.
- */
-static inline int kvm_vgic_get_max_vcpus(void)
-{
-       return kvm_vgic_global_state.max_gic_vcpus;
-}
-
-#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
index 3f10307..c357f27 100644 (file)
@@ -163,6 +163,7 @@ struct backing_dev_info {
        wait_queue_head_t wb_waitq;
 
        struct device *dev;
+       struct device *owner;
 
        struct timer_list laptop_mode_wb_timer;
 
index 491a917..43b93a9 100644 (file)
@@ -24,6 +24,7 @@ __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
 void bdi_unregister(struct backing_dev_info *bdi);
 
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
index 314b3ca..1303b57 100644 (file)
@@ -113,6 +113,8 @@ extern int suid_dumpable;
 extern int setup_arg_pages(struct linux_binprm * bprm,
                           unsigned long stack_top,
                           int executable_stack);
+extern int transfer_args_to_stack(struct linux_binprm *bprm,
+                                 unsigned long *sp_location);
 extern int bprm_change_interp(char *interp, struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc, const char *const *argv,
                               struct linux_binprm *bprm);
index 583c108..59ffaa6 100644 (file)
@@ -95,7 +95,7 @@ static inline bool bio_is_rw(struct bio *bio)
 
 static inline bool bio_mergeable(struct bio *bio)
 {
-       if (bio->bi_rw & REQ_NOMERGE_FLAGS)
+       if (bio->bi_opf & REQ_NOMERGE_FLAGS)
                return false;
 
        return true;
@@ -318,7 +318,7 @@ struct bio_integrity_payload {
 
 static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
 {
-       if (bio->bi_rw & REQ_INTEGRITY)
+       if (bio->bi_opf & REQ_INTEGRITY)
                return bio->bi_integrity;
 
        return NULL;
@@ -470,11 +470,14 @@ extern unsigned int bvec_nr_vecs(unsigned short idx);
 int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css);
 int bio_associate_current(struct bio *bio);
 void bio_disassociate_task(struct bio *bio);
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src);
 #else  /* CONFIG_BLK_CGROUP */
 static inline int bio_associate_blkcg(struct bio *bio,
                        struct cgroup_subsys_state *blkcg_css) { return 0; }
 static inline int bio_associate_current(struct bio *bio) { return -ENOENT; }
 static inline void bio_disassociate_task(struct bio *bio) { }
+static inline void bio_clone_blkcg_association(struct bio *dst,
+                       struct bio *src) { }
 #endif /* CONFIG_BLK_CGROUP */
 
 #ifdef CONFIG_HIGHMEM
index 27bfc0b..598bc99 100644 (file)
@@ -266,13 +266,12 @@ static inline int bitmap_equal(const unsigned long *src1,
                        const unsigned long *src2, unsigned int nbits)
 {
        if (small_const_nbits(nbits))
-               return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+               return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
 #ifdef CONFIG_S390
-       else if (__builtin_constant_p(nbits) && (nbits % BITS_PER_LONG) == 0)
+       if (__builtin_constant_p(nbits) && (nbits % BITS_PER_LONG) == 0)
                return !memcmp(src1, src2, nbits / 8);
 #endif
-       else
-               return __bitmap_equal(src1, src2, nbits);
+       return __bitmap_equal(src1, src2, nbits);
 }
 
 static inline int bitmap_intersects(const unsigned long *src1,
index f77150a..10648e3 100644 (file)
@@ -714,9 +714,9 @@ static inline bool blkcg_bio_issue_check(struct request_queue *q,
 
        if (!throtl) {
                blkg = blkg ?: q->root_blkg;
-               blkg_rwstat_add(&blkg->stat_bytes, bio_op(bio), bio->bi_rw,
+               blkg_rwstat_add(&blkg->stat_bytes, bio_op(bio), bio->bi_opf,
                                bio->bi_iter.bi_size);
-               blkg_rwstat_add(&blkg->stat_ios, bio_op(bio), bio->bi_rw, 1);
+               blkg_rwstat_add(&blkg->stat_ios, bio_op(bio), bio->bi_opf, 1);
        }
 
        rcu_read_unlock();
index f254eb2..436f43f 100644 (file)
@@ -27,8 +27,9 @@ struct bio {
        struct bio              *bi_next;       /* request queue link */
        struct block_device     *bi_bdev;
        int                     bi_error;
-       unsigned int            bi_rw;          /* bottom bits req flags,
-                                                * top bits REQ_OP
+       unsigned int            bi_opf;         /* bottom bits req flags,
+                                                * top bits REQ_OP. Use
+                                                * accessors.
                                                 */
        unsigned short          bi_flags;       /* status, command, etc */
        unsigned short          bi_ioprio;
@@ -89,13 +90,13 @@ struct bio {
 };
 
 #define BIO_OP_SHIFT   (8 * sizeof(unsigned int) - REQ_OP_BITS)
-#define bio_op(bio)    ((bio)->bi_rw >> BIO_OP_SHIFT)
+#define bio_op(bio)    ((bio)->bi_opf >> BIO_OP_SHIFT)
 
 #define bio_set_op_attrs(bio, op, op_flags) do {               \
        WARN_ON(op >= (1 << REQ_OP_BITS));                      \
-       (bio)->bi_rw &= ((1 << BIO_OP_SHIFT) - 1);              \
-       (bio)->bi_rw |= ((unsigned int) (op) << BIO_OP_SHIFT);  \
-       (bio)->bi_rw |= op_flags;                               \
+       (bio)->bi_opf &= ((1 << BIO_OP_SHIFT) - 1);             \
+       (bio)->bi_opf |= ((unsigned int) (op) << BIO_OP_SHIFT); \
+       (bio)->bi_opf |= op_flags;                              \
 } while (0)
 
 #define BIO_RESET_BYTES                offsetof(struct bio, bi_max_vecs)
@@ -138,7 +139,7 @@ struct bio {
 
 /*
  * Request flags.  For use in the cmd_flags field of struct request, and in
- * bi_rw of struct bio.  Note that some flags are only valid in either one.
+ * bi_opf of struct bio.  Note that some flags are only valid in either one.
  */
 enum rq_flag_bits {
        /* common flags */
index adf3307..2c210b6 100644 (file)
@@ -47,7 +47,6 @@ struct pr_ops;
  */
 #define BLKCG_MAX_POLS         2
 
-struct request;
 typedef void (rq_end_io_fn)(struct request *, int);
 
 #define BLK_RL_SYNCFULL                (1U << 0)
@@ -1673,7 +1672,7 @@ struct blk_dax_ctl {
 struct block_device_operations {
        int (*open) (struct block_device *, fmode_t);
        void (*release) (struct gendisk *, fmode_t);
-       int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
+       int (*rw_page)(struct block_device *, sector_t, struct page *, bool);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        long (*direct_access)(struct block_device *, sector_t, void **, pfn_t *,
index 5f3c63d..dbc21c7 100644 (file)
@@ -38,6 +38,7 @@ struct cpu_vfs_cap_data {
 struct file;
 struct inode;
 struct dentry;
+struct task_struct;
 struct user_namespace;
 
 extern const kernel_cap_t __cap_empty_set;
index dfce616..7868d60 100644 (file)
@@ -34,9 +34,9 @@
 #define CEPH_MAX_MON   31
 
 /*
- * ceph_file_layout - describe data layout for a file/inode
+ * legacy ceph_file_layoute
  */
-struct ceph_file_layout {
+struct ceph_file_layout_legacy {
        /* file -> object mapping */
        __le32 fl_stripe_unit;     /* stripe unit, in bytes.  must be multiple
                                      of page size. */
@@ -53,33 +53,27 @@ struct ceph_file_layout {
        __le32 fl_pg_pool;      /* namespace, crush ruleset, rep level */
 } __attribute__ ((packed));
 
-#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
-#define ceph_file_layout_stripe_count(l) \
-       ((__s32)le32_to_cpu((l).fl_stripe_count))
-#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
-#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
-#define ceph_file_layout_object_su(l) \
-       ((__s32)le32_to_cpu((l).fl_object_stripe_unit))
-#define ceph_file_layout_pg_pool(l) \
-       ((__s32)le32_to_cpu((l).fl_pg_pool))
-
-static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
-{
-       return le32_to_cpu(l->fl_stripe_unit) *
-               le32_to_cpu(l->fl_stripe_count);
-}
-
-/* "period" == bytes before i start on a new set of objects */
-static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
-{
-       return le32_to_cpu(l->fl_object_size) *
-               le32_to_cpu(l->fl_stripe_count);
-}
+struct ceph_string;
+/*
+ * ceph_file_layout - describe data layout for a file/inode
+ */
+struct ceph_file_layout {
+       /* file -> object mapping */
+       u32 stripe_unit;   /* stripe unit, in bytes */
+       u32 stripe_count;  /* over this many objects */
+       u32 object_size;   /* until objects are this big */
+       s64 pool_id;        /* rados pool id */
+       struct ceph_string __rcu *pool_ns; /* rados pool namespace */
+};
+
+extern int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
+extern void ceph_file_layout_from_legacy(struct ceph_file_layout *fl,
+                               struct ceph_file_layout_legacy *legacy);
+extern void ceph_file_layout_to_legacy(struct ceph_file_layout *fl,
+                               struct ceph_file_layout_legacy *legacy);
 
 #define CEPH_MIN_STRIPE_UNIT 65536
 
-int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
-
 struct ceph_dir_layout {
        __u8   dl_dir_hash;   /* see ceph_hash.h for ids */
        __u8   dl_unused1;
@@ -127,6 +121,7 @@ struct ceph_dir_layout {
 
 /* client <-> mds */
 #define CEPH_MSG_MDS_MAP                21
+#define CEPH_MSG_FS_MAP_USER            103
 
 #define CEPH_MSG_CLIENT_SESSION         22
 #define CEPH_MSG_CLIENT_RECONNECT       23
@@ -399,7 +394,7 @@ union ceph_mds_request_args {
                __le32 flags;
        } __attribute__ ((packed)) setxattr;
        struct {
-               struct ceph_file_layout layout;
+               struct ceph_file_layout_legacy layout;
        } __attribute__ ((packed)) setlayout;
        struct {
                __u8 rule; /* currently fcntl or flock */
@@ -478,7 +473,7 @@ struct ceph_mds_reply_inode {
        __le64 version;                /* inode version */
        __le64 xattr_version;          /* version for xattr blob */
        struct ceph_mds_reply_cap cap; /* caps issued for this inode */
-       struct ceph_file_layout layout;
+       struct ceph_file_layout_legacy layout;
        struct ceph_timespec ctime, mtime, atime;
        __le32 time_warp_seq;
        __le64 size, max_size, truncate_size;
@@ -531,7 +526,7 @@ struct ceph_filelock {
 #define CEPH_FILE_MODE_WR         2
 #define CEPH_FILE_MODE_RDWR       3  /* RD | WR */
 #define CEPH_FILE_MODE_LAZY       4  /* lazy io */
-#define CEPH_FILE_MODE_NUM        8  /* bc these are bit fields.. mostly */
+#define CEPH_FILE_MODE_BITS       4
 
 int ceph_flags_to_mode(int flags);
 
@@ -673,7 +668,7 @@ struct ceph_mds_caps {
        __le64 size, max_size, truncate_size;
        __le32 truncate_seq;
        struct ceph_timespec mtime, atime, ctime;
-       struct ceph_file_layout layout;
+       struct ceph_file_layout_legacy layout;
        __le32 time_warp_seq;
 } __attribute__ ((packed));
 
index 19e9932..f990f2c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/err.h>
 #include <linux/bug.h>
+#include <linux/slab.h>
 #include <linux/time.h>
 #include <asm/unaligned.h>
 
@@ -217,6 +218,60 @@ static inline void ceph_encode_string(void **p, void *end,
        *p += len;
 }
 
+/*
+ * version and length starting block encoders/decoders
+ */
+
+/* current code version (u8) + compat code version (u8) + len of struct (u32) */
+#define CEPH_ENCODING_START_BLK_LEN 6
+
+/**
+ * ceph_start_encoding - start encoding block
+ * @struct_v: current (code) version of the encoding
+ * @struct_compat: oldest code version that can decode it
+ * @struct_len: length of struct encoding
+ */
+static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat,
+                                      u32 struct_len)
+{
+       ceph_encode_8(p, struct_v);
+       ceph_encode_8(p, struct_compat);
+       ceph_encode_32(p, struct_len);
+}
+
+/**
+ * ceph_start_decoding - start decoding block
+ * @v: current version of the encoding that the code supports
+ * @name: name of the struct (free-form)
+ * @struct_v: out param for the encoding version
+ * @struct_len: out param for the length of struct encoding
+ *
+ * Validates the length of struct encoding, so unsafe ceph_decode_*
+ * variants can be used for decoding.
+ */
+static inline int ceph_start_decoding(void **p, void *end, u8 v,
+                                     const char *name, u8 *struct_v,
+                                     u32 *struct_len)
+{
+       u8 struct_compat;
+
+       ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad);
+       *struct_v = ceph_decode_8(p);
+       struct_compat = ceph_decode_8(p);
+       if (v < struct_compat) {
+               pr_warn("got struct_v %d struct_compat %d > %d of %s\n",
+                       *struct_v, struct_compat, v, name);
+               return -EINVAL;
+       }
+
+       *struct_len = ceph_decode_32(p);
+       ceph_decode_need(p, end, *struct_len, bad);
+       return 0;
+
+bad:
+       return -ERANGE;
+}
+
 #define ceph_encode_need(p, end, n, bad)                       \
        do {                                                    \
                if (!likely(ceph_has_room(p, end, n)))          \
index 690985d..83fc1ff 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ceph/mon_client.h>
 #include <linux/ceph/osd_client.h>
 #include <linux/ceph/ceph_fs.h>
+#include <linux/ceph/string_table.h>
 
 /*
  * mount options
@@ -214,8 +215,9 @@ static void erase_##name(struct rb_root *root, type *t)                     \
 }
 
 #define DEFINE_RB_LOOKUP_FUNC(name, type, keyfld, nodefld)             \
+extern type __lookup_##name##_key;                                     \
 static type *lookup_##name(struct rb_root *root,                       \
-                          typeof(((type *)0)->keyfld) key)             \
+                          typeof(__lookup_##name##_key.keyfld) key)    \
 {                                                                      \
        struct rb_node *n = root->rb_node;                              \
                                                                        \
index e2a92df..24d704d 100644 (file)
@@ -95,7 +95,7 @@ struct ceph_mon_client {
                struct ceph_mon_subscribe_item item;
                bool want;
                u32 have; /* epoch */
-       } subs[3];
+       } subs[4];
        int fs_cluster_id; /* "mdsmap.<id>" sub */
 
 #ifdef CONFIG_DEBUG_FS
@@ -111,9 +111,10 @@ extern int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl);
 extern void ceph_monc_stop(struct ceph_mon_client *monc);
 
 enum {
-       CEPH_SUB_MDSMAP = 0,
-       CEPH_SUB_MONMAP,
+       CEPH_SUB_MONMAP = 0,
        CEPH_SUB_OSDMAP,
+       CEPH_SUB_FSMAP,
+       CEPH_SUB_MDSMAP,
 };
 
 extern const char *ceph_sub_str[];
index 4b0d389..ddd0d48 100644 (file)
@@ -2,7 +2,6 @@
 #define _FS_CEPH_MSGPOOL
 
 #include <linux/mempool.h>
-#include <linux/ceph/messenger.h>
 
 /*
  * we use memory pools for preallocating messages we may receive, to
index 1b3b6e1..8589323 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/ceph/types.h>
 #include <linux/ceph/osdmap.h>
 #include <linux/ceph/messenger.h>
+#include <linux/ceph/msgpool.h>
 #include <linux/ceph/auth.h>
 #include <linux/ceph/pagelist.h>
 
index 9ccf4db..9a90417 100644 (file)
@@ -63,11 +63,13 @@ static inline bool ceph_can_shift_osds(struct ceph_pg_pool_info *pool)
 
 struct ceph_object_locator {
        s64 pool;
+       struct ceph_string *pool_ns;
 };
 
 static inline void ceph_oloc_init(struct ceph_object_locator *oloc)
 {
        oloc->pool = -1;
+       oloc->pool_ns = NULL;
 }
 
 static inline bool ceph_oloc_empty(const struct ceph_object_locator *oloc)
@@ -75,11 +77,9 @@ static inline bool ceph_oloc_empty(const struct ceph_object_locator *oloc)
        return oloc->pool == -1;
 }
 
-static inline void ceph_oloc_copy(struct ceph_object_locator *dest,
-                                 const struct ceph_object_locator *src)
-{
-       dest->pool = src->pool;
-}
+void ceph_oloc_copy(struct ceph_object_locator *dest,
+                   const struct ceph_object_locator *src);
+void ceph_oloc_destroy(struct ceph_object_locator *oloc);
 
 /*
  * Maximum supported by kernel client object name length
@@ -115,6 +115,11 @@ static inline void ceph_oid_init(struct ceph_object_id *oid)
        oid->name_len = 0;
 }
 
+#define CEPH_OID_INIT_ONSTACK(oid)                                     \
+    ({ ceph_oid_init(&oid); oid; })
+#define CEPH_DEFINE_OID_ONSTACK(oid)                                   \
+       struct ceph_object_id oid = CEPH_OID_INIT_ONSTACK(oid)
+
 static inline bool ceph_oid_empty(const struct ceph_object_id *oid)
 {
        return oid->name == oid->inline_name && !oid->name_len;
diff --git a/include/linux/ceph/string_table.h b/include/linux/ceph/string_table.h
new file mode 100644 (file)
index 0000000..1b02c96
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef _FS_CEPH_STRING_TABLE_H
+#define _FS_CEPH_STRING_TABLE_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/rbtree.h>
+#include <linux/rcupdate.h>
+
+struct ceph_string {
+       struct kref kref;
+       union {
+               struct rb_node node;
+               struct rcu_head rcu;
+       };
+       size_t len;
+       char str[];
+};
+
+extern void ceph_release_string(struct kref *ref);
+extern struct ceph_string *ceph_find_or_create_string(const char *str,
+                                                     size_t len);
+extern bool ceph_strings_empty(void);
+
+static inline struct ceph_string *ceph_get_string(struct ceph_string *str)
+{
+       kref_get(&str->kref);
+       return str;
+}
+
+static inline void ceph_put_string(struct ceph_string *str)
+{
+       if (!str)
+               return;
+       kref_put(&str->kref, ceph_release_string);
+}
+
+static inline int ceph_compare_string(struct ceph_string *cs,
+                                     const char* str, size_t len)
+{
+       size_t cs_len = cs ? cs->len : 0;
+       if (cs_len != len)
+               return cs_len - len;
+       if (len == 0)
+               return 0;
+       return strncmp(cs->str, str, len);
+}
+
+#define ceph_try_get_string(x)                                 \
+({                                                             \
+       struct ceph_string *___str;                             \
+       rcu_read_lock();                                        \
+       for (;;) {                                              \
+               ___str = rcu_dereference(x);                    \
+               if (!___str ||                                  \
+                   kref_get_unless_zero(&___str->kref))        \
+                       break;                                  \
+       }                                                       \
+       rcu_read_unlock();                                      \
+       (___str);                                               \
+})
+
+#endif
index d9aef2a..c78fc27 100644 (file)
@@ -99,7 +99,8 @@ static inline void context_tracking_init(void) { }
 
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
-static inline void guest_enter(void)
+/* must be called with irqs disabled */
+static inline void guest_enter_irqoff(void)
 {
        if (vtime_accounting_cpu_enabled())
                vtime_guest_enter(current);
@@ -108,9 +109,19 @@ static inline void guest_enter(void)
 
        if (context_tracking_is_enabled())
                __context_tracking_enter(CONTEXT_GUEST);
+
+       /* KVM does not hold any references to rcu protected data when it
+        * switches CPU into a guest mode. In fact switching to a guest mode
+        * is very similar to exiting to userspace from rcu point of view. In
+        * addition CPU may stay in a guest mode for quite a long time (up to
+        * one time slice). Lets treat guest mode as quiescent state, just like
+        * we do with user-mode execution.
+        */
+       if (!context_tracking_cpu_is_enabled())
+               rcu_virt_note_context_switch(smp_processor_id());
 }
 
-static inline void guest_exit(void)
+static inline void guest_exit_irqoff(void)
 {
        if (context_tracking_is_enabled())
                __context_tracking_exit(CONTEXT_GUEST);
@@ -122,7 +133,7 @@ static inline void guest_exit(void)
 }
 
 #else
-static inline void guest_enter(void)
+static inline void guest_enter_irqoff(void)
 {
        /*
         * This is running in ioctl context so its safe
@@ -131,9 +142,10 @@ static inline void guest_enter(void)
         */
        vtime_account_system(current);
        current->flags |= PF_VCPU;
+       rcu_virt_note_context_switch(smp_processor_id());
 }
 
-static inline void guest_exit(void)
+static inline void guest_exit_irqoff(void)
 {
        /* Flush the guest cputime we spent on the guest */
        vtime_account_system(current);
@@ -141,4 +153,22 @@ static inline void guest_exit(void)
 }
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
 
+static inline void guest_enter(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       guest_enter_irqoff();
+       local_irq_restore(flags);
+}
+
+static inline void guest_exit(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       guest_exit_irqoff();
+       local_irq_restore(flags);
+}
+
 #endif
index e828cf6..da7fbf1 100644 (file)
@@ -579,7 +579,7 @@ static inline int cpumask_parselist_user(const char __user *buf, int len,
 }
 
 /**
- * cpumask_parse - extract a cpumask from from a string
+ * cpumask_parse - extract a cpumask from a string
  * @buf: the buffer to extract from
  * @dstp: the cpumask to set.
  *
index 98044a8..5ff3e9a 100644 (file)
@@ -130,7 +130,7 @@ struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct dentry *,
+       int (*d_compare)(const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        int (*d_init)(struct dentry *);
@@ -263,7 +263,7 @@ extern void d_rehash(struct dentry *);
  
 extern void d_add(struct dentry *, struct inode *);
 
-extern void dentry_update_name_case(struct dentry *, struct qstr *);
+extern void dentry_update_name_case(struct dentry *, const struct qstr *);
 
 /* used for rename() and baskets */
 extern void d_move(struct dentry *, struct dentry *);
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
deleted file mode 100644 (file)
index 5246239..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef _DMA_ATTR_H
-#define _DMA_ATTR_H
-
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
-#include <linux/bug.h>
-
-/**
- * an enum dma_attr represents an attribute associated with a DMA
- * mapping. The semantics of each attribute should be defined in
- * Documentation/DMA-attributes.txt.
- */
-enum dma_attr {
-       DMA_ATTR_WRITE_BARRIER,
-       DMA_ATTR_WEAK_ORDERING,
-       DMA_ATTR_WRITE_COMBINE,
-       DMA_ATTR_NON_CONSISTENT,
-       DMA_ATTR_NO_KERNEL_MAPPING,
-       DMA_ATTR_SKIP_CPU_SYNC,
-       DMA_ATTR_FORCE_CONTIGUOUS,
-       DMA_ATTR_ALLOC_SINGLE_PAGES,
-       DMA_ATTR_MAX,
-};
-
-#define __DMA_ATTRS_LONGS BITS_TO_LONGS(DMA_ATTR_MAX)
-
-/**
- * struct dma_attrs - an opaque container for DMA attributes
- * @flags - bitmask representing a collection of enum dma_attr
- */
-struct dma_attrs {
-       unsigned long flags[__DMA_ATTRS_LONGS];
-};
-
-#define DEFINE_DMA_ATTRS(x)                                    \
-       struct dma_attrs x = {                                  \
-               .flags = { [0 ... __DMA_ATTRS_LONGS-1] = 0 },   \
-       }
-
-static inline void init_dma_attrs(struct dma_attrs *attrs)
-{
-       bitmap_zero(attrs->flags, __DMA_ATTRS_LONGS);
-}
-
-/**
- * dma_set_attr - set a specific attribute
- * @attr: attribute to set
- * @attrs: struct dma_attrs (may be NULL)
- */
-static inline void dma_set_attr(enum dma_attr attr, struct dma_attrs *attrs)
-{
-       if (attrs == NULL)
-               return;
-       BUG_ON(attr >= DMA_ATTR_MAX);
-       __set_bit(attr, attrs->flags);
-}
-
-/**
- * dma_get_attr - check for a specific attribute
- * @attr: attribute to set
- * @attrs: struct dma_attrs (may be NULL)
- */
-static inline int dma_get_attr(enum dma_attr attr, struct dma_attrs *attrs)
-{
-       if (attrs == NULL)
-               return 0;
-       BUG_ON(attr >= DMA_ATTR_MAX);
-       return test_bit(attr, attrs->flags);
-}
-
-#endif /* _DMA_ATTR_H */
index 8443bbb..81c5c8d 100644 (file)
@@ -39,7 +39,7 @@ int dma_direction_to_prot(enum dma_data_direction dir, bool coherent);
  * the arch code to take care of attributes and cache maintenance
  */
 struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp,
-               struct dma_attrs *attrs, int prot, dma_addr_t *handle,
+               unsigned long attrs, int prot, dma_addr_t *handle,
                void (*flush_page)(struct device *, const void *, phys_addr_t));
 void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
                dma_addr_t *handle);
@@ -56,9 +56,9 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
  * directly as DMA mapping callbacks for simplicity
  */
 void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
-               enum dma_data_direction dir, struct dma_attrs *attrs);
+               enum dma_data_direction dir, unsigned long attrs);
 void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
-               enum dma_data_direction dir, struct dma_attrs *attrs);
+               enum dma_data_direction dir, unsigned long attrs);
 int iommu_dma_supported(struct device *dev, u64 mask);
 int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
 
index 71c1b21..66533e1 100644 (file)
@@ -5,13 +5,58 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/err.h>
-#include <linux/dma-attrs.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-direction.h>
 #include <linux/scatterlist.h>
 #include <linux/kmemcheck.h>
 #include <linux/bug.h>
 
+/**
+ * List of possible attributes associated with a DMA mapping. The semantics
+ * of each attribute should be defined in Documentation/DMA-attributes.txt.
+ *
+ * DMA_ATTR_WRITE_BARRIER: DMA to a memory region with this attribute
+ * forces all pending DMA writes to complete.
+ */
+#define DMA_ATTR_WRITE_BARRIER         (1UL << 0)
+/*
+ * DMA_ATTR_WEAK_ORDERING: Specifies that reads and writes to the mapping
+ * may be weakly ordered, that is that reads and writes may pass each other.
+ */
+#define DMA_ATTR_WEAK_ORDERING         (1UL << 1)
+/*
+ * DMA_ATTR_WRITE_COMBINE: Specifies that writes to the mapping may be
+ * buffered to improve performance.
+ */
+#define DMA_ATTR_WRITE_COMBINE         (1UL << 2)
+/*
+ * DMA_ATTR_NON_CONSISTENT: Lets the platform to choose to return either
+ * consistent or non-consistent memory as it sees fit.
+ */
+#define DMA_ATTR_NON_CONSISTENT                (1UL << 3)
+/*
+ * DMA_ATTR_NO_KERNEL_MAPPING: Lets the platform to avoid creating a kernel
+ * virtual mapping for the allocated buffer.
+ */
+#define DMA_ATTR_NO_KERNEL_MAPPING     (1UL << 4)
+/*
+ * DMA_ATTR_SKIP_CPU_SYNC: Allows platform code to skip synchronization of
+ * the CPU cache for the given buffer assuming that it has been already
+ * transferred to 'device' domain.
+ */
+#define DMA_ATTR_SKIP_CPU_SYNC         (1UL << 5)
+/*
+ * DMA_ATTR_FORCE_CONTIGUOUS: Forces contiguous allocation of the buffer
+ * in physical memory.
+ */
+#define DMA_ATTR_FORCE_CONTIGUOUS      (1UL << 6)
+/*
+ * DMA_ATTR_ALLOC_SINGLE_PAGES: This is a hint to the DMA-mapping subsystem
+ * that it's probably not worth the time to try to allocate memory to in a way
+ * that gives better TLB efficiency.
+ */
+#define DMA_ATTR_ALLOC_SINGLE_PAGES    (1UL << 7)
+
 /*
  * A dma_addr_t can hold any valid DMA or bus address for the platform.
  * It can be given to a device to use as a DMA source or target.  A CPU cannot
 struct dma_map_ops {
        void* (*alloc)(struct device *dev, size_t size,
                                dma_addr_t *dma_handle, gfp_t gfp,
-                               struct dma_attrs *attrs);
+                               unsigned long attrs);
        void (*free)(struct device *dev, size_t size,
                              void *vaddr, dma_addr_t dma_handle,
-                             struct dma_attrs *attrs);
+                             unsigned long attrs);
        int (*mmap)(struct device *, struct vm_area_struct *,
-                         void *, dma_addr_t, size_t, struct dma_attrs *attrs);
+                         void *, dma_addr_t, size_t,
+                         unsigned long attrs);
 
        int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *,
-                          dma_addr_t, size_t, struct dma_attrs *attrs);
+                          dma_addr_t, size_t, unsigned long attrs);
 
        dma_addr_t (*map_page)(struct device *dev, struct page *page,
                               unsigned long offset, size_t size,
                               enum dma_data_direction dir,
-                              struct dma_attrs *attrs);
+                              unsigned long attrs);
        void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
                           size_t size, enum dma_data_direction dir,
-                          struct dma_attrs *attrs);
+                          unsigned long attrs);
        /*
         * map_sg returns 0 on error and a value > 0 on success.
         * It should never return a value < 0.
         */
        int (*map_sg)(struct device *dev, struct scatterlist *sg,
                      int nents, enum dma_data_direction dir,
-                     struct dma_attrs *attrs);
+                     unsigned long attrs);
        void (*unmap_sg)(struct device *dev,
                         struct scatterlist *sg, int nents,
                         enum dma_data_direction dir,
-                        struct dma_attrs *attrs);
+                        unsigned long attrs);
        void (*sync_single_for_cpu)(struct device *dev,
                                    dma_addr_t dma_handle, size_t size,
                                    enum dma_data_direction dir);
@@ -123,7 +169,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
                                              size_t size,
                                              enum dma_data_direction dir,
-                                             struct dma_attrs *attrs)
+                                             unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        dma_addr_t addr;
@@ -142,7 +188,7 @@ static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
 static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
                                          size_t size,
                                          enum dma_data_direction dir,
-                                         struct dma_attrs *attrs)
+                                         unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -158,7 +204,7 @@ static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
  */
 static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
                                   int nents, enum dma_data_direction dir,
-                                  struct dma_attrs *attrs)
+                                  unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        int i, ents;
@@ -176,7 +222,7 @@ static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
 
 static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
                                      int nents, enum dma_data_direction dir,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -195,7 +241,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
 
        kmemcheck_mark_initialized(page_address(page) + offset, size);
        BUG_ON(!valid_dma_direction(dir));
-       addr = ops->map_page(dev, page, offset, size, dir, NULL);
+       addr = ops->map_page(dev, page, offset, size, dir, 0);
        debug_dma_map_page(dev, page, offset, size, dir, addr, false);
 
        return addr;
@@ -208,7 +254,7 @@ static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
 
        BUG_ON(!valid_dma_direction(dir));
        if (ops->unmap_page)
-               ops->unmap_page(dev, addr, size, dir, NULL);
+               ops->unmap_page(dev, addr, size, dir, 0);
        debug_dma_unmap_page(dev, addr, size, dir, false);
 }
 
@@ -289,10 +335,10 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 
 }
 
-#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)
-#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL)
-#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL)
-#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL)
+#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
+#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
+#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
+#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
 
 extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
                           void *cpu_addr, dma_addr_t dma_addr, size_t size);
@@ -321,7 +367,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
  */
 static inline int
 dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
-              dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+              dma_addr_t dma_addr, size_t size, unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        BUG_ON(!ops);
@@ -330,7 +376,7 @@ dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr,
        return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
 }
 
-#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0)
 
 int
 dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
@@ -338,7 +384,8 @@ dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
 
 static inline int
 dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
-                     dma_addr_t dma_addr, size_t size, struct dma_attrs *attrs)
+                     dma_addr_t dma_addr, size_t size,
+                     unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        BUG_ON(!ops);
@@ -348,7 +395,7 @@ dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
        return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size);
 }
 
-#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL)
+#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0)
 
 #ifndef arch_dma_alloc_attrs
 #define arch_dma_alloc_attrs(dev, flag)        (true)
@@ -356,7 +403,7 @@ dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr,
 
 static inline void *dma_alloc_attrs(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag,
-                                      struct dma_attrs *attrs)
+                                      unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        void *cpu_addr;
@@ -378,7 +425,7 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
 
 static inline void dma_free_attrs(struct device *dev, size_t size,
                                     void *cpu_addr, dma_addr_t dma_handle,
-                                    struct dma_attrs *attrs)
+                                    unsigned long attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -398,31 +445,27 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t flag)
 {
-       return dma_alloc_attrs(dev, size, dma_handle, flag, NULL);
+       return dma_alloc_attrs(dev, size, dma_handle, flag, 0);
 }
 
 static inline void dma_free_coherent(struct device *dev, size_t size,
                void *cpu_addr, dma_addr_t dma_handle)
 {
-       return dma_free_attrs(dev, size, cpu_addr, dma_handle, NULL);
+       return dma_free_attrs(dev, size, cpu_addr, dma_handle, 0);
 }
 
 static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
                dma_addr_t *dma_handle, gfp_t gfp)
 {
-       DEFINE_DMA_ATTRS(attrs);
-
-       dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
-       return dma_alloc_attrs(dev, size, dma_handle, gfp, &attrs);
+       return dma_alloc_attrs(dev, size, dma_handle, gfp,
+                              DMA_ATTR_NON_CONSISTENT);
 }
 
 static inline void dma_free_noncoherent(struct device *dev, size_t size,
                void *cpu_addr, dma_addr_t dma_handle)
 {
-       DEFINE_DMA_ATTRS(attrs);
-
-       dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs);
-       dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+       dma_free_attrs(dev, size, cpu_addr, dma_handle,
+                      DMA_ATTR_NON_CONSISTENT);
 }
 
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
@@ -646,9 +689,8 @@ static inline void dmam_release_declared_memory(struct device *dev)
 static inline void *dma_alloc_wc(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t gfp)
 {
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_alloc_attrs(dev, size, dma_addr, gfp, &attrs);
+       return dma_alloc_attrs(dev, size, dma_addr, gfp,
+                              DMA_ATTR_WRITE_COMBINE);
 }
 #ifndef dma_alloc_writecombine
 #define dma_alloc_writecombine dma_alloc_wc
@@ -657,9 +699,8 @@ static inline void *dma_alloc_wc(struct device *dev, size_t size,
 static inline void dma_free_wc(struct device *dev, size_t size,
                               void *cpu_addr, dma_addr_t dma_addr)
 {
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_free_attrs(dev, size, cpu_addr, dma_addr, &attrs);
+       return dma_free_attrs(dev, size, cpu_addr, dma_addr,
+                             DMA_ATTR_WRITE_COMBINE);
 }
 #ifndef dma_free_writecombine
 #define dma_free_writecombine dma_free_wc
@@ -670,9 +711,8 @@ static inline int dma_mmap_wc(struct device *dev,
                              void *cpu_addr, dma_addr_t dma_addr,
                              size_t size)
 {
-       DEFINE_DMA_ATTRS(attrs);
-       dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
-       return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+       return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size,
+                             DMA_ATTR_WRITE_COMBINE);
 }
 #ifndef dma_mmap_writecombine
 #define dma_mmap_writecombine dma_mmap_wc
diff --git a/include/linux/ds1286.h b/include/linux/ds1286.h
deleted file mode 100644 (file)
index 45ea0aa..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 1998, 1999, 2003 Ralf Baechle
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __LINUX_DS1286_H
-#define __LINUX_DS1286_H
-
-/**********************************************************************
- * register summary
- **********************************************************************/
-#define RTC_HUNDREDTH_SECOND   0
-#define RTC_SECONDS            1
-#define RTC_MINUTES            2
-#define RTC_MINUTES_ALARM      3
-#define RTC_HOURS              4
-#define RTC_HOURS_ALARM                5
-#define RTC_DAY                        6
-#define RTC_DAY_ALARM          7
-#define RTC_DATE               8
-#define RTC_MONTH              9
-#define RTC_YEAR               10
-#define RTC_CMD                        11
-#define RTC_WHSEC              12
-#define RTC_WSEC               13
-#define RTC_UNUSED             14
-
-/* RTC_*_alarm is always true if 2 MSBs are set */
-# define RTC_ALARM_DONT_CARE   0xC0
-
-
-/*
- * Bits in the month register
- */
-#define RTC_EOSC               0x80
-#define RTC_ESQW               0x40
-
-/*
- * Bits in the Command register
- */
-#define RTC_TDF                        0x01
-#define RTC_WAF                        0x02
-#define RTC_TDM                        0x04
-#define RTC_WAM                        0x08
-#define RTC_PU_LVL             0x10
-#define RTC_IBH_LO             0x20
-#define RTC_IPSW               0x40
-#define RTC_TE                 0x80
-
-#endif /* __LINUX_DS1286_H */
diff --git a/include/linux/ds17287rtc.h b/include/linux/ds17287rtc.h
deleted file mode 100644 (file)
index d85d3f4..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * ds17287rtc.h - register definitions for the ds1728[57] RTC / CMOS RAM
- *
- * 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.
- *
- * (C) 2003 Guido Guenther <agx@sigxcpu.org>
- */
-#ifndef __LINUX_DS17287RTC_H
-#define __LINUX_DS17287RTC_H
-
-#include <linux/rtc.h>                 /* get the user-level API */
-#include <linux/mc146818rtc.h>
-
-/* Register A */
-#define DS_REGA_DV2    0x40            /* countdown chain */
-#define DS_REGA_DV1    0x20            /* oscillator enable */
-#define DS_REGA_DV0    0x10            /* bank select */
-
-/* bank 1 registers */
-#define DS_B1_MODEL    0x40            /* model number byte */
-#define DS_B1_SN1      0x41            /* serial number byte 1 */
-#define DS_B1_SN2      0x42            /* serial number byte 2 */
-#define DS_B1_SN3      0x43            /* serial number byte 3 */
-#define DS_B1_SN4      0x44            /* serial number byte 4 */
-#define DS_B1_SN5      0x45            /* serial number byte 5 */
-#define DS_B1_SN6      0x46            /* serial number byte 6 */
-#define DS_B1_CRC      0x47            /* CRC byte */
-#define DS_B1_CENTURY  0x48            /* Century byte */
-#define DS_B1_DALARM   0x49            /* date alarm */
-#define DS_B1_XCTRL4A  0x4a            /* extendec control register 4a */
-#define DS_B1_XCTRL4B  0x4b            /* extendec control register 4b */
-#define DS_B1_RTCADDR2         0x4e            /* rtc address 2 */
-#define DS_B1_RTCADDR3         0x4f            /* rtc address 3 */
-#define DS_B1_RAMLSB   0x50            /* extended ram LSB */
-#define DS_B1_RAMMSB   0x51            /* extended ram MSB */
-#define DS_B1_RAMDPORT 0x53            /* extended ram data port */
-
-/* register details */
-/* extended control register 4a */
-#define DS_XCTRL4A_VRT2        0x80            /* valid ram and time */
-#define DS_XCTRL4A_INCR        0x40            /* increment progress status */
-#define DS_XCTRL4A_BME 0x20            /* burst mode enable */
-#define DS_XCTRL4A_PAB 0x08            /* power active bar ctrl */
-#define DS_XCTRL4A_RF  0x04            /* ram clear flag */
-#define DS_XCTRL4A_WF  0x02            /* wake up alarm flag */
-#define DS_XCTRL4A_KF  0x01            /* kickstart flag */
-
-/* interrupt causes */
-#define DS_XCTRL4A_IFS (DS_XCTRL4A_RF|DS_XCTRL4A_WF|DS_XCTRL4A_KF)
-
-/* extended control register 4b */
-#define DS_XCTRL4B_ABE 0x80            /* auxiliary battery enable */
-#define DS_XCTRL4B_E32K        0x40            /* enable 32.768 kHz Output */
-#define DS_XCTRL4B_CS  0x20            /* crystal select */
-#define DS_XCTRL4B_RCE 0x10            /* ram clear enable */
-#define DS_XCTRL4B_PRS 0x08            /* PAB resec select */
-#define DS_XCTRL4B_RIE 0x04            /* ram clear interrupt enable */
-#define DS_XCTRL4B_WFE 0x02            /* wake up alarm interrupt enable */
-#define DS_XCTRL4B_KFE 0x01            /* kickstart interrupt enable */
-
-/* interrupt enable bits */
-#define DS_XCTRL4B_IFES        (DS_XCTRL4B_RIE|DS_XCTRL4B_WFE|DS_XCTRL4B_KFE)
-
-#endif /* __LINUX_DS17287RTC_H */
index 4f1bbc6..546d680 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _DYNAMIC_DEBUG_H
 #define _DYNAMIC_DEBUG_H
 
+#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
+#include <linux/jump_label.h>
+#endif
+
 /*
  * An instance of this structure is created in a special
  * ELF section at every dynamic debug callsite.  At runtime,
@@ -33,6 +37,12 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_DEFAULT 0
 #endif
        unsigned int flags:8;
+#ifdef HAVE_JUMP_LABEL
+       union {
+               struct static_key_true dd_key_true;
+               struct static_key_false dd_key_false;
+       } key;
+#endif
 } __attribute__((aligned(8)));
 
 
@@ -60,7 +70,7 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor,
                          const struct net_device *dev,
                          const char *fmt, ...);
 
-#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)               \
+#define DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, key, init)        \
        static struct _ddebug  __aligned(8)                     \
        __attribute__((section("__verbose"))) name = {          \
                .modname = KBUILD_MODNAME,                      \
@@ -68,13 +78,51 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor,
                .filename = __FILE__,                           \
                .format = (fmt),                                \
                .lineno = __LINE__,                             \
-               .flags =  _DPRINTK_FLAGS_DEFAULT,               \
+               .flags = _DPRINTK_FLAGS_DEFAULT,                \
+               dd_key_init(key, init)                          \
        }
 
+#ifdef HAVE_JUMP_LABEL
+
+#define dd_key_init(key, init) key = (init)
+
+#ifdef DEBUG
+#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
+       DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_true, \
+                                         (STATIC_KEY_TRUE_INIT))
+
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+       static_branch_likely(&descriptor.key.dd_key_true)
+#else
+#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
+       DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_false, \
+                                         (STATIC_KEY_FALSE_INIT))
+
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+       static_branch_unlikely(&descriptor.key.dd_key_false)
+#endif
+
+#else
+
+#define dd_key_init(key, init)
+
+#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
+       DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, 0, 0)
+
+#ifdef DEBUG
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+       likely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+#else
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+       unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+#endif
+
+#endif
+
 #define dynamic_pr_debug(fmt, ...)                             \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
-       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
+       if (DYNAMIC_DEBUG_BRANCH(descriptor))                   \
                __dynamic_pr_debug(&descriptor, pr_fmt(fmt),    \
                                   ##__VA_ARGS__);              \
 } while (0)
@@ -82,7 +130,7 @@ do {                                                         \
 #define dynamic_dev_dbg(dev, fmt, ...)                         \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
-       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
+       if (DYNAMIC_DEBUG_BRANCH(descriptor))                   \
                __dynamic_dev_dbg(&descriptor, dev, fmt,        \
                                  ##__VA_ARGS__);               \
 } while (0)
@@ -90,7 +138,7 @@ do {                                                         \
 #define dynamic_netdev_dbg(dev, fmt, ...)                      \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
-       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
+       if (DYNAMIC_DEBUG_BRANCH(descriptor))                   \
                __dynamic_netdev_dbg(&descriptor, dev, fmt,     \
                                     ##__VA_ARGS__);            \
 } while (0)
@@ -100,7 +148,7 @@ do {                                                                \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor,               \
                __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
-       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
+       if (DYNAMIC_DEBUG_BRANCH(descriptor))                   \
                print_hex_dump(KERN_DEBUG, prefix_str,          \
                               prefix_type, rowsize, groupsize, \
                               buf, len, ascii);                \
index 2f9ccbe..c565f87 100644 (file)
@@ -82,7 +82,7 @@ extern struct module __this_module;
 #include <generated/autoksyms.h>
 
 #define __EXPORT_SYMBOL(sym, sec)                              \
-       __cond_export_sym(sym, sec, config_enabled(__KSYM_##sym))
+       __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))
 #define __cond_export_sym(sym, sec, conf)                      \
        ___cond_export_sym(sym, sec, conf)
 #define ___cond_export_sym(sym, sec, enabled)                  \
diff --git a/include/linux/extable.h b/include/linux/extable.h
new file mode 100644 (file)
index 0000000..7effea4
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _LINUX_EXTABLE_H
+#define _LINUX_EXTABLE_H
+
+#include <linux/stddef.h>      /* for NULL */
+
+struct module;
+struct exception_table_entry;
+
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+              const struct exception_table_entry *last,
+              unsigned long value);
+void sort_extable(struct exception_table_entry *start,
+                 struct exception_table_entry *finish);
+void sort_main_extable(void);
+void trim_init_extable(struct module *m);
+
+/* Given an address, look for it in the exception tables */
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+
+#ifdef CONFIG_MODULES
+/* For extable.c to search modules' exception tables. */
+const struct exception_table_entry *search_module_extables(unsigned long addr);
+#else
+static inline const struct exception_table_entry *
+search_module_extables(unsigned long addr)
+{
+       return NULL;
+}
+#endif /*CONFIG_MODULES*/
+
+#endif /* _LINUX_EXTABLE_H */
index 523ea3f..8cc719a 100644 (file)
@@ -358,7 +358,7 @@ u64 fence_context_alloc(unsigned num);
 #define FENCE_TRACE(f, fmt, args...) \
        do {                                                            \
                struct fence *__ff = (f);                               \
-               if (config_enabled(CONFIG_FENCE_TRACE))                 \
+               if (IS_ENABLED(CONFIG_FENCE_TRACE))                     \
                        pr_info("f %llu#%u: " fmt,                      \
                                __ff->context, __ff->seqno, ##args);    \
        } while (0)
index 5c41c5e..b1f9f0c 100644 (file)
@@ -47,6 +47,8 @@ int request_firmware_nowait(
        void (*cont)(const struct firmware *fw, void *context));
 int request_firmware_direct(const struct firmware **fw, const char *name,
                            struct device *device);
+int request_firmware_into_buf(const struct firmware **firmware_p,
+       const char *name, struct device *device, void *buf, size_t size);
 
 void release_firmware(const struct firmware *fw);
 #else
@@ -75,5 +77,11 @@ static inline int request_firmware_direct(const struct firmware **fw,
        return -EINVAL;
 }
 
+static inline int request_firmware_into_buf(const struct firmware **firmware_p,
+       const char *name, struct device *device, void *buf, size_t size)
+{
+       return -EINVAL;
+}
+
 #endif
 #endif
index 577365a..3523bf6 100644 (file)
@@ -2652,6 +2652,7 @@ extern int do_pipe_flags(int *, int);
 #define __kernel_read_file_id(id) \
        id(UNKNOWN, unknown)            \
        id(FIRMWARE, firmware)          \
+       id(FIRMWARE_PREALLOC_BUFFER, firmware)  \
        id(MODULE, kernel-module)               \
        id(KEXEC_IMAGE, kexec-image)            \
        id(KEXEC_INITRAMFS, kexec-initramfs)    \
@@ -2746,11 +2747,6 @@ extern struct inode *new_inode(struct super_block *sb);
 extern void free_inode_nonrcu(struct inode *inode);
 extern int should_remove_suid(struct dentry *);
 extern int file_remove_privs(struct file *);
-extern int dentry_needs_remove_privs(struct dentry *dentry);
-static inline int file_needs_remove_privs(struct file *file)
-{
-       return dentry_needs_remove_privs(file->f_path.dentry);
-}
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 static inline void insert_inode_hash(struct inode *inode)
index 0f9bafa..d98780c 100644 (file)
@@ -62,7 +62,6 @@ struct serio;
 void i8042_lock_chip(void);
 void i8042_unlock_chip(void);
 int i8042_command(unsigned char *param, int command);
-bool i8042_check_port_owner(const struct serio *);
 int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
                                        struct serio *serio));
 int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
@@ -83,11 +82,6 @@ static inline int i8042_command(unsigned char *param, int command)
        return -ENODEV;
 }
 
-static inline bool i8042_check_port_owner(const struct serio *serio)
-{
-       return false;
-}
-
 static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
                                        struct serio *serio))
 {
index aedb254..6935d02 100644 (file)
 #define __refdata        __section(.ref.data)
 #define __refconst       __constsection(.ref.rodata)
 
-/* compatibility defines */
-#define __init_refok     __ref
-#define __initdata_refok __refdata
-#define __exit_refok     __ref
-
-
 #ifdef MODULE
 #define __exitused
 #else
index 1eee6bc..d10e54f 100644 (file)
@@ -63,8 +63,6 @@ struct ipc_namespace {
 };
 
 extern struct ipc_namespace init_ipc_ns;
-extern atomic_t nr_ipc_ns;
-
 extern spinlock_t mq_lock;
 
 #ifdef CONFIG_SYSVIPC
index 107eed4..56b0b7e 100644 (file)
 #define GICR_WAKER_ProcessorSleep      (1U << 1)
 #define GICR_WAKER_ChildrenAsleep      (1U << 2)
 
-#define GICR_PROPBASER_NonShareable    (0U << 10)
-#define GICR_PROPBASER_InnerShareable  (1U << 10)
-#define GICR_PROPBASER_OuterShareable  (2U << 10)
-#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
-#define GICR_PROPBASER_nCnB            (0U << 7)
-#define GICR_PROPBASER_nC              (1U << 7)
-#define GICR_PROPBASER_RaWt            (2U << 7)
-#define GICR_PROPBASER_RaWb            (3U << 7)
-#define GICR_PROPBASER_WaWt            (4U << 7)
-#define GICR_PROPBASER_WaWb            (5U << 7)
-#define GICR_PROPBASER_RaWaWt          (6U << 7)
-#define GICR_PROPBASER_RaWaWb          (7U << 7)
-#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
-#define GICR_PROPBASER_IDBITS_MASK     (0x1f)
-
-#define GICR_PENDBASER_NonShareable    (0U << 10)
-#define GICR_PENDBASER_InnerShareable  (1U << 10)
-#define GICR_PENDBASER_OuterShareable  (2U << 10)
-#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
-#define GICR_PENDBASER_nCnB            (0U << 7)
-#define GICR_PENDBASER_nC              (1U << 7)
-#define GICR_PENDBASER_RaWt            (2U << 7)
-#define GICR_PENDBASER_RaWb            (3U << 7)
-#define GICR_PENDBASER_WaWt            (4U << 7)
-#define GICR_PENDBASER_WaWb            (5U << 7)
-#define GICR_PENDBASER_RaWaWt          (6U << 7)
-#define GICR_PENDBASER_RaWaWb          (7U << 7)
-#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+#define GIC_BASER_CACHE_nCnB           0ULL
+#define GIC_BASER_CACHE_SameAsInner    0ULL
+#define GIC_BASER_CACHE_nC             1ULL
+#define GIC_BASER_CACHE_RaWt           2ULL
+#define GIC_BASER_CACHE_RaWb           3ULL
+#define GIC_BASER_CACHE_WaWt           4ULL
+#define GIC_BASER_CACHE_WaWb           5ULL
+#define GIC_BASER_CACHE_RaWaWt         6ULL
+#define GIC_BASER_CACHE_RaWaWb         7ULL
+#define GIC_BASER_CACHE_MASK           7ULL
+#define GIC_BASER_NonShareable         0ULL
+#define GIC_BASER_InnerShareable       1ULL
+#define GIC_BASER_OuterShareable       2ULL
+#define GIC_BASER_SHAREABILITY_MASK    3ULL
+
+#define GIC_BASER_CACHEABILITY(reg, inner_outer, type)                 \
+       (GIC_BASER_CACHE_##type << reg##_##inner_outer##_CACHEABILITY_SHIFT)
+
+#define GIC_BASER_SHAREABILITY(reg, type)                              \
+       (GIC_BASER_##type << reg##_SHAREABILITY_SHIFT)
+
+#define GICR_PROPBASER_SHAREABILITY_SHIFT              (10)
+#define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT                (7)
+#define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT                (56)
+#define GICR_PROPBASER_SHAREABILITY_MASK                               \
+       GIC_BASER_SHAREABILITY(GICR_PROPBASER, SHAREABILITY_MASK)
+#define GICR_PROPBASER_INNER_CACHEABILITY_MASK                         \
+       GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, MASK)
+#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK                         \
+       GIC_BASER_CACHEABILITY(GICR_PROPBASER, OUTER, MASK)
+#define GICR_PROPBASER_CACHEABILITY_MASK GICR_PROPBASER_INNER_CACHEABILITY_MASK
+
+#define GICR_PROPBASER_InnerShareable                                  \
+       GIC_BASER_SHAREABILITY(GICR_PROPBASER, InnerShareable)
+
+#define GICR_PROPBASER_nCnB    GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nCnB)
+#define GICR_PROPBASER_nC      GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nC)
+#define GICR_PROPBASER_RaWt    GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt)
+#define GICR_PROPBASER_RaWb    GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt)
+#define GICR_PROPBASER_WaWt    GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWt)
+#define GICR_PROPBASER_WaWb    GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWb)
+#define GICR_PROPBASER_RaWaWt  GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWt)
+#define GICR_PROPBASER_RaWaWb  GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
+
+#define GICR_PROPBASER_IDBITS_MASK                     (0x1f)
+
+#define GICR_PENDBASER_SHAREABILITY_SHIFT              (10)
+#define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT                (7)
+#define GICR_PENDBASER_OUTER_CACHEABILITY_SHIFT                (56)
+#define GICR_PENDBASER_SHAREABILITY_MASK                               \
+       GIC_BASER_SHAREABILITY(GICR_PENDBASER, SHAREABILITY_MASK)
+#define GICR_PENDBASER_INNER_CACHEABILITY_MASK                         \
+       GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, MASK)
+#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK                         \
+       GIC_BASER_CACHEABILITY(GICR_PENDBASER, OUTER, MASK)
+#define GICR_PENDBASER_CACHEABILITY_MASK GICR_PENDBASER_INNER_CACHEABILITY_MASK
+
+#define GICR_PENDBASER_InnerShareable                                  \
+       GIC_BASER_SHAREABILITY(GICR_PENDBASER, InnerShareable)
+
+#define GICR_PENDBASER_nCnB    GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nCnB)
+#define GICR_PENDBASER_nC      GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nC)
+#define GICR_PENDBASER_RaWt    GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt)
+#define GICR_PENDBASER_RaWb    GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt)
+#define GICR_PENDBASER_WaWt    GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWt)
+#define GICR_PENDBASER_WaWb    GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWb)
+#define GICR_PENDBASER_RaWaWt  GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWaWt)
+#define GICR_PENDBASER_RaWaWb  GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWaWb)
+
+#define GICR_PENDBASER_PTZ                             BIT_ULL(62)
 
 /*
  * Re-Distributor registers, offsets from SGI_base
 #define GITS_CWRITER                   0x0088
 #define GITS_CREADR                    0x0090
 #define GITS_BASER                     0x0100
+#define GITS_IDREGS_BASE               0xffd0
+#define GITS_PIDR0                     0xffe0
+#define GITS_PIDR1                     0xffe4
 #define GITS_PIDR2                     GICR_PIDR2
+#define GITS_PIDR4                     0xffd0
+#define GITS_CIDR0                     0xfff0
+#define GITS_CIDR1                     0xfff4
+#define GITS_CIDR2                     0xfff8
+#define GITS_CIDR3                     0xfffc
 
 #define GITS_TRANSLATER                        0x10040
 
 #define GITS_CTLR_ENABLE               (1U << 0)
 #define GITS_CTLR_QUIESCENT            (1U << 31)
 
+#define GITS_TYPER_PLPIS               (1UL << 0)
+#define GITS_TYPER_IDBITS_SHIFT                8
 #define GITS_TYPER_DEVBITS_SHIFT       13
 #define GITS_TYPER_DEVBITS(r)          ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
 #define GITS_TYPER_PTA                 (1UL << 19)
-
-#define GITS_CBASER_VALID              (1UL << 63)
-#define GITS_CBASER_nCnB               (0UL << 59)
-#define GITS_CBASER_nC                 (1UL << 59)
-#define GITS_CBASER_RaWt               (2UL << 59)
-#define GITS_CBASER_RaWb               (3UL << 59)
-#define GITS_CBASER_WaWt               (4UL << 59)
-#define GITS_CBASER_WaWb               (5UL << 59)
-#define GITS_CBASER_RaWaWt             (6UL << 59)
-#define GITS_CBASER_RaWaWb             (7UL << 59)
-#define GITS_CBASER_CACHEABILITY_MASK  (7UL << 59)
-#define GITS_CBASER_NonShareable       (0UL << 10)
-#define GITS_CBASER_InnerShareable     (1UL << 10)
-#define GITS_CBASER_OuterShareable     (2UL << 10)
-#define GITS_CBASER_SHAREABILITY_MASK  (3UL << 10)
+#define GITS_TYPER_HWCOLLCNT_SHIFT     24
+
+#define GITS_CBASER_VALID                      (1UL << 63)
+#define GITS_CBASER_SHAREABILITY_SHIFT         (10)
+#define GITS_CBASER_INNER_CACHEABILITY_SHIFT   (59)
+#define GITS_CBASER_OUTER_CACHEABILITY_SHIFT   (53)
+#define GITS_CBASER_SHAREABILITY_MASK                                  \
+       GIC_BASER_SHAREABILITY(GITS_CBASER, SHAREABILITY_MASK)
+#define GITS_CBASER_INNER_CACHEABILITY_MASK                            \
+       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, MASK)
+#define GITS_CBASER_OUTER_CACHEABILITY_MASK                            \
+       GIC_BASER_CACHEABILITY(GITS_CBASER, OUTER, MASK)
+#define GITS_CBASER_CACHEABILITY_MASK GITS_CBASER_INNER_CACHEABILITY_MASK
+
+#define GITS_CBASER_InnerShareable                                     \
+       GIC_BASER_SHAREABILITY(GITS_CBASER, InnerShareable)
+
+#define GITS_CBASER_nCnB       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nCnB)
+#define GITS_CBASER_nC         GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nC)
+#define GITS_CBASER_RaWt       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt)
+#define GITS_CBASER_RaWb       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt)
+#define GITS_CBASER_WaWt       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWt)
+#define GITS_CBASER_WaWb       GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWb)
+#define GITS_CBASER_RaWaWt     GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWt)
+#define GITS_CBASER_RaWaWb     GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWb)
 
 #define GITS_BASER_NR_REGS             8
 
-#define GITS_BASER_VALID               (1UL << 63)
-#define GITS_BASER_INDIRECT            (1UL << 62)
-#define GITS_BASER_nCnB                        (0UL << 59)
-#define GITS_BASER_nC                  (1UL << 59)
-#define GITS_BASER_RaWt                        (2UL << 59)
-#define GITS_BASER_RaWb                        (3UL << 59)
-#define GITS_BASER_WaWt                        (4UL << 59)
-#define GITS_BASER_WaWb                        (5UL << 59)
-#define GITS_BASER_RaWaWt              (6UL << 59)
-#define GITS_BASER_RaWaWb              (7UL << 59)
-#define GITS_BASER_CACHEABILITY_MASK   (7UL << 59)
-#define GITS_BASER_TYPE_SHIFT          (56)
+#define GITS_BASER_VALID                       (1UL << 63)
+#define GITS_BASER_INDIRECT                    (1ULL << 62)
+
+#define GITS_BASER_INNER_CACHEABILITY_SHIFT    (59)
+#define GITS_BASER_OUTER_CACHEABILITY_SHIFT    (53)
+#define GITS_BASER_INNER_CACHEABILITY_MASK                             \
+       GIC_BASER_CACHEABILITY(GITS_BASER, INNER, MASK)
+#define GITS_BASER_CACHEABILITY_MASK           GITS_BASER_INNER_CACHEABILITY_MASK
+#define GITS_BASER_OUTER_CACHEABILITY_MASK                             \
+       GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, MASK)
+#define GITS_BASER_SHAREABILITY_MASK                                   \
+       GIC_BASER_SHAREABILITY(GITS_BASER, SHAREABILITY_MASK)
+
+#define GITS_BASER_nCnB                GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nCnB)
+#define GITS_BASER_nC          GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nC)
+#define GITS_BASER_RaWt                GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt)
+#define GITS_BASER_RaWb                GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt)
+#define GITS_BASER_WaWt                GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWt)
+#define GITS_BASER_WaWb                GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWb)
+#define GITS_BASER_RaWaWt      GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWaWt)
+#define GITS_BASER_RaWaWb      GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWaWb)
+
+#define GITS_BASER_TYPE_SHIFT                  (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
-#define GITS_BASER_ENTRY_SIZE_SHIFT    (48)
+#define GITS_BASER_ENTRY_SIZE_SHIFT            (48)
 #define GITS_BASER_ENTRY_SIZE(r)       ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
-#define GITS_BASER_NonShareable                (0UL << 10)
-#define GITS_BASER_InnerShareable      (1UL << 10)
-#define GITS_BASER_OuterShareable      (2UL << 10)
 #define GITS_BASER_SHAREABILITY_SHIFT  (10)
-#define GITS_BASER_SHAREABILITY_MASK   (3UL << GITS_BASER_SHAREABILITY_SHIFT)
+#define GITS_BASER_InnerShareable                                      \
+       GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
 #define GITS_BASER_PAGE_SIZE_SHIFT     (8)
 #define GITS_BASER_PAGE_SIZE_4K                (0UL << GITS_BASER_PAGE_SIZE_SHIFT)
 #define GITS_BASER_PAGE_SIZE_16K       (1UL << GITS_BASER_PAGE_SIZE_SHIFT)
 #define GITS_BASER_PAGE_SIZE_MASK      (3UL << GITS_BASER_PAGE_SIZE_SHIFT)
 #define GITS_BASER_PAGES_MAX           256
 #define GITS_BASER_PAGES_SHIFT         (0)
+#define GITS_BASER_NR_PAGES(r)         (((r) & 0xff) + 1)
 
 #define GITS_BASER_TYPE_NONE           0
 #define GITS_BASER_TYPE_DEVICE         1
  */
 #define GITS_CMD_MAPD                  0x08
 #define GITS_CMD_MAPC                  0x09
-#define GITS_CMD_MAPVI                 0x0a
+#define GITS_CMD_MAPTI                 0x0a
+/* older GIC documentation used MAPVI for this command */
+#define GITS_CMD_MAPVI                 GITS_CMD_MAPTI
+#define GITS_CMD_MAPI                  0x0b
 #define GITS_CMD_MOVI                  0x01
 #define GITS_CMD_DISCARD               0x0f
 #define GITS_CMD_INV                   0x0c
 #define GITS_CMD_CLEAR                 0x04
 #define GITS_CMD_SYNC                  0x05
 
+/*
+ * ITS error numbers
+ */
+#define E_ITS_MOVI_UNMAPPED_INTERRUPT          0x010107
+#define E_ITS_MOVI_UNMAPPED_COLLECTION         0x010109
+#define E_ITS_CLEAR_UNMAPPED_INTERRUPT         0x010507
+#define E_ITS_MAPD_DEVICE_OOR                  0x010801
+#define E_ITS_MAPC_PROCNUM_OOR                 0x010902
+#define E_ITS_MAPC_COLLECTION_OOR              0x010903
+#define E_ITS_MAPTI_UNMAPPED_DEVICE            0x010a04
+#define E_ITS_MAPTI_PHYSICALID_OOR             0x010a06
+#define E_ITS_INV_UNMAPPED_INTERRUPT           0x010c07
+#define E_ITS_INVALL_UNMAPPED_COLLECTION       0x010d09
+#define E_ITS_MOVALL_PROCNUM_OOR               0x010e01
+#define E_ITS_DISCARD_UNMAPPED_INTERRUPT       0x010f07
+
 /*
  * CPU interface registers
  */
index 6890446..661af56 100644 (file)
@@ -76,7 +76,6 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
-#include <linux/bug.h>
 
 extern bool static_key_initialized;
 
@@ -115,20 +114,8 @@ enum jump_label_type {
 
 struct module;
 
-#include <linux/atomic.h>
-
 #ifdef HAVE_JUMP_LABEL
 
-static inline int static_key_count(struct static_key *key)
-{
-       /*
-        * -1 means the first static_key_slow_inc() is in progress.
-        *  static_key_enabled() must return true, so return 1 here.
-        */
-       int n = atomic_read(&key->enabled);
-       return n >= 0 ? n : 1;
-}
-
 #define JUMP_TYPE_FALSE        0UL
 #define JUMP_TYPE_TRUE 1UL
 #define JUMP_TYPE_MASK 1UL
@@ -157,16 +144,29 @@ extern int jump_label_text_reserved(void *start, void *end);
 extern void static_key_slow_inc(struct static_key *key);
 extern void static_key_slow_dec(struct static_key *key);
 extern void jump_label_apply_nops(struct module *mod);
+extern int static_key_count(struct static_key *key);
+extern void static_key_enable(struct static_key *key);
+extern void static_key_disable(struct static_key *key);
 
+/*
+ * We should be using ATOMIC_INIT() for initializing .enabled, but
+ * the inclusion of atomic.h is problematic for inclusion of jump_label.h
+ * in 'low-level' headers. Thus, we are initializing .enabled with a
+ * raw value, but have added a BUILD_BUG_ON() to catch any issues in
+ * jump_label_init() see: kernel/jump_label.c.
+ */
 #define STATIC_KEY_INIT_TRUE                                   \
-       { .enabled = ATOMIC_INIT(1),                            \
+       { .enabled = { 1 },                                     \
          .entries = (void *)JUMP_TYPE_TRUE }
 #define STATIC_KEY_INIT_FALSE                                  \
-       { .enabled = ATOMIC_INIT(0),                            \
+       { .enabled = { 0 },                                     \
          .entries = (void *)JUMP_TYPE_FALSE }
 
 #else  /* !HAVE_JUMP_LABEL */
 
+#include <linux/atomic.h>
+#include <linux/bug.h>
+
 static inline int static_key_count(struct static_key *key)
 {
        return atomic_read(&key->enabled);
@@ -216,14 +216,6 @@ static inline int jump_label_apply_nops(struct module *mod)
        return 0;
 }
 
-#define STATIC_KEY_INIT_TRUE   { .enabled = ATOMIC_INIT(1) }
-#define STATIC_KEY_INIT_FALSE  { .enabled = ATOMIC_INIT(0) }
-
-#endif /* HAVE_JUMP_LABEL */
-
-#define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE
-#define jump_label_enabled static_key_enabled
-
 static inline void static_key_enable(struct static_key *key)
 {
        int count = static_key_count(key);
@@ -244,6 +236,14 @@ static inline void static_key_disable(struct static_key *key)
                static_key_slow_dec(key);
 }
 
+#define STATIC_KEY_INIT_TRUE   { .enabled = ATOMIC_INIT(1) }
+#define STATIC_KEY_INIT_FALSE  { .enabled = ATOMIC_INIT(0) }
+
+#endif /* HAVE_JUMP_LABEL */
+
+#define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE
+#define jump_label_enabled static_key_enabled
+
 /* -------------------------------------------------------------------------- */
 
 /*
index c9cf374..d600303 100644 (file)
@@ -56,6 +56,7 @@ void kasan_cache_destroy(struct kmem_cache *cache);
 void kasan_poison_slab(struct page *page);
 void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
 void kasan_poison_object_data(struct kmem_cache *cache, void *object);
+void kasan_init_slab_obj(struct kmem_cache *cache, const void *object);
 
 void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
 void kasan_kfree_large(const void *ptr);
@@ -102,6 +103,8 @@ static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
                                        void *object) {}
 static inline void kasan_poison_object_data(struct kmem_cache *cache,
                                        void *object) {}
+static inline void kasan_init_slab_obj(struct kmem_cache *cache,
+                               const void *object) {}
 
 static inline void kasan_kmalloc_large(void *ptr, size_t size, gfp_t flags) {}
 static inline void kasan_kfree_large(const void *ptr) {}
index b33c779..15ec117 100644 (file)
@@ -3,6 +3,21 @@
 
 #include <generated/autoconf.h>
 
+#define __ARG_PLACEHOLDER_1 0,
+#define __take_second_arg(__ignored, val, ...) val
+
+/*
+ * The use of "&&" / "||" is limited in certain expressions.
+ * The followings enable to calculate "and" / "or" with macro expansion only.
+ */
+#define __and(x, y)                    ___and(x, y)
+#define ___and(x, y)                   ____and(__ARG_PLACEHOLDER_##x, y)
+#define ____and(arg1_or_junk, y)       __take_second_arg(arg1_or_junk y, 0)
+
+#define __or(x, y)                     ___or(x, y)
+#define ___or(x, y)                    ____or(__ARG_PLACEHOLDER_##x, y)
+#define ____or(arg1_or_junk, y)                __take_second_arg(arg1_or_junk 1, y)
+
 /*
  * Helper macros to use CONFIG_ options in C/CPP expressions. Note that
  * these only work with boolean and tristate options.
  * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
  * the last step cherry picks the 2nd arg, we get a zero.
  */
-#define __ARG_PLACEHOLDER_1 0,
-#define config_enabled(cfg) _config_enabled(cfg)
-#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
-#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0)
-#define ___config_enabled(__ignored, val, ...) val
+#define config_enabled(cfg)            ___is_defined(cfg)
+#define __is_defined(x)                        ___is_defined(x)
+#define ___is_defined(val)             ____is_defined(__ARG_PLACEHOLDER_##val)
+#define ____is_defined(arg1_or_junk)   __take_second_arg(arg1_or_junk 1, 0)
 
 /*
  * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
  * This is similar to IS_ENABLED(), but returns false when invoked from
  * built-in code when CONFIG_FOO is set to 'm'.
  */
-#define IS_REACHABLE(option) (config_enabled(option) || \
-                (config_enabled(option##_MODULE) && config_enabled(MODULE)))
+#define IS_REACHABLE(option) __or(IS_BUILTIN(option), \
+                               __and(IS_MODULE(option), __is_defined(MODULE)))
 
 /*
  * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
  * 0 otherwise.
  */
-#define IS_ENABLED(option) \
-       (IS_BUILTIN(option) || IS_MODULE(option))
+#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
 
 #endif /* __LINUX_KCONFIG_H */
index c420821..d96a611 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/log2.h>
 #include <linux/typecheck.h>
 #include <linux/printk.h>
-#include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
 #include <uapi/linux/kernel.h>
 
index e8acb2b..d743777 100644 (file)
@@ -14,6 +14,8 @@
 
 #if !defined(__ASSEMBLY__)
 
+#include <asm/io.h>
+
 #include <uapi/linux/kexec.h>
 
 #ifdef CONFIG_KEXEC_CORE
@@ -41,7 +43,7 @@
 #endif
 
 #ifndef KEXEC_CONTROL_MEMORY_GFP
-#define KEXEC_CONTROL_MEMORY_GFP GFP_KERNEL
+#define KEXEC_CONTROL_MEMORY_GFP (GFP_KERNEL | __GFP_NORETRY)
 #endif
 
 #ifndef KEXEC_CONTROL_PAGE_SIZE
@@ -228,12 +230,13 @@ extern void *kexec_purgatory_get_symbol_addr(struct kimage *image,
 extern void __crash_kexec(struct pt_regs *);
 extern void crash_kexec(struct pt_regs *);
 int kexec_should_crash(struct task_struct *);
+int kexec_crash_loaded(void);
 void crash_save_cpu(struct pt_regs *regs, int cpu);
 void crash_save_vmcoreinfo(void);
 void arch_crash_save_vmcoreinfo(void);
 __printf(1, 2)
 void vmcoreinfo_append_str(const char *fmt, ...);
-unsigned long paddr_vmcoreinfo_note(void);
+phys_addr_t paddr_vmcoreinfo_note(void);
 
 #define VMCOREINFO_OSRELEASE(value) \
        vmcoreinfo_append_str("OSRELEASE=%s\n", value)
@@ -318,12 +321,51 @@ int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
 void arch_kexec_protect_crashkres(void);
 void arch_kexec_unprotect_crashkres(void);
 
+#ifndef page_to_boot_pfn
+static inline unsigned long page_to_boot_pfn(struct page *page)
+{
+       return page_to_pfn(page);
+}
+#endif
+
+#ifndef boot_pfn_to_page
+static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
+{
+       return pfn_to_page(boot_pfn);
+}
+#endif
+
+#ifndef phys_to_boot_phys
+static inline unsigned long phys_to_boot_phys(phys_addr_t phys)
+{
+       return phys;
+}
+#endif
+
+#ifndef boot_phys_to_phys
+static inline phys_addr_t boot_phys_to_phys(unsigned long boot_phys)
+{
+       return boot_phys;
+}
+#endif
+
+static inline unsigned long virt_to_boot_phys(void *addr)
+{
+       return phys_to_boot_phys(__pa((unsigned long)addr));
+}
+
+static inline void *boot_phys_to_virt(unsigned long entry)
+{
+       return phys_to_virt(boot_phys_to_phys(entry));
+}
+
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
 static inline void __crash_kexec(struct pt_regs *regs) { }
 static inline void crash_kexec(struct pt_regs *regs) { }
 static inline int kexec_should_crash(struct task_struct *p) { return 0; }
+static inline int kexec_crash_loaded(void) { return 0; }
 #define kexec_in_progress false
 #endif /* CONFIG_KEXEC_CORE */
 
index 1c9c973..01e908a 100644 (file)
@@ -164,6 +164,8 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                            int len, struct kvm_io_device *dev);
 int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
                              struct kvm_io_device *dev);
+struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+                                        gpa_t addr);
 
 #ifdef CONFIG_KVM_ASYNC_PF
 struct kvm_async_pf {
@@ -315,7 +317,13 @@ struct kvm_kernel_irq_routing_entry {
                        unsigned irqchip;
                        unsigned pin;
                } irqchip;
-               struct msi_msg msi;
+               struct {
+                       u32 address_lo;
+                       u32 address_hi;
+                       u32 data;
+                       u32 flags;
+                       u32 devid;
+               } msi;
                struct kvm_s390_adapter_int adapter;
                struct kvm_hv_sint hv_sint;
        };
@@ -371,7 +379,15 @@ struct kvm {
        struct srcu_struct srcu;
        struct srcu_struct irq_srcu;
        struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+
+       /*
+        * created_vcpus is protected by kvm->lock, and is incremented
+        * at the beginning of KVM_CREATE_VCPU.  online_vcpus is only
+        * incremented after storing the kvm_vcpu pointer in vcpus,
+        * and is accessed atomically.
+        */
        atomic_t online_vcpus;
+       int created_vcpus;
        int last_boosted_vcpu;
        struct list_head vm_list;
        struct mutex lock;
@@ -867,45 +883,6 @@ static inline void kvm_iommu_unmap_pages(struct kvm *kvm,
 }
 #endif
 
-/* must be called with irqs disabled */
-static inline void __kvm_guest_enter(void)
-{
-       guest_enter();
-       /* KVM does not hold any references to rcu protected data when it
-        * switches CPU into a guest mode. In fact switching to a guest mode
-        * is very similar to exiting to userspace from rcu point of view. In
-        * addition CPU may stay in a guest mode for quite a long time (up to
-        * one time slice). Lets treat guest mode as quiescent state, just like
-        * we do with user-mode execution.
-        */
-       if (!context_tracking_cpu_is_enabled())
-               rcu_virt_note_context_switch(smp_processor_id());
-}
-
-/* must be called with irqs disabled */
-static inline void __kvm_guest_exit(void)
-{
-       guest_exit();
-}
-
-static inline void kvm_guest_enter(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __kvm_guest_enter();
-       local_irq_restore(flags);
-}
-
-static inline void kvm_guest_exit(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __kvm_guest_exit();
-       local_irq_restore(flags);
-}
-
 /*
  * search_memslots() and __gfn_to_memslot() are here because they are
  * used in non-modular code in arch/powerpc/kvm/book3s_hv_rm_mmu.c.
@@ -1032,17 +1009,18 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
 
 #ifdef CONFIG_S390
 #define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that...
+#elif defined(CONFIG_ARM64)
+#define KVM_MAX_IRQ_ROUTES 4096
 #else
 #define KVM_MAX_IRQ_ROUTES 1024
 #endif
 
-int kvm_setup_default_irq_routing(struct kvm *kvm);
-int kvm_setup_empty_irq_routing(struct kvm *kvm);
 int kvm_set_irq_routing(struct kvm *kvm,
                        const struct kvm_irq_routing_entry *entries,
                        unsigned nr,
                        unsigned flags);
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue);
 void kvm_free_irq_routing(struct kvm *kvm);
 
@@ -1097,12 +1075,6 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 
 #endif /* CONFIG_HAVE_KVM_EVENTFD */
 
-#ifdef CONFIG_KVM_APIC_ARCHITECTURE
-bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu);
-#else
-static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; }
-#endif
-
 static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
 {
        /*
index 7ae3976..101bf19 100644 (file)
@@ -1356,7 +1356,7 @@ union security_list_options {
                                        struct super_block *newsb);
        int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts);
        int (*dentry_init_security)(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen);
 
 
diff --git a/include/linux/m48t86.h b/include/linux/m48t86.h
deleted file mode 100644 (file)
index 915d6b4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * ST M48T86 / Dallas DS12887 RTC driver
- * Copyright (c) 2006 Tower Technologies
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-struct m48t86_ops
-{
-       void (*writebyte)(unsigned char value, unsigned long addr);
-       unsigned char (*readbyte)(unsigned long addr);
-};
index 433e0c7..a585b4b 100644 (file)
@@ -14,6 +14,8 @@
 #include <asm/io.h>
 #include <linux/rtc.h>                 /* get the user-level API */
 #include <asm/mc146818rtc.h>           /* register access macros */
+#include <linux/bcd.h>
+#include <linux/delay.h>
 
 #ifdef __KERNEL__
 #include <linux/spinlock.h>            /* spinlock_t */
@@ -120,4 +122,7 @@ struct cmos_rtc_board_info {
 #define RTC_IO_EXTENT_USED      RTC_IO_EXTENT
 #endif /* ARCH_RTC_LOCATION */
 
+unsigned int mc146818_get_time(struct rtc_time *time);
+int mc146818_set_time(struct rtc_time *time);
+
 #endif /* _MC146818RTC_H */
index 64184d2..d641a18 100644 (file)
@@ -225,6 +225,21 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
                     struct cros_ec_command *msg);
 
+/**
+ * cros_ec_cmd_xfer_status - Send a command to the ChromeOS EC
+ *
+ * This function is identical to cros_ec_cmd_xfer, except it returns success
+ * status only if both the command was transmitted successfully and the EC
+ * replied with success status. It's not necessary to check msg->result when
+ * using this function.
+ *
+ * @ec_dev: EC device
+ * @msg: Message to write
+ * @return: Num. of bytes transferred on success, <0 on failure
+ */
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+                           struct cros_ec_command *msg);
+
 /**
  * cros_ec_remove - Remove a ChromeOS EC
  *
index 13b630c..7e7a8d4 100644 (file)
@@ -949,6 +949,37 @@ struct ec_params_pwm_set_fan_duty {
        uint32_t percent;
 } __packed;
 
+#define EC_CMD_PWM_SET_DUTY 0x25
+/* 16 bit duty cycle, 0xffff = 100% */
+#define EC_PWM_MAX_DUTY 0xffff
+
+enum ec_pwm_type {
+       /* All types, indexed by board-specific enum pwm_channel */
+       EC_PWM_TYPE_GENERIC = 0,
+       /* Keyboard backlight */
+       EC_PWM_TYPE_KB_LIGHT,
+       /* Display backlight */
+       EC_PWM_TYPE_DISPLAY_LIGHT,
+       EC_PWM_TYPE_COUNT,
+};
+
+struct ec_params_pwm_set_duty {
+       uint16_t duty;     /* Duty cycle, EC_PWM_MAX_DUTY = 100% */
+       uint8_t pwm_type;  /* ec_pwm_type */
+       uint8_t index;     /* Type-specific index, or 0 if unique */
+} __packed;
+
+#define EC_CMD_PWM_GET_DUTY 0x26
+
+struct ec_params_pwm_get_duty {
+       uint8_t pwm_type;  /* ec_pwm_type */
+       uint8_t index;     /* Type-specific index, or 0 if unique */
+} __packed;
+
+struct ec_response_pwm_get_duty {
+       uint16_t duty;     /* Duty cycle, EC_PWM_MAX_DUTY = 100% */
+} __packed;
+
 /*****************************************************************************/
 /*
  * Lightbar commands. This looks worse than it is. Since we only use one HOST
index e6f6910..42da355 100644 (file)
@@ -220,6 +220,7 @@ enum {
        MLX4_DEV_CAP_FLAG2_LB_SRC_CHK           = 1ULL << 32,
        MLX4_DEV_CAP_FLAG2_ROCE_V1_V2           = 1ULL <<  33,
        MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER   = 1ULL <<  34,
+       MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT        = 1ULL <<  35,
 };
 
 enum {
@@ -1342,6 +1343,9 @@ enum {
        VXLAN_STEER_BY_INNER_VLAN       = 1 << 4,
 };
 
+enum {
+       MLX4_OP_MOD_QUERY_TRANSPORT_CI_ERRORS = 0x2,
+};
 
 int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port, u32 qpn,
                                enum mlx4_net_trans_promisc_mode mode);
@@ -1382,6 +1386,9 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
 int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
 int mlx4_SYNC_TPT(struct mlx4_dev *dev);
 int mlx4_test_interrupts(struct mlx4_dev *dev);
+int mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier,
+                            const u32 offset[], u32 value[],
+                            size_t array_len, u8 port);
 u32 mlx4_get_eqs_per_port(struct mlx4_dev *dev, u8 port);
 bool mlx4_is_eq_vector_valid(struct mlx4_dev *dev, u8 port, int vector);
 struct cpu_rmap *mlx4_get_cpu_rmap(struct mlx4_dev *dev, int port);
index 2be976d..2566f6d 100644 (file)
@@ -58,6 +58,8 @@ struct mlx5_core_cq {
                void (*comp)(struct mlx5_core_cq *);
                void            *priv;
        } tasklet_ctx;
+       int                     reset_notify_added;
+       struct list_head        reset_notify;
 };
 
 
index a041b99..ccea6fb 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <linux/mlx5/device.h>
 #include <linux/mlx5/doorbell.h>
+#include <linux/mlx5/srq.h>
 
 enum {
        MLX5_RQ_BITMASK_VSD = 1 << 1,
@@ -798,11 +799,10 @@ struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev,
 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 is_xrc);
+                        struct mlx5_srq_attr *in);
 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);
+                       struct mlx5_srq_attr *out);
 int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq,
                      u16 lwm, int is_srq);
 void mlx5_init_mkey_table(struct mlx5_core_dev *dev);
index ab31081..7879bf4 100644 (file)
@@ -556,9 +556,9 @@ struct mlx5_destroy_qp_mbox_out {
 struct mlx5_modify_qp_mbox_in {
        struct mlx5_inbox_hdr   hdr;
        __be32                  qpn;
-       u8                      rsvd1[4];
-       __be32                  optparam;
        u8                      rsvd0[4];
+       __be32                  optparam;
+       u8                      rsvd1[4];
        struct mlx5_qp_context  ctx;
        u8                      rsvd2[16];
 };
index f43ed05..33c97dc 100644 (file)
 
 #include <linux/mlx5/driver.h>
 
+enum {
+       MLX5_SRQ_FLAG_ERR    = (1 << 0),
+       MLX5_SRQ_FLAG_WQ_SIG = (1 << 1),
+};
+
+struct mlx5_srq_attr {
+       u32 type;
+       u32 flags;
+       u32 log_size;
+       u32 wqe_shift;
+       u32 log_page_size;
+       u32 wqe_cnt;
+       u32 srqn;
+       u32 xrcd;
+       u32 page_offset;
+       u32 cqn;
+       u32 pd;
+       u32 lwm;
+       u32 user_index;
+       u64 db_record;
+       u64 *pas;
+};
+
+struct mlx5_core_dev;
+
 void mlx5_init_srq_table(struct mlx5_core_dev *dev);
 void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev);
 
index 33e17f6..634c4c5 100644 (file)
@@ -49,7 +49,7 @@ static inline void vm_unacct_memory(long pages)
  *
  * Returns true if the prot flags are valid
  */
-static inline int arch_validate_prot(unsigned long prot)
+static inline bool arch_validate_prot(unsigned long prot)
 {
        return (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM)) == 0;
 }
index f2e4e90..d572b78 100644 (file)
@@ -68,8 +68,10 @@ extern char * const migratetype_names[MIGRATE_TYPES];
 
 #ifdef CONFIG_CMA
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
+#  define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA)
 #else
 #  define is_migrate_cma(migratetype) false
+#  define is_migrate_cma_page(_page) false
 #endif
 
 #define for_each_migratetype_order(order, type) \
index 3daf2b3..0c3207d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/moduleparam.h>
 #include <linux/jump_label.h>
 #include <linux/export.h>
+#include <linux/extable.h>     /* only as arch move module.h -> extable.h */
 #include <linux/rbtree_latch.h>
 
 #include <linux/percpu.h>
@@ -37,6 +38,7 @@ struct modversion_info {
 };
 
 struct module;
+struct exception_table_entry;
 
 struct module_kobject {
        struct kobject kobj;
@@ -155,18 +157,6 @@ extern void cleanup_module(void);
 #define __INITRODATA_OR_MODULE __INITRODATA
 #endif /*CONFIG_MODULES*/
 
-/* Archs provide a method of finding the correct exception table. */
-struct exception_table_entry;
-
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
-              const struct exception_table_entry *last,
-              unsigned long value);
-void sort_extable(struct exception_table_entry *start,
-                 struct exception_table_entry *finish);
-void sort_main_extable(void);
-void trim_init_extable(struct module *m);
-
 /* Generic info of form tag = "info" */
 #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
 
@@ -268,9 +258,6 @@ extern const typeof(name) __mod_##type##__##name##_device_table             \
  * files require multiple MODULE_FIRMWARE() specifiers */
 #define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
 
-/* Given an address, look for it in the exception tables */
-const struct exception_table_entry *search_exception_tables(unsigned long add);
-
 struct notifier_block;
 
 #ifdef CONFIG_MODULES
@@ -311,6 +298,8 @@ struct module_layout {
        unsigned int text_size;
        /* Size of RO section of the module (text+rodata) */
        unsigned int ro_size;
+       /* Size of RO after init section */
+       unsigned int ro_after_init_size;
 
 #ifdef CONFIG_MODULES_TREE_LOOKUP
        struct mod_tree_node mtn;
@@ -575,8 +564,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
                                             struct module *, unsigned long),
                                   void *data);
 
-extern void __module_put_and_exit(struct module *mod, long code)
-       __attribute__((noreturn));
+extern void __noreturn __module_put_and_exit(struct module *mod,
+                       long code);
 #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code)
 
 #ifdef CONFIG_MODULE_UNLOAD
@@ -630,9 +619,6 @@ const char *module_address_lookup(unsigned long addr,
 int lookup_module_symbol_name(unsigned long addr, char *symname);
 int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 
-/* For extable.c to search modules' exception tables. */
-const struct exception_table_entry *search_module_extables(unsigned long addr);
-
 int register_module_notifier(struct notifier_block *nb);
 int unregister_module_notifier(struct notifier_block *nb);
 
@@ -657,13 +643,6 @@ static inline bool is_livepatch_module(struct module *mod)
 
 #else /* !CONFIG_MODULES... */
 
-/* Given an address, look for it in the exception tables. */
-static inline const struct exception_table_entry *
-search_module_extables(unsigned long addr)
-{
-       return NULL;
-}
-
 static inline struct module *__module_address(unsigned long addr)
 {
        return NULL;
@@ -788,12 +767,12 @@ extern int module_sysfs_initialized;
 #ifdef CONFIG_DEBUG_SET_MODULE_RONX
 extern void set_all_modules_text_rw(void);
 extern void set_all_modules_text_ro(void);
-extern void module_enable_ro(const struct module *mod);
+extern void module_enable_ro(const struct module *mod, bool after_init);
 extern void module_disable_ro(const struct module *mod);
 #else
 static inline void set_all_modules_text_rw(void) { }
 static inline void set_all_modules_text_ro(void) { }
-static inline void module_enable_ro(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) { }
 static inline void module_disable_ro(const struct module *mod) { }
 #endif
 
index fbe8e16..8dd6e01 100644 (file)
@@ -783,6 +783,7 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
  * NAND Flash Manufacturer ID Codes
  */
 #define NAND_MFR_TOSHIBA       0x98
+#define NAND_MFR_ESMT          0xc8
 #define NAND_MFR_SAMSUNG       0xec
 #define NAND_MFR_FUJITSU       0x04
 #define NAND_MFR_NATIONAL      0x8f
index 7f041bd..c425c7b 100644 (file)
@@ -173,10 +173,10 @@ struct spi_nor {
        int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
        int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
 
-       int (*read)(struct spi_nor *nor, loff_t from,
-                       size_t len, size_t *retlen, u_char *read_buf);
-       void (*write)(struct spi_nor *nor, loff_t to,
-                       size_t len, size_t *retlen, const u_char *write_buf);
+       ssize_t (*read)(struct spi_nor *nor, loff_t from,
+                       size_t len, u_char *read_buf);
+       ssize_t (*write)(struct spi_nor *nor, loff_t to,
+                       size_t len, const u_char *write_buf);
        int (*erase)(struct spi_nor *nor, loff_t offs);
 
        int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
index bfed6b3..c6564ad 100644 (file)
@@ -643,4 +643,15 @@ enum pnfs_update_layout_reason {
        PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET,
 };
 
+#define NFS4_OP_MAP_NUM_LONGS                                  \
+       DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long))
+#define NFS4_OP_MAP_NUM_WORDS \
+       (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32))
+struct nfs4_op_map {
+       union {
+               unsigned long longs[NFS4_OP_MAP_NUM_LONGS];
+               u32 words[NFS4_OP_MAP_NUM_WORDS];
+       } u;
+};
+
 #endif
index 82b81a1..7cc0dee 100644 (file)
@@ -1185,17 +1185,6 @@ struct pnfs_ds_commit_info {
        struct pnfs_commit_bucket *buckets;
 };
 
-#define NFS4_OP_MAP_NUM_LONGS \
-       DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long))
-#define NFS4_OP_MAP_NUM_WORDS \
-       (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32))
-struct nfs4_op_map {
-       union {
-               unsigned long longs[NFS4_OP_MAP_NUM_LONGS];
-               u32 words[NFS4_OP_MAP_NUM_WORDS];
-       } u;
-};
-
 struct nfs41_state_protection {
        u32 how;
        struct nfs4_op_map enforce;
@@ -1543,7 +1532,7 @@ struct nfs_rpc_ops {
                            struct nfs_fattr *, struct nfs4_label *);
        int     (*setattr) (struct dentry *, struct nfs_fattr *,
                            struct iattr *);
-       int     (*lookup)  (struct inode *, struct qstr *,
+       int     (*lookup)  (struct inode *, const struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *,
                            struct nfs4_label *);
        int     (*access)  (struct inode *, struct nfs_access_entry *);
@@ -1551,18 +1540,18 @@ struct nfs_rpc_ops {
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
                            struct iattr *, int);
-       int     (*remove)  (struct inode *, struct qstr *);
+       int     (*remove)  (struct inode *, const struct qstr *);
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
        void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
        void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
        void    (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
        int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
-       int     (*link)    (struct inode *, struct inode *, struct qstr *);
+       int     (*link)    (struct inode *, struct inode *, const struct qstr *);
        int     (*symlink) (struct inode *, struct dentry *, struct page *,
                            unsigned int, struct iattr *);
        int     (*mkdir)   (struct inode *, struct dentry *, struct iattr *);
-       int     (*rmdir)   (struct inode *, struct qstr *);
+       int     (*rmdir)   (struct inode *, const struct qstr *);
        int     (*readdir) (struct dentry *, struct rpc_cred *,
                            u64, struct page **, unsigned int, int);
        int     (*mknod)   (struct inode *, struct dentry *, struct iattr *,
diff --git a/include/linux/nilfs2_fs.h b/include/linux/nilfs2_fs.h
deleted file mode 100644 (file)
index 5988dd5..0000000
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
- * nilfs2_fs.h - NILFS2 on-disk structures and common declarations.
- *
- * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
- *
- * Written by Koji Sato and Ryusuke Konishi.
- */
-/*
- *  linux/include/linux/ext2_fs.h
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- *  from
- *
- *  linux/include/linux/minix_fs.h
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#ifndef _LINUX_NILFS_FS_H
-#define _LINUX_NILFS_FS_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/magic.h>
-#include <linux/bug.h>
-
-
-#define NILFS_INODE_BMAP_SIZE  7
-/**
- * struct nilfs_inode - structure of an inode on disk
- * @i_blocks: blocks count
- * @i_size: size in bytes
- * @i_ctime: creation time (seconds)
- * @i_mtime: modification time (seconds)
- * @i_ctime_nsec: creation time (nano seconds)
- * @i_mtime_nsec: modification time (nano seconds)
- * @i_uid: user id
- * @i_gid: group id
- * @i_mode: file mode
- * @i_links_count: links count
- * @i_flags: file flags
- * @i_bmap: block mapping
- * @i_xattr: extended attributes
- * @i_generation: file generation (for NFS)
- * @i_pad:     padding
- */
-struct nilfs_inode {
-       __le64  i_blocks;
-       __le64  i_size;
-       __le64  i_ctime;
-       __le64  i_mtime;
-       __le32  i_ctime_nsec;
-       __le32  i_mtime_nsec;
-       __le32  i_uid;
-       __le32  i_gid;
-       __le16  i_mode;
-       __le16  i_links_count;
-       __le32  i_flags;
-       __le64  i_bmap[NILFS_INODE_BMAP_SIZE];
-#define i_device_code  i_bmap[0]
-       __le64  i_xattr;
-       __le32  i_generation;
-       __le32  i_pad;
-};
-
-#define NILFS_MIN_INODE_SIZE           128
-
-/**
- * struct nilfs_super_root - structure of super root
- * @sr_sum: check sum
- * @sr_bytes: byte count of the structure
- * @sr_flags: flags (reserved)
- * @sr_nongc_ctime: write time of the last segment not for cleaner operation
- * @sr_dat: DAT file inode
- * @sr_cpfile: checkpoint file inode
- * @sr_sufile: segment usage file inode
- */
-struct nilfs_super_root {
-       __le32 sr_sum;
-       __le16 sr_bytes;
-       __le16 sr_flags;
-       __le64 sr_nongc_ctime;
-       struct nilfs_inode sr_dat;
-       struct nilfs_inode sr_cpfile;
-       struct nilfs_inode sr_sufile;
-};
-
-#define NILFS_SR_MDT_OFFSET(inode_size, i)  \
-       ((unsigned long)&((struct nilfs_super_root *)0)->sr_dat + \
-                       (inode_size) * (i))
-#define NILFS_SR_DAT_OFFSET(inode_size)     NILFS_SR_MDT_OFFSET(inode_size, 0)
-#define NILFS_SR_CPFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 1)
-#define NILFS_SR_SUFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 2)
-#define NILFS_SR_BYTES(inode_size)         NILFS_SR_MDT_OFFSET(inode_size, 3)
-
-/*
- * Maximal mount counts
- */
-#define NILFS_DFL_MAX_MNT_COUNT                50      /* 50 mounts */
-
-/*
- * File system states (sbp->s_state, nilfs->ns_mount_state)
- */
-#define NILFS_VALID_FS                 0x0001  /* Unmounted cleanly */
-#define NILFS_ERROR_FS                 0x0002  /* Errors detected */
-#define NILFS_RESIZE_FS                        0x0004  /* Resize required */
-
-/*
- * Mount flags (sbi->s_mount_opt)
- */
-#define NILFS_MOUNT_ERROR_MODE         0x0070  /* Error mode mask */
-#define NILFS_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */
-#define NILFS_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */
-#define NILFS_MOUNT_ERRORS_PANIC       0x0040  /* Panic on errors */
-#define NILFS_MOUNT_BARRIER            0x1000  /* Use block barriers */
-#define NILFS_MOUNT_STRICT_ORDER       0x2000  /*
-                                                * Apply strict in-order
-                                                * semantics also for data
-                                                */
-#define NILFS_MOUNT_NORECOVERY         0x4000  /*
-                                                * Disable write access during
-                                                * mount-time recovery
-                                                */
-#define NILFS_MOUNT_DISCARD            0x8000  /* Issue DISCARD requests */
-
-
-/**
- * struct nilfs_super_block - structure of super block on disk
- */
-struct nilfs_super_block {
-/*00*/ __le32  s_rev_level;            /* Revision level */
-       __le16  s_minor_rev_level;      /* minor revision level */
-       __le16  s_magic;                /* Magic signature */
-
-       __le16  s_bytes;                /*
-                                        * Bytes count of CRC calculation
-                                        * for this structure. s_reserved
-                                        * is excluded.
-                                        */
-       __le16  s_flags;                /* flags */
-       __le32  s_crc_seed;             /* Seed value of CRC calculation */
-/*10*/ __le32  s_sum;                  /* Check sum of super block */
-
-       __le32  s_log_block_size;       /*
-                                        * Block size represented as follows
-                                        * blocksize =
-                                        *     1 << (s_log_block_size + 10)
-                                        */
-       __le64  s_nsegments;            /* Number of segments in filesystem */
-/*20*/ __le64  s_dev_size;             /* block device size in bytes */
-       __le64  s_first_data_block;     /* 1st seg disk block number */
-/*30*/ __le32  s_blocks_per_segment;   /* number of blocks per full segment */
-       __le32  s_r_segments_percentage; /* Reserved segments percentage */
-
-       __le64  s_last_cno;             /* Last checkpoint number */
-/*40*/ __le64  s_last_pseg;            /* disk block addr pseg written last */
-       __le64  s_last_seq;             /* seq. number of seg written last */
-/*50*/ __le64  s_free_blocks_count;    /* Free blocks count */
-
-       __le64  s_ctime;                /*
-                                        * Creation time (execution time of
-                                        * newfs)
-                                        */
-/*60*/ __le64  s_mtime;                /* Mount time */
-       __le64  s_wtime;                /* Write time */
-/*70*/ __le16  s_mnt_count;            /* Mount count */
-       __le16  s_max_mnt_count;        /* Maximal mount count */
-       __le16  s_state;                /* File system state */
-       __le16  s_errors;               /* Behaviour when detecting errors */
-       __le64  s_lastcheck;            /* time of last check */
-
-/*80*/ __le32  s_checkinterval;        /* max. time between checks */
-       __le32  s_creator_os;           /* OS */
-       __le16  s_def_resuid;           /* Default uid for reserved blocks */
-       __le16  s_def_resgid;           /* Default gid for reserved blocks */
-       __le32  s_first_ino;            /* First non-reserved inode */
-
-/*90*/ __le16  s_inode_size;           /* Size of an inode */
-       __le16  s_dat_entry_size;       /* Size of a dat entry */
-       __le16  s_checkpoint_size;      /* Size of a checkpoint */
-       __le16  s_segment_usage_size;   /* Size of a segment usage */
-
-/*98*/ __u8    s_uuid[16];             /* 128-bit uuid for volume */
-/*A8*/ char    s_volume_name[80];      /* volume name */
-
-/*F8*/ __le32  s_c_interval;           /* Commit interval of segment */
-       __le32  s_c_block_max;          /*
-                                        * Threshold of data amount for
-                                        * the segment construction
-                                        */
-/*100*/        __le64  s_feature_compat;       /* Compatible feature set */
-       __le64  s_feature_compat_ro;    /* Read-only compatible feature set */
-       __le64  s_feature_incompat;     /* Incompatible feature set */
-       __u32   s_reserved[186];        /* padding to the end of the block */
-};
-
-/*
- * Codes for operating systems
- */
-#define NILFS_OS_LINUX         0
-/* Codes from 1 to 4 are reserved to keep compatibility with ext2 creator-OS */
-
-/*
- * Revision levels
- */
-#define NILFS_CURRENT_REV      2       /* current major revision */
-#define NILFS_MINOR_REV                0       /* minor revision */
-#define NILFS_MIN_SUPP_REV     2       /* minimum supported revision */
-
-/*
- * Feature set definitions
- *
- * If there is a bit set in the incompatible feature set that the kernel
- * doesn't know about, it should refuse to mount the filesystem.
- */
-#define NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT    0x00000001ULL
-
-#define NILFS_FEATURE_COMPAT_SUPP      0ULL
-#define NILFS_FEATURE_COMPAT_RO_SUPP   NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT
-#define NILFS_FEATURE_INCOMPAT_SUPP    0ULL
-
-/*
- * Bytes count of super_block for CRC-calculation
- */
-#define NILFS_SB_BYTES  \
-       ((long)&((struct nilfs_super_block *)0)->s_reserved)
-
-/*
- * Special inode number
- */
-#define NILFS_ROOT_INO         2       /* Root file inode */
-#define NILFS_DAT_INO          3       /* DAT file */
-#define NILFS_CPFILE_INO       4       /* checkpoint file */
-#define NILFS_SUFILE_INO       5       /* segment usage file */
-#define NILFS_IFILE_INO                6       /* ifile */
-#define NILFS_ATIME_INO                7       /* Atime file (reserved) */
-#define NILFS_XATTR_INO                8       /* Xattribute file (reserved) */
-#define NILFS_SKETCH_INO       10      /* Sketch file */
-#define NILFS_USER_INO         11      /* Fisrt user's file inode number */
-
-#define NILFS_SB_OFFSET_BYTES  1024    /* byte offset of nilfs superblock */
-
-#define NILFS_SEG_MIN_BLOCKS   16      /*
-                                        * Minimum number of blocks in
-                                        * a full segment
-                                        */
-#define NILFS_PSEG_MIN_BLOCKS  2       /*
-                                        * Minimum number of blocks in
-                                        * a partial segment
-                                        */
-#define NILFS_MIN_NRSVSEGS     8       /*
-                                        * Minimum number of reserved
-                                        * segments
-                                        */
-
-/*
- * We call DAT, cpfile, and sufile root metadata files.  Inodes of
- * these files are written in super root block instead of ifile, and
- * garbage collector doesn't keep any past versions of these files.
- */
-#define NILFS_ROOT_METADATA_FILE(ino) \
-       ((ino) >= NILFS_DAT_INO && (ino) <= NILFS_SUFILE_INO)
-
-/*
- * bytes offset of secondary super block
- */
-#define NILFS_SB2_OFFSET_BYTES(devsize)        ((((devsize) >> 12) - 1) << 12)
-
-/*
- * Maximal count of links to a file
- */
-#define NILFS_LINK_MAX         32000
-
-/*
- * Structure of a directory entry
- *  (Same as ext2)
- */
-
-#define NILFS_NAME_LEN 255
-
-/*
- * Block size limitations
- */
-#define NILFS_MIN_BLOCK_SIZE           1024
-#define NILFS_MAX_BLOCK_SIZE           65536
-
-/*
- * The new version of the directory entry.  Since V0 structures are
- * stored in intel byte order, and the name_len field could never be
- * bigger than 255 chars, it's safe to reclaim the extra byte for the
- * file_type field.
- */
-struct nilfs_dir_entry {
-       __le64  inode;                  /* Inode number */
-       __le16  rec_len;                /* Directory entry length */
-       __u8    name_len;               /* Name length */
-       __u8    file_type;              /* Dir entry type (file, dir, etc) */
-       char    name[NILFS_NAME_LEN];   /* File name */
-       char    pad;
-};
-
-/*
- * NILFS directory file types.  Only the low 3 bits are used.  The
- * other bits are reserved for now.
- */
-enum {
-       NILFS_FT_UNKNOWN,
-       NILFS_FT_REG_FILE,
-       NILFS_FT_DIR,
-       NILFS_FT_CHRDEV,
-       NILFS_FT_BLKDEV,
-       NILFS_FT_FIFO,
-       NILFS_FT_SOCK,
-       NILFS_FT_SYMLINK,
-       NILFS_FT_MAX
-};
-
-/*
- * NILFS_DIR_PAD defines the directory entries boundaries
- *
- * NOTE: It must be a multiple of 8
- */
-#define NILFS_DIR_PAD                  8
-#define NILFS_DIR_ROUND                        (NILFS_DIR_PAD - 1)
-#define NILFS_DIR_REC_LEN(name_len)    (((name_len) + 12 + NILFS_DIR_ROUND) & \
-                                       ~NILFS_DIR_ROUND)
-#define NILFS_MAX_REC_LEN              ((1<<16)-1)
-
-static inline unsigned int nilfs_rec_len_from_disk(__le16 dlen)
-{
-       unsigned int len = le16_to_cpu(dlen);
-
-#if !defined(__KERNEL__) || (PAGE_SIZE >= 65536)
-       if (len == NILFS_MAX_REC_LEN)
-               return 1 << 16;
-#endif
-       return len;
-}
-
-static inline __le16 nilfs_rec_len_to_disk(unsigned int len)
-{
-#if !defined(__KERNEL__) || (PAGE_SIZE >= 65536)
-       if (len == (1 << 16))
-               return cpu_to_le16(NILFS_MAX_REC_LEN);
-       else if (len > (1 << 16))
-               BUG();
-#endif
-       return cpu_to_le16(len);
-}
-
-/**
- * struct nilfs_finfo - file information
- * @fi_ino: inode number
- * @fi_cno: checkpoint number
- * @fi_nblocks: number of blocks (including intermediate blocks)
- * @fi_ndatablk: number of file data blocks
- */
-struct nilfs_finfo {
-       __le64 fi_ino;
-       __le64 fi_cno;
-       __le32 fi_nblocks;
-       __le32 fi_ndatablk;
-       /* array of virtual block numbers */
-};
-
-/**
- * struct nilfs_binfo_v - information for the block to which a virtual block number is assigned
- * @bi_vblocknr: virtual block number
- * @bi_blkoff: block offset
- */
-struct nilfs_binfo_v {
-       __le64 bi_vblocknr;
-       __le64 bi_blkoff;
-};
-
-/**
- * struct nilfs_binfo_dat - information for the block which belongs to the DAT file
- * @bi_blkoff: block offset
- * @bi_level: level
- * @bi_pad: padding
- */
-struct nilfs_binfo_dat {
-       __le64 bi_blkoff;
-       __u8 bi_level;
-       __u8 bi_pad[7];
-};
-
-/**
- * union nilfs_binfo: block information
- * @bi_v: nilfs_binfo_v structure
- * @bi_dat: nilfs_binfo_dat structure
- */
-union nilfs_binfo {
-       struct nilfs_binfo_v bi_v;
-       struct nilfs_binfo_dat bi_dat;
-};
-
-/**
- * struct nilfs_segment_summary - segment summary header
- * @ss_datasum: checksum of data
- * @ss_sumsum: checksum of segment summary
- * @ss_magic: magic number
- * @ss_bytes: size of this structure in bytes
- * @ss_flags: flags
- * @ss_seq: sequence number
- * @ss_create: creation timestamp
- * @ss_next: next segment
- * @ss_nblocks: number of blocks
- * @ss_nfinfo: number of finfo structures
- * @ss_sumbytes: total size of segment summary in bytes
- * @ss_pad: padding
- * @ss_cno: checkpoint number
- */
-struct nilfs_segment_summary {
-       __le32 ss_datasum;
-       __le32 ss_sumsum;
-       __le32 ss_magic;
-       __le16 ss_bytes;
-       __le16 ss_flags;
-       __le64 ss_seq;
-       __le64 ss_create;
-       __le64 ss_next;
-       __le32 ss_nblocks;
-       __le32 ss_nfinfo;
-       __le32 ss_sumbytes;
-       __le32 ss_pad;
-       __le64 ss_cno;
-       /* array of finfo structures */
-};
-
-#define NILFS_SEGSUM_MAGIC     0x1eaffa11  /* segment summary magic number */
-
-/*
- * Segment summary flags
- */
-#define NILFS_SS_LOGBGN 0x0001  /* begins a logical segment */
-#define NILFS_SS_LOGEND 0x0002  /* ends a logical segment */
-#define NILFS_SS_SR     0x0004  /* has super root */
-#define NILFS_SS_SYNDT  0x0008  /* includes data only updates */
-#define NILFS_SS_GC     0x0010  /* segment written for cleaner operation */
-
-/**
- * struct nilfs_btree_node - B-tree node
- * @bn_flags: flags
- * @bn_level: level
- * @bn_nchildren: number of children
- * @bn_pad: padding
- */
-struct nilfs_btree_node {
-       __u8 bn_flags;
-       __u8 bn_level;
-       __le16 bn_nchildren;
-       __le32 bn_pad;
-};
-
-/* flags */
-#define NILFS_BTREE_NODE_ROOT   0x01
-
-/* level */
-#define NILFS_BTREE_LEVEL_DATA          0
-#define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
-#define NILFS_BTREE_LEVEL_MAX           14     /* Max level (exclusive) */
-
-/**
- * struct nilfs_palloc_group_desc - block group descriptor
- * @pg_nfrees: number of free entries in block group
- */
-struct nilfs_palloc_group_desc {
-       __le32 pg_nfrees;
-};
-
-/**
- * struct nilfs_dat_entry - disk address translation entry
- * @de_blocknr: block number
- * @de_start: start checkpoint number
- * @de_end: end checkpoint number
- * @de_rsv: reserved for future use
- */
-struct nilfs_dat_entry {
-       __le64 de_blocknr;
-       __le64 de_start;
-       __le64 de_end;
-       __le64 de_rsv;
-};
-
-#define NILFS_MIN_DAT_ENTRY_SIZE       32
-
-/**
- * struct nilfs_snapshot_list - snapshot list
- * @ssl_next: next checkpoint number on snapshot list
- * @ssl_prev: previous checkpoint number on snapshot list
- */
-struct nilfs_snapshot_list {
-       __le64 ssl_next;
-       __le64 ssl_prev;
-};
-
-/**
- * struct nilfs_checkpoint - checkpoint structure
- * @cp_flags: flags
- * @cp_checkpoints_count: checkpoints count in a block
- * @cp_snapshot_list: snapshot list
- * @cp_cno: checkpoint number
- * @cp_create: creation timestamp
- * @cp_nblk_inc: number of blocks incremented by this checkpoint
- * @cp_inodes_count: inodes count
- * @cp_blocks_count: blocks count
- * @cp_ifile_inode: inode of ifile
- */
-struct nilfs_checkpoint {
-       __le32 cp_flags;
-       __le32 cp_checkpoints_count;
-       struct nilfs_snapshot_list cp_snapshot_list;
-       __le64 cp_cno;
-       __le64 cp_create;
-       __le64 cp_nblk_inc;
-       __le64 cp_inodes_count;
-       __le64 cp_blocks_count;
-
-       /*
-        * Do not change the byte offset of ifile inode.
-        * To keep the compatibility of the disk format,
-        * additional fields should be added behind cp_ifile_inode.
-        */
-       struct nilfs_inode cp_ifile_inode;
-};
-
-#define NILFS_MIN_CHECKPOINT_SIZE      (64 + NILFS_MIN_INODE_SIZE)
-
-/* checkpoint flags */
-enum {
-       NILFS_CHECKPOINT_SNAPSHOT,
-       NILFS_CHECKPOINT_INVALID,
-       NILFS_CHECKPOINT_SKETCH,
-       NILFS_CHECKPOINT_MINOR,
-};
-
-#define NILFS_CHECKPOINT_FNS(flag, name)                               \
-static inline void                                                     \
-nilfs_checkpoint_set_##name(struct nilfs_checkpoint *cp)               \
-{                                                                      \
-       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) |          \
-                                  (1UL << NILFS_CHECKPOINT_##flag));   \
-}                                                                      \
-static inline void                                                     \
-nilfs_checkpoint_clear_##name(struct nilfs_checkpoint *cp)             \
-{                                                                      \
-       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) &          \
-                                  ~(1UL << NILFS_CHECKPOINT_##flag));  \
-}                                                                      \
-static inline int                                                      \
-nilfs_checkpoint_##name(const struct nilfs_checkpoint *cp)             \
-{                                                                      \
-       return !!(le32_to_cpu(cp->cp_flags) &                           \
-                 (1UL << NILFS_CHECKPOINT_##flag));                    \
-}
-
-NILFS_CHECKPOINT_FNS(SNAPSHOT, snapshot)
-NILFS_CHECKPOINT_FNS(INVALID, invalid)
-NILFS_CHECKPOINT_FNS(MINOR, minor)
-
-/**
- * struct nilfs_cpinfo - checkpoint information
- * @ci_flags: flags
- * @ci_pad: padding
- * @ci_cno: checkpoint number
- * @ci_create: creation timestamp
- * @ci_nblk_inc: number of blocks incremented by this checkpoint
- * @ci_inodes_count: inodes count
- * @ci_blocks_count: blocks count
- * @ci_next: next checkpoint number in snapshot list
- */
-struct nilfs_cpinfo {
-       __u32 ci_flags;
-       __u32 ci_pad;
-       __u64 ci_cno;
-       __u64 ci_create;
-       __u64 ci_nblk_inc;
-       __u64 ci_inodes_count;
-       __u64 ci_blocks_count;
-       __u64 ci_next;
-};
-
-#define NILFS_CPINFO_FNS(flag, name)                                   \
-static inline int                                                      \
-nilfs_cpinfo_##name(const struct nilfs_cpinfo *cpinfo)                 \
-{                                                                      \
-       return !!(cpinfo->ci_flags & (1UL << NILFS_CHECKPOINT_##flag)); \
-}
-
-NILFS_CPINFO_FNS(SNAPSHOT, snapshot)
-NILFS_CPINFO_FNS(INVALID, invalid)
-NILFS_CPINFO_FNS(MINOR, minor)
-
-
-/**
- * struct nilfs_cpfile_header - checkpoint file header
- * @ch_ncheckpoints: number of checkpoints
- * @ch_nsnapshots: number of snapshots
- * @ch_snapshot_list: snapshot list
- */
-struct nilfs_cpfile_header {
-       __le64 ch_ncheckpoints;
-       __le64 ch_nsnapshots;
-       struct nilfs_snapshot_list ch_snapshot_list;
-};
-
-#define NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET   \
-       ((sizeof(struct nilfs_cpfile_header) +                          \
-         sizeof(struct nilfs_checkpoint) - 1) /                        \
-                       sizeof(struct nilfs_checkpoint))
-
-/**
- * struct nilfs_segment_usage - segment usage
- * @su_lastmod: last modified timestamp
- * @su_nblocks: number of blocks in segment
- * @su_flags: flags
- */
-struct nilfs_segment_usage {
-       __le64 su_lastmod;
-       __le32 su_nblocks;
-       __le32 su_flags;
-};
-
-#define NILFS_MIN_SEGMENT_USAGE_SIZE   16
-
-/* segment usage flag */
-enum {
-       NILFS_SEGMENT_USAGE_ACTIVE,
-       NILFS_SEGMENT_USAGE_DIRTY,
-       NILFS_SEGMENT_USAGE_ERROR,
-
-       /* ... */
-};
-
-#define NILFS_SEGMENT_USAGE_FNS(flag, name)                            \
-static inline void                                                     \
-nilfs_segment_usage_set_##name(struct nilfs_segment_usage *su)         \
-{                                                                      \
-       su->su_flags = cpu_to_le32(le32_to_cpu(su->su_flags) |          \
-                                  (1UL << NILFS_SEGMENT_USAGE_##flag));\
-}                                                                      \
-static inline void                                                     \
-nilfs_segment_usage_clear_##name(struct nilfs_segment_usage *su)       \
-{                                                                      \
-       su->su_flags =                                                  \
-               cpu_to_le32(le32_to_cpu(su->su_flags) &                 \
-                           ~(1UL << NILFS_SEGMENT_USAGE_##flag));      \
-}                                                                      \
-static inline int                                                      \
-nilfs_segment_usage_##name(const struct nilfs_segment_usage *su)       \
-{                                                                      \
-       return !!(le32_to_cpu(su->su_flags) &                           \
-                 (1UL << NILFS_SEGMENT_USAGE_##flag));                 \
-}
-
-NILFS_SEGMENT_USAGE_FNS(ACTIVE, active)
-NILFS_SEGMENT_USAGE_FNS(DIRTY, dirty)
-NILFS_SEGMENT_USAGE_FNS(ERROR, error)
-
-static inline void
-nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
-{
-       su->su_lastmod = cpu_to_le64(0);
-       su->su_nblocks = cpu_to_le32(0);
-       su->su_flags = cpu_to_le32(0);
-}
-
-static inline int
-nilfs_segment_usage_clean(const struct nilfs_segment_usage *su)
-{
-       return !le32_to_cpu(su->su_flags);
-}
-
-/**
- * struct nilfs_sufile_header - segment usage file header
- * @sh_ncleansegs: number of clean segments
- * @sh_ndirtysegs: number of dirty segments
- * @sh_last_alloc: last allocated segment number
- */
-struct nilfs_sufile_header {
-       __le64 sh_ncleansegs;
-       __le64 sh_ndirtysegs;
-       __le64 sh_last_alloc;
-       /* ... */
-};
-
-#define NILFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET        \
-       ((sizeof(struct nilfs_sufile_header) +                          \
-         sizeof(struct nilfs_segment_usage) - 1) /                     \
-                        sizeof(struct nilfs_segment_usage))
-
-/**
- * nilfs_suinfo - segment usage information
- * @sui_lastmod: timestamp of last modification
- * @sui_nblocks: number of written blocks in segment
- * @sui_flags: segment usage flags
- */
-struct nilfs_suinfo {
-       __u64 sui_lastmod;
-       __u32 sui_nblocks;
-       __u32 sui_flags;
-};
-
-#define NILFS_SUINFO_FNS(flag, name)                                   \
-static inline int                                                      \
-nilfs_suinfo_##name(const struct nilfs_suinfo *si)                     \
-{                                                                      \
-       return si->sui_flags & (1UL << NILFS_SEGMENT_USAGE_##flag);     \
-}
-
-NILFS_SUINFO_FNS(ACTIVE, active)
-NILFS_SUINFO_FNS(DIRTY, dirty)
-NILFS_SUINFO_FNS(ERROR, error)
-
-static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
-{
-       return !si->sui_flags;
-}
-
-/* ioctl */
-/**
- * nilfs_suinfo_update - segment usage information update
- * @sup_segnum: segment number
- * @sup_flags: flags for which fields are active in sup_sui
- * @sup_reserved: reserved necessary for alignment
- * @sup_sui: segment usage information
- */
-struct nilfs_suinfo_update {
-       __u64 sup_segnum;
-       __u32 sup_flags;
-       __u32 sup_reserved;
-       struct nilfs_suinfo sup_sui;
-};
-
-enum {
-       NILFS_SUINFO_UPDATE_LASTMOD,
-       NILFS_SUINFO_UPDATE_NBLOCKS,
-       NILFS_SUINFO_UPDATE_FLAGS,
-       __NR_NILFS_SUINFO_UPDATE_FIELDS,
-};
-
-#define NILFS_SUINFO_UPDATE_FNS(flag, name)                            \
-static inline void                                                     \
-nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)                \
-{                                                                      \
-       sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;            \
-}                                                                      \
-static inline void                                                     \
-nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)      \
-{                                                                      \
-       sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);         \
-}                                                                      \
-static inline int                                                      \
-nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)      \
-{                                                                      \
-       return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
-}
-
-NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
-NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
-NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
-
-enum {
-       NILFS_CHECKPOINT,
-       NILFS_SNAPSHOT,
-};
-
-/**
- * struct nilfs_cpmode - change checkpoint mode structure
- * @cm_cno: checkpoint number
- * @cm_mode: mode of checkpoint
- * @cm_pad: padding
- */
-struct nilfs_cpmode {
-       __u64 cm_cno;
-       __u32 cm_mode;
-       __u32 cm_pad;
-};
-
-/**
- * struct nilfs_argv - argument vector
- * @v_base: pointer on data array from userspace
- * @v_nmembs: number of members in data array
- * @v_size: size of data array in bytes
- * @v_flags: flags
- * @v_index: start number of target data items
- */
-struct nilfs_argv {
-       __u64 v_base;
-       __u32 v_nmembs; /* number of members */
-       __u16 v_size;   /* size of members */
-       __u16 v_flags;
-       __u64 v_index;
-};
-
-/**
- * struct nilfs_period - period of checkpoint numbers
- * @p_start: start checkpoint number (inclusive)
- * @p_end: end checkpoint number (exclusive)
- */
-struct nilfs_period {
-       __u64 p_start;
-       __u64 p_end;
-};
-
-/**
- * struct nilfs_cpstat - checkpoint statistics
- * @cs_cno: checkpoint number
- * @cs_ncps: number of checkpoints
- * @cs_nsss: number of snapshots
- */
-struct nilfs_cpstat {
-       __u64 cs_cno;
-       __u64 cs_ncps;
-       __u64 cs_nsss;
-};
-
-/**
- * struct nilfs_sustat - segment usage statistics
- * @ss_nsegs: number of segments
- * @ss_ncleansegs: number of clean segments
- * @ss_ndirtysegs: number of dirty segments
- * @ss_ctime: creation time of the last segment
- * @ss_nongc_ctime: creation time of the last segment not for GC
- * @ss_prot_seq: least sequence number of segments which must not be reclaimed
- */
-struct nilfs_sustat {
-       __u64 ss_nsegs;
-       __u64 ss_ncleansegs;
-       __u64 ss_ndirtysegs;
-       __u64 ss_ctime;
-       __u64 ss_nongc_ctime;
-       __u64 ss_prot_seq;
-};
-
-/**
- * struct nilfs_vinfo - virtual block number information
- * @vi_vblocknr: virtual block number
- * @vi_start: start checkpoint number (inclusive)
- * @vi_end: end checkpoint number (exclusive)
- * @vi_blocknr: disk block number
- */
-struct nilfs_vinfo {
-       __u64 vi_vblocknr;
-       __u64 vi_start;
-       __u64 vi_end;
-       __u64 vi_blocknr;
-};
-
-/**
- * struct nilfs_vdesc - descriptor of virtual block number
- * @vd_ino: inode number
- * @vd_cno: checkpoint number
- * @vd_vblocknr: virtual block number
- * @vd_period: period of checkpoint numbers
- * @vd_blocknr: disk block number
- * @vd_offset: logical block offset inside a file
- * @vd_flags: flags (data or node block)
- * @vd_pad: padding
- */
-struct nilfs_vdesc {
-       __u64 vd_ino;
-       __u64 vd_cno;
-       __u64 vd_vblocknr;
-       struct nilfs_period vd_period;
-       __u64 vd_blocknr;
-       __u64 vd_offset;
-       __u32 vd_flags;
-       __u32 vd_pad;
-};
-
-/**
- * struct nilfs_bdesc - descriptor of disk block number
- * @bd_ino: inode number
- * @bd_oblocknr: disk block address (for skipping dead blocks)
- * @bd_blocknr: disk block address
- * @bd_offset: logical block offset inside a file
- * @bd_level: level in the b-tree organization
- * @bd_pad: padding
- */
-struct nilfs_bdesc {
-       __u64 bd_ino;
-       __u64 bd_oblocknr;
-       __u64 bd_blocknr;
-       __u64 bd_offset;
-       __u32 bd_level;
-       __u32 bd_pad;
-};
-
-#define NILFS_IOCTL_IDENT              'n'
-
-#define NILFS_IOCTL_CHANGE_CPMODE  \
-       _IOW(NILFS_IOCTL_IDENT, 0x80, struct nilfs_cpmode)
-#define NILFS_IOCTL_DELETE_CHECKPOINT  \
-       _IOW(NILFS_IOCTL_IDENT, 0x81, __u64)
-#define NILFS_IOCTL_GET_CPINFO  \
-       _IOR(NILFS_IOCTL_IDENT, 0x82, struct nilfs_argv)
-#define NILFS_IOCTL_GET_CPSTAT  \
-       _IOR(NILFS_IOCTL_IDENT, 0x83, struct nilfs_cpstat)
-#define NILFS_IOCTL_GET_SUINFO  \
-       _IOR(NILFS_IOCTL_IDENT, 0x84, struct nilfs_argv)
-#define NILFS_IOCTL_GET_SUSTAT  \
-       _IOR(NILFS_IOCTL_IDENT, 0x85, struct nilfs_sustat)
-#define NILFS_IOCTL_GET_VINFO  \
-       _IOWR(NILFS_IOCTL_IDENT, 0x86, struct nilfs_argv)
-#define NILFS_IOCTL_GET_BDESCS  \
-       _IOWR(NILFS_IOCTL_IDENT, 0x87, struct nilfs_argv)
-#define NILFS_IOCTL_CLEAN_SEGMENTS  \
-       _IOW(NILFS_IOCTL_IDENT, 0x88, struct nilfs_argv[5])
-#define NILFS_IOCTL_SYNC  \
-       _IOR(NILFS_IOCTL_IDENT, 0x8A, __u64)
-#define NILFS_IOCTL_RESIZE  \
-       _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
-#define NILFS_IOCTL_SET_ALLOC_RANGE  \
-       _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
-#define NILFS_IOCTL_SET_SUINFO  \
-       _IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
-
-#endif /* _LINUX_NILFS_FS_H */
index 8b5e0a9..610e132 100644 (file)
@@ -124,6 +124,15 @@ static inline int page_ref_sub_and_test(struct page *page, int nr)
        return ret;
 }
 
+static inline int page_ref_inc_return(struct page *page)
+{
+       int ret = atomic_inc_return(&page->_refcount);
+
+       if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return))
+               __page_ref_mod_and_return(page, 1, ret);
+       return ret;
+}
+
 static inline int page_ref_dec_and_test(struct page *page)
 {
        int ret = atomic_dec_and_test(&page->_refcount);
index 81363b8..66a1260 100644 (file)
@@ -510,7 +510,7 @@ static inline void wait_on_page_writeback(struct page *page)
 extern void end_page_writeback(struct page *page);
 void wait_for_stable_page(struct page *page);
 
-void page_endio(struct page *page, int rw, int err);
+void page_endio(struct page *page, bool is_write, int err);
 
 /*
  * Add an arbitrary waiter to a page's wait queue
index 89ab057..7d63a66 100644 (file)
@@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
 }
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
+extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
+
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
        struct pci_bus *pbus = pdev->bus;
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
new file mode 100644 (file)
index 0000000..7adad20
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 Broadcom
+ *
+ * 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 (the "GPL").
+ *
+ * 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 version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+#ifndef DRIVERS_PCI_ECAM_H
+#define DRIVERS_PCI_ECAM_H
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+/*
+ * struct to hold pci ops and bus shift of the config window
+ * for a PCI controller.
+ */
+struct pci_config_window;
+struct pci_ecam_ops {
+       unsigned int                    bus_shift;
+       struct pci_ops                  pci_ops;
+       int                             (*init)(struct pci_config_window *);
+};
+
+/*
+ * struct to hold the mappings of a config space window. This
+ * is expected to be used as sysdata for PCI controllers that
+ * use ECAM.
+ */
+struct pci_config_window {
+       struct resource                 res;
+       struct resource                 busr;
+       void                            *priv;
+       struct pci_ecam_ops             *ops;
+       union {
+               void __iomem            *win;   /* 64-bit single mapping */
+               void __iomem            **winp; /* 32-bit per-bus mapping */
+       };
+       struct device                   *parent;/* ECAM res was from this dev */
+};
+
+/* create and free pci_config_window */
+struct pci_config_window *pci_ecam_create(struct device *dev,
+               struct resource *cfgres, struct resource *busr,
+               struct pci_ecam_ops *ops);
+void pci_ecam_free(struct pci_config_window *cfg);
+
+/* map_bus when ->sysdata is an instance of pci_config_window */
+void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
+                              int where);
+/* default ECAM ops */
+extern struct pci_ecam_ops pci_generic_ecam_ops;
+
+#ifdef CONFIG_PCI_HOST_GENERIC
+/* for DT-based PCI controllers that support ECAM */
+int pci_host_common_probe(struct platform_device *pdev,
+                         struct pci_ecam_ops *ops);
+#endif
+#endif
index c40ac91..2599a98 100644 (file)
@@ -101,6 +101,10 @@ enum {
        DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
 };
 
+/*
+ * pci_power_t values must match the bits in the Capabilities PME_Support
+ * and Control/Status PowerState fields in the Power Management capability.
+ */
 typedef int __bitwise pci_power_t;
 
 #define PCI_D0         ((pci_power_t __force) 0)
@@ -116,7 +120,7 @@ extern const char *pci_power_names[];
 
 static inline const char *pci_power_name(pci_power_t state)
 {
-       return pci_power_names[1 + (int) state];
+       return pci_power_names[1 + (__force int) state];
 }
 
 #define PCI_PM_D2_DELAY                200
@@ -294,6 +298,7 @@ struct pci_dev {
        unsigned int    d2_support:1;   /* Low power state D2 is supported */
        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */
        unsigned int    no_d3cold:1;    /* D3cold is forbidden */
+       unsigned int    bridge_d3:1;    /* Allow D3 for bridge */
        unsigned int    d3cold_allowed:1;       /* D3cold is allowed by user */
        unsigned int    mmio_always_on:1;       /* disallow turning off io/mem
                                                   decoding during bar sizing */
@@ -320,6 +325,7 @@ struct pci_dev {
         * directly, use the values stored here. They might be different!
         */
        unsigned int    irq;
+       struct cpumask  *irq_affinity;
        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
 
        bool match_driver;              /* Skip attaching driver */
@@ -1084,6 +1090,8 @@ int pci_back_from_sleep(struct pci_dev *dev);
 bool pci_dev_run_wake(struct pci_dev *dev);
 bool pci_check_pme_status(struct pci_dev *dev);
 void pci_pme_wakeup_bus(struct pci_bus *bus);
+void pci_d3cold_enable(struct pci_dev *dev);
+void pci_d3cold_disable(struct pci_dev *dev);
 
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
                                  bool enable)
@@ -1115,6 +1123,7 @@ int pci_set_vpd_size(struct pci_dev *dev, size_t len);
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
+void pci_bus_claim_resources(struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 int pci_claim_bridge_resource(struct pci_dev *bridge, int i);
@@ -1144,9 +1153,12 @@ void pci_add_resource(struct list_head *resources, struct resource *res);
 void pci_add_resource_offset(struct list_head *resources, struct resource *res,
                             resource_size_t offset);
 void pci_free_resource_list(struct list_head *resources);
-void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
+void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
+                         unsigned int flags);
 struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
 void pci_bus_remove_resources(struct pci_bus *bus);
+int devm_request_pci_bus_resources(struct device *dev,
+                                  struct list_head *resources);
 
 #define pci_bus_for_each_resource(bus, res, i)                         \
        for (i = 0;                                                     \
@@ -1168,6 +1180,7 @@ int pci_register_io_range(phys_addr_t addr, resource_size_t size);
 unsigned long pci_address_to_pio(phys_addr_t addr);
 phys_addr_t pci_pio_to_address(unsigned long pio);
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr);
+void pci_unmap_iospace(struct resource *res);
 
 static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar)
 {
@@ -1238,6 +1251,11 @@ resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno);
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, u32 flags);
 
+#define PCI_IRQ_NOLEGACY       (1 << 0) /* don't use legacy interrupts */
+#define PCI_IRQ_NOMSI          (1 << 1) /* don't use MSI interrupts */
+#define PCI_IRQ_NOMSIX         (1 << 2) /* don't use MSI-X interrupts */
+#define PCI_IRQ_NOAFFINITY     (1 << 3) /* don't auto-assign affinity */
+
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
 #include <linux/pci-dma.h>
@@ -1285,6 +1303,11 @@ static inline int pci_enable_msix_exact(struct pci_dev *dev,
                return rc;
        return 0;
 }
+int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
+               unsigned int max_vecs, unsigned int flags);
+void pci_free_irq_vectors(struct pci_dev *dev);
+int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
+
 #else
 static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
 static inline void pci_msi_shutdown(struct pci_dev *dev) { }
@@ -1308,6 +1331,24 @@ static inline int pci_enable_msix_range(struct pci_dev *dev,
 static inline int pci_enable_msix_exact(struct pci_dev *dev,
                      struct msix_entry *entries, int nvec)
 { return -ENOSYS; }
+static inline int pci_alloc_irq_vectors(struct pci_dev *dev,
+               unsigned int min_vecs, unsigned int max_vecs,
+               unsigned int flags)
+{
+       if (min_vecs > 1)
+               return -EINVAL;
+       return 1;
+}
+static inline void pci_free_irq_vectors(struct pci_dev *dev)
+{
+}
+
+static inline int pci_irq_vector(struct pci_dev *dev, unsigned int nr)
+{
+       if (WARN_ON_ONCE(nr > 0))
+               return -EINVAL;
+       return dev->irq;
+}
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
@@ -1390,12 +1431,13 @@ static inline int pci_domain_nr(struct pci_bus *bus)
 {
        return bus->domain_nr;
 }
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#ifdef CONFIG_ACPI
+int acpi_pci_bus_find_domain_nr(struct pci_bus *bus);
 #else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-                                       struct device *parent)
-{
-}
+static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+{ return 0; }
+#endif
+int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
 #endif
 
 /* some architectures require additional setup to direct VGA traffic */
@@ -1403,6 +1445,34 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
                      unsigned int command_bits, u32 flags);
 void pci_register_set_vga_state(arch_set_vga_state_t func);
 
+static inline int
+pci_request_io_regions(struct pci_dev *pdev, const char *name)
+{
+       return pci_request_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_IO), name);
+}
+
+static inline void
+pci_release_io_regions(struct pci_dev *pdev)
+{
+       return pci_release_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_IO));
+}
+
+static inline int
+pci_request_mem_regions(struct pci_dev *pdev, const char *name)
+{
+       return pci_request_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_MEM), name);
+}
+
+static inline void
+pci_release_mem_regions(struct pci_dev *pdev)
+{
+       return pci_release_selected_regions(pdev,
+                           pci_select_bars(pdev, IORESOURCE_MEM));
+}
+
 #else /* CONFIG_PCI is not enabled */
 
 static inline void pci_set_flags(int flags) { }
@@ -1555,7 +1625,11 @@ static inline const char *pci_name(const struct pci_dev *pdev)
 /* Some archs don't want to expose struct resource to userland as-is
  * in sysfs and /proc
  */
-#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
+#ifdef HAVE_ARCH_PCI_RESOURCE_TO_USER
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         resource_size_t *start, resource_size_t *end);
+#else
 static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
                const struct resource *rsrc, resource_size_t *start,
                resource_size_t *end)
@@ -1707,6 +1781,7 @@ extern u8 pci_cache_line_size;
 
 extern unsigned long pci_hotplug_io_size;
 extern unsigned long pci_hotplug_mem_size;
+extern unsigned long pci_hotplug_bus_size;
 
 /* Architecture-specific versions may override these (weak) */
 void pcibios_disable_device(struct pci_dev *dev);
@@ -1723,7 +1798,7 @@ void pcibios_free_irq(struct pci_dev *dev);
 extern struct dev_pm_ops pcibios_pm_ops;
 #endif
 
-#ifdef CONFIG_PCI_MMCONFIG
+#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
 void __init pci_mmcfg_early_init(void);
 void __init pci_mmcfg_late_init(void);
 #else
diff --git a/include/linux/platform_data/rtc-ds2404.h b/include/linux/platform_data/rtc-ds2404.h
new file mode 100644 (file)
index 0000000..22c5382
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * ds2404.h - platform data structure for the DS2404 RTC.
+ *
+ * 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 Sven Schnelle <svens@stackframe.org>
+ */
+
+#ifndef __LINUX_DS2404_H
+#define __LINUX_DS2404_H
+
+struct ds2404_platform_data {
+
+       unsigned int gpio_rst;
+       unsigned int gpio_clk;
+       unsigned int gpio_dq;
+};
+#endif
diff --git a/include/linux/platform_data/rtc-m48t86.h b/include/linux/platform_data/rtc-m48t86.h
new file mode 100644 (file)
index 0000000..915d6b4
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * ST M48T86 / Dallas DS12887 RTC driver
+ * Copyright (c) 2006 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct m48t86_ops
+{
+       void (*writebyte)(unsigned char value, unsigned long addr);
+       unsigned char (*readbyte)(unsigned long addr);
+};
diff --git a/include/linux/platform_data/rtc-v3020.h b/include/linux/platform_data/rtc-v3020.h
new file mode 100644 (file)
index 0000000..e55d82c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * v3020.h - Registers definition and platform data structure for the v3020 RTC.
+ *
+ * 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, 8D Technologies inc.
+ */
+#ifndef __LINUX_V3020_H
+#define __LINUX_V3020_H
+
+/* The v3020 has only one data pin but which one
+ * is used depends on the board. */
+struct v3020_platform_data {
+       int leftshift; /* (1<<(leftshift)) & readl() */
+
+       unsigned int use_gpio:1;
+       unsigned int gpio_cs;
+       unsigned int gpio_wr;
+       unsigned int gpio_rd;
+       unsigned int gpio_io;
+};
+
+#define V3020_STATUS_0 0x00
+#define V3020_STATUS_1 0x01
+#define V3020_SECONDS  0x02
+#define V3020_MINUTES  0x03
+#define V3020_HOURS            0x04
+#define V3020_MONTH_DAY        0x05
+#define V3020_MONTH            0x06
+#define V3020_YEAR             0x07
+#define V3020_WEEK_DAY 0x08
+#define V3020_WEEK             0x09
+
+#define V3020_IS_COMMAND(val) ((val)>=0x0E)
+
+#define V3020_CMD_RAM2CLOCK    0x0E
+#define V3020_CMD_CLOCK2RAM    0x0F
+
+#endif /* __LINUX_V3020_H */
index f136b22..696a56b 100644 (file)
@@ -61,6 +61,11 @@ static inline void console_verbose(void)
                console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
 }
 
+/* strlen("ratelimit") + 1 */
+#define DEVKMSG_STR_MAX_SIZE 10
+extern char devkmsg_log_str[];
+struct ctl_table;
+
 struct va_format {
        const char *fmt;
        va_list *va;
@@ -175,6 +180,10 @@ extern int printk_delay_msec;
 extern int dmesg_restrict;
 extern int kptr_restrict;
 
+extern int
+devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, void __user *buf,
+                         size_t *lenp, loff_t *ppos);
+
 extern void wake_up_klogd(void);
 
 char *log_buf_addr_get(void);
@@ -289,10 +298,11 @@ extern asmlinkage void dump_stack(void) __cold;
        no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
 #endif
 
-#include <linux/dynamic_debug.h>
 
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(CONFIG_DYNAMIC_DEBUG)
+#include <linux/dynamic_debug.h>
+
 /* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
 #define pr_debug(fmt, ...) \
        dynamic_pr_debug(fmt, ##__VA_ARGS__)
index c038ae3..f1bbae0 100644 (file)
@@ -5,7 +5,9 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 
+struct pwm_capture;
 struct seq_file;
+
 struct pwm_chip;
 
 /**
@@ -147,12 +149,101 @@ static inline void pwm_get_args(const struct pwm_device *pwm,
        *args = pwm->args;
 }
 
+/**
+ * pwm_init_state() - prepare a new state to be applied with pwm_apply_state()
+ * @pwm: PWM device
+ * @state: state to fill with the prepared PWM state
+ *
+ * This functions prepares a state that can later be tweaked and applied
+ * to the PWM device with pwm_apply_state(). This is a convenient function
+ * that first retrieves the current PWM state and the replaces the period
+ * and polarity fields with the reference values defined in pwm->args.
+ * Once the function returns, you can adjust the ->enabled and ->duty_cycle
+ * fields according to your needs before calling pwm_apply_state().
+ *
+ * ->duty_cycle is initially set to zero to avoid cases where the current
+ * ->duty_cycle value exceed the pwm_args->period one, which would trigger
+ * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle
+ * first.
+ */
+static inline void pwm_init_state(const struct pwm_device *pwm,
+                                 struct pwm_state *state)
+{
+       struct pwm_args args;
+
+       /* First get the current state. */
+       pwm_get_state(pwm, state);
+
+       /* Then fill it with the reference config */
+       pwm_get_args(pwm, &args);
+
+       state->period = args.period;
+       state->polarity = args.polarity;
+       state->duty_cycle = 0;
+}
+
+/**
+ * pwm_get_relative_duty_cycle() - Get a relative duty cycle value
+ * @state: PWM state to extract the duty cycle from
+ * @scale: target scale of the relative duty cycle
+ *
+ * This functions converts the absolute duty cycle stored in @state (expressed
+ * in nanosecond) into a value relative to the period.
+ *
+ * For example if you want to get the duty_cycle expressed in percent, call:
+ *
+ * pwm_get_state(pwm, &state);
+ * duty = pwm_get_relative_duty_cycle(&state, 100);
+ */
+static inline unsigned int
+pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale)
+{
+       if (!state->period)
+               return 0;
+
+       return DIV_ROUND_CLOSEST_ULL((u64)state->duty_cycle * scale,
+                                    state->period);
+}
+
+/**
+ * pwm_set_relative_duty_cycle() - Set a relative duty cycle value
+ * @state: PWM state to fill
+ * @duty_cycle: relative duty cycle value
+ * @scale: scale in which @duty_cycle is expressed
+ *
+ * This functions converts a relative into an absolute duty cycle (expressed
+ * in nanoseconds), and puts the result in state->duty_cycle.
+ *
+ * For example if you want to configure a 50% duty cycle, call:
+ *
+ * pwm_init_state(pwm, &state);
+ * pwm_set_relative_duty_cycle(&state, 50, 100);
+ * pwm_apply_state(pwm, &state);
+ *
+ * This functions returns -EINVAL if @duty_cycle and/or @scale are
+ * inconsistent (@scale == 0 or @duty_cycle > @scale).
+ */
+static inline int
+pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
+                           unsigned int scale)
+{
+       if (!scale || duty_cycle > scale)
+               return -EINVAL;
+
+       state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_cycle *
+                                                 state->period,
+                                                 scale);
+
+       return 0;
+}
+
 /**
  * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
  * @free: optional hook for freeing a PWM
  * @config: configure duty cycles and period length for this PWM
  * @set_polarity: configure the polarity of this PWM
+ * @capture: capture and report PWM signal
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
  * @apply: atomically apply a new PWM config. The state argument
@@ -172,6 +263,8 @@ struct pwm_ops {
                      int duty_ns, int period_ns);
        int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm,
                            enum pwm_polarity polarity);
+       int (*capture)(struct pwm_chip *chip, struct pwm_device *pwm,
+                      struct pwm_capture *result, unsigned long timeout);
        int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
        void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
        int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -212,6 +305,16 @@ struct pwm_chip {
        bool can_sleep;
 };
 
+/**
+ * struct pwm_capture - PWM capture data
+ * @period: period of the PWM signal (in nanoseconds)
+ * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
+ */
+struct pwm_capture {
+       unsigned int period;
+       unsigned int duty_cycle;
+};
+
 #if IS_ENABLED(CONFIG_PWM)
 /* PWM user APIs */
 struct pwm_device *pwm_request(int pwm_id, const char *label);
@@ -323,8 +426,9 @@ static inline void pwm_disable(struct pwm_device *pwm)
        pwm_apply_state(pwm, &state);
 }
 
-
 /* PWM provider APIs */
+int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
+               unsigned long timeout);
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
 void *pwm_get_chip_data(struct pwm_device *pwm);
 
@@ -376,6 +480,13 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
        return -EINVAL;
 }
 
+static inline int pwm_capture(struct pwm_device *pwm,
+                             struct pwm_capture *result,
+                             unsigned long timeout)
+{
+       return -EINVAL;
+}
+
 static inline int pwm_set_polarity(struct pwm_device *pwm,
                                   enum pwm_polarity polarity)
 {
index cbfee50..4c45105 100644 (file)
@@ -35,7 +35,7 @@
  * 00 - data pointer
  * 01 - internal entry
  * 10 - exceptional entry
- * 11 - locked exceptional entry
+ * 11 - this bit combination is currently unused/reserved
  *
  * The internal entry may be a pointer to the next level in the tree, a
  * sibling entry, or an indicator that the entry in this slot has been moved
index 1810252..57c9e06 100644 (file)
@@ -2,11 +2,15 @@
 #define _LINUX_RATELIMIT_H
 
 #include <linux/param.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 
 #define DEFAULT_RATELIMIT_INTERVAL     (5 * HZ)
 #define DEFAULT_RATELIMIT_BURST                10
 
+/* issue num suppressed message on exit */
+#define RATELIMIT_MSG_ON_RELEASE       BIT(0)
+
 struct ratelimit_state {
        raw_spinlock_t  lock;           /* protect the state */
 
@@ -15,6 +19,7 @@ struct ratelimit_state {
        int             printed;
        int             missed;
        unsigned long   begin;
+       unsigned long   flags;
 };
 
 #define RATELIMIT_STATE_INIT(name, interval_init, burst_init) {                \
@@ -34,12 +39,35 @@ struct ratelimit_state {
 static inline void ratelimit_state_init(struct ratelimit_state *rs,
                                        int interval, int burst)
 {
+       memset(rs, 0, sizeof(*rs));
+
        raw_spin_lock_init(&rs->lock);
-       rs->interval = interval;
-       rs->burst = burst;
-       rs->printed = 0;
-       rs->missed = 0;
-       rs->begin = 0;
+       rs->interval    = interval;
+       rs->burst       = burst;
+}
+
+static inline void ratelimit_default_init(struct ratelimit_state *rs)
+{
+       return ratelimit_state_init(rs, DEFAULT_RATELIMIT_INTERVAL,
+                                       DEFAULT_RATELIMIT_BURST);
+}
+
+static inline void ratelimit_state_exit(struct ratelimit_state *rs)
+{
+       if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE))
+               return;
+
+       if (rs->missed) {
+               pr_warn("%s: %d output lines suppressed due to ratelimiting\n",
+                       current->comm, rs->missed);
+               rs->missed = 0;
+       }
+}
+
+static inline void
+ratelimit_set_flags(struct ratelimit_state *rs, unsigned long flags)
+{
+       rs->flags = flags;
 }
 
 extern struct ratelimit_state printk_ratelimit_state;
index aa23238..37b95c4 100644 (file)
@@ -163,6 +163,7 @@ enum rio_device_state {
  * @dst_ops: Destination operation capabilities
  * @comp_tag: RIO component tag
  * @phys_efptr: RIO device extended features pointer
+ * @phys_rmap: LP-Serial Register Map Type (1 or 2)
  * @em_efptr: RIO Error Management features pointer
  * @dma_mask: Mask of bits of RIO address this device implements
  * @driver: Driver claiming this device
@@ -193,6 +194,7 @@ struct rio_dev {
        u32 dst_ops;
        u32 comp_tag;
        u32 phys_efptr;
+       u32 phys_rmap;
        u32 em_efptr;
        u64 dma_mask;
        struct rio_driver *driver;      /* RIO driver claiming this device */
@@ -237,11 +239,6 @@ struct rio_dbell {
        void *dev_id;
 };
 
-enum rio_phy_type {
-       RIO_PHY_PARALLEL,
-       RIO_PHY_SERIAL,
-};
-
 /**
  * struct rio_mport - RIO master port info
  * @dbells: List of doorbell events
@@ -259,8 +256,8 @@ enum rio_phy_type {
  * @id: Port ID, unique among all ports
  * @index: Port index, unique among all port interfaces of the same type
  * @sys_size: RapidIO common transport system size
- * @phy_type: RapidIO phy type
  * @phys_efptr: RIO port extended features pointer
+ * @phys_rmap: LP-Serial EFB Register Mapping type (1 or 2).
  * @name: Port name string
  * @dev: device structure associated with an mport
  * @priv: Master port private data
@@ -289,8 +286,8 @@ struct rio_mport {
                                 * 0 - Small size. 256 devices.
                                 * 1 - Large size, 65536 devices.
                                 */
-       enum rio_phy_type phy_type;     /* RapidIO phy type */
        u32 phys_efptr;
+       u32 phys_rmap;
        unsigned char name[RIO_MAX_MPORT_NAME];
        struct device dev;
        void *priv;             /* Master port private data */
@@ -425,7 +422,7 @@ struct rio_ops {
        int (*add_inb_buffer)(struct rio_mport *mport, int mbox, void *buf);
        void *(*get_inb_message)(struct rio_mport *mport, int mbox);
        int (*map_inb)(struct rio_mport *mport, dma_addr_t lstart,
-                       u64 rstart, u32 size, u32 flags);
+                       u64 rstart, u64 size, u32 flags);
        void (*unmap_inb)(struct rio_mport *mport, dma_addr_t lstart);
        int (*query_mport)(struct rio_mport *mport,
                           struct rio_mport_attr *attr);
index 2543bc1..334c576 100644 (file)
@@ -38,5 +38,7 @@
 #define RIO_DID_IDTVPS1616             0x0377
 #define RIO_DID_IDTSPS1616             0x0378
 #define RIO_DID_TSI721                 0x80ab
+#define RIO_DID_IDTRXS1632             0x80e5
+#define RIO_DID_IDTRXS2448             0x80e6
 
 #endif                         /* LINUX_RIO_IDS_H */
index 1063ae3..40c04ef 100644 (file)
 #define  RIO_PEF_INB_MBOX2             0x00200000      /* [II, <= 1.2] Mailbox 2 */
 #define  RIO_PEF_INB_MBOX3             0x00100000      /* [II, <= 1.2] Mailbox 3 */
 #define  RIO_PEF_INB_DOORBELL          0x00080000      /* [II, <= 1.2] Doorbells */
+#define  RIO_PEF_DEV32                 0x00001000      /* [III] PE supports Common TRansport Dev32 */
 #define  RIO_PEF_EXT_RT                        0x00000200      /* [III, 1.3] Extended route table support */
 #define  RIO_PEF_STD_RT                        0x00000100      /* [III, 1.3] Standard route table support */
-#define  RIO_PEF_CTLS                  0x00000010      /* [III] CTLS */
+#define  RIO_PEF_CTLS                  0x00000010      /* [III] Common Transport Large System (< rev.3) */
+#define  RIO_PEF_DEV16                 0x00000010      /* [III] PE Supports Common Transport Dev16 (rev.3) */
 #define  RIO_PEF_EXT_FEATURES          0x00000008      /* [I] EFT_PTR valid */
 #define  RIO_PEF_ADDR_66               0x00000004      /* [I] 66 bits */
 #define  RIO_PEF_ADDR_50               0x00000002      /* [I] 50 bits */
 #define RIO_GET_BLOCK_ID(x)    (x & RIO_EFB_ID_MASK)
 
 /* Extended Feature Block IDs */
-#define RIO_EFB_PAR_EP_ID      0x0001  /* [IV] LP/LVDS EP Devices */
-#define RIO_EFB_PAR_EP_REC_ID  0x0002  /* [IV] LP/LVDS EP Recovery Devices */
-#define RIO_EFB_PAR_EP_FREE_ID 0x0003  /* [IV] LP/LVDS EP Free Devices */
-#define RIO_EFB_SER_EP_ID_V13P 0x0001  /* [VI] LP/Serial EP Devices, RapidIO Spec ver 1.3 and above */
-#define RIO_EFB_SER_EP_REC_ID_V13P     0x0002  /* [VI] LP/Serial EP Recovery Devices, RapidIO Spec ver 1.3 and above */
-#define RIO_EFB_SER_EP_FREE_ID_V13P    0x0003  /* [VI] LP/Serial EP Free Devices, RapidIO Spec ver 1.3 and above */
-#define RIO_EFB_SER_EP_ID      0x0004  /* [VI] LP/Serial EP Devices */
-#define RIO_EFB_SER_EP_REC_ID  0x0005  /* [VI] LP/Serial EP Recovery Devices */
-#define RIO_EFB_SER_EP_FREE_ID 0x0006  /* [VI] LP/Serial EP Free Devices */
-#define RIO_EFB_SER_EP_FREC_ID 0x0009  /* [VI] LP/Serial EP Free Recovery Devices */
+#define RIO_EFB_SER_EP_M1_ID   0x0001  /* [VI] LP-Serial EP Devices, Map I */
+#define RIO_EFB_SER_EP_SW_M1_ID        0x0002  /* [VI] LP-Serial EP w SW Recovery Devices, Map I */
+#define RIO_EFB_SER_EPF_M1_ID  0x0003  /* [VI] LP-Serial EP Free Devices, Map I */
+#define RIO_EFB_SER_EP_ID      0x0004  /* [VI] LP-Serial EP Devices, RIO 1.2 */
+#define RIO_EFB_SER_EP_REC_ID  0x0005  /* [VI] LP-Serial EP w SW Recovery Devices, RIO 1.2 */
+#define RIO_EFB_SER_EP_FREE_ID 0x0006  /* [VI] LP-Serial EP Free Devices, RIO 1.2 */
 #define RIO_EFB_ERR_MGMNT      0x0007  /* [VIII] Error Management Extensions */
+#define RIO_EFB_SER_EPF_SW_M1_ID       0x0009  /* [VI] LP-Serial EP Free w SW Recovery Devices, Map I */
+#define RIO_EFB_SW_ROUTING_TBL 0x000E  /* [III] Switch Routing Table Block */
+#define RIO_EFB_SER_EP_M2_ID   0x0011  /* [VI] LP-Serial EP Devices, Map II */
+#define RIO_EFB_SER_EP_SW_M2_ID        0x0012  /* [VI] LP-Serial EP w SW Recovery Devices, Map II */
+#define RIO_EFB_SER_EPF_M2_ID  0x0013  /* [VI] LP-Serial EP Free Devices, Map II */
+#define RIO_EFB_ERR_MGMNT_HS   0x0017  /* [VIII] Error Management Extensions, Hot-Swap only */
+#define RIO_EFB_SER_EPF_SW_M2_ID       0x0019  /* [VI] LP-Serial EP Free w SW Recovery Devices, Map II */
 
 /*
- * Physical 8/16 LP-LVDS
- * ID=0x0001, Generic End Point Devices
- * ID=0x0002, Generic End Point Devices, software assisted recovery option
- * ID=0x0003, Generic End Point Free Devices
- *
- * Physical LP-Serial
- * ID=0x0004, Generic End Point Devices
- * ID=0x0005, Generic End Point Devices, software assisted recovery option
- * ID=0x0006, Generic End Point Free Devices
+ * Physical LP-Serial Registers Definitions
+ * Parameters in register macros:
+ *    n - port number, m - Register Map Type (1 or 2)
  */
 #define RIO_PORT_MNT_HEADER            0x0000
 #define RIO_PORT_REQ_CTL_CSR           0x0020
-#define RIO_PORT_RSP_CTL_CSR           0x0024  /* 0x0001/0x0002 */
-#define RIO_PORT_LINKTO_CTL_CSR                0x0020  /* Serial */
-#define RIO_PORT_RSPTO_CTL_CSR         0x0024  /* Serial */
+#define RIO_PORT_RSP_CTL_CSR           0x0024
+#define RIO_PORT_LINKTO_CTL_CSR                0x0020
+#define RIO_PORT_RSPTO_CTL_CSR         0x0024
 #define RIO_PORT_GEN_CTL_CSR           0x003c
 #define  RIO_PORT_GEN_HOST             0x80000000
 #define  RIO_PORT_GEN_MASTER           0x40000000
 #define  RIO_PORT_GEN_DISCOVERED       0x20000000
-#define RIO_PORT_N_MNT_REQ_CSR(x)      (0x0040 + x*0x20)       /* 0x0002 */
+#define RIO_PORT_N_MNT_REQ_CSR(n, m)   (0x40 + (n) * (0x20 * (m)))
 #define  RIO_MNT_REQ_CMD_RD            0x03    /* Reset-device command */
 #define  RIO_MNT_REQ_CMD_IS            0x04    /* Input-status command */
-#define RIO_PORT_N_MNT_RSP_CSR(x)      (0x0044 + x*0x20)       /* 0x0002 */
+#define RIO_PORT_N_MNT_RSP_CSR(n, m)   (0x44 + (n) * (0x20 * (m)))
 #define  RIO_PORT_N_MNT_RSP_RVAL       0x80000000 /* Response Valid */
 #define  RIO_PORT_N_MNT_RSP_ASTAT      0x000007e0 /* ackID Status */
 #define  RIO_PORT_N_MNT_RSP_LSTAT      0x0000001f /* Link Status */
-#define RIO_PORT_N_ACK_STS_CSR(x)      (0x0048 + x*0x20)       /* 0x0002 */
+#define RIO_PORT_N_ACK_STS_CSR(n)      (0x48 + (n) * 0x20) /* Only in RM-I */
 #define  RIO_PORT_N_ACK_CLEAR          0x80000000
 #define  RIO_PORT_N_ACK_INBOUND                0x3f000000
 #define  RIO_PORT_N_ACK_OUTSTAND       0x00003f00
 #define  RIO_PORT_N_ACK_OUTBOUND       0x0000003f
-#define RIO_PORT_N_CTL2_CSR(x)         (0x0054 + x*0x20)
+#define RIO_PORT_N_CTL2_CSR(n, m)      (0x54 + (n) * (0x20 * (m)))
 #define  RIO_PORT_N_CTL2_SEL_BAUD      0xf0000000
-#define RIO_PORT_N_ERR_STS_CSR(x)      (0x0058 + x*0x20)
-#define  RIO_PORT_N_ERR_STS_PW_OUT_ES  0x00010000 /* Output Error-stopped */
-#define  RIO_PORT_N_ERR_STS_PW_INP_ES  0x00000100 /* Input Error-stopped */
+#define RIO_PORT_N_ERR_STS_CSR(n, m)   (0x58 + (n) * (0x20 * (m)))
+#define  RIO_PORT_N_ERR_STS_OUT_ES     0x00010000 /* Output Error-stopped */
+#define  RIO_PORT_N_ERR_STS_INP_ES     0x00000100 /* Input Error-stopped */
 #define  RIO_PORT_N_ERR_STS_PW_PEND    0x00000010 /* Port-Write Pending */
+#define  RIO_PORT_N_ERR_STS_PORT_UA    0x00000008 /* Port Unavailable */
 #define  RIO_PORT_N_ERR_STS_PORT_ERR   0x00000004
 #define  RIO_PORT_N_ERR_STS_PORT_OK    0x00000002
 #define  RIO_PORT_N_ERR_STS_PORT_UNINIT        0x00000001
-#define RIO_PORT_N_CTL_CSR(x)          (0x005c + x*0x20)
+#define RIO_PORT_N_CTL_CSR(n, m)       (0x5c + (n) * (0x20 * (m)))
 #define  RIO_PORT_N_CTL_PWIDTH         0xc0000000
 #define  RIO_PORT_N_CTL_PWIDTH_1       0x00000000
 #define  RIO_PORT_N_CTL_PWIDTH_4       0x40000000
 #define  RIO_PORT_N_CTL_IPW            0x38000000 /* Initialized Port Width */
 #define  RIO_PORT_N_CTL_P_TYP_SER      0x00000001
 #define  RIO_PORT_N_CTL_LOCKOUT                0x00000002
-#define  RIO_PORT_N_CTL_EN_RX_SER      0x00200000
-#define  RIO_PORT_N_CTL_EN_TX_SER      0x00400000
-#define  RIO_PORT_N_CTL_EN_RX_PAR      0x08000000
-#define  RIO_PORT_N_CTL_EN_TX_PAR      0x40000000
+#define  RIO_PORT_N_CTL_EN_RX          0x00200000
+#define  RIO_PORT_N_CTL_EN_TX          0x00400000
+#define RIO_PORT_N_OB_ACK_CSR(n)       (0x60 + (n) * 0x40) /* Only in RM-II */
+#define  RIO_PORT_N_OB_ACK_CLEAR       0x80000000
+#define  RIO_PORT_N_OB_ACK_OUTSTD      0x00fff000
+#define  RIO_PORT_N_OB_ACK_OUTBND      0x00000fff
+#define RIO_PORT_N_IB_ACK_CSR(n)       (0x64 + (n) * 0x40) /* Only in RM-II */
+#define  RIO_PORT_N_IB_ACK_INBND       0x00000fff
+
+/*
+ * Device-based helper macros for serial port register access.
+ *   d - pointer to rapidio device object, n - port number
+ */
+
+#define RIO_DEV_PORT_N_MNT_REQ_CSR(d, n)       \
+               (d->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(n, d->phys_rmap))
+
+#define RIO_DEV_PORT_N_MNT_RSP_CSR(d, n)       \
+               (d->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(n, d->phys_rmap))
+
+#define RIO_DEV_PORT_N_ACK_STS_CSR(d, n)       \
+               (d->phys_efptr + RIO_PORT_N_ACK_STS_CSR(n))
+
+#define RIO_DEV_PORT_N_CTL2_CSR(d, n)          \
+               (d->phys_efptr + RIO_PORT_N_CTL2_CSR(n, d->phys_rmap))
+
+#define RIO_DEV_PORT_N_ERR_STS_CSR(d, n)       \
+               (d->phys_efptr + RIO_PORT_N_ERR_STS_CSR(n, d->phys_rmap))
+
+#define RIO_DEV_PORT_N_CTL_CSR(d, n)           \
+               (d->phys_efptr + RIO_PORT_N_CTL_CSR(n, d->phys_rmap))
+
+#define RIO_DEV_PORT_N_OB_ACK_CSR(d, n)                \
+               (d->phys_efptr + RIO_PORT_N_OB_ACK_CSR(n))
+
+#define RIO_DEV_PORT_N_IB_ACK_CSR(d, n)                \
+               (d->phys_efptr + RIO_PORT_N_IB_ACK_CSR(n))
 
 /*
  * Error Management Extensions (RapidIO 1.3+, Part 8)
 /* General EM Registers (Common for all Ports) */
 
 #define RIO_EM_EFB_HEADER      0x000   /* Error Management Extensions Block Header */
+#define RIO_EM_EMHS_CAR                0x004   /* EM Functionality CAR */
 #define RIO_EM_LTL_ERR_DETECT  0x008   /* Logical/Transport Layer Error Detect CSR */
 #define RIO_EM_LTL_ERR_EN      0x00c   /* Logical/Transport Layer Error Enable CSR */
 #define  REM_LTL_ERR_ILLTRAN           0x08000000 /* Illegal Transaction decode */
 #define RIO_EM_LTL_ADDR_CAP    0x014   /* Logical/Transport Layer Address Capture CSR */
 #define RIO_EM_LTL_DEVID_CAP   0x018   /* Logical/Transport Layer Device ID Capture CSR */
 #define RIO_EM_LTL_CTRL_CAP    0x01c   /* Logical/Transport Layer Control Capture CSR */
+#define RIO_EM_LTL_DID32_CAP   0x020   /* Logical/Transport Layer Dev32 DestID Capture CSR */
+#define RIO_EM_LTL_SID32_CAP   0x024   /* Logical/Transport Layer Dev32  source ID Capture CSR */
 #define RIO_EM_PW_TGT_DEVID    0x028   /* Port-write Target deviceID CSR */
+#define  RIO_EM_PW_TGT_DEVID_D16M      0xff000000      /* Port-write Target DID16 MSB */
+#define  RIO_EM_PW_TGT_DEVID_D8                0x00ff0000      /* Port-write Target DID16 LSB or DID8 */
+#define  RIO_EM_PW_TGT_DEVID_DEV16     0x00008000      /* Port-write Target DID16 LSB or DID8 */
+#define  RIO_EM_PW_TGT_DEVID_DEV32     0x00004000      /* Port-write Target DID16 LSB or DID8 */
 #define RIO_EM_PKT_TTL         0x02c   /* Packet Time-to-live CSR */
+#define RIO_EM_PKT_TTL_VAL             0xffff0000      /* Packet Time-to-live value */
+#define RIO_EM_PW_TGT32_DEVID  0x030   /* Port-write Dev32 Target deviceID CSR */
+#define RIO_EM_PW_TX_CTRL      0x034   /* Port-write Transmission Control CSR */
+#define RIO_EM_PW_TX_CTRL_PW_DIS       0x00000001      /* Port-write Transmission Disable bit */
 
 /* Per-Port EM Registers */
 
 #define RIO_EM_PN_ERR_DETECT(x)        (0x040 + x*0x40) /* Port N Error Detect CSR */
 #define  REM_PED_IMPL_SPEC             0x80000000
+#define  REM_PED_LINK_OK2U             0x40000000 /* Link OK to Uninit transition */
+#define  REM_PED_LINK_UPDA             0x20000000 /* Link Uninit Packet Discard Active */
+#define  REM_PED_LINK_U2OK             0x10000000 /* Link Uninit to OK transition */
 #define  REM_PED_LINK_TO               0x00000001
+
 #define RIO_EM_PN_ERRRATE_EN(x) (0x044 + x*0x40) /* Port N Error Rate Enable CSR */
+#define RIO_EM_PN_ERRRATE_EN_OK2U      0x40000000 /* Enable notification for OK2U */
+#define RIO_EM_PN_ERRRATE_EN_UPDA      0x20000000 /* Enable notification for UPDA */
+#define RIO_EM_PN_ERRRATE_EN_U2OK      0x10000000 /* Enable notification for U2OK */
+
 #define RIO_EM_PN_ATTRIB_CAP(x)        (0x048 + x*0x40) /* Port N Attributes Capture CSR */
 #define RIO_EM_PN_PKT_CAP_0(x) (0x04c + x*0x40) /* Port N Packet/Control Symbol Capture 0 CSR */
 #define RIO_EM_PN_PKT_CAP_1(x) (0x050 + x*0x40) /* Port N Packet Capture 1 CSR */
 #define RIO_EM_PN_PKT_CAP_3(x) (0x058 + x*0x40) /* Port N Packet Capture 3 CSR */
 #define RIO_EM_PN_ERRRATE(x)   (0x068 + x*0x40) /* Port N Error Rate CSR */
 #define RIO_EM_PN_ERRRATE_TR(x) (0x06c + x*0x40) /* Port N Error Rate Threshold CSR */
+#define RIO_EM_PN_LINK_UDT(x)  (0x070 + x*0x40) /* Port N Link Uninit Discard Timer CSR */
+#define RIO_EM_PN_LINK_UDT_TO          0xffffff00 /* Link Uninit Timeout value */
+
+/*
+ * Switch Routing Table Register Block ID=0x000E (RapidIO 3.0+, part 3)
+ * Register offsets are defined from beginning of the block.
+ */
+
+/* Broadcast Routing Table Control CSR */
+#define RIO_BC_RT_CTL_CSR      0x020
+#define  RIO_RT_CTL_THREE_LVL          0x80000000
+#define  RIO_RT_CTL_DEV32_RT_CTRL      0x40000000
+#define  RIO_RT_CTL_MC_MASK_SZ         0x03000000 /* 3.0+ Part 11: Multicast */
+
+/* Broadcast Level 0 Info CSR */
+#define RIO_BC_RT_LVL0_INFO_CSR        0x030
+#define  RIO_RT_L0I_NUM_GR             0xff000000
+#define  RIO_RT_L0I_GR_PTR             0x00fffc00
+
+/* Broadcast Level 1 Info CSR */
+#define RIO_BC_RT_LVL1_INFO_CSR        0x034
+#define  RIO_RT_L1I_NUM_GR             0xff000000
+#define  RIO_RT_L1I_GR_PTR             0x00fffc00
+
+/* Broadcast Level 2 Info CSR */
+#define RIO_BC_RT_LVL2_INFO_CSR        0x038
+#define  RIO_RT_L2I_NUM_GR             0xff000000
+#define  RIO_RT_L2I_GR_PTR             0x00fffc00
+
+/* Per-Port Routing Table registers.
+ * Register fields defined in the broadcast section above are
+ * applicable to the corresponding registers below.
+ */
+#define RIO_SPx_RT_CTL_CSR(x)  (0x040 + (0x20 * x))
+#define RIO_SPx_RT_LVL0_INFO_CSR(x)    (0x50 + (0x20 * x))
+#define RIO_SPx_RT_LVL1_INFO_CSR(x)    (0x54 + (0x20 * x))
+#define RIO_SPx_RT_LVL2_INFO_CSR(x)    (0x58 + (0x20 * x))
+
+/* Register Formats for Routing Table Group entry.
+ * Register offsets are calculated using GR_PTR field in the corresponding
+ * table Level_N and group/entry numbers (see RapidIO 3.0+ Part 3).
+ */
+#define RIO_RT_Ln_ENTRY_IMPL_DEF       0xf0000000
+#define RIO_RT_Ln_ENTRY_RTE_VAL                0x000003ff
+#define RIO_RT_ENTRY_DROP_PKT          0x300
 
 #endif                         /* LINUX_RIO_REGS_H */
diff --git a/include/linux/rtc-ds2404.h b/include/linux/rtc-ds2404.h
deleted file mode 100644 (file)
index 22c5382..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ds2404.h - platform data structure for the DS2404 RTC.
- *
- * 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 Sven Schnelle <svens@stackframe.org>
- */
-
-#ifndef __LINUX_DS2404_H
-#define __LINUX_DS2404_H
-
-struct ds2404_platform_data {
-
-       unsigned int gpio_rst;
-       unsigned int gpio_clk;
-       unsigned int gpio_dq;
-};
-#endif
diff --git a/include/linux/rtc-v3020.h b/include/linux/rtc-v3020.h
deleted file mode 100644 (file)
index e55d82c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * v3020.h - Registers definition and platform data structure for the v3020 RTC.
- *
- * 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, 8D Technologies inc.
- */
-#ifndef __LINUX_V3020_H
-#define __LINUX_V3020_H
-
-/* The v3020 has only one data pin but which one
- * is used depends on the board. */
-struct v3020_platform_data {
-       int leftshift; /* (1<<(leftshift)) & readl() */
-
-       unsigned int use_gpio:1;
-       unsigned int gpio_cs;
-       unsigned int gpio_wr;
-       unsigned int gpio_rd;
-       unsigned int gpio_io;
-};
-
-#define V3020_STATUS_0 0x00
-#define V3020_STATUS_1 0x01
-#define V3020_SECONDS  0x02
-#define V3020_MINUTES  0x03
-#define V3020_HOURS            0x04
-#define V3020_MONTH_DAY        0x05
-#define V3020_MONTH            0x06
-#define V3020_YEAR             0x07
-#define V3020_WEEK_DAY 0x08
-#define V3020_WEEK             0x09
-
-#define V3020_IS_COMMAND(val) ((val)>=0x0E)
-
-#define V3020_CMD_RAM2CLOCK    0x0E
-#define V3020_CMD_CLOCK2RAM    0x0F
-
-#endif /* __LINUX_V3020_H */
diff --git a/include/linux/rtc/ds1286.h b/include/linux/rtc/ds1286.h
new file mode 100644 (file)
index 0000000..45ea0aa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1998, 1999, 2003 Ralf Baechle
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __LINUX_DS1286_H
+#define __LINUX_DS1286_H
+
+/**********************************************************************
+ * register summary
+ **********************************************************************/
+#define RTC_HUNDREDTH_SECOND   0
+#define RTC_SECONDS            1
+#define RTC_MINUTES            2
+#define RTC_MINUTES_ALARM      3
+#define RTC_HOURS              4
+#define RTC_HOURS_ALARM                5
+#define RTC_DAY                        6
+#define RTC_DAY_ALARM          7
+#define RTC_DATE               8
+#define RTC_MONTH              9
+#define RTC_YEAR               10
+#define RTC_CMD                        11
+#define RTC_WHSEC              12
+#define RTC_WSEC               13
+#define RTC_UNUSED             14
+
+/* RTC_*_alarm is always true if 2 MSBs are set */
+# define RTC_ALARM_DONT_CARE   0xC0
+
+
+/*
+ * Bits in the month register
+ */
+#define RTC_EOSC               0x80
+#define RTC_ESQW               0x40
+
+/*
+ * Bits in the Command register
+ */
+#define RTC_TDF                        0x01
+#define RTC_WAF                        0x02
+#define RTC_TDM                        0x04
+#define RTC_WAM                        0x08
+#define RTC_PU_LVL             0x10
+#define RTC_IBH_LO             0x20
+#define RTC_IPSW               0x40
+#define RTC_TE                 0x80
+
+#endif /* __LINUX_DS1286_H */
index 553af29..62c68e5 100644 (file)
@@ -1547,6 +1547,9 @@ struct task_struct {
        /* unserialized, strictly 'current' */
        unsigned in_execve:1; /* bit to tell LSMs we're in execve */
        unsigned in_iowait:1;
+#if !defined(TIF_RESTORE_SIGMASK)
+       unsigned restore_sigmask:1;
+#endif
 #ifdef CONFIG_MEMCG
        unsigned memcg_may_oom:1;
 #ifndef CONFIG_SLOB
@@ -2680,6 +2683,66 @@ extern void sigqueue_free(struct sigqueue *);
 extern int send_sigqueue(struct sigqueue *,  struct task_struct *, int group);
 extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
 
+#ifdef TIF_RESTORE_SIGMASK
+/*
+ * Legacy restore_sigmask accessors.  These are inefficient on
+ * SMP architectures because they require atomic operations.
+ */
+
+/**
+ * set_restore_sigmask() - make sure saved_sigmask processing gets done
+ *
+ * This sets TIF_RESTORE_SIGMASK and ensures that the arch signal code
+ * will run before returning to user mode, to process the flag.  For
+ * all callers, TIF_SIGPENDING is already set or it's no harm to set
+ * it.  TIF_RESTORE_SIGMASK need not be in the set of bits that the
+ * arch code will notice on return to user mode, in case those bits
+ * are scarce.  We set TIF_SIGPENDING here to ensure that the arch
+ * signal code always gets run when TIF_RESTORE_SIGMASK is set.
+ */
+static inline void set_restore_sigmask(void)
+{
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+       WARN_ON(!test_thread_flag(TIF_SIGPENDING));
+}
+static inline void clear_restore_sigmask(void)
+{
+       clear_thread_flag(TIF_RESTORE_SIGMASK);
+}
+static inline bool test_restore_sigmask(void)
+{
+       return test_thread_flag(TIF_RESTORE_SIGMASK);
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+       return test_and_clear_thread_flag(TIF_RESTORE_SIGMASK);
+}
+
+#else  /* TIF_RESTORE_SIGMASK */
+
+/* Higher-quality implementation, used if TIF_RESTORE_SIGMASK doesn't exist. */
+static inline void set_restore_sigmask(void)
+{
+       current->restore_sigmask = true;
+       WARN_ON(!test_thread_flag(TIF_SIGPENDING));
+}
+static inline void clear_restore_sigmask(void)
+{
+       current->restore_sigmask = false;
+}
+static inline bool test_restore_sigmask(void)
+{
+       return current->restore_sigmask;
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+       if (!current->restore_sigmask)
+               return false;
+       current->restore_sigmask = false;
+       return true;
+}
+#endif
+
 static inline void restore_saved_sigmask(void)
 {
        if (test_and_clear_restore_sigmask())
index 14df373..7831cd5 100644 (file)
@@ -240,7 +240,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
                                struct super_block *newsb);
 int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
 int security_dentry_init_security(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen);
 
 int security_inode_alloc(struct inode *inode);
@@ -591,7 +591,7 @@ static inline void security_inode_free(struct inode *inode)
 
 static inline int security_dentry_init_security(struct dentry *dentry,
                                                 int mode,
-                                                struct qstr *name,
+                                                const struct qstr *name,
                                                 void **ctx,
                                                 u32 *ctxlen)
 {
index df4ab5d..c733cff 100644 (file)
@@ -31,7 +31,8 @@ struct serio {
 
        struct serio_device_id id;
 
-       spinlock_t lock;                /* protects critical sections from port's interrupt handler */
+       /* Protects critical sections from port's interrupt handler */
+       spinlock_t lock;
 
        int (*write)(struct serio *, unsigned char);
        int (*open)(struct serio *);
@@ -40,16 +41,29 @@ struct serio {
        void (*stop)(struct serio *);
 
        struct serio *parent;
-       struct list_head child_node;    /* Entry in parent->children list */
+       /* Entry in parent->children list */
+       struct list_head child_node;
        struct list_head children;
-       unsigned int depth;             /* level of nesting in serio hierarchy */
+       /* Level of nesting in serio hierarchy */
+       unsigned int depth;
 
-       struct serio_driver *drv;       /* accessed from interrupt, must be protected by serio->lock and serio->sem */
-       struct mutex drv_mutex;         /* protects serio->drv so attributes can pin driver */
+       /*
+        * serio->drv is accessed from interrupt handlers; when modifying
+        * caller should acquire serio->drv_mutex and serio->lock.
+        */
+       struct serio_driver *drv;
+       /* Protects serio->drv so attributes can pin current driver */
+       struct mutex drv_mutex;
 
        struct device dev;
 
        struct list_head node;
+
+       /*
+        * For use by PS/2 layer when several ports share hardware and
+        * may get indigestion when exposed to concurrent access (i8042).
+        */
+       struct mutex *ps2_cmd_mutex;
 };
 #define to_serio_port(d)       container_of(d, struct serio, dev)
 
index 1a4ea55..4293808 100644 (file)
@@ -155,6 +155,18 @@ void kfree(const void *);
 void kzfree(const void *);
 size_t ksize(const void *);
 
+#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page);
+#else
+static inline const char *__check_heap_object(const void *ptr,
+                                             unsigned long n,
+                                             struct page *page)
+{
+       return NULL;
+}
+#endif
+
 /*
  * Some archs want to perform DMA into kmalloc caches and need a guaranteed
  * alignment larger than the alignment of a 64-bit integer.
index ed03c9f..62a60ee 100644 (file)
@@ -78,8 +78,6 @@ struct cache_detail {
        struct hlist_head *     hash_table;
        rwlock_t                hash_lock;
 
-       atomic_t                inuse; /* active user-space update or lookup */
-
        char                    *name;
        void                    (*cache_put)(struct kref *);
 
index 7ca44fb..7321ae9 100644 (file)
@@ -268,6 +268,7 @@ struct svc_rqst {
                                                 * cache pages */
 #define        RQ_VICTIM       (5)                     /* about to be shut down */
 #define        RQ_BUSY         (6)                     /* request is busy */
+#define        RQ_DATA         (7)                     /* request has data */
        unsigned long           rq_flags;       /* flags field */
 
        void *                  rq_argp;        /* decoded arguments */
index 79ba508..ab02a45 100644 (file)
@@ -25,7 +25,6 @@ struct svc_xprt_ops {
        void            (*xpo_detach)(struct svc_xprt *);
        void            (*xpo_free)(struct svc_xprt *);
        int             (*xpo_secure_port)(struct svc_rqst *);
-       void            (*xpo_adjust_wspace)(struct svc_xprt *);
 };
 
 struct svc_xprt_class {
@@ -69,6 +68,7 @@ struct svc_xprt {
 
        struct svc_serv         *xpt_server;    /* service for transport */
        atomic_t                xpt_reserved;   /* space on outq that is rsvd */
+       atomic_t                xpt_nr_rqsts;   /* Number of requests */
        struct mutex            xpt_mutex;      /* to serialize sending data */
        spinlock_t              xpt_lock;       /* protects sk_deferred
                                                 * and xpt_auth_cache */
index 017fced..5f81f8a 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/types.h>
 
 struct device;
-struct dma_attrs;
 struct page;
 struct scatterlist;
 
@@ -68,10 +67,10 @@ swiotlb_free_coherent(struct device *hwdev, size_t size,
 extern dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
                                   unsigned long offset, size_t size,
                                   enum dma_data_direction dir,
-                                  struct dma_attrs *attrs);
+                                  unsigned long attrs);
 extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                               size_t size, enum dma_data_direction dir,
-                              struct dma_attrs *attrs);
+                              unsigned long attrs);
 
 extern int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
@@ -83,12 +82,13 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
 
 extern int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    enum dma_data_direction dir, struct dma_attrs *attrs);
+                    enum dma_data_direction dir,
+                    unsigned long attrs);
 
 extern void
 swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                       int nelems, enum dma_data_direction dir,
-                      struct dma_attrs *attrs);
+                      unsigned long attrs);
 
 extern void
 swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
index fa7bc29..697e160 100644 (file)
@@ -28,6 +28,7 @@
 #include <uapi/linux/sysctl.h>
 
 /* For the /proc/sys support */
+struct completion;
 struct ctl_table;
 struct nsproxy;
 struct ctl_table_root;
index b4c2a48..cbd8990 100644 (file)
@@ -105,46 +105,29 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
 
 #define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)
 
-#if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK
-/*
- * An arch can define its own version of set_restore_sigmask() to get the
- * job done however works, with or without TIF_RESTORE_SIGMASK.
- */
-#define HAVE_SET_RESTORE_SIGMASK       1
-
-/**
- * set_restore_sigmask() - make sure saved_sigmask processing gets done
- *
- * This sets TIF_RESTORE_SIGMASK and ensures that the arch signal code
- * will run before returning to user mode, to process the flag.  For
- * all callers, TIF_SIGPENDING is already set or it's no harm to set
- * it.  TIF_RESTORE_SIGMASK need not be in the set of bits that the
- * arch code will notice on return to user mode, in case those bits
- * are scarce.  We set TIF_SIGPENDING here to ensure that the arch
- * signal code always gets run when TIF_RESTORE_SIGMASK is set.
- */
-static inline void set_restore_sigmask(void)
-{
-       set_thread_flag(TIF_RESTORE_SIGMASK);
-       WARN_ON(!test_thread_flag(TIF_SIGPENDING));
-}
-static inline void clear_restore_sigmask(void)
+#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
+static inline int arch_within_stack_frames(const void * const stack,
+                                          const void * const stackend,
+                                          const void *obj, unsigned long len)
 {
-       clear_thread_flag(TIF_RESTORE_SIGMASK);
+       return 0;
 }
-static inline bool test_restore_sigmask(void)
-{
-       return test_thread_flag(TIF_RESTORE_SIGMASK);
-}
-static inline bool test_and_clear_restore_sigmask(void)
+#endif
+
+#ifdef CONFIG_HARDENED_USERCOPY
+extern void __check_object_size(const void *ptr, unsigned long n,
+                                       bool to_user);
+
+static inline void check_object_size(const void *ptr, unsigned long n,
+                                    bool to_user)
 {
-       return test_and_clear_thread_flag(TIF_RESTORE_SIGMASK);
+       __check_object_size(ptr, n, to_user);
 }
-#endif /* TIF_RESTORE_SIGMASK && !HAVE_SET_RESTORE_SIGMASK */
-
-#ifndef HAVE_SET_RESTORE_SIGMASK
-#error "no set_restore_sigmask() provided and default one won't work"
-#endif
+#else
+static inline void check_object_size(const void *ptr, unsigned long n,
+                                    bool to_user)
+{ }
+#endif /* CONFIG_HARDENED_USERCOPY */
 
 #endif /* __KERNEL__ */
 
index 3495578..f30c187 100644 (file)
@@ -114,8 +114,8 @@ extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
 #ifndef user_access_begin
 #define user_access_begin() do { } while (0)
 #define user_access_end() do { } while (0)
-#define unsafe_get_user(x, ptr) __get_user(x, ptr)
-#define unsafe_put_user(x, ptr) __put_user(x, ptr)
+#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)
+#define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0)
 #endif
 
 #endif         /* __LINUX_UACCESS_H__ */
index 6e6cb0c..26c155b 100644 (file)
@@ -149,6 +149,19 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
        return __virtio_test_bit(vdev, fbit);
 }
 
+/**
+ * virtio_has_iommu_quirk - determine whether this device has the iommu quirk
+ * @vdev: the device
+ */
+static inline bool virtio_has_iommu_quirk(const struct virtio_device *vdev)
+{
+       /*
+        * Note the reverse polarity of the quirk feature (compared to most
+        * other features), this is for compatibility with legacy systems.
+        */
+       return !virtio_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
+}
+
 static inline
 struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
                                        vq_callback_t *c, const char *n)
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
new file mode 100644 (file)
index 0000000..9638bfe
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef _LINUX_VIRTIO_VSOCK_H
+#define _LINUX_VIRTIO_VSOCK_H
+
+#include <uapi/linux/virtio_vsock.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/af_vsock.h>
+
+#define VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE      128
+#define VIRTIO_VSOCK_DEFAULT_BUF_SIZE          (1024 * 256)
+#define VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE      (1024 * 256)
+#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE       (1024 * 4)
+#define VIRTIO_VSOCK_MAX_BUF_SIZE              0xFFFFFFFFUL
+#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE          (1024 * 64)
+
+enum {
+       VSOCK_VQ_RX     = 0, /* for host to guest data */
+       VSOCK_VQ_TX     = 1, /* for guest to host data */
+       VSOCK_VQ_EVENT  = 2,
+       VSOCK_VQ_MAX    = 3,
+};
+
+/* Per-socket state (accessed via vsk->trans) */
+struct virtio_vsock_sock {
+       struct vsock_sock *vsk;
+
+       /* Protected by lock_sock(sk_vsock(trans->vsk)) */
+       u32 buf_size;
+       u32 buf_size_min;
+       u32 buf_size_max;
+
+       spinlock_t tx_lock;
+       spinlock_t rx_lock;
+
+       /* Protected by tx_lock */
+       u32 tx_cnt;
+       u32 buf_alloc;
+       u32 peer_fwd_cnt;
+       u32 peer_buf_alloc;
+
+       /* Protected by rx_lock */
+       u32 fwd_cnt;
+       u32 rx_bytes;
+       struct list_head rx_queue;
+};
+
+struct virtio_vsock_pkt {
+       struct virtio_vsock_hdr hdr;
+       struct work_struct work;
+       struct list_head list;
+       void *buf;
+       u32 len;
+       u32 off;
+       bool reply;
+};
+
+struct virtio_vsock_pkt_info {
+       u32 remote_cid, remote_port;
+       struct msghdr *msg;
+       u32 pkt_len;
+       u16 type;
+       u16 op;
+       u32 flags;
+       bool reply;
+};
+
+struct virtio_transport {
+       /* This must be the first field */
+       struct vsock_transport transport;
+
+       /* Takes ownership of the packet */
+       int (*send_pkt)(struct virtio_vsock_pkt *pkt);
+};
+
+ssize_t
+virtio_transport_stream_dequeue(struct vsock_sock *vsk,
+                               struct msghdr *msg,
+                               size_t len,
+                               int type);
+int
+virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
+                              struct msghdr *msg,
+                              size_t len, int flags);
+
+s64 virtio_transport_stream_has_data(struct vsock_sock *vsk);
+s64 virtio_transport_stream_has_space(struct vsock_sock *vsk);
+
+int virtio_transport_do_socket_init(struct vsock_sock *vsk,
+                                struct vsock_sock *psk);
+u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk);
+u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk);
+u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk);
+void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val);
+void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val);
+void virtio_transport_set_max_buffer_size(struct vsock_sock *vs, u64 val);
+int
+virtio_transport_notify_poll_in(struct vsock_sock *vsk,
+                               size_t target,
+                               bool *data_ready_now);
+int
+virtio_transport_notify_poll_out(struct vsock_sock *vsk,
+                                size_t target,
+                                bool *space_available_now);
+
+int virtio_transport_notify_recv_init(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data);
+int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data);
+int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data);
+int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk,
+       size_t target, ssize_t copied, bool data_read,
+       struct vsock_transport_recv_notify_data *data);
+int virtio_transport_notify_send_init(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data);
+int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data);
+int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data);
+int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk,
+       ssize_t written, struct vsock_transport_send_notify_data *data);
+
+u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk);
+bool virtio_transport_stream_is_active(struct vsock_sock *vsk);
+bool virtio_transport_stream_allow(u32 cid, u32 port);
+int virtio_transport_dgram_bind(struct vsock_sock *vsk,
+                               struct sockaddr_vm *addr);
+bool virtio_transport_dgram_allow(u32 cid, u32 port);
+
+int virtio_transport_connect(struct vsock_sock *vsk);
+
+int virtio_transport_shutdown(struct vsock_sock *vsk, int mode);
+
+void virtio_transport_release(struct vsock_sock *vsk);
+
+ssize_t
+virtio_transport_stream_enqueue(struct vsock_sock *vsk,
+                               struct msghdr *msg,
+                               size_t len);
+int
+virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
+                              struct sockaddr_vm *remote_addr,
+                              struct msghdr *msg,
+                              size_t len);
+
+void virtio_transport_destruct(struct vsock_sock *vsk);
+
+void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt);
+void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt);
+void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt);
+u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 wanted);
+void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit);
+
+#endif /* _LINUX_VIRTIO_VSOCK_H */
index 760399a..2bb5deb 100644 (file)
@@ -173,14 +173,14 @@ static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
        mutex_release(&ctx->dep_map, 0, _THIS_IP_);
 
        DEBUG_LOCKS_WARN_ON(ctx->acquired);
-       if (!config_enabled(CONFIG_PROVE_LOCKING))
+       if (!IS_ENABLED(CONFIG_PROVE_LOCKING))
                /*
                 * lockdep will normally handle this,
                 * but fail without anyway
                 */
                ctx->done_acquire = 1;
 
-       if (!config_enabled(CONFIG_DEBUG_LOCK_ALLOC))
+       if (!IS_ENABLED(CONFIG_DEBUG_LOCK_ALLOC))
                /* ensure ww_acquire_fini will still fail if called twice */
                ctx->acquired = ~0U;
 #endif
index 946340c..a4a9a55 100644 (file)
@@ -98,7 +98,7 @@ struct vb2_threadio_data;
  *    #) Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf, unmap_dmabuf.
  */
 struct vb2_mem_ops {
-       void            *(*alloc)(struct device *dev, const struct dma_attrs *attrs,
+       void            *(*alloc)(struct device *dev, unsigned long attrs,
                                  unsigned long size, enum dma_data_direction dma_dir,
                                  gfp_t gfp_flags);
        void            (*put)(void *buf_priv);
@@ -408,7 +408,7 @@ struct vb2_buf_ops {
  * @io_modes:  supported io methods (see vb2_io_modes enum)
  * @dev:       device to use for the default allocation context if the driver
  *             doesn't fill in the @alloc_devs array.
- * @dma_attrs: DMA attributes to use for the DMA. May be NULL.
+ * @dma_attrs: DMA attributes to use for the DMA.
  * @fileio_read_once:          report EOF after reading the first buffer
  * @fileio_write_immediately:  queue buffer after each write() call
  * @allow_zero_bytesused:      allow bytesused == 0 to be passed to the driver
@@ -476,7 +476,7 @@ struct vb2_queue {
        unsigned int                    type;
        unsigned int                    io_modes;
        struct device                   *dev;
-       const struct dma_attrs          *dma_attrs;
+       unsigned long                   dma_attrs;
        unsigned                        fileio_read_once:1;
        unsigned                        fileio_write_immediately:1;
        unsigned                        allow_zero_bytesused:1;
index df2aabe..5604818 100644 (file)
@@ -16,8 +16,6 @@
 #include <media/videobuf2-v4l2.h>
 #include <linux/dma-mapping.h>
 
-struct dma_attrs;
-
 static inline dma_addr_t
 vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no)
 {
index e9eb2d6..f275896 100644 (file)
@@ -63,6 +63,8 @@ struct vsock_sock {
        struct list_head accept_queue;
        bool rejected;
        struct delayed_work dwork;
+       struct delayed_work close_work;
+       bool close_work_scheduled;
        u32 peer_shutdown;
        bool sent_request;
        bool ignore_connecting_rst;
@@ -165,6 +167,9 @@ static inline int vsock_core_init(const struct vsock_transport *t)
 }
 void vsock_core_exit(void);
 
+/* The transport may downcast this to access transport-specific functions */
+const struct vsock_transport *vsock_core_get_transport(void);
+
 /**** UTILS ****/
 
 void vsock_release_pending(struct sock *pending);
@@ -177,6 +182,7 @@ void vsock_remove_connected(struct vsock_sock *vsk);
 struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr);
 struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
                                         struct sockaddr_vm *dst);
+void vsock_remove_sock(struct vsock_sock *vsk);
 void vsock_for_each_connected_socket(void (*fn)(struct sock *sk));
 
 #endif /* __AF_VSOCK_H__ */
index 4089abc..0933c74 100644 (file)
@@ -275,7 +275,7 @@ static inline struct net *read_pnet(const possible_net_t *pnet)
 #define __net_initconst
 #else
 #define __net_init     __init
-#define __net_exit     __exit_refok
+#define __net_exit     __ref
 #define __net_initdata __initdata
 #define __net_initconst        __initconst
 #endif
index 8c337cd..5b847e4 100644 (file)
@@ -214,7 +214,7 @@ typedef enum {
        SCTP_SS_LISTENING      = TCP_LISTEN,
        SCTP_SS_ESTABLISHING   = TCP_SYN_SENT,
        SCTP_SS_ESTABLISHED    = TCP_ESTABLISHED,
-       SCTP_SS_CLOSING        = TCP_CLOSING,
+       SCTP_SS_CLOSING        = TCP_CLOSE_WAIT,
 } sctp_sock_state_t;
 
 /* These functions map various type to printable names.  */
index 3840416..5ee7aab 100644 (file)
@@ -94,6 +94,19 @@ enum ib_sa_selector {
        IB_SA_BEST = 3
 };
 
+/*
+ * There are 4 types of join states:
+ * FullMember, NonMember, SendOnlyNonMember, SendOnlyFullMember.
+ * The order corresponds to JoinState bits in MCMemberRecord.
+ */
+enum ib_sa_mc_join_states {
+       FULLMEMBER_JOIN,
+       NONMEMBER_JOIN,
+       SENDONLY_NONMEBER_JOIN,
+       SENDONLY_FULLMEMBER_JOIN,
+       NUM_JOIN_MEMBERSHIP_TYPES,
+};
+
 #define IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT      BIT(12)
 
 /*
index 7e440d4..8e90dd2 100644 (file)
@@ -562,6 +562,7 @@ enum ib_event_type {
        IB_EVENT_QP_LAST_WQE_REACHED,
        IB_EVENT_CLIENT_REREGISTER,
        IB_EVENT_GID_CHANGE,
+       IB_EVENT_WQ_FATAL,
 };
 
 const char *__attribute_const__ ib_event_msg(enum ib_event_type event);
@@ -572,6 +573,7 @@ struct ib_event {
                struct ib_cq    *cq;
                struct ib_qp    *qp;
                struct ib_srq   *srq;
+               struct ib_wq    *wq;
                u8              port_num;
        } element;
        enum ib_event_type      event;
@@ -1015,6 +1017,7 @@ struct ib_qp_init_attr {
         * Only needed for special QP types, or when using the RW API.
         */
        u8                      port_num;
+       struct ib_rwq_ind_table *rwq_ind_tbl;
 };
 
 struct ib_qp_open_attr {
@@ -1323,6 +1326,8 @@ struct ib_ucontext {
        struct list_head        ah_list;
        struct list_head        xrcd_list;
        struct list_head        rule_list;
+       struct list_head        wq_list;
+       struct list_head        rwq_ind_tbl_list;
        int                     closing;
 
        struct pid             *tgid;
@@ -1428,6 +1433,67 @@ struct ib_srq {
        } ext;
 };
 
+enum ib_wq_type {
+       IB_WQT_RQ
+};
+
+enum ib_wq_state {
+       IB_WQS_RESET,
+       IB_WQS_RDY,
+       IB_WQS_ERR
+};
+
+struct ib_wq {
+       struct ib_device       *device;
+       struct ib_uobject      *uobject;
+       void                *wq_context;
+       void                (*event_handler)(struct ib_event *, void *);
+       struct ib_pd           *pd;
+       struct ib_cq           *cq;
+       u32             wq_num;
+       enum ib_wq_state       state;
+       enum ib_wq_type wq_type;
+       atomic_t                usecnt;
+};
+
+struct ib_wq_init_attr {
+       void                   *wq_context;
+       enum ib_wq_type wq_type;
+       u32             max_wr;
+       u32             max_sge;
+       struct  ib_cq          *cq;
+       void                (*event_handler)(struct ib_event *, void *);
+};
+
+enum ib_wq_attr_mask {
+       IB_WQ_STATE     = 1 << 0,
+       IB_WQ_CUR_STATE = 1 << 1,
+};
+
+struct ib_wq_attr {
+       enum    ib_wq_state     wq_state;
+       enum    ib_wq_state     curr_wq_state;
+};
+
+struct ib_rwq_ind_table {
+       struct ib_device        *device;
+       struct ib_uobject      *uobject;
+       atomic_t                usecnt;
+       u32             ind_tbl_num;
+       u32             log_ind_tbl_size;
+       struct ib_wq    **ind_tbl;
+};
+
+struct ib_rwq_ind_table_init_attr {
+       u32             log_ind_tbl_size;
+       /* Each entry is a pointer to Receive Work Queue */
+       struct ib_wq    **ind_tbl;
+};
+
+/*
+ * @max_write_sge: Maximum SGE elements per RDMA WRITE request.
+ * @max_read_sge:  Maximum SGE elements per RDMA READ request.
+ */
 struct ib_qp {
        struct ib_device       *device;
        struct ib_pd           *pd;
@@ -1449,7 +1515,10 @@ struct ib_qp {
        void                  (*event_handler)(struct ib_event *, void *);
        void                   *qp_context;
        u32                     qp_num;
+       u32                     max_write_sge;
+       u32                     max_read_sge;
        enum ib_qp_type         qp_type;
+       struct ib_rwq_ind_table *rwq_ind_tbl;
 };
 
 struct ib_mr {
@@ -1506,6 +1575,7 @@ enum ib_flow_spec_type {
        IB_FLOW_SPEC_IB         = 0x22,
        /* L3 header*/
        IB_FLOW_SPEC_IPV4       = 0x30,
+       IB_FLOW_SPEC_IPV6       = 0x31,
        /* L4 headers*/
        IB_FLOW_SPEC_TCP        = 0x40,
        IB_FLOW_SPEC_UDP        = 0x41
@@ -1567,6 +1637,18 @@ struct ib_flow_spec_ipv4 {
        struct ib_flow_ipv4_filter mask;
 };
 
+struct ib_flow_ipv6_filter {
+       u8      src_ip[16];
+       u8      dst_ip[16];
+};
+
+struct ib_flow_spec_ipv6 {
+       enum ib_flow_spec_type     type;
+       u16                        size;
+       struct ib_flow_ipv6_filter val;
+       struct ib_flow_ipv6_filter mask;
+};
+
 struct ib_flow_tcp_udp_filter {
        __be16  dst_port;
        __be16  src_port;
@@ -1588,6 +1670,7 @@ union ib_flow_spec {
        struct ib_flow_spec_ib          ib;
        struct ib_flow_spec_ipv4        ipv4;
        struct ib_flow_spec_tcp_udp     tcp_udp;
+       struct ib_flow_spec_ipv6        ipv6;
 };
 
 struct ib_flow_attr {
@@ -1921,7 +2004,18 @@ struct ib_device {
                                                   struct ifla_vf_stats *stats);
        int                        (*set_vf_guid)(struct ib_device *device, int vf, u8 port, u64 guid,
                                                  int type);
-
+       struct ib_wq *             (*create_wq)(struct ib_pd *pd,
+                                               struct ib_wq_init_attr *init_attr,
+                                               struct ib_udata *udata);
+       int                        (*destroy_wq)(struct ib_wq *wq);
+       int                        (*modify_wq)(struct ib_wq *wq,
+                                               struct ib_wq_attr *attr,
+                                               u32 wq_attr_mask,
+                                               struct ib_udata *udata);
+       struct ib_rwq_ind_table *  (*create_rwq_ind_table)(struct ib_device *device,
+                                                          struct ib_rwq_ind_table_init_attr *init_attr,
+                                                          struct ib_udata *udata);
+       int                        (*destroy_rwq_ind_table)(struct ib_rwq_ind_table *wq_ind_table);
        struct ib_dma_mapping_ops   *dma_ops;
 
        struct module               *owner;
@@ -1956,6 +2050,7 @@ struct ib_device {
         * in fast paths.
         */
        int (*get_port_immutable)(struct ib_device *, u8, struct ib_port_immutable *);
+       void (*get_dev_fw_str)(struct ib_device *, char *str, size_t str_len);
 };
 
 struct ib_client {
@@ -1991,6 +2086,8 @@ struct ib_client {
 struct ib_device *ib_alloc_device(size_t size);
 void ib_dealloc_device(struct ib_device *device);
 
+void ib_get_device_fw_str(struct ib_device *device, char *str, size_t str_len);
+
 int ib_register_device(struct ib_device *device,
                       int (*port_callback)(struct ib_device *,
                                            u8, struct kobject *));
@@ -2819,19 +2916,19 @@ static inline void ib_dma_unmap_single(struct ib_device *dev,
 static inline u64 ib_dma_map_single_attrs(struct ib_device *dev,
                                          void *cpu_addr, size_t size,
                                          enum dma_data_direction direction,
-                                         struct dma_attrs *attrs)
+                                         unsigned long dma_attrs)
 {
        return dma_map_single_attrs(dev->dma_device, cpu_addr, size,
-                                   direction, attrs);
+                                   direction, dma_attrs);
 }
 
 static inline void ib_dma_unmap_single_attrs(struct ib_device *dev,
                                             u64 addr, size_t size,
                                             enum dma_data_direction direction,
-                                            struct dma_attrs *attrs)
+                                            unsigned long dma_attrs)
 {
        return dma_unmap_single_attrs(dev->dma_device, addr, size,
-                                     direction, attrs);
+                                     direction, dma_attrs);
 }
 
 /**
@@ -2906,17 +3003,18 @@ static inline void ib_dma_unmap_sg(struct ib_device *dev,
 static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
                                      struct scatterlist *sg, int nents,
                                      enum dma_data_direction direction,
-                                     struct dma_attrs *attrs)
+                                     unsigned long dma_attrs)
 {
-       return dma_map_sg_attrs(dev->dma_device, sg, nents, direction, attrs);
+       return dma_map_sg_attrs(dev->dma_device, sg, nents, direction,
+                               dma_attrs);
 }
 
 static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev,
                                         struct scatterlist *sg, int nents,
                                         enum dma_data_direction direction,
-                                        struct dma_attrs *attrs)
+                                        unsigned long dma_attrs)
 {
-       dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, attrs);
+       dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, dma_attrs);
 }
 /**
  * ib_sg_dma_address - Return the DMA address from a scatter/gather entry
@@ -3167,6 +3265,15 @@ int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
 struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, u8 port,
                                            u16 pkey, const union ib_gid *gid,
                                            const struct sockaddr *addr);
+struct ib_wq *ib_create_wq(struct ib_pd *pd,
+                          struct ib_wq_init_attr *init_attr);
+int ib_destroy_wq(struct ib_wq *wq);
+int ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *attr,
+                u32 wq_attr_mask);
+struct ib_rwq_ind_table *ib_create_rwq_ind_table(struct ib_device *device,
+                                                struct ib_rwq_ind_table_init_attr*
+                                                wq_ind_table_init_attr);
+int ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *wq_ind_table);
 
 int ib_map_mr_sg(struct ib_mr *mr, struct scatterlist *sg, int sg_nents,
                 unsigned int *sg_offset, unsigned int page_size);
index 2b95c2c..9303e0e 100644 (file)
 #if !defined(OPA_PORT_INFO_H)
 #define OPA_PORT_INFO_H
 
-/* Temporary until HFI driver is updated */
-#ifndef USE_PI_LED_ENABLE
-#define USE_PI_LED_ENABLE 0
-#endif
-
 #define OPA_PORT_LINK_MODE_NOP 0               /* No change */
 #define OPA_PORT_LINK_MODE_OPA 4               /* Port mode is OPA */
 
@@ -274,23 +269,12 @@ enum port_info_field_masks {
        OPA_PI_MASK_MTU_CAP                       = 0x0F,
 };
 
-#if USE_PI_LED_ENABLE
 struct opa_port_states {
        u8     reserved;
        u8     ledenable_offlinereason;   /* 1 res, 1 bit, 6 bits */
        u8     reserved2;
        u8     portphysstate_portstate;   /* 4 bits, 4 bits */
 };
-#define PI_LED_ENABLE_SUP 1
-#else
-struct opa_port_states {
-       u8     reserved;
-       u8     offline_reason;            /* 2 res, 6 bits */
-       u8     reserved2;
-       u8     portphysstate_portstate;   /* 4 bits, 4 bits */
-};
-#define PI_LED_ENABLE_SUP 0
-#endif
 
 struct opa_port_state_info {
        struct opa_port_states port_states;
index afe44fd..81fb1d1 100644 (file)
@@ -333,11 +333,13 @@ int rdma_disconnect(struct rdma_cm_id *id);
  *   address.
  * @id: Communication identifier associated with the request.
  * @addr: Multicast address identifying the group to join.
+ * @join_state: Multicast JoinState bitmap requested by port.
+ *             Bitmap is based on IB_SA_MCMEMBER_REC_JOIN_STATE bits.
  * @context: User-defined context associated with the join request, returned
  * to the user through the private_data pointer in multicast events.
  */
 int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
-                       void *context);
+                       u8 join_state, void *context);
 
 /**
  * rdma_leave_multicast - Leave the multicast group specified by the given
index 9c9a27d..e315021 100644 (file)
@@ -158,6 +158,7 @@ struct rvt_driver_params {
        u32 max_mad_size;
        u8 qos_shift;
        u8 max_rdma_atomic;
+       u8 reserved_operations;
 };
 
 /* Protection domain */
@@ -351,6 +352,9 @@ struct rvt_dev_info {
        /* Driver specific properties */
        struct rvt_driver_params dparms;
 
+       /* post send table */
+       const struct rvt_operation_params *post_parms;
+
        struct rvt_mregion __rcu *dma_mr;
        struct rvt_lkey_table lkey_table;
 
@@ -484,6 +488,9 @@ void rvt_unregister_device(struct rvt_dev_info *rvd);
 int rvt_check_ah(struct ib_device *ibdev, struct ib_ah_attr *ah_attr);
 int rvt_init_port(struct rvt_dev_info *rdi, struct rvt_ibport *port,
                  int port_index, u16 *pkey_table);
+int rvt_fast_reg_mr(struct rvt_qp *qp, struct ib_mr *ibmr, u32 key,
+                   int access);
+int rvt_invalidate_rkey(struct rvt_qp *qp, u32 rkey);
 int rvt_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge,
                u32 len, u64 vaddr, u32 rkey, int acc);
 int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd,
index 5edffdc..6b3c6c8 100644 (file)
@@ -81,6 +81,7 @@ struct rvt_mregion {
        u32 mapsz;              /* size of the map array */
        u8  page_shift;         /* 0 - non unform/non powerof2 sizes */
        u8  lkey_published;     /* in global table */
+       atomic_t lkey_invalid;  /* true if current lkey is invalid */
        struct completion comp; /* complete when refcount goes to zero */
        atomic_t refcount;
        struct rvt_segarray *map[0];    /* the segments */
index 6d23b87..bd34d0b 100644 (file)
 #define RVT_PROCESS_OR_FLUSH_SEND \
        (RVT_PROCESS_SEND_OK | RVT_FLUSH_SEND)
 
+/*
+ * Internal send flags
+ */
+#define RVT_SEND_RESERVE_USED           IB_SEND_RESERVED_START
+#define RVT_SEND_COMPLETION_ONLY       (IB_SEND_RESERVED_START << 1)
+
 /*
  * Send work request queue entry.
  * The size of the sg_list is determined when the QP is created and stored
@@ -216,23 +222,43 @@ struct rvt_mmap_info {
  * to send a RDMA read response or atomic operation.
  */
 struct rvt_ack_entry {
-       u8 opcode;
-       u8 sent;
+       struct rvt_sge rdma_sge;
+       u64 atomic_data;
        u32 psn;
        u32 lpsn;
-       union {
-               struct rvt_sge rdma_sge;
-               u64 atomic_data;
-       };
+       u8 opcode;
+       u8 sent;
 };
 
 #define        RC_QP_SCALING_INTERVAL  5
 
-/*
- * Variables prefixed with s_ are for the requester (sender).
- * Variables prefixed with r_ are for the responder (receiver).
- * Variables prefixed with ack_ are for responder replies.
+#define RVT_OPERATION_PRIV        0x00000001
+#define RVT_OPERATION_ATOMIC      0x00000002
+#define RVT_OPERATION_ATOMIC_SGE  0x00000004
+#define RVT_OPERATION_LOCAL       0x00000008
+#define RVT_OPERATION_USE_RESERVE 0x00000010
+
+#define RVT_OPERATION_MAX (IB_WR_RESERVED10 + 1)
+
+/**
+ * rvt_operation_params - op table entry
+ * @length - the length to copy into the swqe entry
+ * @qpt_support - a bit mask indicating QP type support
+ * @flags - RVT_OPERATION flags (see above)
  *
+ * This supports table driven post send so that
+ * the driver can have differing an potentially
+ * different sets of operations.
+ *
+ **/
+
+struct rvt_operation_params {
+       size_t length;
+       u32 qpt_support;
+       u32 flags;
+};
+
+/*
  * Common variables are protected by both r_rq.lock and s_lock in that order
  * which only happens in modify_qp() or changing the QP 'state'.
  */
@@ -307,6 +333,7 @@ struct rvt_qp {
        u32 s_next_psn;         /* PSN for next request */
        u32 s_avail;            /* number of entries avail */
        u32 s_ssn;              /* SSN of tail entry */
+       atomic_t s_reserved_used; /* reserved entries in use */
 
        spinlock_t s_lock ____cacheline_aligned_in_smp;
        u32 s_flags;
@@ -343,6 +370,8 @@ struct rvt_qp {
        struct rvt_sge_state s_ack_rdma_sge;
        struct timer_list s_timer;
 
+       atomic_t local_ops_pending; /* number of fast_reg/local_inv reqs */
+
        /*
         * This sge list MUST be last. Do not add anything below here.
         */
@@ -436,6 +465,49 @@ static inline struct rvt_rwqe *rvt_get_rwqe_ptr(struct rvt_rq *rq, unsigned n)
                  rq->max_sge * sizeof(struct ib_sge)) * n);
 }
 
+/**
+ * rvt_qp_wqe_reserve - reserve operation
+ * @qp - the rvt qp
+ * @wqe - the send wqe
+ *
+ * This routine used in post send to record
+ * a wqe relative reserved operation use.
+ */
+static inline void rvt_qp_wqe_reserve(
+       struct rvt_qp *qp,
+       struct rvt_swqe *wqe)
+{
+       wqe->wr.send_flags |= RVT_SEND_RESERVE_USED;
+       atomic_inc(&qp->s_reserved_used);
+}
+
+/**
+ * rvt_qp_wqe_unreserve - clean reserved operation
+ * @qp - the rvt qp
+ * @wqe - the send wqe
+ *
+ * This decrements the reserve use count.
+ *
+ * This call MUST precede the change to
+ * s_last to insure that post send sees a stable
+ * s_avail.
+ *
+ * An smp_mp__after_atomic() is used to insure
+ * the compiler does not juggle the order of the s_last
+ * ring index and the decrementing of s_reserved_used.
+ */
+static inline void rvt_qp_wqe_unreserve(
+       struct rvt_qp *qp,
+       struct rvt_swqe *wqe)
+{
+       if (unlikely(wqe->wr.send_flags & RVT_SEND_RESERVE_USED)) {
+               wqe->wr.send_flags &= ~RVT_SEND_RESERVE_USED;
+               atomic_dec(&qp->s_reserved_used);
+               /* insure no compiler re-order up to s_last change */
+               smp_mb__after_atomic();
+       }
+}
+
 extern const int  ib_rvt_state_ops[];
 
 struct rvt_dev_info;
diff --git a/include/scsi/viosrp.h b/include/scsi/viosrp.h
new file mode 100644 (file)
index 0000000..974e07b
--- /dev/null
@@ -0,0 +1,220 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* 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.                              */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef VIOSRP_H
+#define VIOSRP_H
+#include <scsi/srp.h>
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN 256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+       struct srp_login_req login_req;
+       struct srp_login_rsp login_rsp;
+       struct srp_login_rej login_rej;
+       struct srp_i_logout i_logout;
+       struct srp_t_logout t_logout;
+       struct srp_tsk_mgmt tsk_mgmt;
+       struct srp_cmd cmd;
+       struct srp_rsp rsp;
+       u8 reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_headers {
+       VIOSRP_CRQ_FREE = 0x00,
+       VIOSRP_CRQ_CMD_RSP = 0x80,
+       VIOSRP_CRQ_INIT_RSP = 0xC0,
+       VIOSRP_CRQ_XPORT_EVENT = 0xFF
+};
+
+enum viosrp_crq_init_formats {
+       VIOSRP_CRQ_INIT = 0x01,
+       VIOSRP_CRQ_INIT_COMPLETE = 0x02
+};
+
+enum viosrp_crq_formats {
+       VIOSRP_SRP_FORMAT = 0x01,
+       VIOSRP_MAD_FORMAT = 0x02,
+       VIOSRP_OS400_FORMAT = 0x03,
+       VIOSRP_AIX_FORMAT = 0x04,
+       VIOSRP_LINUX_FORMAT = 0x05,
+       VIOSRP_INLINE_FORMAT = 0x06
+};
+
+enum viosrp_crq_status {
+       VIOSRP_OK = 0x0,
+       VIOSRP_NONRECOVERABLE_ERR = 0x1,
+       VIOSRP_VIOLATES_MAX_XFER = 0x2,
+       VIOSRP_PARTNER_PANIC = 0x3,
+       VIOSRP_DEVICE_BUSY = 0x8,
+       VIOSRP_ADAPTER_FAIL = 0x10,
+       VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+       u8 valid;               /* used by RPA */
+       u8 format;              /* SCSI vs out-of-band */
+       u8 reserved;
+       u8 status;              /* non-scsi failure? (e.g. DMA failure) */
+       __be16 timeout;         /* in seconds */
+       __be16 IU_length;               /* in bytes */
+       __be64 IU_data_ptr;     /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+       VIOSRP_EMPTY_IU_TYPE = 0x01,
+       VIOSRP_ERROR_LOG_TYPE = 0x02,
+       VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+       VIOSRP_CAPABILITIES_TYPE = 0x05,
+       VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+       VIOSRP_MAD_SUCCESS = 0x00,
+       VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+       VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+       MIGRATION_CAPABILITIES = 0x01,
+       RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+       SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+       SERVER_SUPPORTS_CAP = 0x01,
+       SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+       CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+       CLIENT_MIGRATED = 0x01,
+       CLIENT_RECONNECT = 0x02,
+       CAP_LIST_SUPPORTED = 0x04,
+       CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+       __be32 type;
+       __be16 status;
+       __be16 length;
+       __be64 tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+       struct mad_common common;
+       __be64 buffer;
+       __be32 port;
+};
+
+struct viosrp_error_log {
+       struct mad_common common;
+       __be64 buffer;
+};
+
+struct viosrp_adapter_info {
+       struct mad_common common;
+       __be64 buffer;
+};
+
+struct viosrp_fast_fail {
+       struct mad_common common;
+};
+
+struct viosrp_capabilities {
+       struct mad_common common;
+       __be64 buffer;
+};
+
+struct mad_capability_common {
+       __be32 cap_type;
+       __be16 length;
+       __be16 server_support;
+};
+
+struct mad_reserve_cap {
+       struct mad_capability_common common;
+       __be32 type;
+};
+
+struct mad_migration_cap {
+       struct mad_capability_common common;
+       __be32 ecl;
+};
+
+struct capabilities {
+       __be32 flags;
+       char name[SRP_MAX_LOC_LEN];
+       char loc[SRP_MAX_LOC_LEN];
+       struct mad_migration_cap migration;
+       struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+       struct viosrp_empty_iu empty_iu;
+       struct viosrp_error_log error_log;
+       struct viosrp_adapter_info adapter_info;
+       struct viosrp_fast_fail fast_fail;
+       struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+       union srp_iu srp;
+       union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+       char srp_version[8];
+       char partition_name[96];
+       __be32 partition_number;
+#define SRP_MAD_VERSION_1 1
+       __be32 mad_version;
+#define SRP_MAD_OS_LINUX 2
+#define SRP_MAD_OS_AIX 3
+       __be32 os_type;
+       __be32 port_max_txu[8]; /* per-port maximum transfer */
+};
+
+#endif
index d8ab510..f6f3bc5 100644 (file)
@@ -95,6 +95,6 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
 bool target_sense_desc_format(struct se_device *dev);
 sector_t target_to_linux_sector(struct se_device *dev, sector_t lb);
 bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
-                                      struct request_queue *q, int block_size);
+                                      struct request_queue *q);
 
 #endif /* TARGET_CORE_BACKEND_H */
index b316b44..fb8e3b6 100644 (file)
@@ -142,6 +142,7 @@ enum se_cmd_flags_table {
        SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000,
        SCF_ACK_KREF                    = 0x00400000,
        SCF_USE_CPUID                   = 0x00800000,
+       SCF_TASK_ATTR_SET               = 0x01000000,
 };
 
 /*
index de44462..5cd6faa 100644 (file)
@@ -163,7 +163,6 @@ int core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
 void   core_tmr_release_req(struct se_tmr_req *);
 int    transport_generic_handle_tmr(struct se_cmd *);
 void   transport_generic_request_failure(struct se_cmd *, sense_reason_t);
-void   __target_execute_cmd(struct se_cmd *);
 int    transport_lookup_tmr_lun(struct se_cmd *, u64);
 void   core_allocate_nexus_loss_ua(struct se_node_acl *acl);
 
index 65673d8..d336b89 100644 (file)
@@ -27,7 +27,7 @@ DECLARE_EVENT_CLASS(bcache_request,
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->orig_sector    = bio->bi_iter.bi_sector - 16;
                __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
        ),
 
@@ -102,7 +102,7 @@ DECLARE_EVENT_CLASS(bcache_bio,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
        ),
 
@@ -138,7 +138,7 @@ TRACE_EVENT(bcache_read,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                __entry->cache_hit = hit;
                __entry->bypass = bypass;
@@ -170,7 +170,7 @@ TRACE_EVENT(bcache_write,
                __entry->inode          = inode;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                __entry->writeback = writeback;
                __entry->bypass = bypass;
index 5a2a759..8f3a163 100644 (file)
@@ -274,7 +274,7 @@ TRACE_EVENT(block_bio_bounce,
                                          bio->bi_bdev->bd_dev : 0;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -313,7 +313,7 @@ TRACE_EVENT(block_bio_complete,
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
                __entry->error          = error;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
        ),
 
@@ -341,7 +341,7 @@ DECLARE_EVENT_CLASS(block_bio_merge,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -409,7 +409,7 @@ TRACE_EVENT(block_bio_queue,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -439,7 +439,7 @@ DECLARE_EVENT_CLASS(block_get_rq,
                __entry->sector         = bio ? bio->bi_iter.bi_sector : 0;
                __entry->nr_sector      = bio ? bio_sectors(bio) : 0;
                blk_fill_rwbs(__entry->rwbs, bio ? bio_op(bio) : 0,
-                             bio ? bio->bi_rw : 0, __entry->nr_sector);
+                             bio ? bio->bi_opf : 0, __entry->nr_sector);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
         ),
 
@@ -573,7 +573,7 @@ TRACE_EVENT(block_split,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->sector         = bio->bi_iter.bi_sector;
                __entry->new_sector     = new_sector;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -617,7 +617,7 @@ TRACE_EVENT(block_bio_remap,
                __entry->nr_sector      = bio_sectors(bio);
                __entry->old_dev        = dev;
                __entry->old_sector     = from;
-               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw,
+               blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf,
                              bio->bi_iter.bi_size);
        ),
 
index 5b81ef3..e030d6f 100644 (file)
@@ -66,6 +66,21 @@ struct btrfs_qgroup_extent_record;
        { BTRFS_BLOCK_GROUP_RAID6,      "RAID6"}
 
 #define BTRFS_UUID_SIZE 16
+#define TP_STRUCT__entry_fsid __array(u8, fsid, BTRFS_UUID_SIZE)
+
+#define TP_fast_assign_fsid(fs_info)                                   \
+       memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE)
+
+#define TP_STRUCT__entry_btrfs(args...)                                        \
+       TP_STRUCT__entry(                                               \
+               TP_STRUCT__entry_fsid                                   \
+               args)
+#define TP_fast_assign_btrfs(fs_info, args...)                         \
+       TP_fast_assign(                                                 \
+               TP_fast_assign_fsid(fs_info);                           \
+               args)
+#define TP_printk_btrfs(fmt, args...) \
+       TP_printk("%pU: " fmt, __entry->fsid, args)
 
 TRACE_EVENT(btrfs_transaction_commit,
 
@@ -73,17 +88,17 @@ TRACE_EVENT(btrfs_transaction_commit,
 
        TP_ARGS(root),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  generation                )
                __field(        u64,  root_objectid             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->generation     = root->fs_info->generation;
                __entry->root_objectid  = root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), gen = %llu",
+       TP_printk_btrfs("root = %llu(%s), gen = %llu",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->generation)
 );
@@ -94,7 +109,7 @@ DECLARE_EVENT_CLASS(btrfs__inode,
 
        TP_ARGS(inode),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        ino_t,  ino                     )
                __field(        blkcnt_t,  blocks               )
                __field(        u64,  disk_i_size               )
@@ -104,7 +119,7 @@ DECLARE_EVENT_CLASS(btrfs__inode,
                __field(        u64,  root_objectid             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
                __entry->ino    = inode->i_ino;
                __entry->blocks = inode->i_blocks;
                __entry->disk_i_size  = BTRFS_I(inode)->disk_i_size;
@@ -115,7 +130,7 @@ DECLARE_EVENT_CLASS(btrfs__inode,
                                BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, "
+       TP_printk_btrfs("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, "
                  "disk_i_size = %llu, last_trans = %llu, logged_trans = %llu",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->generation,
@@ -175,7 +190,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
 
        TP_CONDITION(map),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  root_objectid     )
                __field(        u64,  start             )
                __field(        u64,  len               )
@@ -187,7 +202,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
                __field(        unsigned int,  compress_type    )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
                __entry->start          = map->start;
                __entry->len            = map->len;
@@ -199,7 +214,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
                __entry->compress_type  = map->compress_type;
        ),
 
-       TP_printk("root = %llu(%s), start = %llu, len = %llu, "
+       TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu, "
                  "orig_start = %llu, block_start = %llu(%s), "
                  "block_len = %llu, flags = %s, refs = %u, "
                  "compress_type = %u",
@@ -233,7 +248,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
 
        TP_ARGS(inode, ordered),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        ino_t,  ino             )
                __field(        u64,  file_offset       )
                __field(        u64,  start             )
@@ -246,7 +261,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
                __field(        u64,  root_objectid     )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
                __entry->ino            = inode->i_ino;
                __entry->file_offset    = ordered->file_offset;
                __entry->start          = ordered->start;
@@ -260,7 +275,7 @@ DECLARE_EVENT_CLASS(btrfs__ordered_extent,
                                BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), ino = %llu, file_offset = %llu, "
+       TP_printk_btrfs("root = %llu(%s), ino = %llu, file_offset = %llu, "
                  "start = %llu, len = %llu, disk_len = %llu, "
                  "bytes_left = %llu, flags = %s, compress_type = %d, "
                  "refs = %d",
@@ -310,7 +325,7 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
 
        TP_ARGS(page, inode, wbc),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        ino_t,  ino                     )
                __field(        pgoff_t,  index                 )
                __field(        long,   nr_to_write             )
@@ -324,7 +339,7 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
                __field(        u64,    root_objectid           )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
                __entry->ino            = inode->i_ino;
                __entry->index          = page->index;
                __entry->nr_to_write    = wbc->nr_to_write;
@@ -339,7 +354,7 @@ DECLARE_EVENT_CLASS(btrfs__writepage,
                                 BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, "
+       TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, "
                  "nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, "
                  "range_end = %llu, for_kupdate = %d, "
                  "for_reclaim = %d, range_cyclic = %d, writeback_index = %lu",
@@ -366,7 +381,7 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
 
        TP_ARGS(page, start, end, uptodate),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        ino_t,   ino            )
                __field(        pgoff_t, index          )
                __field(        u64,     start          )
@@ -375,7 +390,7 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
                __field(        u64,    root_objectid   )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(page->mapping->host->i_sb),
                __entry->ino    = page->mapping->host->i_ino;
                __entry->index  = page->index;
                __entry->start  = start;
@@ -385,7 +400,7 @@ TRACE_EVENT(btrfs_writepage_end_io_hook,
                         BTRFS_I(page->mapping->host)->root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, "
+       TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, "
                  "end = %llu, uptodate = %d",
                  show_root_type(__entry->root_objectid),
                  (unsigned long)__entry->ino, (unsigned long)__entry->index,
@@ -399,7 +414,7 @@ TRACE_EVENT(btrfs_sync_file,
 
        TP_ARGS(file, datasync),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        ino_t,  ino             )
                __field(        ino_t,  parent          )
                __field(        int,    datasync        )
@@ -410,6 +425,7 @@ TRACE_EVENT(btrfs_sync_file,
                struct dentry *dentry = file->f_path.dentry;
                struct inode *inode = d_inode(dentry);
 
+               TP_fast_assign_fsid(btrfs_sb(file->f_path.dentry->d_sb));
                __entry->ino            = inode->i_ino;
                __entry->parent         = d_inode(dentry->d_parent)->i_ino;
                __entry->datasync       = datasync;
@@ -417,7 +433,7 @@ TRACE_EVENT(btrfs_sync_file,
                                 BTRFS_I(inode)->root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d",
+       TP_printk_btrfs("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d",
                  show_root_type(__entry->root_objectid),
                  (unsigned long)__entry->ino, (unsigned long)__entry->parent,
                  __entry->datasync)
@@ -425,19 +441,19 @@ TRACE_EVENT(btrfs_sync_file,
 
 TRACE_EVENT(btrfs_sync_fs,
 
-       TP_PROTO(int wait),
+       TP_PROTO(struct btrfs_fs_info *fs_info, int wait),
 
-       TP_ARGS(wait),
+       TP_ARGS(fs_info, wait),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        int,  wait              )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->wait   = wait;
        ),
 
-       TP_printk("wait = %d", __entry->wait)
+       TP_printk_btrfs("wait = %d", __entry->wait)
 );
 
 TRACE_EVENT(btrfs_add_block_group,
@@ -490,13 +506,14 @@ TRACE_EVENT(btrfs_add_block_group,
 
 DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action),
+       TP_ARGS(fs_info, ref, full_ref, action),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  bytenr            )
                __field(        u64,  num_bytes         )
                __field(        int,  action            ) 
@@ -507,7 +524,7 @@ DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
                __field(        u64,  seq               )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->bytenr         = ref->bytenr;
                __entry->num_bytes      = ref->num_bytes;
                __entry->action         = action;
@@ -518,7 +535,7 @@ DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
                __entry->seq            = ref->seq;
        ),
 
-       TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
+       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
                  "parent = %llu(%s), ref_root = %llu(%s), level = %d, "
                  "type = %s, seq = %llu",
                  (unsigned long long)__entry->bytenr,
@@ -532,31 +549,34 @@ DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
 
 DEFINE_EVENT(btrfs_delayed_tree_ref,  add_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action)
+       TP_ARGS(fs_info, ref, full_ref, action)
 );
 
 DEFINE_EVENT(btrfs_delayed_tree_ref,  run_delayed_tree_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_tree_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action)
+       TP_ARGS(fs_info, ref, full_ref, action)
 );
 
 DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action),
+       TP_ARGS(fs_info, ref, full_ref, action),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  bytenr            )
                __field(        u64,  num_bytes         )
                __field(        int,  action            ) 
@@ -568,7 +588,7 @@ DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
                __field(        u64,  seq               )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->bytenr         = ref->bytenr;
                __entry->num_bytes      = ref->num_bytes;
                __entry->action         = action;
@@ -580,7 +600,7 @@ DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
                __entry->seq            = ref->seq;
        ),
 
-       TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
+       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
                  "parent = %llu(%s), ref_root = %llu(%s), owner = %llu, "
                  "offset = %llu, type = %s, seq = %llu",
                  (unsigned long long)__entry->bytenr,
@@ -596,45 +616,48 @@ DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
 
 DEFINE_EVENT(btrfs_delayed_data_ref,  add_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action)
+       TP_ARGS(fs_info, ref, full_ref, action)
 );
 
 DEFINE_EVENT(btrfs_delayed_data_ref,  run_delayed_data_ref,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_data_ref *full_ref,
                 int action),
 
-       TP_ARGS(ref, full_ref, action)
+       TP_ARGS(fs_info, ref, full_ref, action)
 );
 
 DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
-       TP_ARGS(ref, head_ref, action),
+       TP_ARGS(fs_info, ref, head_ref, action),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  bytenr            )
                __field(        u64,  num_bytes         )
                __field(        int,  action            ) 
                __field(        int,  is_data           )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->bytenr         = ref->bytenr;
                __entry->num_bytes      = ref->num_bytes;
                __entry->action         = action;
                __entry->is_data        = head_ref->is_data;
        ),
 
-       TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d",
+       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes,
                  show_ref_action(__entry->action),
@@ -643,20 +666,22 @@ DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
 
 DEFINE_EVENT(btrfs_delayed_ref_head,  add_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
-       TP_ARGS(ref, head_ref, action)
+       TP_ARGS(fs_info, ref, head_ref, action)
 );
 
 DEFINE_EVENT(btrfs_delayed_ref_head,  run_delayed_ref_head,
 
-       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_ref_head *head_ref,
                 int action),
 
-       TP_ARGS(ref, head_ref, action)
+       TP_ARGS(fs_info, ref, head_ref, action)
 );
 
 #define show_chunk_type(type)                                  \
@@ -678,7 +703,7 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
 
        TP_ARGS(root, map, offset, size),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        int,  num_stripes               )
                __field(        u64,  type                      )
                __field(        int,  sub_stripes               )
@@ -687,7 +712,7 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
                __field(        u64,  root_objectid             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->num_stripes    = map->num_stripes;
                __entry->type           = map->type;
                __entry->sub_stripes    = map->sub_stripes;
@@ -696,7 +721,7 @@ DECLARE_EVENT_CLASS(btrfs__chunk,
                __entry->root_objectid  = root->root_key.objectid;
        ),
 
-       TP_printk("root = %llu(%s), offset = %llu, size = %llu, "
+       TP_printk_btrfs("root = %llu(%s), offset = %llu, size = %llu, "
                  "num_stripes = %d, sub_stripes = %d, type = %s",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->offset,
@@ -728,7 +753,7 @@ TRACE_EVENT(btrfs_cow_block,
 
        TP_ARGS(root, buf, cow),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  root_objectid             )
                __field(        u64,  buf_start                 )
                __field(        int,  refs                      )
@@ -737,7 +762,7 @@ TRACE_EVENT(btrfs_cow_block,
                __field(        int,  cow_level                 )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
                __entry->buf_start      = buf->start;
                __entry->refs           = atomic_read(&buf->refs);
@@ -746,7 +771,7 @@ TRACE_EVENT(btrfs_cow_block,
                __entry->cow_level      = btrfs_header_level(cow);
        ),
 
-       TP_printk("root = %llu(%s), refs = %d, orig_buf = %llu "
+       TP_printk_btrfs("root = %llu(%s), refs = %d, orig_buf = %llu "
                  "(orig_level = %d), cow_buf = %llu (cow_level = %d)",
                  show_root_type(__entry->root_objectid),
                  __entry->refs,
@@ -763,25 +788,23 @@ TRACE_EVENT(btrfs_space_reservation,
 
        TP_ARGS(fs_info, type, val, bytes, reserve),
 
-       TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+       TP_STRUCT__entry_btrfs(
                __string(       type,   type                    )
                __field(        u64,    val                     )
                __field(        u64,    bytes                   )
                __field(        int,    reserve                 )
        ),
 
-       TP_fast_assign(
-               memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
+       TP_fast_assign_btrfs(fs_info,
                __assign_str(type, type);
                __entry->val            = val;
                __entry->bytes          = bytes;
                __entry->reserve        = reserve;
        ),
 
-       TP_printk("%pU: %s: %Lu %s %Lu", __entry->fsid, __get_str(type),
-                 __entry->val, __entry->reserve ? "reserve" : "release",
-                 __entry->bytes)
+       TP_printk_btrfs("%s: %Lu %s %Lu", __get_str(type), __entry->val,
+                       __entry->reserve ? "reserve" : "release",
+                       __entry->bytes)
 );
 
 #define show_flush_action(action)                                              \
@@ -872,22 +895,19 @@ DECLARE_EVENT_CLASS(btrfs__reserved_extent,
 
        TP_ARGS(root, start, len),
 
-       TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
-               __field(        u64,    root_objectid           )
-               __field(        u64,    start                   )
-               __field(        u64,    len                     )
+       TP_STRUCT__entry_btrfs(
+               __field(        u64,  root_objectid             )
+               __field(        u64,  start                     )
+               __field(        u64,  len                       )
        ),
 
-       TP_fast_assign(
-               memcpy(__entry->fsid, root->fs_info->fsid, BTRFS_UUID_SIZE);
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
                __entry->start          = start;
                __entry->len            = len;
        ),
 
-       TP_printk("%pU: root = %llu(%s), start = %llu, len = %llu",
-                 __entry->fsid,
+       TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu",
                  show_root_type(__entry->root_objectid),
                  (unsigned long long)__entry->start,
                  (unsigned long long)__entry->len)
@@ -914,21 +934,21 @@ TRACE_EVENT(find_free_extent,
 
        TP_ARGS(root, num_bytes, empty_size, data),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,    root_objectid           )
                __field(        u64,    num_bytes               )
                __field(        u64,    empty_size              )
                __field(        u64,    data                    )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
                __entry->num_bytes      = num_bytes;
                __entry->empty_size     = empty_size;
                __entry->data           = data;
        ),
 
-       TP_printk("root = %Lu(%s), len = %Lu, empty_size = %Lu, "
+       TP_printk_btrfs("root = %Lu(%s), len = %Lu, empty_size = %Lu, "
                  "flags = %Lu(%s)", show_root_type(__entry->root_objectid),
                  __entry->num_bytes, __entry->empty_size, __entry->data,
                  __print_flags((unsigned long)__entry->data, "|",
@@ -943,8 +963,7 @@ DECLARE_EVENT_CLASS(btrfs__reserve_extent,
 
        TP_ARGS(root, block_group, start, len),
 
-       TP_STRUCT__entry(
-               __array(        u8,     fsid,   BTRFS_UUID_SIZE )
+       TP_STRUCT__entry_btrfs(
                __field(        u64,    root_objectid           )
                __field(        u64,    bg_objectid             )
                __field(        u64,    flags                   )
@@ -952,8 +971,7 @@ DECLARE_EVENT_CLASS(btrfs__reserve_extent,
                __field(        u64,    len                     )
        ),
 
-       TP_fast_assign(
-               memcpy(__entry->fsid, root->fs_info->fsid, BTRFS_UUID_SIZE);
+       TP_fast_assign_btrfs(root->fs_info,
                __entry->root_objectid  = root->root_key.objectid;
                __entry->bg_objectid    = block_group->key.objectid;
                __entry->flags          = block_group->flags;
@@ -961,8 +979,8 @@ DECLARE_EVENT_CLASS(btrfs__reserve_extent,
                __entry->len            = len;
        ),
 
-       TP_printk("%pU: root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), "
-                 "start = %Lu, len = %Lu", __entry->fsid,
+       TP_printk_btrfs("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), "
+                 "start = %Lu, len = %Lu",
                  show_root_type(__entry->root_objectid), __entry->bg_objectid,
                  __entry->flags, __print_flags((unsigned long)__entry->flags,
                                                "|", BTRFS_GROUP_FLAGS),
@@ -994,7 +1012,7 @@ TRACE_EVENT(btrfs_find_cluster,
 
        TP_ARGS(block_group, start, bytes, empty_size, min_bytes),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,    bg_objectid             )
                __field(        u64,    flags                   )
                __field(        u64,    start                   )
@@ -1003,7 +1021,7 @@ TRACE_EVENT(btrfs_find_cluster,
                __field(        u64,    min_bytes               )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(block_group->fs_info,
                __entry->bg_objectid    = block_group->key.objectid;
                __entry->flags          = block_group->flags;
                __entry->start          = start;
@@ -1012,7 +1030,7 @@ TRACE_EVENT(btrfs_find_cluster,
                __entry->min_bytes      = min_bytes;
        ),
 
-       TP_printk("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu,"
+       TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu,"
                  " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid,
                  __entry->flags,
                  __print_flags((unsigned long)__entry->flags, "|",
@@ -1026,15 +1044,15 @@ TRACE_EVENT(btrfs_failed_cluster_setup,
 
        TP_ARGS(block_group),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,    bg_objectid             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(block_group->fs_info,
                __entry->bg_objectid    = block_group->key.objectid;
        ),
 
-       TP_printk("block_group = %Lu", __entry->bg_objectid)
+       TP_printk_btrfs("block_group = %Lu", __entry->bg_objectid)
 );
 
 TRACE_EVENT(btrfs_setup_cluster,
@@ -1044,7 +1062,7 @@ TRACE_EVENT(btrfs_setup_cluster,
 
        TP_ARGS(block_group, cluster, size, bitmap),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,    bg_objectid             )
                __field(        u64,    flags                   )
                __field(        u64,    start                   )
@@ -1053,7 +1071,7 @@ TRACE_EVENT(btrfs_setup_cluster,
                __field(        int,    bitmap                  )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(block_group->fs_info,
                __entry->bg_objectid    = block_group->key.objectid;
                __entry->flags          = block_group->flags;
                __entry->start          = cluster->window_start;
@@ -1062,7 +1080,7 @@ TRACE_EVENT(btrfs_setup_cluster,
                __entry->bitmap         = bitmap;
        ),
 
-       TP_printk("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, "
+       TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, "
                  "size = %Lu, max_size = %Lu, bitmap = %d",
                  __entry->bg_objectid,
                  __entry->flags,
@@ -1120,7 +1138,7 @@ DECLARE_EVENT_CLASS(btrfs__work,
 
        TP_ARGS(work),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        void *, work                    )
                __field(        void *, wq                      )
                __field(        void *, func                    )
@@ -1129,7 +1147,7 @@ DECLARE_EVENT_CLASS(btrfs__work,
                __field(        void *, normal_work             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_work_owner(work),
                __entry->work           = work;
                __entry->wq             = work->wq;
                __entry->func           = work->func;
@@ -1138,7 +1156,7 @@ DECLARE_EVENT_CLASS(btrfs__work,
                __entry->normal_work    = &work->normal_work;
        ),
 
-       TP_printk("work=%p (normal_work=%p), wq=%p, func=%pf, ordered_func=%p,"
+       TP_printk_btrfs("work=%p (normal_work=%p), wq=%p, func=%pf, ordered_func=%p,"
                  " ordered_free=%p",
                  __entry->work, __entry->normal_work, __entry->wq,
                   __entry->func, __entry->ordered_func, __entry->ordered_free)
@@ -1151,15 +1169,15 @@ DECLARE_EVENT_CLASS(btrfs__work__done,
 
        TP_ARGS(work),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        void *, work                    )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_work_owner(work),
                __entry->work           = work;
        ),
 
-       TP_printk("work->%p", __entry->work)
+       TP_printk_btrfs("work->%p", __entry->work)
 );
 
 DEFINE_EVENT(btrfs__work, btrfs_work_queued,
@@ -1196,19 +1214,19 @@ DECLARE_EVENT_CLASS(btrfs__workqueue,
 
        TP_ARGS(wq, name, high),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        void *, wq                      )
                __string(       name,   name                    )
                __field(        int ,   high                    )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_workqueue_owner(wq),
                __entry->wq             = wq;
                __assign_str(name, name);
                __entry->high           = high;
        ),
 
-       TP_printk("name=%s%s, wq=%p", __get_str(name),
+       TP_printk_btrfs("name=%s%s, wq=%p", __get_str(name),
                  __print_flags(__entry->high, "",
                                {(WQ_HIGHPRI),  "-high"}),
                  __entry->wq)
@@ -1227,15 +1245,15 @@ DECLARE_EVENT_CLASS(btrfs__workqueue_done,
 
        TP_ARGS(wq),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        void *, wq                      )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_workqueue_owner(wq),
                __entry->wq             = wq;
        ),
 
-       TP_printk("wq=%p", __entry->wq)
+       TP_printk_btrfs("wq=%p", __entry->wq)
 );
 
 DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy,
@@ -1251,19 +1269,19 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_data_map,
 
        TP_ARGS(inode, free_reserved),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,            rootid          )
                __field(        unsigned long,  ino             )
                __field(        u64,            free_reserved   )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
                __entry->rootid         =       BTRFS_I(inode)->root->objectid;
                __entry->ino            =       inode->i_ino;
                __entry->free_reserved  =       free_reserved;
        ),
 
-       TP_printk("rootid=%llu, ino=%lu, free_reserved=%llu",
+       TP_printk_btrfs("rootid=%llu, ino=%lu, free_reserved=%llu",
                  __entry->rootid, __entry->ino, __entry->free_reserved)
 );
 
@@ -1292,7 +1310,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
 
        TP_ARGS(inode, start, len, reserved, op),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,            rootid          )
                __field(        unsigned long,  ino             )
                __field(        u64,            start           )
@@ -1301,7 +1319,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
                __field(        int,            op              )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
                __entry->rootid         = BTRFS_I(inode)->root->objectid;
                __entry->ino            = inode->i_ino;
                __entry->start          = start;
@@ -1310,7 +1328,7 @@ DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data,
                __entry->op             = op;
        ),
 
-       TP_printk("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s",
+       TP_printk_btrfs("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s",
                  __entry->rootid, __entry->ino, __entry->start, __entry->len,
                  __entry->reserved,
                  __print_flags((unsigned long)__entry->op, "",
@@ -1334,86 +1352,90 @@ DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_release_data,
 
 DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref,
 
-       TP_PROTO(u64 ref_root, u64 reserved),
+       TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved),
 
-       TP_ARGS(ref_root, reserved),
+       TP_ARGS(fs_info, ref_root, reserved),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,            ref_root        )
                __field(        u64,            reserved        )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->ref_root       = ref_root;
                __entry->reserved       = reserved;
        ),
 
-       TP_printk("root=%llu, reserved=%llu, op=free",
+       TP_printk_btrfs("root=%llu, reserved=%llu, op=free",
                  __entry->ref_root, __entry->reserved)
 );
 
 DEFINE_EVENT(btrfs__qgroup_delayed_ref, btrfs_qgroup_free_delayed_ref,
 
-       TP_PROTO(u64 ref_root, u64 reserved),
+       TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved),
 
-       TP_ARGS(ref_root, reserved)
+       TP_ARGS(fs_info, ref_root, reserved)
 );
 
 DECLARE_EVENT_CLASS(btrfs_qgroup_extent,
-       TP_PROTO(struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_qgroup_extent_record *rec),
 
-       TP_ARGS(rec),
+       TP_ARGS(fs_info, rec),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  bytenr            )
                __field(        u64,  num_bytes         )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->bytenr         = rec->bytenr,
                __entry->num_bytes      = rec->num_bytes;
        ),
 
-       TP_printk("bytenr = %llu, num_bytes = %llu",
+       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu",
                  (unsigned long long)__entry->bytenr,
                  (unsigned long long)__entry->num_bytes)
 );
 
 DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_account_extents,
 
-       TP_PROTO(struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_qgroup_extent_record *rec),
 
-       TP_ARGS(rec)
+       TP_ARGS(fs_info, rec)
 );
 
 DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_insert_dirty_extent,
 
-       TP_PROTO(struct btrfs_qgroup_extent_record *rec),
+       TP_PROTO(struct btrfs_fs_info *fs_info,
+                struct btrfs_qgroup_extent_record *rec),
 
-       TP_ARGS(rec)
+       TP_ARGS(fs_info, rec)
 );
 
 TRACE_EVENT(btrfs_qgroup_account_extent,
 
-       TP_PROTO(u64 bytenr, u64 num_bytes, u64 nr_old_roots, u64 nr_new_roots),
+       TP_PROTO(struct btrfs_fs_info *fs_info, u64 bytenr,
+                u64 num_bytes, u64 nr_old_roots, u64 nr_new_roots),
 
-       TP_ARGS(bytenr, num_bytes, nr_old_roots, nr_new_roots),
+       TP_ARGS(fs_info, bytenr, num_bytes, nr_old_roots, nr_new_roots),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  bytenr                    )
                __field(        u64,  num_bytes                 )
                __field(        u64,  nr_old_roots              )
                __field(        u64,  nr_new_roots              )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->bytenr         = bytenr;
                __entry->num_bytes      = num_bytes;
                __entry->nr_old_roots   = nr_old_roots;
                __entry->nr_new_roots   = nr_new_roots;
        ),
 
-       TP_printk("bytenr = %llu, num_bytes = %llu, nr_old_roots = %llu, "
+       TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, nr_old_roots = %llu, "
                  "nr_new_roots = %llu",
                  __entry->bytenr,
                  __entry->num_bytes,
@@ -1423,23 +1445,24 @@ TRACE_EVENT(btrfs_qgroup_account_extent,
 
 TRACE_EVENT(qgroup_update_counters,
 
-       TP_PROTO(u64 qgid, u64 cur_old_count, u64 cur_new_count),
+       TP_PROTO(struct btrfs_fs_info *fs_info, u64 qgid,
+                u64 cur_old_count, u64 cur_new_count),
 
-       TP_ARGS(qgid, cur_old_count, cur_new_count),
+       TP_ARGS(fs_info, qgid, cur_old_count, cur_new_count),
 
-       TP_STRUCT__entry(
+       TP_STRUCT__entry_btrfs(
                __field(        u64,  qgid                      )
                __field(        u64,  cur_old_count             )
                __field(        u64,  cur_new_count             )
        ),
 
-       TP_fast_assign(
+       TP_fast_assign_btrfs(fs_info,
                __entry->qgid           = qgid;
                __entry->cur_old_count  = cur_old_count;
                __entry->cur_new_count  = cur_new_count;
        ),
 
-       TP_printk("qgid = %llu, cur_old_count = %llu, cur_new_count = %llu",
+       TP_printk_btrfs("qgid = %llu, cur_old_count = %llu, cur_new_count = %llu",
                  __entry->qgid,
                  __entry->cur_old_count,
                  __entry->cur_new_count)
index f28292d..8ade3eb 100644 (file)
@@ -151,8 +151,9 @@ TRACE_EVENT(kvm_msi_set_irq,
                __entry->data           = data;
        ),
 
-       TP_printk("dst %u vec %u (%s|%s|%s%s)",
-                 (u8)(__entry->address >> 12), (u8)__entry->data,
+       TP_printk("dst %llx vec %u (%s|%s|%s%s)",
+                 (u8)(__entry->address >> 12) | ((__entry->address >> 32) & 0xffffff00),
+                 (u8)__entry->data,
                  __print_symbolic((__entry->data >> 8 & 0x7), kvm_deliver_mode),
                  (__entry->address & (1<<2)) ? "logical" : "physical",
                  (__entry->data & (1<<15)) ? "level" : "edge",
index 003dca9..8a707f8 100644 (file)
@@ -473,6 +473,39 @@ TRACE_EVENT(svc_recv,
                        show_rqstp_flags(__entry->flags))
 );
 
+DECLARE_EVENT_CLASS(svc_rqst_event,
+
+       TP_PROTO(struct svc_rqst *rqst),
+
+       TP_ARGS(rqst),
+
+       TP_STRUCT__entry(
+               __field(__be32, xid)
+               __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, rqst->rq_addrlen)
+       ),
+
+       TP_fast_assign(
+               __entry->xid = rqst->rq_xid;
+               __entry->flags = rqst->rq_flags;
+               memcpy(__get_dynamic_array(addr),
+                       &rqst->rq_addr, rqst->rq_addrlen);
+       ),
+
+       TP_printk("addr=%pIScp rq_xid=0x%x flags=%s",
+               (struct sockaddr *)__get_dynamic_array(addr),
+               be32_to_cpu(__entry->xid),
+               show_rqstp_flags(__entry->flags))
+);
+
+DEFINE_EVENT(svc_rqst_event, svc_defer,
+       TP_PROTO(struct svc_rqst *rqst),
+       TP_ARGS(rqst));
+
+DEFINE_EVENT(svc_rqst_event, svc_drop,
+       TP_PROTO(struct svc_rqst *rqst),
+       TP_ARGS(rqst));
+
 DECLARE_EVENT_CLASS(svc_rqst_status,
 
        TP_PROTO(struct svc_rqst *rqst, int status),
@@ -529,45 +562,67 @@ TRACE_EVENT(svc_xprt_do_enqueue,
 
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
-               __field_struct(struct sockaddr_storage, ss)
                __field(int, pid)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
                __entry->xprt = xprt;
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
                __entry->pid = rqst? rqst->rq_task->pid : 0;
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                               &xprt->xpt_remote,
+                               xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                __entry->pid, show_svc_xprt_flags(__entry->flags))
 );
 
-TRACE_EVENT(svc_xprt_dequeue,
+DECLARE_EVENT_CLASS(svc_xprt_event,
        TP_PROTO(struct svc_xprt *xprt),
 
        TP_ARGS(xprt),
 
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
-               __field_struct(struct sockaddr_storage, ss)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
-               __entry->xprt = xprt,
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               __entry->xprt = xprt;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                                       &xprt->xpt_remote,
+                                       xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                show_svc_xprt_flags(__entry->flags))
 );
 
+DEFINE_EVENT(svc_xprt_event, svc_xprt_dequeue,
+       TP_PROTO(struct svc_xprt *xprt),
+       TP_ARGS(xprt));
+
+DEFINE_EVENT(svc_xprt_event, svc_xprt_no_write_space,
+       TP_PROTO(struct svc_xprt *xprt),
+       TP_ARGS(xprt));
+
 TRACE_EVENT(svc_wake_up,
        TP_PROTO(int pid),
 
@@ -592,21 +647,56 @@ TRACE_EVENT(svc_handle_xprt,
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
                __field(int, len)
-               __field_struct(struct sockaddr_storage, ss)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
                __entry->xprt = xprt;
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
                __entry->len = len;
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                                       &xprt->xpt_remote,
+                                       xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                __entry->len, show_svc_xprt_flags(__entry->flags))
 );
+
+
+DECLARE_EVENT_CLASS(svc_deferred_event,
+       TP_PROTO(struct svc_deferred_req *dr),
+
+       TP_ARGS(dr),
+
+       TP_STRUCT__entry(
+               __field(__be32, xid)
+               __dynamic_array(unsigned char, addr, dr->addrlen)
+       ),
+
+       TP_fast_assign(
+               __entry->xid = *(__be32 *)(dr->args + (dr->xprt_hlen>>2));
+               memcpy(__get_dynamic_array(addr), &dr->addr, dr->addrlen);
+       ),
+
+       TP_printk("addr=%pIScp xid=0x%x",
+               (struct sockaddr *)__get_dynamic_array(addr),
+               be32_to_cpu(__entry->xid))
+);
+
+DEFINE_EVENT(svc_deferred_event, svc_drop_deferred,
+       TP_PROTO(struct svc_deferred_req *dr),
+       TP_ARGS(dr));
+DEFINE_EVENT(svc_deferred_event, svc_revisit_deferred,
+       TP_PROTO(struct svc_deferred_req *dr),
+       TP_ARGS(dr));
 #endif /* _TRACE_SUNRPC_H */
 
 #include <trace/define_trace.h>
index 5144013..28c5da6 100644 (file)
@@ -330,24 +330,32 @@ TRACE_EVENT(itimer_expire,
 #ifdef CONFIG_NO_HZ_COMMON
 
 #define TICK_DEP_NAMES                                 \
-               tick_dep_name(NONE)                     \
+               tick_dep_mask_name(NONE)                \
                tick_dep_name(POSIX_TIMER)              \
                tick_dep_name(PERF_EVENTS)              \
                tick_dep_name(SCHED)                    \
                tick_dep_name_end(CLOCK_UNSTABLE)
 
 #undef tick_dep_name
+#undef tick_dep_mask_name
 #undef tick_dep_name_end
 
-#define tick_dep_name(sdep) TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep);
-#define tick_dep_name_end(sdep)  TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep);
+/* The MASK will convert to their bits and they need to be processed too */
+#define tick_dep_name(sdep) TRACE_DEFINE_ENUM(TICK_DEP_BIT_##sdep); \
+       TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep);
+#define tick_dep_name_end(sdep)  TRACE_DEFINE_ENUM(TICK_DEP_BIT_##sdep); \
+       TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep);
+/* NONE only has a mask defined for it */
+#define tick_dep_mask_name(sdep) TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep);
 
 TICK_DEP_NAMES
 
 #undef tick_dep_name
+#undef tick_dep_mask_name
 #undef tick_dep_name_end
 
 #define tick_dep_name(sdep) { TICK_DEP_MASK_##sdep, #sdep },
+#define tick_dep_mask_name(sdep) { TICK_DEP_MASK_##sdep, #sdep },
 #define tick_dep_name_end(sdep) { TICK_DEP_MASK_##sdep, #sdep }
 
 #define show_tick_dep_name(val)                                \
diff --git a/include/trace/events/vsock_virtio_transport_common.h b/include/trace/events/vsock_virtio_transport_common.h
new file mode 100644 (file)
index 0000000..b7f1d62
--- /dev/null
@@ -0,0 +1,144 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vsock
+
+#if !defined(_TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H) || \
+    defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H
+
+#include <linux/tracepoint.h>
+
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_TYPE_STREAM);
+
+#define show_type(val) \
+       __print_symbolic(val, { VIRTIO_VSOCK_TYPE_STREAM, "STREAM" })
+
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_INVALID);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_REQUEST);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RESPONSE);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RST);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_SHUTDOWN);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RW);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_UPDATE);
+TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_REQUEST);
+
+#define show_op(val) \
+       __print_symbolic(val, \
+                        { VIRTIO_VSOCK_OP_INVALID, "INVALID" }, \
+                        { VIRTIO_VSOCK_OP_REQUEST, "REQUEST" }, \
+                        { VIRTIO_VSOCK_OP_RESPONSE, "RESPONSE" }, \
+                        { VIRTIO_VSOCK_OP_RST, "RST" }, \
+                        { VIRTIO_VSOCK_OP_SHUTDOWN, "SHUTDOWN" }, \
+                        { VIRTIO_VSOCK_OP_RW, "RW" }, \
+                        { VIRTIO_VSOCK_OP_CREDIT_UPDATE, "CREDIT_UPDATE" }, \
+                        { VIRTIO_VSOCK_OP_CREDIT_REQUEST, "CREDIT_REQUEST" })
+
+TRACE_EVENT(virtio_transport_alloc_pkt,
+       TP_PROTO(
+                __u32 src_cid, __u32 src_port,
+                __u32 dst_cid, __u32 dst_port,
+                __u32 len,
+                __u16 type,
+                __u16 op,
+                __u32 flags
+       ),
+       TP_ARGS(
+               src_cid, src_port,
+               dst_cid, dst_port,
+               len,
+               type,
+               op,
+               flags
+       ),
+       TP_STRUCT__entry(
+               __field(__u32, src_cid)
+               __field(__u32, src_port)
+               __field(__u32, dst_cid)
+               __field(__u32, dst_port)
+               __field(__u32, len)
+               __field(__u16, type)
+               __field(__u16, op)
+               __field(__u32, flags)
+       ),
+       TP_fast_assign(
+               __entry->src_cid = src_cid;
+               __entry->src_port = src_port;
+               __entry->dst_cid = dst_cid;
+               __entry->dst_port = dst_port;
+               __entry->len = len;
+               __entry->type = type;
+               __entry->op = op;
+               __entry->flags = flags;
+       ),
+       TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x",
+                 __entry->src_cid, __entry->src_port,
+                 __entry->dst_cid, __entry->dst_port,
+                 __entry->len,
+                 show_type(__entry->type),
+                 show_op(__entry->op),
+                 __entry->flags)
+);
+
+TRACE_EVENT(virtio_transport_recv_pkt,
+       TP_PROTO(
+                __u32 src_cid, __u32 src_port,
+                __u32 dst_cid, __u32 dst_port,
+                __u32 len,
+                __u16 type,
+                __u16 op,
+                __u32 flags,
+                __u32 buf_alloc,
+                __u32 fwd_cnt
+       ),
+       TP_ARGS(
+               src_cid, src_port,
+               dst_cid, dst_port,
+               len,
+               type,
+               op,
+               flags,
+               buf_alloc,
+               fwd_cnt
+       ),
+       TP_STRUCT__entry(
+               __field(__u32, src_cid)
+               __field(__u32, src_port)
+               __field(__u32, dst_cid)
+               __field(__u32, dst_port)
+               __field(__u32, len)
+               __field(__u16, type)
+               __field(__u16, op)
+               __field(__u32, flags)
+               __field(__u32, buf_alloc)
+               __field(__u32, fwd_cnt)
+       ),
+       TP_fast_assign(
+               __entry->src_cid = src_cid;
+               __entry->src_port = src_port;
+               __entry->dst_cid = dst_cid;
+               __entry->dst_port = dst_port;
+               __entry->len = len;
+               __entry->type = type;
+               __entry->op = op;
+               __entry->flags = flags;
+               __entry->buf_alloc = buf_alloc;
+               __entry->fwd_cnt = fwd_cnt;
+       ),
+       TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x "
+                 "buf_alloc=%u fwd_cnt=%u",
+                 __entry->src_cid, __entry->src_port,
+                 __entry->dst_cid, __entry->dst_port,
+                 __entry->len,
+                 show_type(__entry->type),
+                 show_op(__entry->op),
+                 __entry->flags,
+                 __entry->buf_alloc,
+                 __entry->fwd_cnt)
+);
+
+#endif /* _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H */
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE vsock_virtio_transport_common
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 6d4e92c..185f8ea 100644 (file)
@@ -357,6 +357,7 @@ header-y += reiserfs_fs.h
 header-y += reiserfs_xattr.h
 header-y += resource.h
 header-y += rfkill.h
+header-y += rio_cm_cdev.h
 header-y += rio_mport_cdev.h
 header-y += romfs_fs.h
 header-y += rose.h
@@ -453,6 +454,7 @@ header-y += virtio_ring.h
 header-y += virtio_rng.h
 header-y += virtio_scsi.h
 header-y += virtio_types.h
+header-y += virtio_vsock.h
 header-y += vm_sockets.h
 header-y += vt.h
 header-y += vtpm_proxy.h
index 2bdd1e3..ac5eacd 100644 (file)
@@ -798,7 +798,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
 #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \
                                        struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
-                                       struct btrfs_ioctl_ino_path_args)
+                                       struct btrfs_ioctl_logical_ino_args)
 #define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
                                struct btrfs_ioctl_received_subvol_args)
 #define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args)
index 12c37a1..49bc062 100644 (file)
@@ -15,8 +15,6 @@
 
 #include <linux/types.h>
 
-struct task_struct;
-
 /* User-level do most of the mapping between kernel and user
    capabilities based on the version tag given by the kernel. The
    kernel might be somewhat backwards compatible, but don't bet on
index cb4a72f..b59ee07 100644 (file)
@@ -286,6 +286,7 @@ typedef struct elf64_phdr {
 #define SHF_ALLOC              0x2
 #define SHF_EXECINSTR          0x4
 #define SHF_RELA_LIVEPATCH     0x00100000
+#define SHF_RO_AFTER_INIT      0x00200000
 #define SHF_MASKPROC           0xf0000000
 
 /* special section indexes */
@@ -381,6 +382,19 @@ typedef struct elf64_shdr {
 #define NT_PPC_VMX     0x100           /* PowerPC Altivec/VMX registers */
 #define NT_PPC_SPE     0x101           /* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX     0x102           /* PowerPC VSX registers */
+#define NT_PPC_TAR     0x103           /* Target Address Register */
+#define NT_PPC_PPR     0x104           /* Program Priority Register */
+#define NT_PPC_DSCR    0x105           /* Data Stream Control Register */
+#define NT_PPC_EBB     0x106           /* Event Based Branch Registers */
+#define NT_PPC_PMU     0x107           /* Performance Monitor Registers */
+#define NT_PPC_TM_CGPR 0x108           /* TM checkpointed GPR Registers */
+#define NT_PPC_TM_CFPR 0x109           /* TM checkpointed FPR Registers */
+#define NT_PPC_TM_CVMX 0x10a           /* TM checkpointed VMX Registers */
+#define NT_PPC_TM_CVSX 0x10b           /* TM checkpointed VSX Registers */
+#define NT_PPC_TM_SPR  0x10c           /* TM Special Purpose Registers */
+#define NT_PPC_TM_CTAR 0x10d           /* TM checkpointed Target Address Register */
+#define NT_PPC_TM_CPPR 0x10e           /* TM checkpointed Program Priority Register */
+#define NT_PPC_TM_CDSCR        0x10f           /* TM checkpointed Data Stream Control Register */
 #define NT_386_TLS     0x200           /* i386 TLS slots (struct user_desc) */
 #define NT_386_IOPERM  0x201           /* x86 io permission bitmap (1=deny) */
 #define NT_X86_XSTATE  0x202           /* x86 extended state using xsave */
index 05ebf47..300ef25 100644 (file)
@@ -866,6 +866,10 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_ARM_PMU_V3 126
 #define KVM_CAP_VCPU_ATTRIBUTES 127
 #define KVM_CAP_MAX_VCPU_ID 128
+#define KVM_CAP_X2APIC_API 129
+#define KVM_CAP_S390_USER_INSTR0 130
+#define KVM_CAP_MSI_DEVID 131
+#define KVM_CAP_PPC_HTM 132
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -878,7 +882,10 @@ struct kvm_irq_routing_msi {
        __u32 address_lo;
        __u32 address_hi;
        __u32 data;
-       __u32 pad;
+       union {
+               __u32 pad;
+               __u32 devid;
+       };
 };
 
 struct kvm_irq_routing_s390_adapter {
@@ -1024,12 +1031,14 @@ struct kvm_one_reg {
        __u64 addr;
 };
 
+#define KVM_MSI_VALID_DEVID    (1U << 0)
 struct kvm_msi {
        __u32 address_lo;
        __u32 address_hi;
        __u32 data;
        __u32 flags;
-       __u8  pad[16];
+       __u32 devid;
+       __u8  pad[12];
 };
 
 struct kvm_arm_device_addr {
@@ -1074,6 +1083,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_FLIC              KVM_DEV_TYPE_FLIC
        KVM_DEV_TYPE_ARM_VGIC_V3,
 #define KVM_DEV_TYPE_ARM_VGIC_V3       KVM_DEV_TYPE_ARM_VGIC_V3
+       KVM_DEV_TYPE_ARM_VGIC_ITS,
+#define KVM_DEV_TYPE_ARM_VGIC_ITS      KVM_DEV_TYPE_ARM_VGIC_ITS
        KVM_DEV_TYPE_MAX,
 };
 
@@ -1313,4 +1324,7 @@ struct kvm_assigned_msix_entry {
        __u16 padding[3];
 };
 
+#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
+
 #endif /* __LINUX_KVM_H */
diff --git a/include/uapi/linux/nilfs2_api.h b/include/uapi/linux/nilfs2_api.h
new file mode 100644 (file)
index 0000000..ef4c1de
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * nilfs2_api.h - NILFS2 user space API
+ *
+ * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _LINUX_NILFS2_API_H
+#define _LINUX_NILFS2_API_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/**
+ * struct nilfs_cpinfo - checkpoint information
+ * @ci_flags: flags
+ * @ci_pad: padding
+ * @ci_cno: checkpoint number
+ * @ci_create: creation timestamp
+ * @ci_nblk_inc: number of blocks incremented by this checkpoint
+ * @ci_inodes_count: inodes count
+ * @ci_blocks_count: blocks count
+ * @ci_next: next checkpoint number in snapshot list
+ */
+struct nilfs_cpinfo {
+       __u32 ci_flags;
+       __u32 ci_pad;
+       __u64 ci_cno;
+       __u64 ci_create;
+       __u64 ci_nblk_inc;
+       __u64 ci_inodes_count;
+       __u64 ci_blocks_count;
+       __u64 ci_next;
+};
+
+/* checkpoint flags */
+enum {
+       NILFS_CPINFO_SNAPSHOT,
+       NILFS_CPINFO_INVALID,
+       NILFS_CPINFO_SKETCH,
+       NILFS_CPINFO_MINOR,
+};
+
+#define NILFS_CPINFO_FNS(flag, name)                                   \
+static inline int                                                      \
+nilfs_cpinfo_##name(const struct nilfs_cpinfo *cpinfo)                 \
+{                                                                      \
+       return !!(cpinfo->ci_flags & (1UL << NILFS_CPINFO_##flag));     \
+}
+
+NILFS_CPINFO_FNS(SNAPSHOT, snapshot)
+NILFS_CPINFO_FNS(INVALID, invalid)
+NILFS_CPINFO_FNS(MINOR, minor)
+
+/**
+ * nilfs_suinfo - segment usage information
+ * @sui_lastmod: timestamp of last modification
+ * @sui_nblocks: number of written blocks in segment
+ * @sui_flags: segment usage flags
+ */
+struct nilfs_suinfo {
+       __u64 sui_lastmod;
+       __u32 sui_nblocks;
+       __u32 sui_flags;
+};
+
+/* segment usage flags */
+enum {
+       NILFS_SUINFO_ACTIVE,
+       NILFS_SUINFO_DIRTY,
+       NILFS_SUINFO_ERROR,
+};
+
+#define NILFS_SUINFO_FNS(flag, name)                                   \
+static inline int                                                      \
+nilfs_suinfo_##name(const struct nilfs_suinfo *si)                     \
+{                                                                      \
+       return si->sui_flags & (1UL << NILFS_SUINFO_##flag);            \
+}
+
+NILFS_SUINFO_FNS(ACTIVE, active)
+NILFS_SUINFO_FNS(DIRTY, dirty)
+NILFS_SUINFO_FNS(ERROR, error)
+
+static inline int nilfs_suinfo_clean(const struct nilfs_suinfo *si)
+{
+       return !si->sui_flags;
+}
+
+/**
+ * nilfs_suinfo_update - segment usage information update
+ * @sup_segnum: segment number
+ * @sup_flags: flags for which fields are active in sup_sui
+ * @sup_reserved: reserved necessary for alignment
+ * @sup_sui: segment usage information
+ */
+struct nilfs_suinfo_update {
+       __u64 sup_segnum;
+       __u32 sup_flags;
+       __u32 sup_reserved;
+       struct nilfs_suinfo sup_sui;
+};
+
+enum {
+       NILFS_SUINFO_UPDATE_LASTMOD,
+       NILFS_SUINFO_UPDATE_NBLOCKS,
+       NILFS_SUINFO_UPDATE_FLAGS,
+       __NR_NILFS_SUINFO_UPDATE_FIELDS,
+};
+
+#define NILFS_SUINFO_UPDATE_FNS(flag, name)                            \
+static inline void                                                     \
+nilfs_suinfo_update_set_##name(struct nilfs_suinfo_update *sup)                \
+{                                                                      \
+       sup->sup_flags |= 1UL << NILFS_SUINFO_UPDATE_##flag;            \
+}                                                                      \
+static inline void                                                     \
+nilfs_suinfo_update_clear_##name(struct nilfs_suinfo_update *sup)      \
+{                                                                      \
+       sup->sup_flags &= ~(1UL << NILFS_SUINFO_UPDATE_##flag);         \
+}                                                                      \
+static inline int                                                      \
+nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)      \
+{                                                                      \
+       return !!(sup->sup_flags & (1UL << NILFS_SUINFO_UPDATE_##flag));\
+}
+
+NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
+NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
+NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+
+enum {
+       NILFS_CHECKPOINT,
+       NILFS_SNAPSHOT,
+};
+
+/**
+ * struct nilfs_cpmode - change checkpoint mode structure
+ * @cm_cno: checkpoint number
+ * @cm_mode: mode of checkpoint
+ * @cm_pad: padding
+ */
+struct nilfs_cpmode {
+       __u64 cm_cno;
+       __u32 cm_mode;
+       __u32 cm_pad;
+};
+
+/**
+ * struct nilfs_argv - argument vector
+ * @v_base: pointer on data array from userspace
+ * @v_nmembs: number of members in data array
+ * @v_size: size of data array in bytes
+ * @v_flags: flags
+ * @v_index: start number of target data items
+ */
+struct nilfs_argv {
+       __u64 v_base;
+       __u32 v_nmembs; /* number of members */
+       __u16 v_size;   /* size of members */
+       __u16 v_flags;
+       __u64 v_index;
+};
+
+/**
+ * struct nilfs_period - period of checkpoint numbers
+ * @p_start: start checkpoint number (inclusive)
+ * @p_end: end checkpoint number (exclusive)
+ */
+struct nilfs_period {
+       __u64 p_start;
+       __u64 p_end;
+};
+
+/**
+ * struct nilfs_cpstat - checkpoint statistics
+ * @cs_cno: checkpoint number
+ * @cs_ncps: number of checkpoints
+ * @cs_nsss: number of snapshots
+ */
+struct nilfs_cpstat {
+       __u64 cs_cno;
+       __u64 cs_ncps;
+       __u64 cs_nsss;
+};
+
+/**
+ * struct nilfs_sustat - segment usage statistics
+ * @ss_nsegs: number of segments
+ * @ss_ncleansegs: number of clean segments
+ * @ss_ndirtysegs: number of dirty segments
+ * @ss_ctime: creation time of the last segment
+ * @ss_nongc_ctime: creation time of the last segment not for GC
+ * @ss_prot_seq: least sequence number of segments which must not be reclaimed
+ */
+struct nilfs_sustat {
+       __u64 ss_nsegs;
+       __u64 ss_ncleansegs;
+       __u64 ss_ndirtysegs;
+       __u64 ss_ctime;
+       __u64 ss_nongc_ctime;
+       __u64 ss_prot_seq;
+};
+
+/**
+ * struct nilfs_vinfo - virtual block number information
+ * @vi_vblocknr: virtual block number
+ * @vi_start: start checkpoint number (inclusive)
+ * @vi_end: end checkpoint number (exclusive)
+ * @vi_blocknr: disk block number
+ */
+struct nilfs_vinfo {
+       __u64 vi_vblocknr;
+       __u64 vi_start;
+       __u64 vi_end;
+       __u64 vi_blocknr;
+};
+
+/**
+ * struct nilfs_vdesc - descriptor of virtual block number
+ * @vd_ino: inode number
+ * @vd_cno: checkpoint number
+ * @vd_vblocknr: virtual block number
+ * @vd_period: period of checkpoint numbers
+ * @vd_blocknr: disk block number
+ * @vd_offset: logical block offset inside a file
+ * @vd_flags: flags (data or node block)
+ * @vd_pad: padding
+ */
+struct nilfs_vdesc {
+       __u64 vd_ino;
+       __u64 vd_cno;
+       __u64 vd_vblocknr;
+       struct nilfs_period vd_period;
+       __u64 vd_blocknr;
+       __u64 vd_offset;
+       __u32 vd_flags;
+       __u32 vd_pad;
+};
+
+/**
+ * struct nilfs_bdesc - descriptor of disk block number
+ * @bd_ino: inode number
+ * @bd_oblocknr: disk block address (for skipping dead blocks)
+ * @bd_blocknr: disk block address
+ * @bd_offset: logical block offset inside a file
+ * @bd_level: level in the b-tree organization
+ * @bd_pad: padding
+ */
+struct nilfs_bdesc {
+       __u64 bd_ino;
+       __u64 bd_oblocknr;
+       __u64 bd_blocknr;
+       __u64 bd_offset;
+       __u32 bd_level;
+       __u32 bd_pad;
+};
+
+#define NILFS_IOCTL_IDENT      'n'
+
+#define NILFS_IOCTL_CHANGE_CPMODE                                      \
+       _IOW(NILFS_IOCTL_IDENT, 0x80, struct nilfs_cpmode)
+#define NILFS_IOCTL_DELETE_CHECKPOINT                                  \
+       _IOW(NILFS_IOCTL_IDENT, 0x81, __u64)
+#define NILFS_IOCTL_GET_CPINFO                                         \
+       _IOR(NILFS_IOCTL_IDENT, 0x82, struct nilfs_argv)
+#define NILFS_IOCTL_GET_CPSTAT                                         \
+       _IOR(NILFS_IOCTL_IDENT, 0x83, struct nilfs_cpstat)
+#define NILFS_IOCTL_GET_SUINFO                                         \
+       _IOR(NILFS_IOCTL_IDENT, 0x84, struct nilfs_argv)
+#define NILFS_IOCTL_GET_SUSTAT                                         \
+       _IOR(NILFS_IOCTL_IDENT, 0x85, struct nilfs_sustat)
+#define NILFS_IOCTL_GET_VINFO                                          \
+       _IOWR(NILFS_IOCTL_IDENT, 0x86, struct nilfs_argv)
+#define NILFS_IOCTL_GET_BDESCS                                         \
+       _IOWR(NILFS_IOCTL_IDENT, 0x87, struct nilfs_argv)
+#define NILFS_IOCTL_CLEAN_SEGMENTS                                     \
+       _IOW(NILFS_IOCTL_IDENT, 0x88, struct nilfs_argv[5])
+#define NILFS_IOCTL_SYNC                                               \
+       _IOR(NILFS_IOCTL_IDENT, 0x8A, __u64)
+#define NILFS_IOCTL_RESIZE                                             \
+       _IOW(NILFS_IOCTL_IDENT, 0x8B, __u64)
+#define NILFS_IOCTL_SET_ALLOC_RANGE                                    \
+       _IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
+#define NILFS_IOCTL_SET_SUINFO                                         \
+       _IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
+
+#endif /* _LINUX_NILFS2_API_H */
diff --git a/include/uapi/linux/nilfs2_ondisk.h b/include/uapi/linux/nilfs2_ondisk.h
new file mode 100644 (file)
index 0000000..2a8a3ad
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * nilfs2_ondisk.h - NILFS2 on-disk structures
+ *
+ * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+/*
+ *  linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifndef _LINUX_NILFS2_ONDISK_H
+#define _LINUX_NILFS2_ONDISK_H
+
+#include <linux/types.h>
+#include <linux/magic.h>
+
+
+#define NILFS_INODE_BMAP_SIZE  7
+
+/**
+ * struct nilfs_inode - structure of an inode on disk
+ * @i_blocks: blocks count
+ * @i_size: size in bytes
+ * @i_ctime: creation time (seconds)
+ * @i_mtime: modification time (seconds)
+ * @i_ctime_nsec: creation time (nano seconds)
+ * @i_mtime_nsec: modification time (nano seconds)
+ * @i_uid: user id
+ * @i_gid: group id
+ * @i_mode: file mode
+ * @i_links_count: links count
+ * @i_flags: file flags
+ * @i_bmap: block mapping
+ * @i_xattr: extended attributes
+ * @i_generation: file generation (for NFS)
+ * @i_pad: padding
+ */
+struct nilfs_inode {
+       __le64  i_blocks;
+       __le64  i_size;
+       __le64  i_ctime;
+       __le64  i_mtime;
+       __le32  i_ctime_nsec;
+       __le32  i_mtime_nsec;
+       __le32  i_uid;
+       __le32  i_gid;
+       __le16  i_mode;
+       __le16  i_links_count;
+       __le32  i_flags;
+       __le64  i_bmap[NILFS_INODE_BMAP_SIZE];
+#define i_device_code  i_bmap[0]
+       __le64  i_xattr;
+       __le32  i_generation;
+       __le32  i_pad;
+};
+
+#define NILFS_MIN_INODE_SIZE           128
+
+/**
+ * struct nilfs_super_root - structure of super root
+ * @sr_sum: check sum
+ * @sr_bytes: byte count of the structure
+ * @sr_flags: flags (reserved)
+ * @sr_nongc_ctime: write time of the last segment not for cleaner operation
+ * @sr_dat: DAT file inode
+ * @sr_cpfile: checkpoint file inode
+ * @sr_sufile: segment usage file inode
+ */
+struct nilfs_super_root {
+       __le32 sr_sum;
+       __le16 sr_bytes;
+       __le16 sr_flags;
+       __le64 sr_nongc_ctime;
+       struct nilfs_inode sr_dat;
+       struct nilfs_inode sr_cpfile;
+       struct nilfs_inode sr_sufile;
+};
+
+#define NILFS_SR_MDT_OFFSET(inode_size, i)  \
+       ((unsigned long)&((struct nilfs_super_root *)0)->sr_dat + \
+                       (inode_size) * (i))
+#define NILFS_SR_DAT_OFFSET(inode_size)     NILFS_SR_MDT_OFFSET(inode_size, 0)
+#define NILFS_SR_CPFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 1)
+#define NILFS_SR_SUFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 2)
+#define NILFS_SR_BYTES(inode_size)         NILFS_SR_MDT_OFFSET(inode_size, 3)
+
+/*
+ * Maximal mount counts
+ */
+#define NILFS_DFL_MAX_MNT_COUNT                50      /* 50 mounts */
+
+/*
+ * File system states (sbp->s_state, nilfs->ns_mount_state)
+ */
+#define NILFS_VALID_FS                 0x0001  /* Unmounted cleanly */
+#define NILFS_ERROR_FS                 0x0002  /* Errors detected */
+#define NILFS_RESIZE_FS                        0x0004  /* Resize required */
+
+/*
+ * Mount flags (sbi->s_mount_opt)
+ */
+#define NILFS_MOUNT_ERROR_MODE         0x0070  /* Error mode mask */
+#define NILFS_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */
+#define NILFS_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */
+#define NILFS_MOUNT_ERRORS_PANIC       0x0040  /* Panic on errors */
+#define NILFS_MOUNT_BARRIER            0x1000  /* Use block barriers */
+#define NILFS_MOUNT_STRICT_ORDER       0x2000  /*
+                                                * Apply strict in-order
+                                                * semantics also for data
+                                                */
+#define NILFS_MOUNT_NORECOVERY         0x4000  /*
+                                                * Disable write access during
+                                                * mount-time recovery
+                                                */
+#define NILFS_MOUNT_DISCARD            0x8000  /* Issue DISCARD requests */
+
+
+/**
+ * struct nilfs_super_block - structure of super block on disk
+ */
+struct nilfs_super_block {
+/*00*/ __le32  s_rev_level;            /* Revision level */
+       __le16  s_minor_rev_level;      /* minor revision level */
+       __le16  s_magic;                /* Magic signature */
+
+       __le16  s_bytes;                /*
+                                        * Bytes count of CRC calculation
+                                        * for this structure. s_reserved
+                                        * is excluded.
+                                        */
+       __le16  s_flags;                /* flags */
+       __le32  s_crc_seed;             /* Seed value of CRC calculation */
+/*10*/ __le32  s_sum;                  /* Check sum of super block */
+
+       __le32  s_log_block_size;       /*
+                                        * Block size represented as follows
+                                        * blocksize =
+                                        *     1 << (s_log_block_size + 10)
+                                        */
+       __le64  s_nsegments;            /* Number of segments in filesystem */
+/*20*/ __le64  s_dev_size;             /* block device size in bytes */
+       __le64  s_first_data_block;     /* 1st seg disk block number */
+/*30*/ __le32  s_blocks_per_segment;   /* number of blocks per full segment */
+       __le32  s_r_segments_percentage; /* Reserved segments percentage */
+
+       __le64  s_last_cno;             /* Last checkpoint number */
+/*40*/ __le64  s_last_pseg;            /* disk block addr pseg written last */
+       __le64  s_last_seq;             /* seq. number of seg written last */
+/*50*/ __le64  s_free_blocks_count;    /* Free blocks count */
+
+       __le64  s_ctime;                /*
+                                        * Creation time (execution time of
+                                        * newfs)
+                                        */
+/*60*/ __le64  s_mtime;                /* Mount time */
+       __le64  s_wtime;                /* Write time */
+/*70*/ __le16  s_mnt_count;            /* Mount count */
+       __le16  s_max_mnt_count;        /* Maximal mount count */
+       __le16  s_state;                /* File system state */
+       __le16  s_errors;               /* Behaviour when detecting errors */
+       __le64  s_lastcheck;            /* time of last check */
+
+/*80*/ __le32  s_checkinterval;        /* max. time between checks */
+       __le32  s_creator_os;           /* OS */
+       __le16  s_def_resuid;           /* Default uid for reserved blocks */
+       __le16  s_def_resgid;           /* Default gid for reserved blocks */
+       __le32  s_first_ino;            /* First non-reserved inode */
+
+/*90*/ __le16  s_inode_size;           /* Size of an inode */
+       __le16  s_dat_entry_size;       /* Size of a dat entry */
+       __le16  s_checkpoint_size;      /* Size of a checkpoint */
+       __le16  s_segment_usage_size;   /* Size of a segment usage */
+
+/*98*/ __u8    s_uuid[16];             /* 128-bit uuid for volume */
+/*A8*/ char    s_volume_name[80];      /* volume name */
+
+/*F8*/ __le32  s_c_interval;           /* Commit interval of segment */
+       __le32  s_c_block_max;          /*
+                                        * Threshold of data amount for
+                                        * the segment construction
+                                        */
+/*100*/        __le64  s_feature_compat;       /* Compatible feature set */
+       __le64  s_feature_compat_ro;    /* Read-only compatible feature set */
+       __le64  s_feature_incompat;     /* Incompatible feature set */
+       __u32   s_reserved[186];        /* padding to the end of the block */
+};
+
+/*
+ * Codes for operating systems
+ */
+#define NILFS_OS_LINUX         0
+/* Codes from 1 to 4 are reserved to keep compatibility with ext2 creator-OS */
+
+/*
+ * Revision levels
+ */
+#define NILFS_CURRENT_REV      2       /* current major revision */
+#define NILFS_MINOR_REV                0       /* minor revision */
+#define NILFS_MIN_SUPP_REV     2       /* minimum supported revision */
+
+/*
+ * Feature set definitions
+ *
+ * If there is a bit set in the incompatible feature set that the kernel
+ * doesn't know about, it should refuse to mount the filesystem.
+ */
+#define NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT    0x00000001ULL
+
+#define NILFS_FEATURE_COMPAT_SUPP      0ULL
+#define NILFS_FEATURE_COMPAT_RO_SUPP   NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT
+#define NILFS_FEATURE_INCOMPAT_SUPP    0ULL
+
+/*
+ * Bytes count of super_block for CRC-calculation
+ */
+#define NILFS_SB_BYTES  \
+       ((long)&((struct nilfs_super_block *)0)->s_reserved)
+
+/*
+ * Special inode number
+ */
+#define NILFS_ROOT_INO         2       /* Root file inode */
+#define NILFS_DAT_INO          3       /* DAT file */
+#define NILFS_CPFILE_INO       4       /* checkpoint file */
+#define NILFS_SUFILE_INO       5       /* segment usage file */
+#define NILFS_IFILE_INO                6       /* ifile */
+#define NILFS_ATIME_INO                7       /* Atime file (reserved) */
+#define NILFS_XATTR_INO                8       /* Xattribute file (reserved) */
+#define NILFS_SKETCH_INO       10      /* Sketch file */
+#define NILFS_USER_INO         11      /* Fisrt user's file inode number */
+
+#define NILFS_SB_OFFSET_BYTES  1024    /* byte offset of nilfs superblock */
+
+#define NILFS_SEG_MIN_BLOCKS   16      /*
+                                        * Minimum number of blocks in
+                                        * a full segment
+                                        */
+#define NILFS_PSEG_MIN_BLOCKS  2       /*
+                                        * Minimum number of blocks in
+                                        * a partial segment
+                                        */
+#define NILFS_MIN_NRSVSEGS     8       /*
+                                        * Minimum number of reserved
+                                        * segments
+                                        */
+
+/*
+ * We call DAT, cpfile, and sufile root metadata files.  Inodes of
+ * these files are written in super root block instead of ifile, and
+ * garbage collector doesn't keep any past versions of these files.
+ */
+#define NILFS_ROOT_METADATA_FILE(ino) \
+       ((ino) >= NILFS_DAT_INO && (ino) <= NILFS_SUFILE_INO)
+
+/*
+ * bytes offset of secondary super block
+ */
+#define NILFS_SB2_OFFSET_BYTES(devsize)        ((((devsize) >> 12) - 1) << 12)
+
+/*
+ * Maximal count of links to a file
+ */
+#define NILFS_LINK_MAX         32000
+
+/*
+ * Structure of a directory entry
+ *  (Same as ext2)
+ */
+
+#define NILFS_NAME_LEN 255
+
+/*
+ * Block size limitations
+ */
+#define NILFS_MIN_BLOCK_SIZE           1024
+#define NILFS_MAX_BLOCK_SIZE           65536
+
+/*
+ * The new version of the directory entry.  Since V0 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct nilfs_dir_entry {
+       __le64  inode;                  /* Inode number */
+       __le16  rec_len;                /* Directory entry length */
+       __u8    name_len;               /* Name length */
+       __u8    file_type;              /* Dir entry type (file, dir, etc) */
+       char    name[NILFS_NAME_LEN];   /* File name */
+       char    pad;
+};
+
+/*
+ * NILFS directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+enum {
+       NILFS_FT_UNKNOWN,
+       NILFS_FT_REG_FILE,
+       NILFS_FT_DIR,
+       NILFS_FT_CHRDEV,
+       NILFS_FT_BLKDEV,
+       NILFS_FT_FIFO,
+       NILFS_FT_SOCK,
+       NILFS_FT_SYMLINK,
+       NILFS_FT_MAX
+};
+
+/*
+ * NILFS_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 8
+ */
+#define NILFS_DIR_PAD                  8
+#define NILFS_DIR_ROUND                        (NILFS_DIR_PAD - 1)
+#define NILFS_DIR_REC_LEN(name_len)    (((name_len) + 12 + NILFS_DIR_ROUND) & \
+                                       ~NILFS_DIR_ROUND)
+#define NILFS_MAX_REC_LEN              ((1 << 16) - 1)
+
+/**
+ * struct nilfs_finfo - file information
+ * @fi_ino: inode number
+ * @fi_cno: checkpoint number
+ * @fi_nblocks: number of blocks (including intermediate blocks)
+ * @fi_ndatablk: number of file data blocks
+ */
+struct nilfs_finfo {
+       __le64 fi_ino;
+       __le64 fi_cno;
+       __le32 fi_nblocks;
+       __le32 fi_ndatablk;
+};
+
+/**
+ * struct nilfs_binfo_v - information on a data block (except DAT)
+ * @bi_vblocknr: virtual block number
+ * @bi_blkoff: block offset
+ */
+struct nilfs_binfo_v {
+       __le64 bi_vblocknr;
+       __le64 bi_blkoff;
+};
+
+/**
+ * struct nilfs_binfo_dat - information on a DAT node block
+ * @bi_blkoff: block offset
+ * @bi_level: level
+ * @bi_pad: padding
+ */
+struct nilfs_binfo_dat {
+       __le64 bi_blkoff;
+       __u8 bi_level;
+       __u8 bi_pad[7];
+};
+
+/**
+ * union nilfs_binfo: block information
+ * @bi_v: nilfs_binfo_v structure
+ * @bi_dat: nilfs_binfo_dat structure
+ */
+union nilfs_binfo {
+       struct nilfs_binfo_v bi_v;
+       struct nilfs_binfo_dat bi_dat;
+};
+
+/**
+ * struct nilfs_segment_summary - segment summary header
+ * @ss_datasum: checksum of data
+ * @ss_sumsum: checksum of segment summary
+ * @ss_magic: magic number
+ * @ss_bytes: size of this structure in bytes
+ * @ss_flags: flags
+ * @ss_seq: sequence number
+ * @ss_create: creation timestamp
+ * @ss_next: next segment
+ * @ss_nblocks: number of blocks
+ * @ss_nfinfo: number of finfo structures
+ * @ss_sumbytes: total size of segment summary in bytes
+ * @ss_pad: padding
+ * @ss_cno: checkpoint number
+ */
+struct nilfs_segment_summary {
+       __le32 ss_datasum;
+       __le32 ss_sumsum;
+       __le32 ss_magic;
+       __le16 ss_bytes;
+       __le16 ss_flags;
+       __le64 ss_seq;
+       __le64 ss_create;
+       __le64 ss_next;
+       __le32 ss_nblocks;
+       __le32 ss_nfinfo;
+       __le32 ss_sumbytes;
+       __le32 ss_pad;
+       __le64 ss_cno;
+       /* array of finfo structures */
+};
+
+#define NILFS_SEGSUM_MAGIC     0x1eaffa11  /* segment summary magic number */
+
+/*
+ * Segment summary flags
+ */
+#define NILFS_SS_LOGBGN 0x0001  /* begins a logical segment */
+#define NILFS_SS_LOGEND 0x0002  /* ends a logical segment */
+#define NILFS_SS_SR     0x0004  /* has super root */
+#define NILFS_SS_SYNDT  0x0008  /* includes data only updates */
+#define NILFS_SS_GC     0x0010  /* segment written for cleaner operation */
+
+/**
+ * struct nilfs_btree_node - header of B-tree node block
+ * @bn_flags: flags
+ * @bn_level: level
+ * @bn_nchildren: number of children
+ * @bn_pad: padding
+ */
+struct nilfs_btree_node {
+       __u8 bn_flags;
+       __u8 bn_level;
+       __le16 bn_nchildren;
+       __le32 bn_pad;
+};
+
+/* flags */
+#define NILFS_BTREE_NODE_ROOT   0x01
+
+/* level */
+#define NILFS_BTREE_LEVEL_DATA          0
+#define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
+#define NILFS_BTREE_LEVEL_MAX           14     /* Max level (exclusive) */
+
+/**
+ * struct nilfs_direct_node - header of built-in bmap array
+ * @dn_flags: flags
+ * @dn_pad: padding
+ */
+struct nilfs_direct_node {
+       __u8 dn_flags;
+       __u8 pad[7];
+};
+
+/**
+ * struct nilfs_palloc_group_desc - block group descriptor
+ * @pg_nfrees: number of free entries in block group
+ */
+struct nilfs_palloc_group_desc {
+       __le32 pg_nfrees;
+};
+
+/**
+ * struct nilfs_dat_entry - disk address translation entry
+ * @de_blocknr: block number
+ * @de_start: start checkpoint number
+ * @de_end: end checkpoint number
+ * @de_rsv: reserved for future use
+ */
+struct nilfs_dat_entry {
+       __le64 de_blocknr;
+       __le64 de_start;
+       __le64 de_end;
+       __le64 de_rsv;
+};
+
+#define NILFS_MIN_DAT_ENTRY_SIZE       32
+
+/**
+ * struct nilfs_snapshot_list - snapshot list
+ * @ssl_next: next checkpoint number on snapshot list
+ * @ssl_prev: previous checkpoint number on snapshot list
+ */
+struct nilfs_snapshot_list {
+       __le64 ssl_next;
+       __le64 ssl_prev;
+};
+
+/**
+ * struct nilfs_checkpoint - checkpoint structure
+ * @cp_flags: flags
+ * @cp_checkpoints_count: checkpoints count in a block
+ * @cp_snapshot_list: snapshot list
+ * @cp_cno: checkpoint number
+ * @cp_create: creation timestamp
+ * @cp_nblk_inc: number of blocks incremented by this checkpoint
+ * @cp_inodes_count: inodes count
+ * @cp_blocks_count: blocks count
+ * @cp_ifile_inode: inode of ifile
+ */
+struct nilfs_checkpoint {
+       __le32 cp_flags;
+       __le32 cp_checkpoints_count;
+       struct nilfs_snapshot_list cp_snapshot_list;
+       __le64 cp_cno;
+       __le64 cp_create;
+       __le64 cp_nblk_inc;
+       __le64 cp_inodes_count;
+       __le64 cp_blocks_count;
+
+       /*
+        * Do not change the byte offset of ifile inode.
+        * To keep the compatibility of the disk format,
+        * additional fields should be added behind cp_ifile_inode.
+        */
+       struct nilfs_inode cp_ifile_inode;
+};
+
+#define NILFS_MIN_CHECKPOINT_SIZE      (64 + NILFS_MIN_INODE_SIZE)
+
+/* checkpoint flags */
+enum {
+       NILFS_CHECKPOINT_SNAPSHOT,
+       NILFS_CHECKPOINT_INVALID,
+       NILFS_CHECKPOINT_SKETCH,
+       NILFS_CHECKPOINT_MINOR,
+};
+
+#define NILFS_CHECKPOINT_FNS(flag, name)                               \
+static inline void                                                     \
+nilfs_checkpoint_set_##name(struct nilfs_checkpoint *cp)               \
+{                                                                      \
+       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) |          \
+                                  (1UL << NILFS_CHECKPOINT_##flag));   \
+}                                                                      \
+static inline void                                                     \
+nilfs_checkpoint_clear_##name(struct nilfs_checkpoint *cp)             \
+{                                                                      \
+       cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) &          \
+                                  ~(1UL << NILFS_CHECKPOINT_##flag));  \
+}                                                                      \
+static inline int                                                      \
+nilfs_checkpoint_##name(const struct nilfs_checkpoint *cp)             \
+{                                                                      \
+       return !!(le32_to_cpu(cp->cp_flags) &                           \
+                 (1UL << NILFS_CHECKPOINT_##flag));                    \
+}
+
+NILFS_CHECKPOINT_FNS(SNAPSHOT, snapshot)
+NILFS_CHECKPOINT_FNS(INVALID, invalid)
+NILFS_CHECKPOINT_FNS(MINOR, minor)
+
+/**
+ * struct nilfs_cpfile_header - checkpoint file header
+ * @ch_ncheckpoints: number of checkpoints
+ * @ch_nsnapshots: number of snapshots
+ * @ch_snapshot_list: snapshot list
+ */
+struct nilfs_cpfile_header {
+       __le64 ch_ncheckpoints;
+       __le64 ch_nsnapshots;
+       struct nilfs_snapshot_list ch_snapshot_list;
+};
+
+#define NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET                           \
+       ((sizeof(struct nilfs_cpfile_header) +                          \
+         sizeof(struct nilfs_checkpoint) - 1) /                        \
+                       sizeof(struct nilfs_checkpoint))
+
+/**
+ * struct nilfs_segment_usage - segment usage
+ * @su_lastmod: last modified timestamp
+ * @su_nblocks: number of blocks in segment
+ * @su_flags: flags
+ */
+struct nilfs_segment_usage {
+       __le64 su_lastmod;
+       __le32 su_nblocks;
+       __le32 su_flags;
+};
+
+#define NILFS_MIN_SEGMENT_USAGE_SIZE   16
+
+/* segment usage flag */
+enum {
+       NILFS_SEGMENT_USAGE_ACTIVE,
+       NILFS_SEGMENT_USAGE_DIRTY,
+       NILFS_SEGMENT_USAGE_ERROR,
+};
+
+#define NILFS_SEGMENT_USAGE_FNS(flag, name)                            \
+static inline void                                                     \
+nilfs_segment_usage_set_##name(struct nilfs_segment_usage *su)         \
+{                                                                      \
+       su->su_flags = cpu_to_le32(le32_to_cpu(su->su_flags) |          \
+                                  (1UL << NILFS_SEGMENT_USAGE_##flag));\
+}                                                                      \
+static inline void                                                     \
+nilfs_segment_usage_clear_##name(struct nilfs_segment_usage *su)       \
+{                                                                      \
+       su->su_flags =                                                  \
+               cpu_to_le32(le32_to_cpu(su->su_flags) &                 \
+                           ~(1UL << NILFS_SEGMENT_USAGE_##flag));      \
+}                                                                      \
+static inline int                                                      \
+nilfs_segment_usage_##name(const struct nilfs_segment_usage *su)       \
+{                                                                      \
+       return !!(le32_to_cpu(su->su_flags) &                           \
+                 (1UL << NILFS_SEGMENT_USAGE_##flag));                 \
+}
+
+NILFS_SEGMENT_USAGE_FNS(ACTIVE, active)
+NILFS_SEGMENT_USAGE_FNS(DIRTY, dirty)
+NILFS_SEGMENT_USAGE_FNS(ERROR, error)
+
+static inline void
+nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
+{
+       su->su_lastmod = cpu_to_le64(0);
+       su->su_nblocks = cpu_to_le32(0);
+       su->su_flags = cpu_to_le32(0);
+}
+
+static inline int
+nilfs_segment_usage_clean(const struct nilfs_segment_usage *su)
+{
+       return !le32_to_cpu(su->su_flags);
+}
+
+/**
+ * struct nilfs_sufile_header - segment usage file header
+ * @sh_ncleansegs: number of clean segments
+ * @sh_ndirtysegs: number of dirty segments
+ * @sh_last_alloc: last allocated segment number
+ */
+struct nilfs_sufile_header {
+       __le64 sh_ncleansegs;
+       __le64 sh_ndirtysegs;
+       __le64 sh_last_alloc;
+       /* ... */
+};
+
+#define NILFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET                                \
+       ((sizeof(struct nilfs_sufile_header) +                          \
+         sizeof(struct nilfs_segment_usage) - 1) /                     \
+                        sizeof(struct nilfs_segment_usage))
+
+#endif /* _LINUX_NILFS2_ONDISK_H */
diff --git a/include/uapi/linux/rio_cm_cdev.h b/include/uapi/linux/rio_cm_cdev.h
new file mode 100644 (file)
index 0000000..6edb900
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Integrated Device Technology Inc.
+ * Copyright (c) 2015, Prodrive Technologies
+ * Copyright (c) 2015, RapidIO Trade Association
+ * 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, or the BSD-3 Clause 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RIO_CM_CDEV_H_
+#define _RIO_CM_CDEV_H_
+
+#include <linux/types.h>
+
+struct rio_cm_channel {
+       __u16 id;
+       __u16 remote_channel;
+       __u16 remote_destid;
+       __u8 mport_id;
+};
+
+struct rio_cm_msg {
+       __u16 ch_num;
+       __u16 size;
+       __u32 rxto;     /* receive timeout in mSec. 0 = blocking */
+       __u64 msg;
+};
+
+struct rio_cm_accept {
+       __u16 ch_num;
+       __u16 pad0;
+       __u32 wait_to;  /* accept timeout in mSec. 0 = blocking */
+};
+
+/* RapidIO Channelized Messaging Driver IOCTLs */
+#define RIO_CM_IOC_MAGIC       'c'
+
+#define RIO_CM_EP_GET_LIST_SIZE        _IOWR(RIO_CM_IOC_MAGIC, 1, __u32)
+#define RIO_CM_EP_GET_LIST     _IOWR(RIO_CM_IOC_MAGIC, 2, __u32)
+#define RIO_CM_CHAN_CREATE     _IOWR(RIO_CM_IOC_MAGIC, 3, __u16)
+#define RIO_CM_CHAN_CLOSE      _IOW(RIO_CM_IOC_MAGIC, 4, __u16)
+#define RIO_CM_CHAN_BIND       _IOW(RIO_CM_IOC_MAGIC, 5, struct rio_cm_channel)
+#define RIO_CM_CHAN_LISTEN     _IOW(RIO_CM_IOC_MAGIC, 6, __u16)
+#define RIO_CM_CHAN_ACCEPT     _IOWR(RIO_CM_IOC_MAGIC, 7, struct rio_cm_accept)
+#define RIO_CM_CHAN_CONNECT    _IOW(RIO_CM_IOC_MAGIC, 8, struct rio_cm_channel)
+#define RIO_CM_CHAN_SEND       _IOW(RIO_CM_IOC_MAGIC, 9, struct rio_cm_msg)
+#define RIO_CM_CHAN_RECEIVE    _IOWR(RIO_CM_IOC_MAGIC, 10, struct rio_cm_msg)
+#define RIO_CM_MPORT_GET_LIST  _IOWR(RIO_CM_IOC_MAGIC, 11, __u32)
+
+#endif /* _RIO_CM_CDEV_H_ */
index 0956373..d2b1215 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 
-struct completion;
-
 #define CTL_MAXNAME 10         /* how many path components do we allow in a
                                   call to sysctl?   In other words, what is
                                   the largest acceptable value for the nlen
index 61a8777..56b7ab5 100644 (file)
@@ -47,6 +47,32 @@ struct vhost_vring_addr {
        __u64 log_guest_addr;
 };
 
+/* no alignment requirement */
+struct vhost_iotlb_msg {
+       __u64 iova;
+       __u64 size;
+       __u64 uaddr;
+#define VHOST_ACCESS_RO      0x1
+#define VHOST_ACCESS_WO      0x2
+#define VHOST_ACCESS_RW      0x3
+       __u8 perm;
+#define VHOST_IOTLB_MISS           1
+#define VHOST_IOTLB_UPDATE         2
+#define VHOST_IOTLB_INVALIDATE     3
+#define VHOST_IOTLB_ACCESS_FAIL    4
+       __u8 type;
+};
+
+#define VHOST_IOTLB_MSG 0x1
+
+struct vhost_msg {
+       int type;
+       union {
+               struct vhost_iotlb_msg iotlb;
+               __u8 padding[64];
+       };
+};
+
 struct vhost_memory_region {
        __u64 guest_phys_addr;
        __u64 memory_size; /* bytes */
@@ -146,6 +172,8 @@ struct vhost_memory {
 #define VHOST_F_LOG_ALL 26
 /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
 #define VHOST_NET_F_VIRTIO_NET_HDR 27
+/* Vhost have device IOTLB */
+#define VHOST_F_DEVICE_IOTLB 63
 
 /* VHOST_SCSI specific definitions */
 
@@ -175,4 +203,9 @@ struct vhost_scsi_target {
 #define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32)
 #define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32)
 
+/* VHOST_VSOCK specific defines */
+
+#define VHOST_VSOCK_SET_GUEST_CID      _IOW(VHOST_VIRTIO, 0x60, __u64)
+#define VHOST_VSOCK_SET_RUNNING                _IOW(VHOST_VIRTIO, 0x61, int)
+
 #endif
index 4cb65bb..308e209 100644 (file)
@@ -49,7 +49,7 @@
  * transport being used (eg. virtio_ring), the rest are per-device feature
  * bits. */
 #define VIRTIO_TRANSPORT_F_START       28
-#define VIRTIO_TRANSPORT_F_END         33
+#define VIRTIO_TRANSPORT_F_END         34
 
 #ifndef VIRTIO_CONFIG_NO_LEGACY
 /* Do we get callbacks when the ring is completely used, even if we've
 /* v1.0 compliant. */
 #define VIRTIO_F_VERSION_1             32
 
+/*
+ * If clear - device has the IOMMU bypass quirk feature.
+ * If set - use platform tools to detect the IOMMU.
+ *
+ * Note the reverse polarity (compared to most other features),
+ * this is for compatibility with legacy systems.
+ */
+#define VIRTIO_F_IOMMU_PLATFORM                33
 #endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
index 77925f5..3228d58 100644 (file)
@@ -41,5 +41,6 @@
 #define VIRTIO_ID_CAIF        12 /* Virtio caif */
 #define VIRTIO_ID_GPU          16 /* virtio GPU */
 #define VIRTIO_ID_INPUT        18 /* virtio input */
+#define VIRTIO_ID_VSOCK        19 /* virtio vsock transport */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_vsock.h b/include/uapi/linux/virtio_vsock.h
new file mode 100644 (file)
index 0000000..1d57ed3
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
+ * anyone can use the definitions to implement compatible drivers/servers:
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (C) Red Hat, Inc., 2013-2015
+ * Copyright (C) Asias He <asias@redhat.com>, 2013
+ * Copyright (C) Stefan Hajnoczi <stefanha@redhat.com>, 2015
+ */
+
+#ifndef _UAPI_LINUX_VIRTIO_VSOCK_H
+#define _UAPI_LINUX_VIRTIO_VSOCK_H
+
+#include <linux/types.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+
+struct virtio_vsock_config {
+       __le64 guest_cid;
+} __attribute__((packed));
+
+enum virtio_vsock_event_id {
+       VIRTIO_VSOCK_EVENT_TRANSPORT_RESET = 0,
+};
+
+struct virtio_vsock_event {
+       __le32 id;
+} __attribute__((packed));
+
+struct virtio_vsock_hdr {
+       __le64  src_cid;
+       __le64  dst_cid;
+       __le32  src_port;
+       __le32  dst_port;
+       __le32  len;
+       __le16  type;           /* enum virtio_vsock_type */
+       __le16  op;             /* enum virtio_vsock_op */
+       __le32  flags;
+       __le32  buf_alloc;
+       __le32  fwd_cnt;
+} __attribute__((packed));
+
+enum virtio_vsock_type {
+       VIRTIO_VSOCK_TYPE_STREAM = 1,
+};
+
+enum virtio_vsock_op {
+       VIRTIO_VSOCK_OP_INVALID = 0,
+
+       /* Connect operations */
+       VIRTIO_VSOCK_OP_REQUEST = 1,
+       VIRTIO_VSOCK_OP_RESPONSE = 2,
+       VIRTIO_VSOCK_OP_RST = 3,
+       VIRTIO_VSOCK_OP_SHUTDOWN = 4,
+
+       /* To send payload */
+       VIRTIO_VSOCK_OP_RW = 5,
+
+       /* Tell the peer our credit info */
+       VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6,
+       /* Request the peer to send the credit info to us */
+       VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7,
+};
+
+/* VIRTIO_VSOCK_OP_SHUTDOWN flags values */
+enum virtio_vsock_shutdown {
+       VIRTIO_VSOCK_SHUTDOWN_RCV = 1,
+       VIRTIO_VSOCK_SHUTDOWN_SEND = 2,
+};
+
+#endif /* _UAPI_LINUX_VIRTIO_VSOCK_H */
index 231901b..4edb0f2 100644 (file)
@@ -6,3 +6,4 @@ header-y += ib_user_verbs.h
 header-y += rdma_netlink.h
 header-y += rdma_user_cm.h
 header-y += hfi/
+header-y += rdma_user_rxe.h
index 98bebf8..d15e728 100644 (file)
@@ -75,7 +75,7 @@
  * may not be implemented; the user code must deal with this if it
  * cares, or it must abort after initialization reports the difference.
  */
-#define HFI1_USER_SWMINOR 1
+#define HFI1_USER_SWMINOR 2
 
 /*
  * We will encode the major/minor inside a single 32bit version number.
index b6543d7..7f035f4 100644 (file)
@@ -95,6 +95,11 @@ enum {
        IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP,
        IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
        IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
+       IB_USER_VERBS_EX_CMD_CREATE_WQ,
+       IB_USER_VERBS_EX_CMD_MODIFY_WQ,
+       IB_USER_VERBS_EX_CMD_DESTROY_WQ,
+       IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL,
+       IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL
 };
 
 /*
@@ -518,6 +523,14 @@ struct ib_uverbs_create_qp {
        __u64 driver_data[0];
 };
 
+enum ib_uverbs_create_qp_mask {
+       IB_UVERBS_CREATE_QP_MASK_IND_TABLE = 1UL << 0,
+};
+
+enum {
+       IB_UVERBS_CREATE_QP_SUP_COMP_MASK = IB_UVERBS_CREATE_QP_MASK_IND_TABLE,
+};
+
 struct ib_uverbs_ex_create_qp {
        __u64 user_handle;
        __u32 pd_handle;
@@ -535,6 +548,8 @@ struct ib_uverbs_ex_create_qp {
        __u8 reserved;
        __u32 comp_mask;
        __u32 create_flags;
+       __u32 rwq_ind_tbl_handle;
+       __u32  reserved1;
 };
 
 struct ib_uverbs_open_qp {
@@ -852,6 +867,24 @@ struct ib_uverbs_flow_spec_tcp_udp {
        struct ib_uverbs_flow_tcp_udp_filter mask;
 };
 
+struct ib_uverbs_flow_ipv6_filter {
+       __u8 src_ip[16];
+       __u8 dst_ip[16];
+};
+
+struct ib_uverbs_flow_spec_ipv6 {
+       union {
+               struct ib_uverbs_flow_spec_hdr hdr;
+               struct {
+                       __u32 type;
+                       __u16 size;
+                       __u16 reserved;
+               };
+       };
+       struct ib_uverbs_flow_ipv6_filter val;
+       struct ib_uverbs_flow_ipv6_filter mask;
+};
+
 struct ib_uverbs_flow_attr {
        __u32 type;
        __u16 size;
@@ -946,4 +979,66 @@ struct ib_uverbs_destroy_srq_resp {
        __u32 events_reported;
 };
 
+struct ib_uverbs_ex_create_wq  {
+       __u32 comp_mask;
+       __u32 wq_type;
+       __u64 user_handle;
+       __u32 pd_handle;
+       __u32 cq_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+};
+
+struct ib_uverbs_ex_create_wq_resp {
+       __u32 comp_mask;
+       __u32 response_length;
+       __u32 wq_handle;
+       __u32 max_wr;
+       __u32 max_sge;
+       __u32 wqn;
+};
+
+struct ib_uverbs_ex_destroy_wq  {
+       __u32 comp_mask;
+       __u32 wq_handle;
+};
+
+struct ib_uverbs_ex_destroy_wq_resp {
+       __u32 comp_mask;
+       __u32 response_length;
+       __u32 events_reported;
+       __u32 reserved;
+};
+
+struct ib_uverbs_ex_modify_wq  {
+       __u32 attr_mask;
+       __u32 wq_handle;
+       __u32 wq_state;
+       __u32 curr_wq_state;
+};
+
+/* Prevent memory allocation rather than max expected size */
+#define IB_USER_VERBS_MAX_LOG_IND_TBL_SIZE 0x0d
+struct ib_uverbs_ex_create_rwq_ind_table  {
+       __u32 comp_mask;
+       __u32 log_ind_tbl_size;
+       /* Following are the wq handles according to log_ind_tbl_size
+        * wq_handle1
+        * wq_handle2
+        */
+       __u32 wq_handles[0];
+};
+
+struct ib_uverbs_ex_create_rwq_ind_table_resp {
+       __u32 comp_mask;
+       __u32 response_length;
+       __u32 ind_tbl_handle;
+       __u32 ind_tbl_num;
+};
+
+struct ib_uverbs_ex_destroy_rwq_ind_table  {
+       __u32 comp_mask;
+       __u32 ind_tbl_handle;
+};
+
 #endif /* IB_USER_VERBS_H */
index 3066718..01923d4 100644 (file)
@@ -244,12 +244,19 @@ struct rdma_ucm_join_ip_mcast {
        __u32 id;
 };
 
+/* Multicast join flags */
+enum {
+       RDMA_MC_JOIN_FLAG_FULLMEMBER,
+       RDMA_MC_JOIN_FLAG_SENDONLY_FULLMEMBER,
+       RDMA_MC_JOIN_FLAG_RESERVED,
+};
+
 struct rdma_ucm_join_mcast {
        __u64 response;         /* rdma_ucma_create_id_resp */
        __u64 uid;
        __u32 id;
        __u16 addr_size;
-       __u16 reserved;
+       __u16 join_flags;
        struct sockaddr_storage addr;
 };
 
diff --git a/include/uapi/rdma/rdma_user_rxe.h b/include/uapi/rdma/rdma_user_rxe.h
new file mode 100644 (file)
index 0000000..1de99cf
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies Ltd. 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 RDMA_USER_RXE_H
+#define RDMA_USER_RXE_H
+
+#include <linux/types.h>
+
+union rxe_gid {
+       __u8    raw[16];
+       struct {
+               __be64  subnet_prefix;
+               __be64  interface_id;
+       } global;
+};
+
+struct rxe_global_route {
+       union rxe_gid   dgid;
+       __u32           flow_label;
+       __u8            sgid_index;
+       __u8            hop_limit;
+       __u8            traffic_class;
+};
+
+struct rxe_av {
+       __u8                    port_num;
+       __u8                    network_type;
+       struct rxe_global_route grh;
+       union {
+               struct sockaddr         _sockaddr;
+               struct sockaddr_in      _sockaddr_in;
+               struct sockaddr_in6     _sockaddr_in6;
+       } sgid_addr, dgid_addr;
+};
+
+struct rxe_send_wr {
+       __u64                   wr_id;
+       __u32                   num_sge;
+       __u32                   opcode;
+       __u32                   send_flags;
+       union {
+               __be32          imm_data;
+               __u32           invalidate_rkey;
+       } ex;
+       union {
+               struct {
+                       __u64   remote_addr;
+                       __u32   rkey;
+               } rdma;
+               struct {
+                       __u64   remote_addr;
+                       __u64   compare_add;
+                       __u64   swap;
+                       __u32   rkey;
+               } atomic;
+               struct {
+                       __u32   remote_qpn;
+                       __u32   remote_qkey;
+                       __u16   pkey_index;
+               } ud;
+               struct {
+                       struct ib_mr *mr;
+                       __u32        key;
+                       int          access;
+               } reg;
+       } wr;
+};
+
+struct rxe_sge {
+       __u64   addr;
+       __u32   length;
+       __u32   lkey;
+};
+
+struct mminfo {
+       __u64                   offset;
+       __u32                   size;
+       __u32                   pad;
+};
+
+struct rxe_dma_info {
+       __u32                   length;
+       __u32                   resid;
+       __u32                   cur_sge;
+       __u32                   num_sge;
+       __u32                   sge_offset;
+       union {
+               __u8            inline_data[0];
+               struct rxe_sge  sge[0];
+       };
+};
+
+struct rxe_send_wqe {
+       struct rxe_send_wr      wr;
+       struct rxe_av           av;
+       __u32                   status;
+       __u32                   state;
+       __u64                   iova;
+       __u32                   mask;
+       __u32                   first_psn;
+       __u32                   last_psn;
+       __u32                   ack_length;
+       __u32                   ssn;
+       __u32                   has_rd_atomic;
+       struct rxe_dma_info     dma;
+};
+
+struct rxe_recv_wqe {
+       __u64                   wr_id;
+       __u32                   num_sge;
+       __u32                   padding;
+       struct rxe_dma_info     dma;
+};
+
+#endif /* RDMA_USER_RXE_H */
index 8b2eb93..7c35e27 100644 (file)
@@ -9,30 +9,30 @@ extern int xen_swiotlb_init(int verbose, bool early);
 extern void
 *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                            dma_addr_t *dma_handle, gfp_t flags,
-                           struct dma_attrs *attrs);
+                           unsigned long attrs);
 
 extern void
 xen_swiotlb_free_coherent(struct device *hwdev, size_t size,
                          void *vaddr, dma_addr_t dma_handle,
-                         struct dma_attrs *attrs);
+                         unsigned long attrs);
 
 extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
                                       unsigned long offset, size_t size,
                                       enum dma_data_direction dir,
-                                      struct dma_attrs *attrs);
+                                      unsigned long attrs);
 
 extern void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                                   size_t size, enum dma_data_direction dir,
-                                  struct dma_attrs *attrs);
+                                  unsigned long attrs);
 extern int
 xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                         int nelems, enum dma_data_direction dir,
-                        struct dma_attrs *attrs);
+                        unsigned long attrs);
 
 extern void
 xen_swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                           int nelems, enum dma_data_direction dir,
-                          struct dma_attrs *attrs);
+                          unsigned long attrs);
 
 extern void
 xen_swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
index 46f817a..cac3f09 100644 (file)
@@ -55,6 +55,7 @@ config CROSS_COMPILE
 
 config COMPILE_TEST
        bool "Compile also drivers which will not load"
+       depends on !UML
        default n
        help
          Some drivers can be compiled on a different platform than they are
@@ -80,6 +81,7 @@ config LOCALVERSION
 config LOCALVERSION_AUTO
        bool "Automatically append version information to the version string"
        default y
+       depends on !COMPILE_TEST
        help
          This will try to automatically determine if the current tree is a
          release tree by looking for git tags that belong to the current
@@ -952,7 +954,7 @@ menuconfig CGROUPS
          controls or device isolation.
          See
                - Documentation/scheduler/sched-design-CFS.txt  (CFS)
-               - Documentation/cgroups/ (features for grouping, isolation
+               - Documentation/cgroup-v1/ (features for grouping, isolation
                                          and resource control)
 
          Say N if unsure.
@@ -1009,7 +1011,7 @@ config BLK_CGROUP
        CONFIG_CFQ_GROUP_IOSCHED=y; for enabling throttling policy, set
        CONFIG_BLK_DEV_THROTTLING=y.
 
-       See Documentation/cgroups/blkio-controller.txt for more information.
+       See Documentation/cgroup-v1/blkio-controller.txt for more information.
 
 config DEBUG_BLK_CGROUP
        bool "IO controller debugging"
@@ -1759,6 +1761,7 @@ choice
 
 config SLAB
        bool "SLAB"
+       select HAVE_HARDENED_USERCOPY_ALLOCATOR
        help
          The regular slab allocator that is established and known to work
          well in all environments. It organizes cache hot objects in
@@ -1766,6 +1769,7 @@ config SLAB
 
 config SLUB
        bool "SLUB (Unqueued Allocator)"
+       select HAVE_HARDENED_USERCOPY_ALLOCATOR
        help
           SLUB is a slab allocator that minimizes cache line usage
           instead of managing queues of cached objects (SLAB approach).
@@ -2078,7 +2082,7 @@ config TRIM_UNUSED_KSYMS
          (especially when using LTO) for optimizing the code and reducing
          binary size.  This might have some security advantages as well.
 
-         If unsure say N.
+         If unsure, or if you need to build out-of-tree modules, say N.
 
 endif # MODULES
 
index eae02aa..a8a58e2 100644 (file)
@@ -380,7 +380,7 @@ static void __init setup_command_line(char *command_line)
 
 static __initdata DECLARE_COMPLETION(kthreadd_done);
 
-static noinline void __init_refok rest_init(void)
+static noinline void __ref rest_init(void)
 {
        int pid;
 
@@ -716,6 +716,12 @@ static bool __init_or_module initcall_blacklisted(initcall_t fn)
        addr = (unsigned long) dereference_function_descriptor(fn);
        sprint_symbol_no_offset(fn_name, addr);
 
+       /*
+        * fn will be "function_name [module_name]" where [module_name] is not
+        * displayed for built-in init functions.  Strip off the [module_name].
+        */
+       strreplace(fn_name, ' ', '\0');
+
        list_for_each_entry(entry, &blacklisted_initcalls, next) {
                if (!strcmp(fn_name, entry->buf)) {
                        pr_debug("initcall %s blacklisted\n", fn_name);
index 1471db9..c6521c2 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -680,7 +680,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                rcu_read_lock();
                ipc_lock_object(&msq->q_perm);
 
-               ipc_rcu_putref(msq, ipc_rcu_free);
+               ipc_rcu_putref(msq, msg_rcu_free);
                /* raced with RMID? */
                if (!ipc_valid_object(&msq->q_perm)) {
                        err = -EIDRM;
index ed81aaf..a521999 100644 (file)
@@ -37,8 +37,6 @@ struct ipc_namespace init_ipc_ns = {
 #endif
 };
 
-atomic_t nr_ipc_ns = ATOMIC_INIT(1);
-
 struct msg_msgseg {
        struct msg_msgseg *next;
        /* the next part of the message follows immediately */
index 04cb07e..d87e6ba 100644 (file)
@@ -43,7 +43,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
                kfree(ns);
                return ERR_PTR(err);
        }
-       atomic_inc(&nr_ipc_ns);
 
        sem_init_ns(ns);
        msg_init_ns(ns);
@@ -96,7 +95,6 @@ static void free_ipc_ns(struct ipc_namespace *ns)
        sem_exit_ns(ns);
        msg_exit_ns(ns);
        shm_exit_ns(ns);
-       atomic_dec(&nr_ipc_ns);
 
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
index ae72b3c..7c9d4f7 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -438,7 +438,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
        sem_lock(sma, NULL, -1);
-       ipc_rcu_putref(sma, ipc_rcu_free);
+       ipc_rcu_putref(sma, sem_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -1381,7 +1381,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        rcu_read_unlock();
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                return -ENOMEM;
                        }
 
@@ -1415,20 +1415,20 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                if (nsems > SEMMSL_FAST) {
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                return -ENOMEM;
                        }
                }
 
                if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
-                       ipc_rcu_putref(sma, ipc_rcu_free);
+                       ipc_rcu_putref(sma, sem_rcu_free);
                        err = -EFAULT;
                        goto out_free;
                }
 
                for (i = 0; i < nsems; i++) {
                        if (sem_io[i] > SEMVMX) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                err = -ERANGE;
                                goto out_free;
                        }
@@ -1720,7 +1720,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 2: allocate new undo structure */
        new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
        if (!new) {
-               ipc_rcu_putref(sma, ipc_rcu_free);
+               ipc_rcu_putref(sma, sem_rcu_free);
                return ERR_PTR(-ENOMEM);
        }
 
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
new file mode 100644 (file)
index 0000000..9f748ed
--- /dev/null
@@ -0,0 +1,152 @@
+#  KEEP ALPHABETICALLY SORTED
+# CONFIG_DEVKMEM is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_MODULES is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_SYSVIPC is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_ASHMEM=y
+CONFIG_AUDIT=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_EMBEDDED=y
+CONFIG_FB=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_INET=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IPV6=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_KEY=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_NAT=y
+CONFIG_NO_HZ=y
+CONFIG_PACKET=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PREEMPT=y
+CONFIG_QUOTA=y
+CONFIG_RTC_CLASS=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SETEND_EMULATION=y
+CONFIG_STAGING=y
+CONFIG_SWP_EMULATION=y
+CONFIG_SYNC=y
+CONFIG_TUN=y
+CONFIG_UNIX=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_OTG_WAKELOCK=y
+CONFIG_XFRM_USER=y
diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config
new file mode 100644 (file)
index 0000000..e3b953e
--- /dev/null
@@ -0,0 +1,121 @@
+#  KEEP ALPHABETICALLY SORTED
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_PM_WAKELOCKS_GC is not set
+# CONFIG_VT is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_COMPACTION=y
+CONFIG_DEBUG_RODATA=y
+CONFIG_DM_UEVENT=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HIDRAW=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_HOLTEK=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_ROCCAT=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_UCLOGIC=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_ION=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KSM=y
+CONFIG_LOGIG940_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGITECH_FF=y
+CONFIG_MD=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MSDOS_FS=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANTHERLORD_FF=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_POWER_SUPPLY=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_SND=y
+CONFIG_SOUND=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_TABLET_USB_ACECAD=y
+CONFIG_TABLET_USB_AIPTEK=y
+CONFIG_TABLET_USB_GTCO=y
+CONFIG_TABLET_USB_HANWANG=y
+CONFIG_TABLET_USB_KBTAB=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_TASK_XACCT=y
+CONFIG_TIMER_STATS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UHID=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_USBNET=y
+CONFIG_VFAT_FS=y
index 356a6c7..a19550d 100644 (file)
@@ -448,7 +448,7 @@ static u64 __report_allowed;
 
 static void perf_duration_warn(struct irq_work *w)
 {
-       printk_ratelimited(KERN_WARNING
+       printk_ratelimited(KERN_INFO
                "perf: interrupt took too long (%lld > %lld), lowering "
                "kernel.perf_event_max_sample_rate to %d\n",
                __report_avg, __report_allowed,
index 84ae830..2f974ae 100644 (file)
@@ -715,7 +715,7 @@ static void check_stack_usage(void)
 
        spin_lock(&low_water_lock);
        if (free < lowest_to_date) {
-               pr_warn("%s (%d) used greatest stack depth: %lu bytes left\n",
+               pr_info("%s (%d) used greatest stack depth: %lu bytes left\n",
                        current->comm, task_pid_nr(current), free);
                lowest_to_date = free;
        }
index 0dbea88..93ad6c1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/err.h>
 #include <linux/static_key.h>
 #include <linux/jump_label_ratelimit.h>
+#include <linux/bug.h>
 
 #ifdef HAVE_JUMP_LABEL
 
@@ -56,6 +57,49 @@ jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop)
 
 static void jump_label_update(struct static_key *key);
 
+/*
+ * There are similar definitions for the !HAVE_JUMP_LABEL case in jump_label.h.
+ * The use of 'atomic_read()' requires atomic.h and its problematic for some
+ * kernel headers such as kernel.h and others. Since static_key_count() is not
+ * used in the branch statements as it is for the !HAVE_JUMP_LABEL case its ok
+ * to have it be a function here. Similarly, for 'static_key_enable()' and
+ * 'static_key_disable()', which require bug.h. This should allow jump_label.h
+ * to be included from most/all places for HAVE_JUMP_LABEL.
+ */
+int static_key_count(struct static_key *key)
+{
+       /*
+        * -1 means the first static_key_slow_inc() is in progress.
+        *  static_key_enabled() must return true, so return 1 here.
+        */
+       int n = atomic_read(&key->enabled);
+
+       return n >= 0 ? n : 1;
+}
+EXPORT_SYMBOL_GPL(static_key_count);
+
+void static_key_enable(struct static_key *key)
+{
+       int count = static_key_count(key);
+
+       WARN_ON_ONCE(count < 0 || count > 1);
+
+       if (!count)
+               static_key_slow_inc(key);
+}
+EXPORT_SYMBOL_GPL(static_key_enable);
+
+void static_key_disable(struct static_key *key)
+{
+       int count = static_key_count(key);
+
+       WARN_ON_ONCE(count < 0 || count > 1);
+
+       if (count)
+               static_key_slow_dec(key);
+}
+EXPORT_SYMBOL_GPL(static_key_disable);
+
 void static_key_slow_inc(struct static_key *key)
 {
        int v, v1;
@@ -235,6 +279,18 @@ void __init jump_label_init(void)
        struct static_key *key = NULL;
        struct jump_entry *iter;
 
+       /*
+        * Since we are initializing the static_key.enabled field with
+        * with the 'raw' int values (to avoid pulling in atomic.h) in
+        * jump_label.h, let's make sure that is safe. There are only two
+        * cases to check since we initialize to 0 or 1.
+        */
+       BUILD_BUG_ON((int)ATOMIC_INIT(0) != 0);
+       BUILD_BUG_ON((int)ATOMIC_INIT(1) != 1);
+
+       if (static_key_initialized)
+               return;
+
        jump_label_lock();
        jump_label_sort_entries(iter_start, iter_stop);
 
@@ -284,11 +340,14 @@ static int __jump_label_mod_text_reserved(void *start, void *end)
 {
        struct module *mod;
 
+       preempt_disable();
        mod = __module_text_address((unsigned long)start);
+       WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
+       preempt_enable();
+
        if (!mod)
                return 0;
 
-       WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
 
        return __jump_label_text_reserved(mod->jump_entries,
                                mod->jump_entries + mod->num_jump_entries,
index 4384672..980936a 100644 (file)
@@ -48,7 +48,8 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
 
        if (kexec_on_panic) {
                /* Verify we have a valid entry point */
-               if ((entry < crashk_res.start) || (entry > crashk_res.end))
+               if ((entry < phys_to_boot_phys(crashk_res.start)) ||
+                   (entry > phys_to_boot_phys(crashk_res.end)))
                        return -EADDRNOTAVAIL;
        }
 
index 56b3ed0..5616755 100644 (file)
@@ -95,6 +95,12 @@ int kexec_should_crash(struct task_struct *p)
        return 0;
 }
 
+int kexec_crash_loaded(void)
+{
+       return !!kexec_crash_image;
+}
+EXPORT_SYMBOL_GPL(kexec_crash_loaded);
+
 /*
  * When kexec transitions to the new kernel there is a one-to-one
  * mapping between physical and virtual addresses.  On processors
@@ -140,6 +146,7 @@ int kexec_should_crash(struct task_struct *p)
  * allocating pages whose destination address we do not care about.
  */
 #define KIMAGE_NO_DEST (-1UL)
+#define PAGE_COUNT(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
 
 static struct page *kimage_alloc_page(struct kimage *image,
                                       gfp_t gfp_mask,
@@ -147,8 +154,9 @@ static struct page *kimage_alloc_page(struct kimage *image,
 
 int sanity_check_segment_list(struct kimage *image)
 {
-       int result, i;
+       int i;
        unsigned long nr_segments = image->nr_segments;
+       unsigned long total_pages = 0;
 
        /*
         * Verify we have good destination addresses.  The caller is
@@ -163,16 +171,17 @@ int sanity_check_segment_list(struct kimage *image)
         * simply because addresses are changed to page size
         * granularity.
         */
-       result = -EADDRNOTAVAIL;
        for (i = 0; i < nr_segments; i++) {
                unsigned long mstart, mend;
 
                mstart = image->segment[i].mem;
                mend   = mstart + image->segment[i].memsz;
+               if (mstart > mend)
+                       return -EADDRNOTAVAIL;
                if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK))
-                       return result;
+                       return -EADDRNOTAVAIL;
                if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
-                       return result;
+                       return -EADDRNOTAVAIL;
        }
 
        /* Verify our destination addresses do not overlap.
@@ -180,7 +189,6 @@ int sanity_check_segment_list(struct kimage *image)
         * through very weird things can happen with no
         * easy explanation as one segment stops on another.
         */
-       result = -EINVAL;
        for (i = 0; i < nr_segments; i++) {
                unsigned long mstart, mend;
                unsigned long j;
@@ -194,7 +202,7 @@ int sanity_check_segment_list(struct kimage *image)
                        pend   = pstart + image->segment[j].memsz;
                        /* Do the segments overlap ? */
                        if ((mend > pstart) && (mstart < pend))
-                               return result;
+                               return -EINVAL;
                }
        }
 
@@ -203,12 +211,26 @@ int sanity_check_segment_list(struct kimage *image)
         * and it is easier to check up front than to be surprised
         * later on.
         */
-       result = -EINVAL;
        for (i = 0; i < nr_segments; i++) {
                if (image->segment[i].bufsz > image->segment[i].memsz)
-                       return result;
+                       return -EINVAL;
+       }
+
+       /*
+        * Verify that no more than half of memory will be consumed. If the
+        * request from userspace is too large, a large amount of time will be
+        * wasted allocating pages, which can cause a soft lockup.
+        */
+       for (i = 0; i < nr_segments; i++) {
+               if (PAGE_COUNT(image->segment[i].memsz) > totalram_pages / 2)
+                       return -EINVAL;
+
+               total_pages += PAGE_COUNT(image->segment[i].memsz);
        }
 
+       if (total_pages > totalram_pages / 2)
+               return -EINVAL;
+
        /*
         * Verify we have good destination addresses.  Normally
         * the caller is responsible for making certain we don't
@@ -220,16 +242,15 @@ int sanity_check_segment_list(struct kimage *image)
         */
 
        if (image->type == KEXEC_TYPE_CRASH) {
-               result = -EADDRNOTAVAIL;
                for (i = 0; i < nr_segments; i++) {
                        unsigned long mstart, mend;
 
                        mstart = image->segment[i].mem;
                        mend = mstart + image->segment[i].memsz - 1;
                        /* Ensure we are within the crash kernel limits */
-                       if ((mstart < crashk_res.start) ||
-                           (mend > crashk_res.end))
-                               return result;
+                       if ((mstart < phys_to_boot_phys(crashk_res.start)) ||
+                           (mend > phys_to_boot_phys(crashk_res.end)))
+                               return -EADDRNOTAVAIL;
                }
        }
 
@@ -352,7 +373,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
                pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order);
                if (!pages)
                        break;
-               pfn   = page_to_pfn(pages);
+               pfn   = page_to_boot_pfn(pages);
                epfn  = pfn + count;
                addr  = pfn << PAGE_SHIFT;
                eaddr = epfn << PAGE_SHIFT;
@@ -478,7 +499,7 @@ static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
                        return -ENOMEM;
 
                ind_page = page_address(page);
-               *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
+               *image->entry = virt_to_boot_phys(ind_page) | IND_INDIRECTION;
                image->entry = ind_page;
                image->last_entry = ind_page +
                                      ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
@@ -533,13 +554,13 @@ void kimage_terminate(struct kimage *image)
 #define for_each_kimage_entry(image, ptr, entry) \
        for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
                ptr = (entry & IND_INDIRECTION) ? \
-                       phys_to_virt((entry & PAGE_MASK)) : ptr + 1)
+                       boot_phys_to_virt((entry & PAGE_MASK)) : ptr + 1)
 
 static void kimage_free_entry(kimage_entry_t entry)
 {
        struct page *page;
 
-       page = pfn_to_page(entry >> PAGE_SHIFT);
+       page = boot_pfn_to_page(entry >> PAGE_SHIFT);
        kimage_free_pages(page);
 }
 
@@ -633,7 +654,7 @@ static struct page *kimage_alloc_page(struct kimage *image,
         * have a match.
         */
        list_for_each_entry(page, &image->dest_pages, lru) {
-               addr = page_to_pfn(page) << PAGE_SHIFT;
+               addr = page_to_boot_pfn(page) << PAGE_SHIFT;
                if (addr == destination) {
                        list_del(&page->lru);
                        return page;
@@ -648,12 +669,12 @@ static struct page *kimage_alloc_page(struct kimage *image,
                if (!page)
                        return NULL;
                /* If the page cannot be used file it away */
-               if (page_to_pfn(page) >
+               if (page_to_boot_pfn(page) >
                                (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
                        list_add(&page->lru, &image->unusable_pages);
                        continue;
                }
-               addr = page_to_pfn(page) << PAGE_SHIFT;
+               addr = page_to_boot_pfn(page) << PAGE_SHIFT;
 
                /* If it is the destination page we want use it */
                if (addr == destination)
@@ -676,7 +697,7 @@ static struct page *kimage_alloc_page(struct kimage *image,
                        struct page *old_page;
 
                        old_addr = *old & PAGE_MASK;
-                       old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
+                       old_page = boot_pfn_to_page(old_addr >> PAGE_SHIFT);
                        copy_highpage(page, old_page);
                        *old = addr | (*old & ~PAGE_MASK);
 
@@ -732,7 +753,7 @@ static int kimage_load_normal_segment(struct kimage *image,
                        result  = -ENOMEM;
                        goto out;
                }
-               result = kimage_add_page(image, page_to_pfn(page)
+               result = kimage_add_page(image, page_to_boot_pfn(page)
                                                                << PAGE_SHIFT);
                if (result < 0)
                        goto out;
@@ -793,7 +814,7 @@ static int kimage_load_crash_segment(struct kimage *image,
                char *ptr;
                size_t uchunk, mchunk;
 
-               page = pfn_to_page(maddr >> PAGE_SHIFT);
+               page = boot_pfn_to_page(maddr >> PAGE_SHIFT);
                if (!page) {
                        result  = -ENOMEM;
                        goto out;
@@ -921,7 +942,7 @@ void __weak crash_free_reserved_phys_range(unsigned long begin,
        unsigned long addr;
 
        for (addr = begin; addr < end; addr += PAGE_SIZE)
-               free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
+               free_reserved_page(boot_pfn_to_page(addr >> PAGE_SHIFT));
 }
 
 int crash_shrink_memory(unsigned long new_size)
@@ -1374,7 +1395,7 @@ void vmcoreinfo_append_str(const char *fmt, ...)
 void __weak arch_crash_save_vmcoreinfo(void)
 {}
 
-unsigned long __weak paddr_vmcoreinfo_note(void)
+phys_addr_t __weak paddr_vmcoreinfo_note(void)
 {
        return __pa((unsigned long)(char *)&vmcoreinfo_note);
 }
index 152da4a..ee1bc1b 100644 (file)
@@ -101,7 +101,7 @@ KERNEL_ATTR_RO(kexec_loaded);
 static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
                                       struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", !!kexec_crash_image);
+       return sprintf(buf, "%d\n", kexec_crash_loaded());
 }
 KERNEL_ATTR_RO(kexec_crash_loaded);
 
@@ -128,8 +128,8 @@ KERNEL_ATTR_RW(kexec_crash_size);
 static ssize_t vmcoreinfo_show(struct kobject *kobj,
                               struct kobj_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%lx %x\n",
-                      paddr_vmcoreinfo_note(),
+       phys_addr_t vmcore_base = paddr_vmcoreinfo_note();
+       return sprintf(buf, "%pa %x\n", &vmcore_base,
                       (unsigned int)sizeof(vmcoreinfo_note));
 }
 KERNEL_ATTR_RO(vmcoreinfo);
index 5c2bc10..8bbe507 100644 (file)
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod,
                        break;
        }
 
-       module_enable_ro(pmod);
+       module_enable_ro(pmod, true);
        return ret;
 }
 
index 5f71aa6..529efae 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
+#include <linux/dynamic_debug.h>
 #include <uapi/linux/module.h>
 #include "module-internal.h"
 
@@ -264,7 +265,7 @@ static void module_assert_mutex_or_preempt(void)
        if (unlikely(!debug_locks))
                return;
 
-       WARN_ON(!rcu_read_lock_sched_held() &&
+       WARN_ON_ONCE(!rcu_read_lock_sched_held() &&
                !lockdep_is_held(&module_mutex));
 #endif
 }
@@ -336,7 +337,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag,
  * A thread that wants to hold a reference to a module only while it
  * is running can call this to safely exit.  nfsd and lockd use this.
  */
-void __module_put_and_exit(struct module *mod, long code)
+void __noreturn __module_put_and_exit(struct module *mod, long code)
 {
        module_put(mod);
        do_exit(code);
@@ -1693,8 +1694,7 @@ static int module_add_modinfo_attrs(struct module *mod)
 
        temp_attr = mod->modinfo_attrs;
        for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
-               if (!attr->test ||
-                   (attr->test && attr->test(mod))) {
+               if (!attr->test || attr->test(mod)) {
                        memcpy(temp_attr, attr, sizeof(*temp_attr));
                        sysfs_attr_init(&temp_attr->attr);
                        error = sysfs_create_file(&mod->mkobj.kobj,
@@ -1858,10 +1858,11 @@ static void mod_sysfs_teardown(struct module *mod)
  * from modification and any data from execution.
  *
  * General layout of module is:
- *          [text] [read-only-data] [writable data]
- * text_size -----^                ^               ^
- * ro_size ------------------------|               |
- * size -------------------------------------------|
+ *          [text] [read-only-data] [ro-after-init] [writable data]
+ * text_size -----^                ^               ^               ^
+ * ro_size ------------------------|               |               |
+ * ro_after_init_size -----------------------------|               |
+ * size -----------------------------------------------------------|
  *
  * These values are always page-aligned (as is base)
  */
@@ -1884,14 +1885,24 @@ static void frob_rodata(const struct module_layout *layout,
                   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
 }
 
+static void frob_ro_after_init(const struct module_layout *layout,
+                               int (*set_memory)(unsigned long start, int num_pages))
+{
+       BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
+       BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+       BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
+       set_memory((unsigned long)layout->base + layout->ro_size,
+                  (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
+}
+
 static void frob_writable_data(const struct module_layout *layout,
                               int (*set_memory)(unsigned long start, int num_pages))
 {
        BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-       BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
+       BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
        BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
-       set_memory((unsigned long)layout->base + layout->ro_size,
-                  (layout->size - layout->ro_size) >> PAGE_SHIFT);
+       set_memory((unsigned long)layout->base + layout->ro_after_init_size,
+                  (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
 }
 
 /* livepatching wants to disable read-only so it can frob module. */
@@ -1899,21 +1910,26 @@ void module_disable_ro(const struct module *mod)
 {
        frob_text(&mod->core_layout, set_memory_rw);
        frob_rodata(&mod->core_layout, set_memory_rw);
+       frob_ro_after_init(&mod->core_layout, set_memory_rw);
        frob_text(&mod->init_layout, set_memory_rw);
        frob_rodata(&mod->init_layout, set_memory_rw);
 }
 
-void module_enable_ro(const struct module *mod)
+void module_enable_ro(const struct module *mod, bool after_init)
 {
        frob_text(&mod->core_layout, set_memory_ro);
        frob_rodata(&mod->core_layout, set_memory_ro);
        frob_text(&mod->init_layout, set_memory_ro);
        frob_rodata(&mod->init_layout, set_memory_ro);
+
+       if (after_init)
+               frob_ro_after_init(&mod->core_layout, set_memory_ro);
 }
 
 static void module_enable_nx(const struct module *mod)
 {
        frob_rodata(&mod->core_layout, set_memory_nx);
+       frob_ro_after_init(&mod->core_layout, set_memory_nx);
        frob_writable_data(&mod->core_layout, set_memory_nx);
        frob_rodata(&mod->init_layout, set_memory_nx);
        frob_writable_data(&mod->init_layout, set_memory_nx);
@@ -1922,6 +1938,7 @@ static void module_enable_nx(const struct module *mod)
 static void module_disable_nx(const struct module *mod)
 {
        frob_rodata(&mod->core_layout, set_memory_x);
+       frob_ro_after_init(&mod->core_layout, set_memory_x);
        frob_writable_data(&mod->core_layout, set_memory_x);
        frob_rodata(&mod->init_layout, set_memory_x);
        frob_writable_data(&mod->init_layout, set_memory_x);
@@ -1964,6 +1981,8 @@ static void disable_ro_nx(const struct module_layout *layout)
        frob_text(layout, set_memory_rw);
        frob_rodata(layout, set_memory_rw);
        frob_rodata(layout, set_memory_x);
+       frob_ro_after_init(layout, set_memory_rw);
+       frob_ro_after_init(layout, set_memory_x);
        frob_writable_data(layout, set_memory_x);
 }
 
@@ -2306,6 +2325,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
                 * finder in the two loops below */
                { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
                { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
+               { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL },
                { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
                { ARCH_SHF_SMALL | SHF_ALLOC, 0 }
        };
@@ -2337,7 +2357,11 @@ static void layout_sections(struct module *mod, struct load_info *info)
                        mod->core_layout.size = debug_align(mod->core_layout.size);
                        mod->core_layout.ro_size = mod->core_layout.size;
                        break;
-               case 3: /* whole core */
+               case 2: /* RO after init */
+                       mod->core_layout.size = debug_align(mod->core_layout.size);
+                       mod->core_layout.ro_after_init_size = mod->core_layout.size;
+                       break;
+               case 4: /* whole core */
                        mod->core_layout.size = debug_align(mod->core_layout.size);
                        break;
                }
@@ -2367,7 +2391,14 @@ static void layout_sections(struct module *mod, struct load_info *info)
                        mod->init_layout.size = debug_align(mod->init_layout.size);
                        mod->init_layout.ro_size = mod->init_layout.size;
                        break;
-               case 3: /* whole init */
+               case 2:
+                       /*
+                        * RO after init doesn't apply to init_layout (only
+                        * core_layout), so it just takes the value of ro_size.
+                        */
+                       mod->init_layout.ro_after_init_size = mod->init_layout.ro_size;
+                       break;
+               case 4: /* whole init */
                        mod->init_layout.size = debug_align(mod->init_layout.size);
                        break;
                }
@@ -2687,13 +2718,18 @@ static inline void kmemleak_load_module(const struct module *mod,
 #endif
 
 #ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
        int err = -ENOKEY;
        const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
        const void *mod = info->hdr;
 
-       if (info->len > markerlen &&
+       /*
+        * Require flags == 0, as a module with version information
+        * removed is no longer the module that was signed
+        */
+       if (flags == 0 &&
+           info->len > markerlen &&
            memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
                /* We truncate the module to discard the signature */
                info->len -= markerlen;
@@ -2712,7 +2748,7 @@ static int module_sig_check(struct load_info *info)
        return err;
 }
 #else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
        return 0;
 }
@@ -2920,8 +2956,12 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
                return -ENOEXEC;
        }
 
-       if (!get_modinfo(info, "intree"))
+       if (!get_modinfo(info, "intree")) {
+               if (!test_taint(TAINT_OOT_MODULE))
+                       pr_warn("%s: loading out-of-tree module taints kernel.\n",
+                               mod->name);
                add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
+       }
 
        if (get_modinfo(info, "staging")) {
                add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
@@ -3090,6 +3130,8 @@ static int move_module(struct module *mod, struct load_info *info)
 
 static int check_module_license_and_versions(struct module *mod)
 {
+       int prev_taint = test_taint(TAINT_PROPRIETARY_MODULE);
+
        /*
         * ndiswrapper is under GPL by itself, but loads proprietary modules.
         * Don't use add_taint_module(), as it would prevent ndiswrapper from
@@ -3108,6 +3150,9 @@ static int check_module_license_and_versions(struct module *mod)
                add_taint_module(mod, TAINT_PROPRIETARY_MODULE,
                                 LOCKDEP_NOW_UNRELIABLE);
 
+       if (!prev_taint && test_taint(TAINT_PROPRIETARY_MODULE))
+               pr_warn("%s: module license taints kernel.\n", mod->name);
+
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !mod->crcs)
            || (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -3155,16 +3200,41 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
        return 0;
 }
 
+/* module_blacklist is a comma-separated list of module names */
+static char *module_blacklist;
+static bool blacklisted(char *module_name)
+{
+       const char *p;
+       size_t len;
+
+       if (!module_blacklist)
+               return false;
+
+       for (p = module_blacklist; *p; p += len) {
+               len = strcspn(p, ",");
+               if (strlen(module_name) == len && !memcmp(module_name, p, len))
+                       return true;
+               if (p[len] == ',')
+                       len++;
+       }
+       return false;
+}
+core_param(module_blacklist, module_blacklist, charp, 0400);
+
 static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
+       unsigned int ndx;
        int err;
 
        mod = setup_load_info(info, flags);
        if (IS_ERR(mod))
                return mod;
 
+       if (blacklisted(mod->name))
+               return ERR_PTR(-EPERM);
+
        err = check_modinfo(mod, info, flags);
        if (err)
                return ERR_PTR(err);
@@ -3178,6 +3248,15 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        /* We will do a special allocation for per-cpu sections later. */
        info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
 
+       /*
+        * Mark ro_after_init section with SHF_RO_AFTER_INIT so that
+        * layout_sections() can put it in the right place.
+        * Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set.
+        */
+       ndx = find_sec(info, ".data..ro_after_init");
+       if (ndx)
+               info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
+
        /* Determine total sizes, and put offsets in sh_entsize.  For now
           this is done generically; there doesn't appear to be any
           special cases for the architectures. */
@@ -3344,12 +3423,14 @@ static noinline int do_init_module(struct module *mod)
        /* Switch to core kallsyms now init is done: kallsyms may be walking! */
        rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 #endif
+       module_enable_ro(mod, true);
        mod_tree_remove_init(mod);
        disable_ro_nx(&mod->init_layout);
        module_arch_freeing_init(mod);
        mod->init_layout.base = NULL;
        mod->init_layout.size = 0;
        mod->init_layout.ro_size = 0;
+       mod->init_layout.ro_after_init_size = 0;
        mod->init_layout.text_size = 0;
        /*
         * We want to free module_init, but be aware that kallsyms may be
@@ -3441,8 +3522,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
        /* This relies on module_mutex for list integrity. */
        module_bug_finalize(info->hdr, info->sechdrs, mod);
 
-       /* Set RO and NX regions */
-       module_enable_ro(mod);
+       module_enable_ro(mod, false);
        module_enable_nx(mod);
 
        /* Mark state as coming so strong_try_module_get() ignores us,
@@ -3498,7 +3578,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
        long err;
        char *after_dashes;
 
-       err = module_sig_check(info);
+       err = module_sig_check(info, flags);
        if (err)
                goto free_copy;
 
index 8aa7449..ca8cea1 100644 (file)
@@ -108,6 +108,7 @@ void panic(const char *fmt, ...)
        long i, i_next = 0;
        int state = 0;
        int old_cpu, this_cpu;
+       bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;
 
        /*
         * Disable local interrupts. This will prevent panic_smp_self_stop
@@ -160,7 +161,7 @@ void panic(const char *fmt, ...)
         *
         * Bypass the panic_cpu check and call __crash_kexec directly.
         */
-       if (!crash_kexec_post_notifiers) {
+       if (!_crash_kexec_post_notifiers) {
                printk_nmi_flush_on_panic();
                __crash_kexec(NULL);
        }
@@ -191,7 +192,7 @@ void panic(const char *fmt, ...)
         *
         * Bypass the panic_cpu check and call __crash_kexec directly.
         */
-       if (crash_kexec_post_notifiers)
+       if (_crash_kexec_post_notifiers)
                __crash_kexec(NULL);
 
        bust_spinlocks(0);
@@ -571,13 +572,7 @@ EXPORT_SYMBOL(__stack_chk_fail);
 core_param(panic, panic_timeout, int, 0644);
 core_param(pause_on_oops, pause_on_oops, int, 0644);
 core_param(panic_on_warn, panic_on_warn, int, 0644);
-
-static int __init setup_crash_kexec_post_notifiers(char *s)
-{
-       crash_kexec_post_notifiers = true;
-       return 0;
-}
-early_param("crash_kexec_post_notifiers", setup_crash_kexec_post_notifiers);
+core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
 
 static int __init oops_setup(char *s)
 {
index d4de339..eea6dbc 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/nmi.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/interrupt.h>                   /* For in_interrupt() */
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/security.h>
@@ -48,7 +47,7 @@
 #include <linux/uio.h>
 
 #include <asm/uaccess.h>
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
@@ -86,6 +85,111 @@ static struct lockdep_map console_lock_dep_map = {
 };
 #endif
 
+enum devkmsg_log_bits {
+       __DEVKMSG_LOG_BIT_ON = 0,
+       __DEVKMSG_LOG_BIT_OFF,
+       __DEVKMSG_LOG_BIT_LOCK,
+};
+
+enum devkmsg_log_masks {
+       DEVKMSG_LOG_MASK_ON             = BIT(__DEVKMSG_LOG_BIT_ON),
+       DEVKMSG_LOG_MASK_OFF            = BIT(__DEVKMSG_LOG_BIT_OFF),
+       DEVKMSG_LOG_MASK_LOCK           = BIT(__DEVKMSG_LOG_BIT_LOCK),
+};
+
+/* Keep both the 'on' and 'off' bits clear, i.e. ratelimit by default: */
+#define DEVKMSG_LOG_MASK_DEFAULT       0
+
+static unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT;
+
+static int __control_devkmsg(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       if (!strncmp(str, "on", 2)) {
+               devkmsg_log = DEVKMSG_LOG_MASK_ON;
+               return 2;
+       } else if (!strncmp(str, "off", 3)) {
+               devkmsg_log = DEVKMSG_LOG_MASK_OFF;
+               return 3;
+       } else if (!strncmp(str, "ratelimit", 9)) {
+               devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT;
+               return 9;
+       }
+       return -EINVAL;
+}
+
+static int __init control_devkmsg(char *str)
+{
+       if (__control_devkmsg(str) < 0)
+               return 1;
+
+       /*
+        * Set sysctl string accordingly:
+        */
+       if (devkmsg_log == DEVKMSG_LOG_MASK_ON) {
+               memset(devkmsg_log_str, 0, DEVKMSG_STR_MAX_SIZE);
+               strncpy(devkmsg_log_str, "on", 2);
+       } else if (devkmsg_log == DEVKMSG_LOG_MASK_OFF) {
+               memset(devkmsg_log_str, 0, DEVKMSG_STR_MAX_SIZE);
+               strncpy(devkmsg_log_str, "off", 3);
+       }
+       /* else "ratelimit" which is set by default. */
+
+       /*
+        * Sysctl cannot change it anymore. The kernel command line setting of
+        * this parameter is to force the setting to be permanent throughout the
+        * runtime of the system. This is a precation measure against userspace
+        * trying to be a smarta** and attempting to change it up on us.
+        */
+       devkmsg_log |= DEVKMSG_LOG_MASK_LOCK;
+
+       return 0;
+}
+__setup("printk.devkmsg=", control_devkmsg);
+
+char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE] = "ratelimit";
+
+int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
+                             void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       char old_str[DEVKMSG_STR_MAX_SIZE];
+       unsigned int old;
+       int err;
+
+       if (write) {
+               if (devkmsg_log & DEVKMSG_LOG_MASK_LOCK)
+                       return -EINVAL;
+
+               old = devkmsg_log;
+               strncpy(old_str, devkmsg_log_str, DEVKMSG_STR_MAX_SIZE);
+       }
+
+       err = proc_dostring(table, write, buffer, lenp, ppos);
+       if (err)
+               return err;
+
+       if (write) {
+               err = __control_devkmsg(devkmsg_log_str);
+
+               /*
+                * Do not accept an unknown string OR a known string with
+                * trailing crap...
+                */
+               if (err < 0 || (err + 1 != *lenp)) {
+
+                       /* ... and restore old setting. */
+                       devkmsg_log = old;
+                       strncpy(devkmsg_log_str, old_str, DEVKMSG_STR_MAX_SIZE);
+
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Number of registered extended console drivers.
  *
@@ -614,6 +718,7 @@ struct devkmsg_user {
        u64 seq;
        u32 idx;
        enum log_flags prev;
+       struct ratelimit_state rs;
        struct mutex lock;
        char buf[CONSOLE_EXT_LOG_MAX];
 };
@@ -623,11 +728,24 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
        char *buf, *line;
        int level = default_message_loglevel;
        int facility = 1;       /* LOG_USER */
+       struct file *file = iocb->ki_filp;
+       struct devkmsg_user *user = file->private_data;
        size_t len = iov_iter_count(from);
        ssize_t ret = len;
 
-       if (len > LOG_LINE_MAX)
+       if (!user || len > LOG_LINE_MAX)
                return -EINVAL;
+
+       /* Ignore when user logging is disabled. */
+       if (devkmsg_log & DEVKMSG_LOG_MASK_OFF)
+               return len;
+
+       /* Ratelimit when not explicitly enabled. */
+       if (!(devkmsg_log & DEVKMSG_LOG_MASK_ON)) {
+               if (!___ratelimit(&user->rs, current->comm))
+                       return ret;
+       }
+
        buf = kmalloc(len+1, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
@@ -800,19 +918,24 @@ static int devkmsg_open(struct inode *inode, struct file *file)
        struct devkmsg_user *user;
        int err;
 
-       /* write-only does not need any file context */
-       if ((file->f_flags & O_ACCMODE) == O_WRONLY)
-               return 0;
+       if (devkmsg_log & DEVKMSG_LOG_MASK_OFF)
+               return -EPERM;
 
-       err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
-                                      SYSLOG_FROM_READER);
-       if (err)
-               return err;
+       /* write-only does not need any file context */
+       if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+               err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+                                              SYSLOG_FROM_READER);
+               if (err)
+                       return err;
+       }
 
        user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
        if (!user)
                return -ENOMEM;
 
+       ratelimit_default_init(&user->rs);
+       ratelimit_set_flags(&user->rs, RATELIMIT_MSG_ON_RELEASE);
+
        mutex_init(&user->lock);
 
        raw_spin_lock_irq(&logbuf_lock);
@@ -831,6 +954,8 @@ static int devkmsg_release(struct inode *inode, struct file *file)
        if (!user)
                return 0;
 
+       ratelimit_state_exit(&user->rs);
+
        mutex_destroy(&user->lock);
        kfree(user);
        return 0;
@@ -986,6 +1111,11 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
                 "ignore loglevel setting (prints all kernel messages to the console)");
 
+static bool suppress_message_printing(int level)
+{
+       return (level >= console_loglevel && !ignore_loglevel);
+}
+
 #ifdef CONFIG_BOOT_PRINTK_DELAY
 
 static int boot_delay; /* msecs delay after each printk during bootup */
@@ -1015,7 +1145,7 @@ static void boot_delay_msec(int level)
        unsigned long timeout;
 
        if ((boot_delay == 0 || system_state != SYSTEM_BOOTING)
-               || (level >= console_loglevel && !ignore_loglevel)) {
+               || suppress_message_printing(level)) {
                return;
        }
 
@@ -1439,8 +1569,6 @@ static void call_console_drivers(int level,
 
        trace_console(text, len);
 
-       if (level >= console_loglevel && !ignore_loglevel)
-               return;
        if (!console_drivers)
                return;
 
@@ -1888,6 +2016,7 @@ static void call_console_drivers(int level,
 static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
+static bool suppress_message_printing(int level) { return false; }
 
 /* Still needs to be defined for users */
 DEFINE_PER_CPU(printk_func_t, printk_func);
@@ -2167,6 +2296,13 @@ static void console_cont_flush(char *text, size_t size)
        if (!cont.len)
                goto out;
 
+       if (suppress_message_printing(cont.level)) {
+               cont.cons = cont.len;
+               if (cont.flushed)
+                       cont.len = 0;
+               goto out;
+       }
+
        /*
         * We still queue earlier records, likely because the console was
         * busy. The earlier ones need to be printed before this one, we
@@ -2270,10 +2406,13 @@ skip:
                        break;
 
                msg = log_from_idx(console_idx);
-               if (msg->flags & LOG_NOCONS) {
+               level = msg->level;
+               if ((msg->flags & LOG_NOCONS) ||
+                               suppress_message_printing(level)) {
                        /*
                         * Skip record we have buffered and already printed
-                        * directly to the console when we received it.
+                        * directly to the console when we received it, and
+                        * record that has level above the console loglevel.
                         */
                        console_idx = log_next(console_idx);
                        console_seq++;
@@ -2287,7 +2426,6 @@ skip:
                        goto skip;
                }
 
-               level = msg->level;
                len += msg_print_text(msg, console_prev, false,
                                      text + len, sizeof(text) - len);
                if (nr_ext_console_drivers) {
index d49bfa1..1d3b766 100644 (file)
@@ -585,8 +585,8 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
                return -EINVAL;
 
        if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
-               if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) ||
-                   !config_enabled(CONFIG_SECCOMP))
+               if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) ||
+                   !IS_ENABLED(CONFIG_SECCOMP))
                        return -EINVAL;
 
                if (!capable(CAP_SYS_ADMIN))
index 04d7cf3..d797502 100644 (file)
@@ -451,6 +451,13 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu)
                if (!dentry)
                        goto free_buf;
                relay_set_buf_dentry(buf, dentry);
+       } else {
+               /* Only retrieve global info, nothing more, nothing less */
+               dentry = chan->cb->create_buf_file(NULL, NULL,
+                                                  S_IRUSR, buf,
+                                                  &chan->is_global);
+               if (WARN_ON(dentry))
+                       goto free_buf;
        }
 
        buf->cpu = cpu;
@@ -562,6 +569,10 @@ static int relay_hotcpu_callback(struct notifier_block *nb,
  *     attributes specified.  The created channel buffer files
  *     will be named base_filename0...base_filenameN-1.  File
  *     permissions will be %S_IRUSR.
+ *
+ *     If opening a buffer (@parent = NULL) that you later wish to register
+ *     in a filesystem, call relay_late_setup_files() once the @parent dentry
+ *     is available.
  */
 struct rchan *relay_open(const char *base_filename,
                         struct dentry *parent,
@@ -640,8 +651,12 @@ static void __relay_set_buf_dentry(void *info)
  *
  *     Returns 0 if successful, non-zero otherwise.
  *
- *     Use to setup files for a previously buffer-only channel.
- *     Useful to do early tracing in kernel, before VFS is up, for example.
+ *     Use to setup files for a previously buffer-only channel created
+ *     by relay_open() with a NULL parent dentry.
+ *
+ *     For example, this is useful for perfomring early tracing in kernel,
+ *     before VFS is up and then exposing the early results once the dentry
+ *     is available.
  */
 int relay_late_setup_files(struct rchan *chan,
                           const char *base_filename,
@@ -666,6 +681,20 @@ int relay_late_setup_files(struct rchan *chan,
        }
        chan->has_base_filename = 1;
        chan->parent = parent;
+
+       if (chan->is_global) {
+               err = -EINVAL;
+               if (!WARN_ON_ONCE(!chan->buf[0])) {
+                       dentry = relay_create_buf_file(chan, chan->buf[0], 0);
+                       if (dentry && !WARN_ON_ONCE(!chan->is_global)) {
+                               relay_set_buf_dentry(chan->buf[0], dentry);
+                               err = 0;
+                       }
+               }
+               mutex_unlock(&relay_channels_mutex);
+               return err;
+       }
+
        curr_cpu = get_cpu();
        /*
         * The CPU hotplug notifier ran before us and created buffers with
@@ -706,6 +735,7 @@ int relay_late_setup_files(struct rchan *chan,
 
        return err;
 }
+EXPORT_SYMBOL_GPL(relay_late_setup_files);
 
 /**
  *     relay_switch_subbuf - switch to a new sub-buffer
index 54d15eb..ef6c6c3 100644 (file)
@@ -347,7 +347,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
 {
        struct seccomp_filter *sfilter;
        int ret;
-       const bool save_orig = config_enabled(CONFIG_CHECKPOINT_RESTORE);
+       const bool save_orig = IS_ENABLED(CONFIG_CHECKPOINT_RESTORE);
 
        if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
                return ERR_PTR(-EINVAL);
@@ -542,7 +542,7 @@ void secure_computing_strict(int this_syscall)
 {
        int mode = current->seccomp.mode;
 
-       if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+       if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
            unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
                return;
 
@@ -655,7 +655,7 @@ int __secure_computing(const struct seccomp_data *sd)
        int mode = current->seccomp.mode;
        int this_syscall;
 
-       if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+       if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
            unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
                return 0;
 
index 5395463..b43d0b2 100644 (file)
@@ -813,6 +813,13 @@ static struct ctl_table kern_table[] = {
                .extra1         = &zero,
                .extra2         = &ten_thousand,
        },
+       {
+               .procname       = "printk_devkmsg",
+               .data           = devkmsg_log_str,
+               .maxlen         = DEVKMSG_STR_MAX_SIZE,
+               .mode           = 0644,
+               .proc_handler   = devkmsg_sysctl_set_loglvl,
+       },
        {
                .procname       = "dmesg_restrict",
                .data           = &dmesg_restrict,
index 6ab4842..d513051 100644 (file)
@@ -29,7 +29,7 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
        struct callback_head *head;
 
        do {
-               head = ACCESS_ONCE(task->task_works);
+               head = READ_ONCE(task->task_works);
                if (unlikely(head == &work_exited))
                        return -ESRCH;
                work->next = head;
@@ -57,6 +57,9 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
        struct callback_head **pprev = &task->task_works;
        struct callback_head *work;
        unsigned long flags;
+
+       if (likely(!task->task_works))
+               return NULL;
        /*
         * If cmpxchg() fails we continue without updating pprev.
         * Either we raced with task_work_add() which added the
@@ -64,8 +67,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
         * we raced with task_work_run(), *pprev == NULL/exited.
         */
        raw_spin_lock_irqsave(&task->pi_lock, flags);
-       while ((work = ACCESS_ONCE(*pprev))) {
-               smp_read_barrier_depends();
+       while ((work = lockless_dereference(*pprev))) {
                if (work->func != func)
                        pprev = &work->next;
                else if (cmpxchg(pprev, work, work->next) == work)
@@ -95,7 +97,7 @@ void task_work_run(void)
                 * work_exited unless the list is empty.
                 */
                do {
-                       work = ACCESS_ONCE(task->task_works);
+                       work = READ_ONCE(task->task_works);
                        head = !work && (task->flags & PF_EXITING) ?
                                &work_exited : NULL;
                } while (cmpxchg(&task->task_works, work, head) != work);
index 979e7bf..d0a1617 100644 (file)
@@ -1,4 +1,8 @@
 
+# We are fully aware of the dangers of __builtin_return_address()
+FRAME_CFLAGS := $(call cc-disable-warning,frame-address)
+KBUILD_CFLAGS += $(FRAME_CFLAGS)
+
 # Do not instrument the tracer itself:
 
 ifdef CONFIG_FUNCTION_TRACER
index fb345cd..7598e6c 100644 (file)
@@ -776,7 +776,7 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
                return;
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
-                       bio_op(bio), bio->bi_rw, what, error, 0, NULL);
+                       bio_op(bio), bio->bi_opf, what, error, 0, NULL);
 }
 
 static void blk_add_trace_bio_bounce(void *ignore,
@@ -881,7 +881,7 @@ static void blk_add_trace_split(void *ignore,
                __be64 rpdu = cpu_to_be64(pdu);
 
                __blk_add_trace(bt, bio->bi_iter.bi_sector,
-                               bio->bi_iter.bi_size, bio_op(bio), bio->bi_rw,
+                               bio->bi_iter.bi_size, bio_op(bio), bio->bi_opf,
                                BLK_TA_SPLIT, bio->bi_error, sizeof(rpdu),
                                &rpdu);
        }
@@ -915,7 +915,7 @@ static void blk_add_trace_bio_remap(void *ignore,
        r.sector_from = cpu_to_be64(from);
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
-                       bio_op(bio), bio->bi_rw, BLK_TA_REMAP, bio->bi_error,
+                       bio_op(bio), bio->bi_opf, BLK_TA_REMAP, bio->bi_error,
                        sizeof(r), &r);
 }
 
index 0c05b8a..f3a960e 100644 (file)
@@ -1441,6 +1441,9 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
                goto out;
        }
 
+       if (hist_data->attrs->pause)
+               data->paused = true;
+
        if (named_data) {
                destroy_hist_data(data->private_data);
                data->private_data = named_data->private_data;
@@ -1448,9 +1451,6 @@ static int hist_register_trigger(char *glob, struct event_trigger_ops *ops,
                data->ops = &event_hist_trigger_named_ops;
        }
 
-       if (hist_data->attrs->pause)
-               data->paused = true;
-
        if (data->ops->init) {
                ret = data->ops->init(data->ops, data);
                if (ret < 0)
@@ -1500,9 +1500,9 @@ static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
 
 static void hist_unreg_all(struct trace_event_file *file)
 {
-       struct event_trigger_data *test;
+       struct event_trigger_data *test, *n;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry_safe(test, n, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
                        list_del_rcu(&test->list);
                        trace_event_trigger_enable_disable(file, 0);
@@ -1699,9 +1699,9 @@ hist_enable_get_trigger_ops(char *cmd, char *param)
 
 static void hist_enable_unreg_all(struct trace_event_file *file)
 {
-       struct event_trigger_data *test;
+       struct event_trigger_data *test, *n;
 
-       list_for_each_entry_rcu(test, &file->triggers, list) {
+       list_for_each_entry_safe(test, n, &file->triggers, list) {
                if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
                        list_del_rcu(&test->list);
                        update_cond_flag(file);
index f07842e..2307d7c 100644 (file)
@@ -709,6 +709,8 @@ config KCOV
        bool "Code coverage for fuzzing"
        depends on ARCH_HAS_KCOV
        select DEBUG_FS
+       select GCC_PLUGINS if !COMPILE_TEST
+       select GCC_PLUGIN_SANCOV if !COMPILE_TEST
        help
          KCOV exposes kernel code coverage information in a form suitable
          for coverage-guided fuzzing (randomized testing).
@@ -719,6 +721,17 @@ config KCOV
 
          For more details, see Documentation/kcov.txt.
 
+config KCOV_INSTRUMENT_ALL
+       bool "Instrument all code by default"
+       depends on KCOV
+       default y if KCOV
+       help
+         If you are doing generic system call fuzzing (like e.g. syzkaller),
+         then you will want to instrument the whole kernel and you should
+         say y here. If you are doing more targeted fuzzing (like e.g.
+         filesystem fuzzing with AFL) then you will want to enable coverage
+         for more specific subsets of files, and should say n here.
+
 config DEBUG_SHIRQ
        bool "Debug shared IRQ handlers"
        depends on DEBUG_KERNEL
index 9a907d4..7fbd1a1 100644 (file)
@@ -979,7 +979,6 @@ static int __init crc32c_test(void)
        int i;
        int errors = 0;
        int bytes = 0;
-       struct timespec start, stop;
        u64 nsec;
        unsigned long flags;
 
@@ -999,20 +998,17 @@ static int __init crc32c_test(void)
        local_irq_save(flags);
        local_irq_disable();
 
-       getnstimeofday(&start);
+       nsec = ktime_get_ns();
        for (i = 0; i < 100; i++) {
                if (test[i].crc32c_le != __crc32c_le(test[i].crc, test_buf +
                    test[i].start, test[i].length))
                        errors++;
        }
-       getnstimeofday(&stop);
+       nsec = ktime_get_ns() - nsec;
 
        local_irq_restore(flags);
        local_irq_enable();
 
-       nsec = stop.tv_nsec - start.tv_nsec +
-               1000000000 * (stop.tv_sec - start.tv_sec);
-
        pr_info("crc32c: CRC_LE_BITS = %d\n", CRC_LE_BITS);
 
        if (errors)
@@ -1065,7 +1061,6 @@ static int __init crc32_test(void)
        int i;
        int errors = 0;
        int bytes = 0;
-       struct timespec start, stop;
        u64 nsec;
        unsigned long flags;
 
@@ -1088,7 +1083,7 @@ static int __init crc32_test(void)
        local_irq_save(flags);
        local_irq_disable();
 
-       getnstimeofday(&start);
+       nsec = ktime_get_ns();
        for (i = 0; i < 100; i++) {
                if (test[i].crc_le != crc32_le(test[i].crc, test_buf +
                    test[i].start, test[i].length))
@@ -1098,14 +1093,11 @@ static int __init crc32_test(void)
                    test[i].start, test[i].length))
                        errors++;
        }
-       getnstimeofday(&stop);
+       nsec = ktime_get_ns() - nsec;
 
        local_irq_restore(flags);
        local_irq_enable();
 
-       nsec = stop.tv_nsec - start.tv_nsec +
-               1000000000 * (stop.tv_sec - start.tv_sec);
-
        pr_info("crc32: CRC_LE_BITS = %d, CRC_BE BITS = %d\n",
                 CRC_LE_BITS, CRC_BE_BITS);
 
index 7214564..3d766e7 100644 (file)
@@ -10,7 +10,7 @@
 
 static void *dma_noop_alloc(struct device *dev, size_t size,
                            dma_addr_t *dma_handle, gfp_t gfp,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        void *ret;
 
@@ -22,7 +22,7 @@ static void *dma_noop_alloc(struct device *dev, size_t size,
 
 static void dma_noop_free(struct device *dev, size_t size,
                          void *cpu_addr, dma_addr_t dma_addr,
-                         struct dma_attrs *attrs)
+                         unsigned long attrs)
 {
        free_pages((unsigned long)cpu_addr, get_order(size));
 }
@@ -30,13 +30,14 @@ static void dma_noop_free(struct device *dev, size_t size,
 static dma_addr_t dma_noop_map_page(struct device *dev, struct page *page,
                                      unsigned long offset, size_t size,
                                      enum dma_data_direction dir,
-                                     struct dma_attrs *attrs)
+                                     unsigned long attrs)
 {
        return page_to_phys(page) + offset;
 }
 
 static int dma_noop_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
-                            enum dma_data_direction dir, struct dma_attrs *attrs)
+                            enum dma_data_direction dir,
+                            unsigned long attrs)
 {
        int i;
        struct scatterlist *sg;
index fe42b6e..da796e2 100644 (file)
@@ -188,6 +188,13 @@ static int ddebug_change(const struct ddebug_query *query,
                        newflags = (dp->flags & mask) | flags;
                        if (newflags == dp->flags)
                                continue;
+#ifdef HAVE_JUMP_LABEL
+                       if (dp->flags & _DPRINTK_FLAGS_PRINT) {
+                               if (!(flags & _DPRINTK_FLAGS_PRINT))
+                                       static_branch_disable(&dp->key.dd_key_true);
+                       } else if (flags & _DPRINTK_FLAGS_PRINT)
+                               static_branch_enable(&dp->key.dd_key_true);
+#endif
                        dp->flags = newflags;
                        vpr_info("changed %s:%d [%s]%s =%s\n",
                                 trim_prefix(dp->filename), dp->lineno,
index c27e269..a816f3a 100644 (file)
@@ -29,8 +29,7 @@ again:
        index = bitmap_find_next_zero_area(map, size, start, nr, align_mask);
        if (index < size) {
                if (iommu_is_span_boundary(index, nr, shift, boundary_size)) {
-                       /* we could do more effectively */
-                       start = index + 1;
+                       start = ALIGN(shift + index, boundary_size) - shift;
                        goto again;
                }
                bitmap_set(map, index, nr);
index 61b8fb5..1b7bf73 100644 (file)
@@ -277,10 +277,11 @@ radix_tree_node_alloc(struct radix_tree_root *root)
 
                /*
                 * Even if the caller has preloaded, try to allocate from the
-                * cache first for the new node to get accounted.
+                * cache first for the new node to get accounted to the memory
+                * cgroup.
                 */
                ret = kmem_cache_alloc(radix_tree_node_cachep,
-                                      gfp_mask | __GFP_ACCOUNT | __GFP_NOWARN);
+                                      gfp_mask | __GFP_NOWARN);
                if (ret)
                        goto out;
 
@@ -303,8 +304,7 @@ radix_tree_node_alloc(struct radix_tree_root *root)
                kmemleak_update_trace(ret);
                goto out;
        }
-       ret = kmem_cache_alloc(radix_tree_node_cachep,
-                              gfp_mask | __GFP_ACCOUNT);
+       ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
 out:
        BUG_ON(radix_tree_is_internal_node(ret));
        return ret;
@@ -351,6 +351,12 @@ static int __radix_tree_preload(gfp_t gfp_mask, int nr)
        struct radix_tree_node *node;
        int ret = -ENOMEM;
 
+       /*
+        * Nodes preloaded by one cgroup can be be used by another cgroup, so
+        * they should never be accounted to any particular memory cgroup.
+        */
+       gfp_mask &= ~__GFP_ACCOUNT;
+
        preempt_disable();
        rtp = this_cpu_ptr(&radix_tree_preloads);
        while (rtp->nr < nr) {
index 2c5de86..08f8043 100644 (file)
@@ -46,12 +46,14 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
                rs->begin = jiffies;
 
        if (time_is_before_jiffies(rs->begin + rs->interval)) {
-               if (rs->missed)
-                       printk(KERN_WARNING "%s: %d callbacks suppressed\n",
-                               func, rs->missed);
+               if (rs->missed) {
+                       if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
+                               pr_warn("%s: %d callbacks suppressed\n", func, rs->missed);
+                               rs->missed = 0;
+                       }
+               }
                rs->begin   = jiffies;
                rs->printed = 0;
-               rs->missed  = 0;
        }
        if (rs->burst && rs->burst > rs->printed) {
                rs->printed++;
index 33f655e..9c5fe81 100644 (file)
@@ -40,8 +40,8 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
                unsigned long c, data;
 
                /* Fall back to byte-at-a-time if we get a page fault */
-               if (unlikely(unsafe_get_user(c,(unsigned long __user *)(src+res))))
-                       break;
+               unsafe_get_user(c, (unsigned long __user *)(src+res), byte_at_a_time);
+
                *(unsigned long *)(dst+res) = c;
                if (has_zero(c, &data, &constants)) {
                        data = prep_zero_mask(c, data, &constants);
@@ -56,8 +56,7 @@ byte_at_a_time:
        while (max) {
                char c;
 
-               if (unlikely(unsafe_get_user(c,src+res)))
-                       return -EFAULT;
+               unsafe_get_user(c,src+res, efault);
                dst[res] = c;
                if (!c)
                        return res;
@@ -76,6 +75,7 @@ byte_at_a_time:
         * Nope: we hit the address space limit, and we still had more
         * characters the caller would have wanted. That's an EFAULT.
         */
+efault:
        return -EFAULT;
 }
 
index 2625943..8e105ed 100644 (file)
@@ -45,8 +45,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
        src -= align;
        max += align;
 
-       if (unlikely(unsafe_get_user(c,(unsigned long __user *)src)))
-               return 0;
+       unsafe_get_user(c, (unsigned long __user *)src, efault);
        c |= aligned_byte_mask(align);
 
        for (;;) {
@@ -61,8 +60,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
                if (unlikely(max <= sizeof(unsigned long)))
                        break;
                max -= sizeof(unsigned long);
-               if (unlikely(unsafe_get_user(c,(unsigned long __user *)(src+res))))
-                       return 0;
+               unsafe_get_user(c, (unsigned long __user *)(src+res), efault);
        }
        res -= align;
 
@@ -77,6 +75,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
         * Nope: we hit the address space limit, and we still had more
         * characters the caller would have wanted. That's 0.
         */
+efault:
        return 0;
 }
 
index 76f29ec..22e13a0 100644 (file)
@@ -738,7 +738,7 @@ swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
 dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
                            unsigned long offset, size_t size,
                            enum dma_data_direction dir,
-                           struct dma_attrs *attrs)
+                           unsigned long attrs)
 {
        phys_addr_t map, phys = page_to_phys(page) + offset;
        dma_addr_t dev_addr = phys_to_dma(dev, phys);
@@ -807,7 +807,7 @@ static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
 
 void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                        size_t size, enum dma_data_direction dir,
-                       struct dma_attrs *attrs)
+                       unsigned long attrs)
 {
        unmap_single(hwdev, dev_addr, size, dir);
 }
@@ -877,7 +877,7 @@ EXPORT_SYMBOL(swiotlb_sync_single_for_device);
  */
 int
 swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    enum dma_data_direction dir, struct dma_attrs *attrs)
+                    enum dma_data_direction dir, unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -914,7 +914,7 @@ int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
               enum dma_data_direction dir)
 {
-       return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+       return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, 0);
 }
 EXPORT_SYMBOL(swiotlb_map_sg);
 
@@ -924,7 +924,8 @@ EXPORT_SYMBOL(swiotlb_map_sg);
  */
 void
 swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
-                      int nelems, enum dma_data_direction dir, struct dma_attrs *attrs)
+                      int nelems, enum dma_data_direction dir,
+                      unsigned long attrs)
 {
        struct scatterlist *sg;
        int i;
@@ -941,7 +942,7 @@ void
 swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
                 enum dma_data_direction dir)
 {
-       return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+       return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, 0);
 }
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 
index 8799ae5..fb0409d 100644 (file)
@@ -308,7 +308,7 @@ static void handle_object_size_mismatch(struct type_mismatch_data *data,
                return;
 
        ubsan_prologue(&data->location, &flags);
-       pr_err("%s address %pk with insufficient space\n",
+       pr_err("%s address %p with insufficient space\n",
                type_check_kinds[data->type_check_kind],
                (void *) ptr);
        pr_err("for an object of type %s\n", data->type->type_name);
index c083784..78a23c5 100644 (file)
@@ -187,6 +187,7 @@ config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
+       depends on !KASAN
 
 config MEMORY_HOTPLUG_SPARSE
        def_bool y
index fc05966..2ca1faf 100644 (file)
@@ -21,6 +21,9 @@ KCOV_INSTRUMENT_memcontrol.o := n
 KCOV_INSTRUMENT_mmzone.o := n
 KCOV_INSTRUMENT_vmstat.o := n
 
+# Since __builtin_frame_address does work as used, disable the warning.
+CFLAGS_usercopy.o += $(call cc-disable-warning, frame-address)
+
 mmu-y                  := nommu.o
 mmu-$(CONFIG_MMU)      := gup.o highmem.o memory.o mincore.o \
                           mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
@@ -99,3 +102,4 @@ obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
 obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
 obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
 obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o
+obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
index efe2377..8fde443 100644 (file)
@@ -825,6 +825,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
 }
 EXPORT_SYMBOL(bdi_register_dev);
 
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
+{
+       int rc;
+
+       rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt),
+                       MINOR(owner->devt));
+       if (rc)
+               return rc;
+       bdi->owner = owner;
+       get_device(owner);
+       return 0;
+}
+EXPORT_SYMBOL(bdi_register_owner);
+
 /*
  * Remove bdi from bdi_list, and ensure that it is no longer visible
  */
@@ -849,6 +863,11 @@ void bdi_unregister(struct backing_dev_info *bdi)
                device_unregister(bdi->dev);
                bdi->dev = NULL;
        }
+
+       if (bdi->owner) {
+               put_device(bdi->owner);
+               bdi->owner = NULL;
+       }
 }
 
 void bdi_exit(struct backing_dev_info *bdi)
index 3083ded..8a287df 100644 (file)
@@ -887,9 +887,9 @@ EXPORT_SYMBOL(end_page_writeback);
  * After completing I/O on a page, call this routine to update the page
  * flags appropriately
  */
-void page_endio(struct page *page, int rw, int err)
+void page_endio(struct page *page, bool is_write, int err)
 {
-       if (rw == READ) {
+       if (!is_write) {
                if (!err) {
                        SetPageUptodate(page);
                } else {
@@ -897,7 +897,7 @@ void page_endio(struct page *page, int rw, int err)
                        SetPageError(page);
                }
                unlock_page(page);
-       } else { /* rw == WRITE */
+       } else {
                if (err) {
                        SetPageError(page);
                        if (page->mapping)
index 547741f..96b2b2f 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -723,6 +723,7 @@ retry:
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(fixup_user_fault);
 
 static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
                                                struct mm_struct *mm,
index f904246..b9aa1b0 100644 (file)
@@ -2216,6 +2216,10 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
                 * and reducing the surplus.
                 */
                spin_unlock(&hugetlb_lock);
+
+               /* yield cpu to avoid soft lockup */
+               cond_resched();
+
                if (hstate_is_gigantic(h))
                        ret = alloc_fresh_gigantic_page(h, nodes_allowed);
                else
@@ -3938,6 +3942,14 @@ same_page:
        return i ? i : -EFAULT;
 }
 
+#ifndef __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
+/*
+ * ARCHes with special requirements for evicting HUGETLB backing TLB entries can
+ * implement this.
+ */
+#define flush_hugetlb_tlb_range(vma, addr, end)        flush_tlb_range(vma, addr, end)
+#endif
+
 unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
                unsigned long address, unsigned long end, pgprot_t newprot)
 {
@@ -3998,7 +4010,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
         * once we release i_mmap_rwsem, another task can do the final put_page
         * and that page table be reused and filled with junk.
         */
-       flush_tlb_range(vma, start, end);
+       flush_hugetlb_tlb_range(vma, start, end);
        mmu_notifier_invalidate_range(mm, start, end);
        i_mmap_unlock_write(vma->vm_file->f_mapping);
        mmu_notifier_invalidate_range_end(mm, start, end);
@@ -4306,7 +4318,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
                                pte = (pte_t *)pmd_alloc(mm, pud, addr);
                }
        }
-       BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
+       BUG_ON(pte && pte_present(*pte) && !pte_huge(*pte));
 
        return pte;
 }
index b6f99e8..88af13c 100644 (file)
@@ -442,11 +442,6 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object)
        kasan_poison_shadow(object,
                        round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE),
                        KASAN_KMALLOC_REDZONE);
-       if (cache->flags & SLAB_KASAN) {
-               struct kasan_alloc_meta *alloc_info =
-                       get_alloc_info(cache, object);
-               alloc_info->state = KASAN_STATE_INIT;
-       }
 }
 
 static inline int in_irqentry_text(unsigned long ptr)
@@ -510,6 +505,17 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
        return (void *)object + cache->kasan_info.free_meta_offset;
 }
 
+void kasan_init_slab_obj(struct kmem_cache *cache, const void *object)
+{
+       struct kasan_alloc_meta *alloc_info;
+
+       if (!(cache->flags & SLAB_KASAN))
+               return;
+
+       alloc_info = get_alloc_info(cache, object);
+       __memset(alloc_info, 0, sizeof(*alloc_info));
+}
+
 void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
 {
        kasan_kmalloc(cache, object, cache->object_size, flags);
@@ -529,34 +535,26 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object)
 
 bool kasan_slab_free(struct kmem_cache *cache, void *object)
 {
+       s8 shadow_byte;
+
        /* RCU slabs could be legally used after free within the RCU period */
        if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU))
                return false;
 
-       if (likely(cache->flags & SLAB_KASAN)) {
-               struct kasan_alloc_meta *alloc_info;
-               struct kasan_free_meta *free_info;
+       shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object));
+       if (shadow_byte < 0 || shadow_byte >= KASAN_SHADOW_SCALE_SIZE) {
+               kasan_report_double_free(cache, object, shadow_byte);
+               return true;
+       }
 
-               alloc_info = get_alloc_info(cache, object);
-               free_info = get_free_info(cache, object);
+       kasan_poison_slab_free(cache, object);
 
-               switch (alloc_info->state) {
-               case KASAN_STATE_ALLOC:
-                       alloc_info->state = KASAN_STATE_QUARANTINE;
-                       quarantine_put(free_info, cache);
-                       set_track(&free_info->track, GFP_NOWAIT);
-                       kasan_poison_slab_free(cache, object);
-                       return true;
-               case KASAN_STATE_QUARANTINE:
-               case KASAN_STATE_FREE:
-                       pr_err("Double free");
-                       dump_stack();
-                       break;
-               default:
-                       break;
-               }
-       }
-       return false;
+       if (unlikely(!(cache->flags & SLAB_KASAN)))
+               return false;
+
+       set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT);
+       quarantine_put(get_free_info(cache, object), cache);
+       return true;
 }
 
 void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
@@ -565,7 +563,7 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
        unsigned long redzone_start;
        unsigned long redzone_end;
 
-       if (flags & __GFP_RECLAIM)
+       if (gfpflags_allow_blocking(flags))
                quarantine_reduce();
 
        if (unlikely(object == NULL))
@@ -579,14 +577,9 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
        kasan_unpoison_shadow(object, size);
        kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
                KASAN_KMALLOC_REDZONE);
-       if (cache->flags & SLAB_KASAN) {
-               struct kasan_alloc_meta *alloc_info =
-                       get_alloc_info(cache, object);
 
-               alloc_info->state = KASAN_STATE_ALLOC;
-               alloc_info->alloc_size = size;
-               set_track(&alloc_info->track, flags);
-       }
+       if (cache->flags & SLAB_KASAN)
+               set_track(&get_alloc_info(cache, object)->alloc_track, flags);
 }
 EXPORT_SYMBOL(kasan_kmalloc);
 
@@ -596,7 +589,7 @@ void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
        unsigned long redzone_start;
        unsigned long redzone_end;
 
-       if (flags & __GFP_RECLAIM)
+       if (gfpflags_allow_blocking(flags))
                quarantine_reduce();
 
        if (unlikely(ptr == NULL))
index 31972cd..e5c2181 100644 (file)
@@ -59,13 +59,6 @@ struct kasan_global {
  * Structures to keep alloc and free tracks *
  */
 
-enum kasan_state {
-       KASAN_STATE_INIT,
-       KASAN_STATE_ALLOC,
-       KASAN_STATE_QUARANTINE,
-       KASAN_STATE_FREE
-};
-
 #define KASAN_STACK_DEPTH 64
 
 struct kasan_track {
@@ -74,9 +67,8 @@ struct kasan_track {
 };
 
 struct kasan_alloc_meta {
-       struct kasan_track track;
-       u32 state : 2;  /* enum kasan_state */
-       u32 alloc_size : 30;
+       struct kasan_track alloc_track;
+       struct kasan_track free_track;
 };
 
 struct qlist_node {
@@ -87,7 +79,6 @@ struct kasan_free_meta {
         * Otherwise it might be used for the allocator freelist.
         */
        struct qlist_node quarantine_link;
-       struct kasan_track track;
 };
 
 struct kasan_alloc_meta *get_alloc_info(struct kmem_cache *cache,
@@ -108,6 +99,8 @@ static inline bool kasan_report_enabled(void)
 
 void kasan_report(unsigned long addr, size_t size,
                bool is_write, unsigned long ip);
+void kasan_report_double_free(struct kmem_cache *cache, void *object,
+                       s8 shadow);
 
 #if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
 void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache);
index 65793f1..b6728a3 100644 (file)
@@ -144,13 +144,15 @@ static void *qlink_to_object(struct qlist_node *qlink, struct kmem_cache *cache)
 static void qlink_free(struct qlist_node *qlink, struct kmem_cache *cache)
 {
        void *object = qlink_to_object(qlink, cache);
-       struct kasan_alloc_meta *alloc_info = get_alloc_info(cache, object);
        unsigned long flags;
 
-       local_irq_save(flags);
-       alloc_info->state = KASAN_STATE_FREE;
+       if (IS_ENABLED(CONFIG_SLAB))
+               local_irq_save(flags);
+
        ___cache_free(cache, object, _THIS_IP_);
-       local_irq_restore(flags);
+
+       if (IS_ENABLED(CONFIG_SLAB))
+               local_irq_restore(flags);
 }
 
 static void qlist_free_all(struct qlist_head *q, struct kmem_cache *cache)
@@ -196,7 +198,7 @@ void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache)
 
 void quarantine_reduce(void)
 {
-       size_t new_quarantine_size;
+       size_t new_quarantine_size, percpu_quarantines;
        unsigned long flags;
        struct qlist_head to_free = QLIST_INIT;
        size_t size_to_free = 0;
@@ -214,7 +216,12 @@ void quarantine_reduce(void)
         */
        new_quarantine_size = (READ_ONCE(totalram_pages) << PAGE_SHIFT) /
                QUARANTINE_FRACTION;
-       new_quarantine_size -= QUARANTINE_PERCPU_SIZE * num_online_cpus();
+       percpu_quarantines = QUARANTINE_PERCPU_SIZE * num_online_cpus();
+       if (WARN_ONCE(new_quarantine_size < percpu_quarantines,
+               "Too little memory, disabling global KASAN quarantine.\n"))
+               new_quarantine_size = 0;
+       else
+               new_quarantine_size -= percpu_quarantines;
        WRITE_ONCE(quarantine_size, new_quarantine_size);
 
        last = global_quarantine.head;
index 861b977..24c1211 100644 (file)
@@ -116,6 +116,26 @@ static inline bool init_task_stack_addr(const void *addr)
                        sizeof(init_thread_union.stack));
 }
 
+static DEFINE_SPINLOCK(report_lock);
+
+static void kasan_start_report(unsigned long *flags)
+{
+       /*
+        * Make sure we don't end up in loop.
+        */
+       kasan_disable_current();
+       spin_lock_irqsave(&report_lock, *flags);
+       pr_err("==================================================================\n");
+}
+
+static void kasan_end_report(unsigned long *flags)
+{
+       pr_err("==================================================================\n");
+       add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
+       spin_unlock_irqrestore(&report_lock, *flags);
+       kasan_enable_current();
+}
+
 static void print_track(struct kasan_track *track)
 {
        pr_err("PID = %u\n", track->pid);
@@ -129,37 +149,33 @@ static void print_track(struct kasan_track *track)
        }
 }
 
-static void kasan_object_err(struct kmem_cache *cache, struct page *page,
-                               void *object, char *unused_reason)
+static void kasan_object_err(struct kmem_cache *cache, void *object)
 {
        struct kasan_alloc_meta *alloc_info = get_alloc_info(cache, object);
-       struct kasan_free_meta *free_info;
 
        dump_stack();
-       pr_err("Object at %p, in cache %s\n", object, cache->name);
+       pr_err("Object at %p, in cache %s size: %d\n", object, cache->name,
+               cache->object_size);
+
        if (!(cache->flags & SLAB_KASAN))
                return;
-       switch (alloc_info->state) {
-       case KASAN_STATE_INIT:
-               pr_err("Object not allocated yet\n");
-               break;
-       case KASAN_STATE_ALLOC:
-               pr_err("Object allocated with size %u bytes.\n",
-                      alloc_info->alloc_size);
-               pr_err("Allocation:\n");
-               print_track(&alloc_info->track);
-               break;
-       case KASAN_STATE_FREE:
-       case KASAN_STATE_QUARANTINE:
-               pr_err("Object freed, allocated with size %u bytes\n",
-                      alloc_info->alloc_size);
-               free_info = get_free_info(cache, object);
-               pr_err("Allocation:\n");
-               print_track(&alloc_info->track);
-               pr_err("Deallocation:\n");
-               print_track(&free_info->track);
-               break;
-       }
+
+       pr_err("Allocated:\n");
+       print_track(&alloc_info->alloc_track);
+       pr_err("Freed:\n");
+       print_track(&alloc_info->free_track);
+}
+
+void kasan_report_double_free(struct kmem_cache *cache, void *object,
+                       s8 shadow)
+{
+       unsigned long flags;
+
+       kasan_start_report(&flags);
+       pr_err("BUG: Double free or freeing an invalid pointer\n");
+       pr_err("Unexpected shadow byte: 0x%hhX\n", shadow);
+       kasan_object_err(cache, object);
+       kasan_end_report(&flags);
 }
 
 static void print_address_description(struct kasan_access_info *info)
@@ -175,8 +191,7 @@ static void print_address_description(struct kasan_access_info *info)
                        struct kmem_cache *cache = page->slab_cache;
                        object = nearest_obj(cache, page,
                                                (void *)info->access_addr);
-                       kasan_object_err(cache, page, object,
-                                       "kasan: bad access detected");
+                       kasan_object_err(cache, object);
                        return;
                }
                dump_page(page, "kasan: bad access detected");
@@ -241,19 +256,13 @@ static void print_shadow_for_address(const void *addr)
        }
 }
 
-static DEFINE_SPINLOCK(report_lock);
-
 static void kasan_report_error(struct kasan_access_info *info)
 {
        unsigned long flags;
        const char *bug_type;
 
-       /*
-        * Make sure we don't end up in loop.
-        */
-       kasan_disable_current();
-       spin_lock_irqsave(&report_lock, flags);
-       pr_err("==================================================================\n");
+       kasan_start_report(&flags);
+
        if (info->access_addr <
                        kasan_shadow_to_mem((void *)KASAN_SHADOW_START)) {
                if ((unsigned long)info->access_addr < PAGE_SIZE)
@@ -274,10 +283,8 @@ static void kasan_report_error(struct kasan_access_info *info)
                print_address_description(info);
                print_shadow_for_address(info->first_bad_addr);
        }
-       pr_err("==================================================================\n");
-       add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
-       spin_unlock_irqrestore(&report_lock, flags);
-       kasan_enable_current();
+
+       kasan_end_report(&flags);
 }
 
 void kasan_report(unsigned long addr, size_t size,
index ff5ff3b..483197e 100644 (file)
@@ -482,7 +482,7 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
  * @flags:     flags of the new region
  *
  * Insert new memblock region [@base,@base+@size) into @type at @idx.
- * @type must already have extra room to accomodate the new region.
+ * @type must already have extra room to accommodate the new region.
  */
 static void __init_memblock memblock_insert_region(struct memblock_type *type,
                                                   int idx, phys_addr_t base,
@@ -544,7 +544,7 @@ repeat:
        /*
         * The following is executed twice.  Once with %false @insert and
         * then with %true.  The first counts the number of regions needed
-        * to accomodate the new area.  The second actually inserts them.
+        * to accommodate the new area.  The second actually inserts them.
         */
        base = obase;
        nr_new = 0;
@@ -994,7 +994,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
 
        if (*idx == (u64)ULLONG_MAX) {
                idx_a = type_a->cnt - 1;
-               idx_b = type_b->cnt;
+               if (type_b != NULL)
+                       idx_b = type_b->cnt;
+               else
+                       idx_b = 0;
        }
 
        for (; idx_a >= 0; idx_a--) {
index c265212..e74d708 100644 (file)
@@ -2337,8 +2337,11 @@ int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
                return 0;
 
        memcg = get_mem_cgroup_from_mm(current->mm);
-       if (!mem_cgroup_is_root(memcg))
+       if (!mem_cgroup_is_root(memcg)) {
                ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
+               if (!ret)
+                       __SetPageKmemcg(page);
+       }
        css_put(&memcg->css);
        return ret;
 }
@@ -2365,6 +2368,11 @@ void memcg_kmem_uncharge(struct page *page, int order)
                page_counter_uncharge(&memcg->memsw, nr_pages);
 
        page->mem_cgroup = NULL;
+
+       /* slab pages do not have PageKmemcg flag set */
+       if (PageKmemcg(page))
+               __ClearPageKmemcg(page);
+
        css_put_many(&memcg->css, nr_pages);
 }
 #endif /* !CONFIG_SLOB */
@@ -2559,6 +2567,15 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                return 0;
 
        mctz = soft_limit_tree_node(pgdat->node_id);
+
+       /*
+        * Do not even bother to check the largest node if the root
+        * is empty. Do it lockless to prevent lock bouncing. Races
+        * are acceptable as soft limit is best effort anyway.
+        */
+       if (RB_EMPTY_ROOT(&mctz->rb_root))
+               return 0;
+
        /*
         * This loop can run a while, specially if mem_cgroup's continuously
         * keep exceeding their soft limit and putting the system under
@@ -5528,8 +5545,10 @@ static void uncharge_list(struct list_head *page_list)
                        else
                                nr_file += nr_pages;
                        pgpgout++;
-               } else
+               } else {
                        nr_kmem += 1 << compound_order(page);
+                       __ClearPageKmemcg(page);
+               }
 
                page->mem_cgroup = NULL;
        } while (next != page_list);
index 4425b60..83be99d 100644 (file)
@@ -2642,6 +2642,7 @@ int do_swap_page(struct fault_env *fe, pte_t orig_pte)
        if (page == swapcache) {
                do_page_add_anon_rmap(page, vma, fe->address, exclusive);
                mem_cgroup_commit_charge(page, memcg, true, false);
+               activate_page(page);
        } else { /* ksm created a completely new copy */
                page_add_new_anon_rmap(page, vma, fe->address, false);
                mem_cgroup_commit_charge(page, memcg, false, false);
@@ -3133,6 +3134,8 @@ static int do_fault_around(struct fault_env *fe, pgoff_t start_pgoff)
 
        if (pmd_none(*fe->pmd)) {
                fe->prealloc_pte = pte_alloc_one(fe->vma->vm_mm, fe->address);
+               if (!fe->prealloc_pte)
+                       goto out;
                smp_wmb(); /* See comment in __pte_alloc() */
        }
 
index d44bee9..ca9d91b 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2653,16 +2653,18 @@ static inline void verify_mm_writelocked(struct mm_struct *mm)
  *  anonymous maps.  eventually we may be able to do some
  *  brk-specific accounting here.
  */
-static int do_brk(unsigned long addr, unsigned long len)
+static int do_brk(unsigned long addr, unsigned long request)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma, *prev;
-       unsigned long flags;
+       unsigned long flags, len;
        struct rb_node **rb_link, *rb_parent;
        pgoff_t pgoff = addr >> PAGE_SHIFT;
        int error;
 
-       len = PAGE_ALIGN(len);
+       len = PAGE_ALIGN(request);
+       if (len < request)
+               return -ENOMEM;
        if (!len)
                return 0;
 
index ea759b9..ab2c0ff 100644 (file)
@@ -1008,10 +1008,8 @@ static __always_inline bool free_pages_prepare(struct page *page,
        }
        if (PageMappingFlags(page))
                page->mapping = NULL;
-       if (memcg_kmem_enabled() && PageKmemcg(page)) {
+       if (memcg_kmem_enabled() && PageKmemcg(page))
                memcg_kmem_uncharge(page, order);
-               __ClearPageKmemcg(page);
-       }
        if (check_free)
                bad += free_pages_check(page);
        if (bad)
@@ -3756,12 +3754,10 @@ no_zone:
        }
 
 out:
-       if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page) {
-               if (unlikely(memcg_kmem_charge(page, gfp_mask, order))) {
-                       __free_pages(page, order);
-                       page = NULL;
-               } else
-                       __SetPageKmemcg(page);
+       if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page &&
+           unlikely(memcg_kmem_charge(page, gfp_mask, order) != 0)) {
+               __free_pages(page, order);
+               page = NULL;
        }
 
        if (kmemcheck_enabled && page)
@@ -4761,6 +4757,8 @@ int local_memory_node(int node)
 }
 #endif
 
+static void setup_min_unmapped_ratio(void);
+static void setup_min_slab_ratio(void);
 #else  /* CONFIG_NUMA */
 
 static void set_zonelist_order(void)
@@ -5257,11 +5255,6 @@ static void __meminit setup_zone_pageset(struct zone *zone)
        zone->pageset = alloc_percpu(struct per_cpu_pageset);
        for_each_possible_cpu(cpu)
                zone_pageset_init(zone, cpu);
-
-       if (!zone->zone_pgdat->per_cpu_nodestats) {
-               zone->zone_pgdat->per_cpu_nodestats =
-                       alloc_percpu(struct per_cpu_nodestat);
-       }
 }
 
 /*
@@ -5270,13 +5263,18 @@ static void __meminit setup_zone_pageset(struct zone *zone)
  */
 void __init setup_per_cpu_pageset(void)
 {
+       struct pglist_data *pgdat;
        struct zone *zone;
 
        for_each_populated_zone(zone)
                setup_zone_pageset(zone);
+
+       for_each_online_pgdat(pgdat)
+               pgdat->per_cpu_nodestats =
+                       alloc_percpu(struct per_cpu_nodestat);
 }
 
-static noinline __init_refok
+static noinline __ref
 int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
 {
        int i;
@@ -5882,9 +5880,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                zone->managed_pages = is_highmem_idx(j) ? realsize : freesize;
 #ifdef CONFIG_NUMA
                zone->node = nid;
-               pgdat->min_unmapped_pages += (freesize*sysctl_min_unmapped_ratio)
-                                               / 100;
-               pgdat->min_slab_pages += (freesize * sysctl_min_slab_ratio) / 100;
 #endif
                zone->name = zone_names[j];
                zone->zone_pgdat = pgdat;
@@ -5903,7 +5898,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
        }
 }
 
-static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
+static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
 {
        unsigned long __maybe_unused start = 0;
        unsigned long __maybe_unused offset = 0;
@@ -6805,6 +6800,12 @@ int __meminit init_per_zone_wmark_min(void)
        setup_per_zone_wmarks();
        refresh_zone_stat_thresholds();
        setup_per_zone_lowmem_reserve();
+
+#ifdef CONFIG_NUMA
+       setup_min_unmapped_ratio();
+       setup_min_slab_ratio();
+#endif
+
        return 0;
 }
 core_initcall(init_per_zone_wmark_min)
@@ -6846,43 +6847,58 @@ int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write,
 }
 
 #ifdef CONFIG_NUMA
+static void setup_min_unmapped_ratio(void)
+{
+       pg_data_t *pgdat;
+       struct zone *zone;
+
+       for_each_online_pgdat(pgdat)
+               pgdat->min_unmapped_pages = 0;
+
+       for_each_zone(zone)
+               zone->zone_pgdat->min_unmapped_pages += (zone->managed_pages *
+                               sysctl_min_unmapped_ratio) / 100;
+}
+
+
 int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
-       struct pglist_data *pgdat;
-       struct zone *zone;
        int rc;
 
        rc = proc_dointvec_minmax(table, write, buffer, length, ppos);
        if (rc)
                return rc;
 
+       setup_min_unmapped_ratio();
+
+       return 0;
+}
+
+static void setup_min_slab_ratio(void)
+{
+       pg_data_t *pgdat;
+       struct zone *zone;
+
        for_each_online_pgdat(pgdat)
                pgdat->min_slab_pages = 0;
 
        for_each_zone(zone)
-               zone->zone_pgdat->min_unmapped_pages += (zone->managed_pages *
-                               sysctl_min_unmapped_ratio) / 100;
-       return 0;
+               zone->zone_pgdat->min_slab_pages += (zone->managed_pages *
+                               sysctl_min_slab_ratio) / 100;
 }
 
 int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
-       struct pglist_data *pgdat;
-       struct zone *zone;
        int rc;
 
        rc = proc_dointvec_minmax(table, write, buffer, length, ppos);
        if (rc)
                return rc;
 
-       for_each_online_pgdat(pgdat)
-               pgdat->min_slab_pages = 0;
+       setup_min_slab_ratio();
 
-       for_each_zone(zone)
-               zone->zone_pgdat->min_slab_pages += (zone->managed_pages *
-                               sysctl_min_slab_ratio) / 100;
        return 0;
 }
 #endif
index fb1fa26..16bd82f 100644 (file)
@@ -319,9 +319,10 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
                ret = -ENOMEM;
                goto out;
        }
-       bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
        if (wbc->sync_mode == WB_SYNC_ALL)
-               bio->bi_rw |= REQ_SYNC;
+               bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_SYNC);
+       else
+               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
        count_vm_event(PSWPOUT);
        set_page_writeback(page);
        unlock_page(page);
index 709bc83..1ef3640 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1284,8 +1284,9 @@ void page_add_file_rmap(struct page *page, bool compound)
                VM_BUG_ON_PAGE(!PageSwapBacked(page), page);
                __inc_node_page_state(page, NR_SHMEM_PMDMAPPED);
        } else {
-               if (PageTransCompound(page)) {
-                       VM_BUG_ON_PAGE(!PageLocked(page), page);
+               if (PageTransCompound(page) && page_mapping(page)) {
+                       VM_WARN_ON_ONCE(!PageLocked(page));
+
                        SetPageDoubleMap(compound_head(page));
                        if (PageMlocked(page))
                                clear_page_mlock(compound_head(page));
@@ -1303,7 +1304,7 @@ static void page_remove_file_rmap(struct page *page, bool compound)
 {
        int i, nr = 1;
 
-       VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page);
+       VM_BUG_ON_PAGE(compound && !PageHead(page), page);
        lock_page_memcg(page);
 
        /* Hugepages are not counted in NR_FILE_MAPPED for now. */
index 2ac19a6..fd8b2b5 100644 (file)
@@ -1362,13 +1362,14 @@ static struct page *shmem_alloc_hugepage(gfp_t gfp,
        struct vm_area_struct pvma;
        struct inode *inode = &info->vfs_inode;
        struct address_space *mapping = inode->i_mapping;
-       pgoff_t idx, hindex = round_down(index, HPAGE_PMD_NR);
+       pgoff_t idx, hindex;
        void __rcu **results;
        struct page *page;
 
        if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
                return NULL;
 
+       hindex = round_down(index, HPAGE_PMD_NR);
        rcu_read_lock();
        if (radix_tree_gang_lookup_slot(&mapping->page_tree, &results, &idx,
                                hindex, 1) && idx < hindex + HPAGE_PMD_NR) {
@@ -3974,7 +3975,9 @@ static ssize_t shmem_enabled_store(struct kobject *kobj,
 
 struct kobj_attribute shmem_enabled_attr =
        __ATTR(shmem_enabled, 0644, shmem_enabled_show, shmem_enabled_store);
+#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE && CONFIG_SYSFS */
 
+#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
 bool shmem_huge_enabled(struct vm_area_struct *vma)
 {
        struct inode *inode = file_inode(vma->vm_file);
@@ -4005,7 +4008,7 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
                        return false;
        }
 }
-#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE && CONFIG_SYSFS */
+#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE */
 
 #else /* !CONFIG_SHMEM */
 
index 09771ed..b672710 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1877,7 +1877,7 @@ static struct array_cache __percpu *alloc_kmem_cache_cpus(
        return cpu_cache;
 }
 
-static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
+static int __ref setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 {
        if (slab_state >= FULL)
                return enable_cpucache(cachep, gfp);
@@ -2604,9 +2604,11 @@ static void cache_init_objs(struct kmem_cache *cachep,
        }
 
        for (i = 0; i < cachep->num; i++) {
+               objp = index_to_obj(cachep, page, i);
+               kasan_init_slab_obj(cachep, objp);
+
                /* constructor could break poison info */
                if (DEBUG == 0 && cachep->ctor) {
-                       objp = index_to_obj(cachep, page, i);
                        kasan_unpoison_object_data(cachep, objp);
                        cachep->ctor(objp);
                        kasan_poison_object_data(cachep, objp);
@@ -4439,6 +4441,36 @@ static int __init slab_proc_init(void)
 module_init(slab_proc_init);
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
+/*
+ * Rejects objects that are incorrectly sized.
+ *
+ * Returns NULL if check passes, otherwise const char * to name of cache
+ * to indicate an error.
+ */
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page)
+{
+       struct kmem_cache *cachep;
+       unsigned int objnr;
+       unsigned long offset;
+
+       /* Find and validate object. */
+       cachep = page->slab_cache;
+       objnr = obj_to_index(cachep, page, (void *)ptr);
+       BUG_ON(objnr >= cachep->num);
+
+       /* Find offset within object. */
+       offset = ptr - index_to_obj(cachep, page, objnr) - obj_offset(cachep);
+
+       /* Allow address range falling entirely within object size. */
+       if (offset <= cachep->object_size && n <= cachep->object_size - offset)
+               return NULL;
+
+       return cachep->name;
+}
+#endif /* CONFIG_HARDENED_USERCOPY */
+
 /**
  * ksize - get the actual amount of memory allocated for a given object
  * @objp: Pointer to the object
index 74e7c8c..9adae58 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -124,7 +124,7 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #endif
 }
 
-inline void *fixup_red_left(struct kmem_cache *s, void *p)
+void *fixup_red_left(struct kmem_cache *s, void *p)
 {
        if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE)
                p += s->red_left_pad;
@@ -1384,6 +1384,7 @@ static void setup_object(struct kmem_cache *s, struct page *page,
                                void *object)
 {
        setup_object_debug(s, page, object);
+       kasan_init_slab_obj(s, object);
        if (unlikely(s->ctor)) {
                kasan_unpoison_object_data(s, object);
                s->ctor(object);
@@ -3628,6 +3629,7 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
  */
 static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 {
+       LIST_HEAD(discard);
        struct page *page, *h;
 
        BUG_ON(irqs_disabled());
@@ -3635,13 +3637,16 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
                        remove_partial(n, page);
-                       discard_slab(s, page);
+                       list_add(&page->lru, &discard);
                } else {
                        list_slab_objects(s, page,
                        "Objects remaining in %s on __kmem_cache_shutdown()");
                }
        }
        spin_unlock_irq(&n->list_lock);
+
+       list_for_each_entry_safe(page, h, &discard, lru)
+               discard_slab(s, page);
 }
 
 /*
@@ -3763,6 +3768,46 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 EXPORT_SYMBOL(__kmalloc_node);
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
+/*
+ * Rejects objects that are incorrectly sized.
+ *
+ * Returns NULL if check passes, otherwise const char * to name of cache
+ * to indicate an error.
+ */
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page)
+{
+       struct kmem_cache *s;
+       unsigned long offset;
+       size_t object_size;
+
+       /* Find object and usable object size. */
+       s = page->slab_cache;
+       object_size = slab_ksize(s);
+
+       /* Reject impossible pointers. */
+       if (ptr < page_address(page))
+               return s->name;
+
+       /* Find offset within object. */
+       offset = (ptr - page_address(page)) % s->size;
+
+       /* Adjust for redzone and reject if within the redzone. */
+       if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) {
+               if (offset < s->red_left_pad)
+                       return s->name;
+               offset -= s->red_left_pad;
+       }
+
+       /* Allow address range falling entirely within object size. */
+       if (offset <= object_size && n <= object_size - offset)
+               return NULL;
+
+       return s->name;
+}
+#endif /* CONFIG_HARDENED_USERCOPY */
+
 static size_t __ksize(const void *object)
 {
        struct page *page;
index 68885dc..574c67b 100644 (file)
@@ -36,7 +36,7 @@
  * Uses the main allocators if they are available, else bootmem.
  */
 
-static void * __init_refok __earlyonly_bootmem_alloc(int node,
+static void * __ref __earlyonly_bootmem_alloc(int node,
                                unsigned long size,
                                unsigned long align,
                                unsigned long goal)
index 36d7bbb..1e168bf 100644 (file)
@@ -59,7 +59,7 @@ static inline void set_section_nid(unsigned long section_nr, int nid)
 #endif
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
-static struct mem_section noinline __init_refok *sparse_index_alloc(int nid)
+static noinline struct mem_section __ref *sparse_index_alloc(int nid)
 {
        struct mem_section *section = NULL;
        unsigned long array_size = SECTIONS_PER_ROOT *
diff --git a/mm/usercopy.c b/mm/usercopy.c
new file mode 100644 (file)
index 0000000..8ebae91
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * This implements the various checks for CONFIG_HARDENED_USERCOPY*,
+ * which are designed to protect kernel memory from needless exposure
+ * and overwrite under many unintended conditions. This code is based
+ * on PAX_USERCOPY, which is:
+ *
+ * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source
+ * Security Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/sections.h>
+
+enum {
+       BAD_STACK = -1,
+       NOT_STACK = 0,
+       GOOD_FRAME,
+       GOOD_STACK,
+};
+
+/*
+ * Checks if a given pointer and length is contained by the current
+ * stack frame (if possible).
+ *
+ * Returns:
+ *     NOT_STACK: not at all on the stack
+ *     GOOD_FRAME: fully within a valid stack frame
+ *     GOOD_STACK: fully on the stack (when can't do frame-checking)
+ *     BAD_STACK: error condition (invalid stack position or bad stack frame)
+ */
+static noinline int check_stack_object(const void *obj, unsigned long len)
+{
+       const void * const stack = task_stack_page(current);
+       const void * const stackend = stack + THREAD_SIZE;
+       int ret;
+
+       /* Object is not on the stack at all. */
+       if (obj + len <= stack || stackend <= obj)
+               return NOT_STACK;
+
+       /*
+        * Reject: object partially overlaps the stack (passing the
+        * the check above means at least one end is within the stack,
+        * so if this check fails, the other end is outside the stack).
+        */
+       if (obj < stack || stackend < obj + len)
+               return BAD_STACK;
+
+       /* Check if object is safely within a valid frame. */
+       ret = arch_within_stack_frames(stack, stackend, obj, len);
+       if (ret)
+               return ret;
+
+       return GOOD_STACK;
+}
+
+static void report_usercopy(const void *ptr, unsigned long len,
+                           bool to_user, const char *type)
+{
+       pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
+               to_user ? "exposure" : "overwrite",
+               to_user ? "from" : "to", ptr, type ? : "unknown", len);
+       /*
+        * For greater effect, it would be nice to do do_group_exit(),
+        * but BUG() actually hooks all the lock-breaking and per-arch
+        * Oops code, so that is used here instead.
+        */
+       BUG();
+}
+
+/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */
+static bool overlaps(const void *ptr, unsigned long n, unsigned long low,
+                    unsigned long high)
+{
+       unsigned long check_low = (uintptr_t)ptr;
+       unsigned long check_high = check_low + n;
+
+       /* Does not overlap if entirely above or entirely below. */
+       if (check_low >= high || check_high < low)
+               return false;
+
+       return true;
+}
+
+/* Is this address range in the kernel text area? */
+static inline const char *check_kernel_text_object(const void *ptr,
+                                                  unsigned long n)
+{
+       unsigned long textlow = (unsigned long)_stext;
+       unsigned long texthigh = (unsigned long)_etext;
+       unsigned long textlow_linear, texthigh_linear;
+
+       if (overlaps(ptr, n, textlow, texthigh))
+               return "<kernel text>";
+
+       /*
+        * Some architectures have virtual memory mappings with a secondary
+        * mapping of the kernel text, i.e. there is more than one virtual
+        * kernel address that points to the kernel image. It is usually
+        * when there is a separate linear physical memory mapping, in that
+        * __pa() is not just the reverse of __va(). This can be detected
+        * and checked:
+        */
+       textlow_linear = (unsigned long)__va(__pa(textlow));
+       /* No different mapping: we're done. */
+       if (textlow_linear == textlow)
+               return NULL;
+
+       /* Check the secondary mapping... */
+       texthigh_linear = (unsigned long)__va(__pa(texthigh));
+       if (overlaps(ptr, n, textlow_linear, texthigh_linear))
+               return "<linear kernel text>";
+
+       return NULL;
+}
+
+static inline const char *check_bogus_address(const void *ptr, unsigned long n)
+{
+       /* Reject if object wraps past end of memory. */
+       if (ptr + n < ptr)
+               return "<wrapped address>";
+
+       /* Reject if NULL or ZERO-allocation. */
+       if (ZERO_OR_NULL_PTR(ptr))
+               return "<null>";
+
+       return NULL;
+}
+
+static inline const char *check_heap_object(const void *ptr, unsigned long n,
+                                           bool to_user)
+{
+       struct page *page, *endpage;
+       const void *end = ptr + n - 1;
+       bool is_reserved, is_cma;
+
+       /*
+        * Some architectures (arm64) return true for virt_addr_valid() on
+        * vmalloced addresses. Work around this by checking for vmalloc
+        * first.
+        */
+       if (is_vmalloc_addr(ptr))
+               return NULL;
+
+       if (!virt_addr_valid(ptr))
+               return NULL;
+
+       page = virt_to_head_page(ptr);
+
+       /* Check slab allocator for flags and size. */
+       if (PageSlab(page))
+               return __check_heap_object(ptr, n, page);
+
+       /*
+        * Sometimes the kernel data regions are not marked Reserved (see
+        * check below). And sometimes [_sdata,_edata) does not cover
+        * rodata and/or bss, so check each range explicitly.
+        */
+
+       /* Allow reads of kernel rodata region (if not marked as Reserved). */
+       if (ptr >= (const void *)__start_rodata &&
+           end <= (const void *)__end_rodata) {
+               if (!to_user)
+                       return "<rodata>";
+               return NULL;
+       }
+
+       /* Allow kernel data region (if not marked as Reserved). */
+       if (ptr >= (const void *)_sdata && end <= (const void *)_edata)
+               return NULL;
+
+       /* Allow kernel bss region (if not marked as Reserved). */
+       if (ptr >= (const void *)__bss_start &&
+           end <= (const void *)__bss_stop)
+               return NULL;
+
+       /* Is the object wholly within one base page? */
+       if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) ==
+                  ((unsigned long)end & (unsigned long)PAGE_MASK)))
+               return NULL;
+
+       /* Allow if start and end are inside the same compound page. */
+       endpage = virt_to_head_page(end);
+       if (likely(endpage == page))
+               return NULL;
+
+       /*
+        * Reject if range is entirely either Reserved (i.e. special or
+        * device memory), or CMA. Otherwise, reject since the object spans
+        * several independently allocated pages.
+        */
+       is_reserved = PageReserved(page);
+       is_cma = is_migrate_cma_page(page);
+       if (!is_reserved && !is_cma)
+               goto reject;
+
+       for (ptr += PAGE_SIZE; ptr <= end; ptr += PAGE_SIZE) {
+               page = virt_to_head_page(ptr);
+               if (is_reserved && !PageReserved(page))
+                       goto reject;
+               if (is_cma && !is_migrate_cma_page(page))
+                       goto reject;
+       }
+
+       return NULL;
+
+reject:
+       return "<spans multiple pages>";
+}
+
+/*
+ * Validates that the given object is:
+ * - not bogus address
+ * - known-safe heap or stack object
+ * - not in kernel text
+ */
+void __check_object_size(const void *ptr, unsigned long n, bool to_user)
+{
+       const char *err;
+
+       /* Skip all tests if size is zero. */
+       if (!n)
+               return;
+
+       /* Check for invalid addresses. */
+       err = check_bogus_address(ptr, n);
+       if (err)
+               goto report;
+
+       /* Check for bad heap object. */
+       err = check_heap_object(ptr, n, to_user);
+       if (err)
+               goto report;
+
+       /* Check for bad stack object. */
+       switch (check_stack_object(ptr, n)) {
+       case NOT_STACK:
+               /* Object is not touching the current process stack. */
+               break;
+       case GOOD_FRAME:
+       case GOOD_STACK:
+               /*
+                * Object is either in the correct frame (when it
+                * is possible to check) or just generally on the
+                * process stack (when frame checking not available).
+                */
+               return;
+       default:
+               err = "<process stack>";
+               goto report;
+       }
+
+       /* Check for object in kernel to avoid text exposure. */
+       err = check_kernel_text_object(ptr, n);
+       if (!err)
+               return;
+
+report:
+       report_usercopy(ptr, n, to_user, err);
+}
+EXPORT_SYMBOL(__check_object_size);
index 650d268..374d95d 100644 (file)
@@ -2561,7 +2561,7 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc)
                        shrink_node_memcg(pgdat, memcg, sc, &lru_pages);
                        node_lru_pages += lru_pages;
 
-                       if (!global_reclaim(sc))
+                       if (memcg)
                                shrink_slab(sc->gfp_mask, pgdat->node_id,
                                            memcg, sc->nr_scanned - scanned,
                                            lru_pages);
index 4acb1d5..f24b25c 100644 (file)
@@ -507,8 +507,8 @@ err_out:
                /* wakeup anybody waiting for slots to pin pages */
                wake_up(&vp_wq);
        }
-       kfree(in_pages);
-       kfree(out_pages);
+       kvfree(in_pages);
+       kvfree(out_pages);
        return err;
 }
 
index 958d985..84cbed6 100644 (file)
@@ -11,5 +11,5 @@ libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
        crypto.o armor.o \
        auth_x.o \
        ceph_fs.o ceph_strings.o ceph_hash.o \
-       pagevec.o snapshot.o
+       pagevec.o snapshot.o string_table.o
 
index 55d2bfe..bddfcf6 100644 (file)
@@ -747,6 +747,8 @@ out:
 static void __exit exit_ceph_lib(void)
 {
        dout("exit_ceph_lib\n");
+       WARN_ON(!ceph_strings_empty());
+
        ceph_osdc_cleanup();
        ceph_msgr_exit();
        ceph_crypto_shutdown();
index 41466cc..7d54e94 100644 (file)
@@ -9,9 +9,9 @@
  */
 int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
 {
-       __u32 su = le32_to_cpu(layout->fl_stripe_unit);
-       __u32 sc = le32_to_cpu(layout->fl_stripe_count);
-       __u32 os = le32_to_cpu(layout->fl_object_size);
+       __u32 su = layout->stripe_unit;
+       __u32 sc = layout->stripe_count;
+       __u32 os = layout->object_size;
 
        /* stripe unit, object size must be non-zero, 64k increment */
        if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1)))
@@ -27,6 +27,30 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
        return 1;
 }
 
+void ceph_file_layout_from_legacy(struct ceph_file_layout *fl,
+                                 struct ceph_file_layout_legacy *legacy)
+{
+       fl->stripe_unit = le32_to_cpu(legacy->fl_stripe_unit);
+       fl->stripe_count = le32_to_cpu(legacy->fl_stripe_count);
+       fl->object_size = le32_to_cpu(legacy->fl_object_size);
+       fl->pool_id = le32_to_cpu(legacy->fl_pg_pool);
+       if (fl->pool_id == 0)
+               fl->pool_id = -1;
+}
+EXPORT_SYMBOL(ceph_file_layout_from_legacy);
+
+void ceph_file_layout_to_legacy(struct ceph_file_layout *fl,
+                               struct ceph_file_layout_legacy *legacy)
+{
+       legacy->fl_stripe_unit = cpu_to_le32(fl->stripe_unit);
+       legacy->fl_stripe_count = cpu_to_le32(fl->stripe_count);
+       legacy->fl_object_size = cpu_to_le32(fl->object_size);
+       if (fl->pool_id >= 0)
+               legacy->fl_pg_pool = cpu_to_le32(fl->pool_id);
+       else
+               legacy->fl_pg_pool = 0;
+}
+EXPORT_SYMBOL(ceph_file_layout_to_legacy);
 
 int ceph_flags_to_mode(int flags)
 {
index e77b04c..c62b2b0 100644 (file)
@@ -156,8 +156,16 @@ static void dump_target(struct seq_file *s, struct ceph_osd_request_target *t)
        seq_printf(s, "]/%d\t[", t->up.primary);
        for (i = 0; i < t->acting.size; i++)
                seq_printf(s, "%s%d", (!i ? "" : ","), t->acting.osds[i]);
-       seq_printf(s, "]/%d\t%*pE\t0x%x", t->acting.primary,
-                  t->target_oid.name_len, t->target_oid.name, t->flags);
+       seq_printf(s, "]/%d\t", t->acting.primary);
+       if (t->target_oloc.pool_ns) {
+               seq_printf(s, "%*pE/%*pE\t0x%x",
+                       (int)t->target_oloc.pool_ns->len,
+                       t->target_oloc.pool_ns->str,
+                       t->target_oid.name_len, t->target_oid.name, t->flags);
+       } else {
+               seq_printf(s, "%*pE\t0x%x", t->target_oid.name_len,
+                       t->target_oid.name, t->flags);
+       }
        if (t->paused)
                seq_puts(s, "\tP");
 }
index 37c38a7..ef34a02 100644 (file)
@@ -227,9 +227,10 @@ static void __schedule_delayed(struct ceph_mon_client *monc)
 }
 
 const char *ceph_sub_str[] = {
-       [CEPH_SUB_MDSMAP] = "mdsmap",
        [CEPH_SUB_MONMAP] = "monmap",
        [CEPH_SUB_OSDMAP] = "osdmap",
+       [CEPH_SUB_FSMAP]  = "fsmap.user",
+       [CEPH_SUB_MDSMAP] = "mdsmap",
 };
 
 /*
@@ -573,7 +574,7 @@ static void complete_generic_request(struct ceph_mon_generic_request *req)
        put_generic_request(req);
 }
 
-void cancel_generic_request(struct ceph_mon_generic_request *req)
+static void cancel_generic_request(struct ceph_mon_generic_request *req)
 {
        struct ceph_mon_client *monc = req->monc;
        struct ceph_mon_generic_request *lookup_req;
@@ -1193,6 +1194,7 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
        case CEPH_MSG_MON_MAP:
        case CEPH_MSG_MDS_MAP:
        case CEPH_MSG_OSD_MAP:
+       case CEPH_MSG_FS_MAP_USER:
                m = ceph_msg_new(type, front_len, GFP_NOFS, false);
                if (!m)
                        return NULL;    /* ENOMEM--return skip == 0 */
index ddec1c1..aaed59a 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 
+#include <linux/ceph/messenger.h>
 #include <linux/ceph/msgpool.h>
 
 static void *msgpool_alloc(gfp_t gfp_mask, void *arg)
index 8946959..a97e7b5 100644 (file)
@@ -387,7 +387,9 @@ static void target_copy(struct ceph_osd_request_target *dest,
 static void target_destroy(struct ceph_osd_request_target *t)
 {
        ceph_oid_destroy(&t->base_oid);
+       ceph_oloc_destroy(&t->base_oloc);
        ceph_oid_destroy(&t->target_oid);
+       ceph_oloc_destroy(&t->target_oloc);
 }
 
 /*
@@ -533,6 +535,11 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
 }
 EXPORT_SYMBOL(ceph_osdc_alloc_request);
 
+static int ceph_oloc_encoding_size(struct ceph_object_locator *oloc)
+{
+       return 8 + 4 + 4 + 4 + (oloc->pool_ns ? oloc->pool_ns->len : 0);
+}
+
 int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
 {
        struct ceph_osd_client *osdc = req->r_osdc;
@@ -540,11 +547,13 @@ int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
        int msg_size;
 
        WARN_ON(ceph_oid_empty(&req->r_base_oid));
+       WARN_ON(ceph_oloc_empty(&req->r_base_oloc));
 
        /* create request message */
        msg_size = 4 + 4 + 4; /* client_inc, osdmap_epoch, flags */
        msg_size += 4 + 4 + 4 + 8; /* mtime, reassert_version */
-       msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */
+       msg_size += CEPH_ENCODING_START_BLK_LEN +
+                       ceph_oloc_encoding_size(&req->r_base_oloc); /* oloc */
        msg_size += 1 + 8 + 4 + 4; /* pgid */
        msg_size += 4 + req->r_base_oid.name_len; /* oid */
        msg_size += 2 + req->r_num_ops * sizeof(struct ceph_osd_op);
@@ -932,7 +941,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        if (opcode == CEPH_OSD_OP_CREATE || opcode == CEPH_OSD_OP_DELETE) {
                osd_req_op_init(req, which, opcode, 0);
        } else {
-               u32 object_size = le32_to_cpu(layout->fl_object_size);
+               u32 object_size = layout->object_size;
                u32 object_base = off - objoff;
                if (!(truncate_seq == 1 && truncate_size == -1ULL)) {
                        if (truncate_size <= object_base) {
@@ -948,7 +957,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        }
 
        req->r_flags = flags;
-       req->r_base_oloc.pool = ceph_file_layout_pg_pool(*layout);
+       req->r_base_oloc.pool = layout->pool_id;
+       req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns);
        ceph_oid_printf(&req->r_base_oid, "%llx.%08llx", vino.ino, objnum);
 
        req->r_snapid = vino.snap;
@@ -1489,12 +1499,16 @@ static void encode_request(struct ceph_osd_request *req, struct ceph_msg *msg)
        p += sizeof(req->r_replay_version);
 
        /* oloc */
-       ceph_encode_8(&p, 4);
-       ceph_encode_8(&p, 4);
-       ceph_encode_32(&p, 8 + 4 + 4);
+       ceph_start_encoding(&p, 5, 4,
+                           ceph_oloc_encoding_size(&req->r_t.target_oloc));
        ceph_encode_64(&p, req->r_t.target_oloc.pool);
        ceph_encode_32(&p, -1); /* preferred */
        ceph_encode_32(&p, 0); /* key len */
+       if (req->r_t.target_oloc.pool_ns)
+               ceph_encode_string(&p, end, req->r_t.target_oloc.pool_ns->str,
+                                  req->r_t.target_oloc.pool_ns->len);
+       else
+               ceph_encode_32(&p, 0);
 
        /* pgid */
        ceph_encode_8(&p, 1);
@@ -2594,9 +2608,22 @@ static int ceph_oloc_decode(void **p, void *end,
        }
 
        if (struct_v >= 5) {
+               bool changed = false;
+
                len = ceph_decode_32(p);
                if (len > 0) {
-                       pr_warn("ceph_object_locator::nspace is set\n");
+                       ceph_decode_need(p, end, len, e_inval);
+                       if (!oloc->pool_ns ||
+                           ceph_compare_string(oloc->pool_ns, *p, len))
+                               changed = true;
+                       *p += len;
+               } else {
+                       if (oloc->pool_ns)
+                               changed = true;
+               }
+               if (changed) {
+                       /* redirect changes namespace */
+                       pr_warn("ceph_object_locator::nspace is changed\n");
                        goto e_inval;
                }
        }
@@ -2806,7 +2833,9 @@ static void handle_reply(struct ceph_osd *osd, struct ceph_msg *msg)
                goto out_unlock_session;
        }
 
+       m.redirect.oloc.pool_ns = req->r_t.target_oloc.pool_ns;
        ret = decode_MOSDOpReply(msg, &m);
+       m.redirect.oloc.pool_ns = NULL;
        if (ret) {
                pr_err("failed to decode MOSDOpReply for tid %llu: %d\n",
                       req->r_tid, ret);
@@ -2835,7 +2864,11 @@ static void handle_reply(struct ceph_osd *osd, struct ceph_msg *msg)
                unlink_request(osd, req);
                mutex_unlock(&osd->lock);
 
-               ceph_oloc_copy(&req->r_t.target_oloc, &m.redirect.oloc);
+               /*
+                * Not ceph_oloc_copy() - changing pool_ns is not
+                * supported.
+                */
+               req->r_t.target_oloc.pool = m.redirect.oloc.pool;
                req->r_flags |= CEPH_OSD_FLAG_REDIRECTED;
                req->r_tid = 0;
                __submit_request(req, false);
@@ -4187,7 +4220,7 @@ static struct ceph_msg *alloc_msg_with_page_vector(struct ceph_msg_header *hdr)
 
                pages = ceph_alloc_page_vector(calc_pages_for(0, data_len),
                                               GFP_NOIO);
-               if (!pages) {
+               if (IS_ERR(pages)) {
                        ceph_msg_put(m);
                        return NULL;
                }
index 7e480bf..d243688 100644 (file)
@@ -1510,6 +1510,24 @@ bad:
        return ERR_PTR(err);
 }
 
+void ceph_oloc_copy(struct ceph_object_locator *dest,
+                   const struct ceph_object_locator *src)
+{
+       WARN_ON(!ceph_oloc_empty(dest));
+       WARN_ON(dest->pool_ns); /* empty() only covers ->pool */
+
+       dest->pool = src->pool;
+       if (src->pool_ns)
+               dest->pool_ns = ceph_get_string(src->pool_ns);
+}
+EXPORT_SYMBOL(ceph_oloc_copy);
+
+void ceph_oloc_destroy(struct ceph_object_locator *oloc)
+{
+       ceph_put_string(oloc->pool_ns);
+}
+EXPORT_SYMBOL(ceph_oloc_destroy);
+
 void ceph_oid_copy(struct ceph_object_id *dest,
                   const struct ceph_object_id *src)
 {
@@ -1770,9 +1788,9 @@ int ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
                                   u64 *ono,
                                   u64 *oxoff, u64 *oxlen)
 {
-       u32 osize = le32_to_cpu(layout->fl_object_size);
-       u32 su = le32_to_cpu(layout->fl_stripe_unit);
-       u32 sc = le32_to_cpu(layout->fl_stripe_count);
+       u32 osize = layout->object_size;
+       u32 su = layout->stripe_unit;
+       u32 sc = layout->stripe_count;
        u32 bl, stripeno, stripepos, objsetno;
        u32 su_per_object;
        u64 t, su_offset;
@@ -1844,12 +1862,34 @@ int ceph_object_locator_to_pg(struct ceph_osdmap *osdmap,
        if (!pi)
                return -ENOENT;
 
-       raw_pgid->pool = oloc->pool;
-       raw_pgid->seed = ceph_str_hash(pi->object_hash, oid->name,
-                                      oid->name_len);
-
-       dout("%s %s -> raw_pgid %llu.%x\n", __func__, oid->name,
-            raw_pgid->pool, raw_pgid->seed);
+       if (!oloc->pool_ns) {
+               raw_pgid->pool = oloc->pool;
+               raw_pgid->seed = ceph_str_hash(pi->object_hash, oid->name,
+                                            oid->name_len);
+               dout("%s %s -> raw_pgid %llu.%x\n", __func__, oid->name,
+                    raw_pgid->pool, raw_pgid->seed);
+       } else {
+               char stack_buf[256];
+               char *buf = stack_buf;
+               int nsl = oloc->pool_ns->len;
+               size_t total = nsl + 1 + oid->name_len;
+
+               if (total > sizeof(stack_buf)) {
+                       buf = kmalloc(total, GFP_NOIO);
+                       if (!buf)
+                               return -ENOMEM;
+               }
+               memcpy(buf, oloc->pool_ns->str, nsl);
+               buf[nsl] = '\037';
+               memcpy(buf + nsl + 1, oid->name, oid->name_len);
+               raw_pgid->pool = oloc->pool;
+               raw_pgid->seed = ceph_str_hash(pi->object_hash, buf, total);
+               if (buf != stack_buf)
+                       kfree(buf);
+               dout("%s %s ns %.*s -> raw_pgid %llu.%x\n", __func__,
+                    oid->name, nsl, oloc->pool_ns->str,
+                    raw_pgid->pool, raw_pgid->seed);
+       }
        return 0;
 }
 EXPORT_SYMBOL(ceph_object_locator_to_pg);
diff --git a/net/ceph/string_table.c b/net/ceph/string_table.c
new file mode 100644 (file)
index 0000000..22fb96e
--- /dev/null
@@ -0,0 +1,105 @@
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/ceph/string_table.h>
+
+static DEFINE_SPINLOCK(string_tree_lock);
+static struct rb_root string_tree = RB_ROOT;
+
+struct ceph_string *ceph_find_or_create_string(const char* str, size_t len)
+{
+       struct ceph_string *cs, *exist;
+       struct rb_node **p, *parent;
+       int ret;
+
+       exist = NULL;
+       spin_lock(&string_tree_lock);
+       p = &string_tree.rb_node;
+       while (*p) {
+               exist = rb_entry(*p, struct ceph_string, node);
+               ret = ceph_compare_string(exist, str, len);
+               if (ret > 0)
+                       p = &(*p)->rb_left;
+               else if (ret < 0)
+                       p = &(*p)->rb_right;
+               else
+                       break;
+               exist = NULL;
+       }
+       if (exist && !kref_get_unless_zero(&exist->kref)) {
+               rb_erase(&exist->node, &string_tree);
+               RB_CLEAR_NODE(&exist->node);
+               exist = NULL;
+       }
+       spin_unlock(&string_tree_lock);
+       if (exist)
+               return exist;
+
+       cs = kmalloc(sizeof(*cs) + len + 1, GFP_NOFS);
+       if (!cs)
+               return NULL;
+
+       kref_init(&cs->kref);
+       cs->len = len;
+       memcpy(cs->str, str, len);
+       cs->str[len] = 0;
+
+retry:
+       exist = NULL;
+       parent = NULL;
+       p = &string_tree.rb_node;
+       spin_lock(&string_tree_lock);
+       while (*p) {
+               parent = *p;
+               exist = rb_entry(*p, struct ceph_string, node);
+               ret = ceph_compare_string(exist, str, len);
+               if (ret > 0)
+                       p = &(*p)->rb_left;
+               else if (ret < 0)
+                       p = &(*p)->rb_right;
+               else
+                       break;
+               exist = NULL;
+       }
+       ret = 0;
+       if (!exist) {
+               rb_link_node(&cs->node, parent, p);
+               rb_insert_color(&cs->node, &string_tree);
+       } else if (!kref_get_unless_zero(&exist->kref)) {
+               rb_erase(&exist->node, &string_tree);
+               RB_CLEAR_NODE(&exist->node);
+               ret = -EAGAIN;
+       }
+       spin_unlock(&string_tree_lock);
+       if (ret == -EAGAIN)
+               goto retry;
+
+       if (exist) {
+               kfree(cs);
+               cs = exist;
+       }
+
+       return cs;
+}
+EXPORT_SYMBOL(ceph_find_or_create_string);
+
+void ceph_release_string(struct kref *ref)
+{
+       struct ceph_string *cs = container_of(ref, struct ceph_string, kref);
+
+       spin_lock(&string_tree_lock);
+       if (!RB_EMPTY_NODE(&cs->node)) {
+               rb_erase(&cs->node, &string_tree);
+               RB_CLEAR_NODE(&cs->node);
+       }
+       spin_unlock(&string_tree_lock);
+
+       kfree_rcu(cs, rcu);
+}
+EXPORT_SYMBOL(ceph_release_string);
+
+bool ceph_strings_empty(void)
+{
+       return RB_EMPTY_ROOT(&string_tree);
+}
index b26aa87..bdaef7f 100644 (file)
@@ -236,7 +236,8 @@ void tcp_select_initial_window(int __space, __u32 mss,
                /* Set window scaling on max possible window
                 * See RFC1323 for an explanation of the limit to 14
                 */
-               space = max_t(u32, sysctl_tcp_rmem[2], sysctl_rmem_max);
+               space = max_t(u32, space, sysctl_tcp_rmem[2]);
+               space = max_t(u32, space, sysctl_rmem_max);
                space = min_t(u32, space, *window_clamp);
                while (space > 65535 && (*rcv_wscale) < 14) {
                        space >>= 1;
index 6287a8b..ab3e796 100644 (file)
@@ -3624,8 +3624,7 @@ restart:
                        state = ifa->state;
                        ifa->state = INET6_IFADDR_STATE_DEAD;
 
-                       list_del(&ifa->if_list);
-                       list_add(&ifa->if_list, &del_list);
+                       list_move(&ifa->if_list, &del_list);
                }
 
                spin_unlock_bh(&ifa->lock);
index 7425f6c..1f1682b 100644 (file)
@@ -610,7 +610,8 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
                                /* We will generate more packets, so re-queue
                                 * auth chunk.
                                 */
-                               list_add(&chunk->list, &packet->chunk_list);
+                               list_add(&packet->auth->list,
+                                        &packet->chunk_list);
                        } else {
                                sctp_chunk_free(packet->auth);
                                packet->auth = NULL;
index 8812e1b..9fc417a 100644 (file)
@@ -2079,7 +2079,7 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
        lock_sock(sk);
 
        if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) &&
-           !sctp_sstate(sk, CLOSING)) {
+           !sctp_sstate(sk, CLOSING) && !sctp_sstate(sk, CLOSED)) {
                err = -ENOTCONN;
                goto out;
        }
index ec166d2..877e550 100644 (file)
@@ -204,7 +204,9 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
        /* If the socket is just going to throw this away, do not
         * even try to deliver it.
         */
-       if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (sk->sk_shutdown & RCV_SHUTDOWN &&
+           (sk->sk_shutdown & SEND_SHUTDOWN ||
+            !sctp_ulpevent_is_notification(event)))
                goto out_free;
 
        if (!sctp_ulpevent_is_notification(event)) {
index e085f5a..1d28181 100644 (file)
@@ -1230,8 +1230,9 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
        if (status)
                goto out;
 
-       dprintk("RPC:       svcauth_gss: gss major status = %d\n",
-                       ud.major_status);
+       dprintk("RPC:       svcauth_gss: gss major status = %d "
+                       "minor status = %d\n",
+                       ud.major_status, ud.minor_status);
 
        switch (ud.major_status) {
        case GSS_S_CONTINUE_NEEDED:
index 553bf95..4d8e11f 100644 (file)
@@ -362,7 +362,7 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd)
        cache_purge(cd);
        spin_lock(&cache_list_lock);
        write_lock(&cd->hash_lock);
-       if (cd->entries || atomic_read(&cd->inuse)) {
+       if (cd->entries) {
                write_unlock(&cd->hash_lock);
                spin_unlock(&cache_list_lock);
                goto out;
index 4f01f63..c3f6523 100644 (file)
 
 #define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
+static unsigned int svc_rpc_per_connection_limit __read_mostly;
+module_param(svc_rpc_per_connection_limit, uint, 0644);
+
+
 static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
 static int svc_deferred_recv(struct svc_rqst *rqstp);
 static struct cache_deferred_req *svc_defer(struct cache_req *req);
@@ -329,12 +333,45 @@ char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
 }
 EXPORT_SYMBOL_GPL(svc_print_addr);
 
+static bool svc_xprt_slots_in_range(struct svc_xprt *xprt)
+{
+       unsigned int limit = svc_rpc_per_connection_limit;
+       int nrqsts = atomic_read(&xprt->xpt_nr_rqsts);
+
+       return limit == 0 || (nrqsts >= 0 && nrqsts < limit);
+}
+
+static bool svc_xprt_reserve_slot(struct svc_rqst *rqstp, struct svc_xprt *xprt)
+{
+       if (!test_bit(RQ_DATA, &rqstp->rq_flags)) {
+               if (!svc_xprt_slots_in_range(xprt))
+                       return false;
+               atomic_inc(&xprt->xpt_nr_rqsts);
+               set_bit(RQ_DATA, &rqstp->rq_flags);
+       }
+       return true;
+}
+
+static void svc_xprt_release_slot(struct svc_rqst *rqstp)
+{
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) {
+               atomic_dec(&xprt->xpt_nr_rqsts);
+               svc_xprt_enqueue(xprt);
+       }
+}
+
 static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
 {
        if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
                return true;
-       if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED)))
-               return xprt->xpt_ops->xpo_has_wspace(xprt);
+       if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) {
+               if (xprt->xpt_ops->xpo_has_wspace(xprt) &&
+                   svc_xprt_slots_in_range(xprt))
+                       return true;
+               trace_svc_xprt_no_write_space(xprt);
+               return false;
+       }
        return false;
 }
 
@@ -480,8 +517,6 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
                atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
                rqstp->rq_reserved = space;
 
-               if (xprt->xpt_ops->xpo_adjust_wspace)
-                       xprt->xpt_ops->xpo_adjust_wspace(xprt);
                svc_xprt_enqueue(xprt);
        }
 }
@@ -512,8 +547,8 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
 
        rqstp->rq_res.head[0].iov_len = 0;
        svc_reserve(rqstp, 0);
+       svc_xprt_release_slot(rqstp);
        rqstp->rq_xprt = NULL;
-
        svc_xprt_put(xprt);
 }
 
@@ -781,7 +816,7 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt)
                        svc_add_new_temp_xprt(serv, newxpt);
                else
                        module_put(xprt->xpt_class->xcl_owner);
-       } else {
+       } else if (svc_xprt_reserve_slot(rqstp, xprt)) {
                /* XPT_DATA|XPT_DEFERRED case: */
                dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
                        rqstp, rqstp->rq_pool->sp_id, xprt,
@@ -871,6 +906,7 @@ EXPORT_SYMBOL_GPL(svc_recv);
  */
 void svc_drop(struct svc_rqst *rqstp)
 {
+       trace_svc_drop(rqstp);
        dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
        svc_xprt_release(rqstp);
 }
@@ -1148,6 +1184,7 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
                spin_unlock(&xprt->xpt_lock);
                dprintk("revisit canceled\n");
                svc_xprt_put(xprt);
+               trace_svc_drop_deferred(dr);
                kfree(dr);
                return;
        }
@@ -1205,6 +1242,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
        set_bit(RQ_DROPME, &rqstp->rq_flags);
 
        dr->handle.revisit = svc_revisit;
+       trace_svc_defer(rqstp);
        return &dr->handle;
 }
 
@@ -1245,6 +1283,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
                                struct svc_deferred_req,
                                handle.recent);
                list_del_init(&dr->handle.recent);
+               trace_svc_revisit_deferred(dr);
        } else
                clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
        spin_unlock(&xprt->xpt_lock);
index dadfec6..57625f6 100644 (file)
@@ -60,7 +60,6 @@
 
 static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
                                         int flags);
-static void            svc_udp_data_ready(struct sock *);
 static int             svc_udp_recvfrom(struct svc_rqst *);
 static int             svc_udp_sendto(struct svc_rqst *);
 static void            svc_sock_detach(struct svc_xprt *);
@@ -398,48 +397,21 @@ static int svc_sock_secure_port(struct svc_rqst *rqstp)
        return svc_port_is_privileged(svc_addr(rqstp));
 }
 
-static bool sunrpc_waitqueue_active(wait_queue_head_t *wq)
-{
-       if (!wq)
-               return false;
-       /*
-        * There should normally be a memory * barrier here--see
-        * wq_has_sleeper().
-        *
-        * It appears that isn't currently necessary, though, basically
-        * because callers all appear to have sufficient memory barriers
-        * between the time the relevant change is made and the
-        * time they call these callbacks.
-        *
-        * The nfsd code itself doesn't actually explicitly wait on
-        * these waitqueues, but it may wait on them for example in
-        * sendpage() or sendmsg() calls.  (And those may be the only
-        * places, since it it uses nonblocking reads.)
-        *
-        * Maybe we should add the memory barriers anyway, but these are
-        * hot paths so we'd need to be convinced there's no sigificant
-        * penalty.
-        */
-       return waitqueue_active(wq);
-}
-
 /*
  * INET callback when data has been received on the socket.
  */
-static void svc_udp_data_ready(struct sock *sk)
+static void svc_data_ready(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
-       wait_queue_head_t *wq = sk_sleep(sk);
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), busy=%d\n",
                        svsk, sk,
                        test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
-               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-               svc_xprt_enqueue(&svsk->sk_xprt);
+               svsk->sk_odata(sk);
+               if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
+                       svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sunrpc_waitqueue_active(wq))
-               wake_up_interruptible(wq);
 }
 
 /*
@@ -448,56 +420,22 @@ static void svc_udp_data_ready(struct sock *sk)
 static void svc_write_space(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
-       wait_queue_head_t *wq = sk_sleep(sk);
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
                        svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+               svsk->sk_owspace(sk);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-
-       if (sunrpc_waitqueue_active(wq)) {
-               dprintk("RPC svc_write_space: someone sleeping on %p\n",
-                      svsk);
-               wake_up_interruptible(wq);
-       }
 }
 
 static int svc_tcp_has_wspace(struct svc_xprt *xprt)
 {
-       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
-       struct svc_serv *serv = svsk->sk_xprt.xpt_server;
-       int required;
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
 
        if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
                return 1;
-       required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg;
-       if (sk_stream_wspace(svsk->sk_sk) >= required ||
-           (sk_stream_min_wspace(svsk->sk_sk) == 0 &&
-            atomic_read(&xprt->xpt_reserved) == 0))
-               return 1;
-       set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
-       return 0;
-}
-
-static void svc_tcp_write_space(struct sock *sk)
-{
-       struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
-       struct socket *sock = sk->sk_socket;
-
-       if (!sk_stream_is_writeable(sk) || !sock)
-               return;
-       if (!svsk || svc_tcp_has_wspace(&svsk->sk_xprt))
-               clear_bit(SOCK_NOSPACE, &sock->flags);
-       svc_write_space(sk);
-}
-
-static void svc_tcp_adjust_wspace(struct svc_xprt *xprt)
-{
-       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
-
-       if (svc_tcp_has_wspace(xprt))
-               clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+       return !test_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
 }
 
 /*
@@ -746,7 +684,7 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
        svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class,
                      &svsk->sk_xprt, serv);
        clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
-       svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
+       svsk->sk_sk->sk_data_ready = svc_data_ready;
        svsk->sk_sk->sk_write_space = svc_write_space;
 
        /* initialise setting must have enough space to
@@ -786,11 +724,12 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
 static void svc_tcp_listen_data_ready(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
-       wait_queue_head_t *wq;
 
        dprintk("svc: socket %p TCP (listen) state change %d\n",
                sk, sk->sk_state);
 
+       if (svsk)
+               svsk->sk_odata(sk);
        /*
         * This callback may called twice when a new connection
         * is established as a child socket inherits everything
@@ -808,10 +747,6 @@ static void svc_tcp_listen_data_ready(struct sock *sk)
                } else
                        printk("svc: socket %p: no user data\n", sk);
        }
-
-       wq = sk_sleep(sk);
-       if (sunrpc_waitqueue_active(wq))
-               wake_up_interruptible_all(wq);
 }
 
 /*
@@ -820,7 +755,6 @@ static void svc_tcp_listen_data_ready(struct sock *sk)
 static void svc_tcp_state_change(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
-       wait_queue_head_t *wq = sk_sleep(sk);
 
        dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n",
                sk, sk->sk_state, sk->sk_user_data);
@@ -828,26 +762,12 @@ static void svc_tcp_state_change(struct sock *sk)
        if (!svsk)
                printk("svc: socket %p: no user data\n", sk);
        else {
-               set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
-               svc_xprt_enqueue(&svsk->sk_xprt);
-       }
-       if (sunrpc_waitqueue_active(wq))
-               wake_up_interruptible_all(wq);
-}
-
-static void svc_tcp_data_ready(struct sock *sk)
-{
-       struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
-       wait_queue_head_t *wq = sk_sleep(sk);
-
-       dprintk("svc: socket %p TCP data ready (svsk %p)\n",
-               sk, sk->sk_user_data);
-       if (svsk) {
-               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-               svc_xprt_enqueue(&svsk->sk_xprt);
+               svsk->sk_ostate(sk);
+               if (sk->sk_state != TCP_ESTABLISHED) {
+                       set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+                       svc_xprt_enqueue(&svsk->sk_xprt);
+               }
        }
-       if (sunrpc_waitqueue_active(wq))
-               wake_up_interruptible(wq);
 }
 
 /*
@@ -901,6 +821,11 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
        dprintk("%s: connect from %s\n", serv->sv_name,
                __svc_print_addr(sin, buf, sizeof(buf)));
 
+       /* Reset the inherited callbacks before calling svc_setup_socket */
+       newsock->sk->sk_state_change = svsk->sk_ostate;
+       newsock->sk->sk_data_ready = svsk->sk_odata;
+       newsock->sk->sk_write_space = svsk->sk_owspace;
+
        /* make sure that a write doesn't block forever when
         * low on memory
         */
@@ -1317,7 +1242,6 @@ static struct svc_xprt_ops svc_tcp_ops = {
        .xpo_has_wspace = svc_tcp_has_wspace,
        .xpo_accept = svc_tcp_accept,
        .xpo_secure_port = svc_sock_secure_port,
-       .xpo_adjust_wspace = svc_tcp_adjust_wspace,
 };
 
 static struct svc_xprt_class svc_tcp_class = {
@@ -1357,8 +1281,8 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
        } else {
                dprintk("setting up TCP socket for reading\n");
                sk->sk_state_change = svc_tcp_state_change;
-               sk->sk_data_ready = svc_tcp_data_ready;
-               sk->sk_write_space = svc_tcp_write_space;
+               sk->sk_data_ready = svc_data_ready;
+               sk->sk_write_space = svc_write_space;
 
                svsk->sk_reclen = 0;
                svsk->sk_tcplen = 0;
@@ -1368,8 +1292,13 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
                tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
 
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
-               if (sk->sk_state != TCP_ESTABLISHED)
+               switch (sk->sk_state) {
+               case TCP_SYN_RECV:
+               case TCP_ESTABLISHED:
+                       break;
+               default:
                        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+               }
        }
 }
 
@@ -1428,17 +1357,14 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)
                svc_udp_init(svsk, serv);
-       else {
-               /* initialise setting must have enough space to
-                * receive and respond to one request.
-                */
-               svc_sock_setbufsize(svsk->sk_sock, 4 * serv->sv_max_mesg,
-                                       4 * serv->sv_max_mesg);
+       else
                svc_tcp_init(svsk, serv);
-       }
 
-       dprintk("svc: svc_setup_socket created %p (inet %p)\n",
-                               svsk, svsk->sk_sk);
+       dprintk("svc: svc_setup_socket created %p (inet %p), "
+                       "listen %d close %d\n",
+                       svsk, svsk->sk_sk,
+                       test_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags),
+                       test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
 
        return svsk;
 }
@@ -1606,18 +1532,16 @@ static void svc_sock_detach(struct svc_xprt *xprt)
 {
        struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
        struct sock *sk = svsk->sk_sk;
-       wait_queue_head_t *wq;
 
        dprintk("svc: svc_sock_detach(%p)\n", svsk);
 
        /* put back the old socket callbacks */
+       lock_sock(sk);
        sk->sk_state_change = svsk->sk_ostate;
        sk->sk_data_ready = svsk->sk_odata;
        sk->sk_write_space = svsk->sk_owspace;
-
-       wq = sk_sleep(sk);
-       if (sunrpc_waitqueue_active(wq))
-               wake_up_interruptible(wq);
+       sk->sk_user_data = NULL;
+       release_sock(sk);
 }
 
 /*
index be70a57..b62caa1 100644 (file)
@@ -794,10 +794,10 @@ int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
        return 0;
 
 attr_msg_full:
+       read_unlock_bh(&mon->lock);
        nla_nest_cancel(msg->skb, attrs);
 msg_full:
        genlmsg_cancel(msg->skb, hdr);
-       read_unlock_bh(&mon->lock);
 
        return -EMSGSIZE;
 }
index 14810ab..8831e7c 100644 (file)
@@ -26,3 +26,23 @@ config VMWARE_VMCI_VSOCKETS
 
          To compile this driver as a module, choose M here: the module
          will be called vmw_vsock_vmci_transport. If unsure, say N.
+
+config VIRTIO_VSOCKETS
+       tristate "virtio transport for Virtual Sockets"
+       depends on VSOCKETS && VIRTIO
+       select VIRTIO_VSOCKETS_COMMON
+       help
+         This module implements a virtio transport for Virtual Sockets.
+
+         Enable this transport if your Virtual Machine host supports Virtual
+         Sockets over virtio.
+
+         To compile this driver as a module, choose M here: the module will be
+         called vmw_vsock_virtio_transport. If unsure, say N.
+
+config VIRTIO_VSOCKETS_COMMON
+       tristate
+       help
+         This option is selected by any driver which needs to access
+         the virtio_vsock.  The module will be called
+         vmw_vsock_virtio_transport_common.
index 2ce52d7..bc27c70 100644 (file)
@@ -1,7 +1,13 @@
 obj-$(CONFIG_VSOCKETS) += vsock.o
 obj-$(CONFIG_VMWARE_VMCI_VSOCKETS) += vmw_vsock_vmci_transport.o
+obj-$(CONFIG_VIRTIO_VSOCKETS) += vmw_vsock_virtio_transport.o
+obj-$(CONFIG_VIRTIO_VSOCKETS_COMMON) += vmw_vsock_virtio_transport_common.o
 
 vsock-y += af_vsock.o vsock_addr.o
 
 vmw_vsock_vmci_transport-y += vmci_transport.o vmci_transport_notify.o \
        vmci_transport_notify_qstate.o
+
+vmw_vsock_virtio_transport-y += virtio_transport.o
+
+vmw_vsock_virtio_transport_common-y += virtio_transport_common.o
index b96ac91..17dbbe6 100644 (file)
@@ -344,6 +344,16 @@ static bool vsock_in_connected_table(struct vsock_sock *vsk)
        return ret;
 }
 
+void vsock_remove_sock(struct vsock_sock *vsk)
+{
+       if (vsock_in_bound_table(vsk))
+               vsock_remove_bound(vsk);
+
+       if (vsock_in_connected_table(vsk))
+               vsock_remove_connected(vsk);
+}
+EXPORT_SYMBOL_GPL(vsock_remove_sock);
+
 void vsock_for_each_connected_socket(void (*fn)(struct sock *sk))
 {
        int i;
@@ -660,12 +670,6 @@ static void __vsock_release(struct sock *sk)
                vsk = vsock_sk(sk);
                pending = NULL; /* Compiler warning. */
 
-               if (vsock_in_bound_table(vsk))
-                       vsock_remove_bound(vsk);
-
-               if (vsock_in_connected_table(vsk))
-                       vsock_remove_connected(vsk);
-
                transport->release(vsk);
 
                lock_sock(sk);
@@ -1995,6 +1999,15 @@ void vsock_core_exit(void)
 }
 EXPORT_SYMBOL_GPL(vsock_core_exit);
 
+const struct vsock_transport *vsock_core_get_transport(void)
+{
+       /* vsock_register_mutex not taken since only the transport uses this
+        * function and only while registered.
+        */
+       return transport;
+}
+EXPORT_SYMBOL_GPL(vsock_core_get_transport);
+
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Socket Family");
 MODULE_VERSION("1.0.1.0-k");
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
new file mode 100644 (file)
index 0000000..699dfab
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * virtio transport for vsock
+ *
+ * Copyright (C) 2013-2015 Red Hat, Inc.
+ * Author: Asias He <asias@redhat.com>
+ *         Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * Some of the code is take from Gerd Hoffmann <kraxel@redhat.com>'s
+ * early virtio-vsock proof-of-concept bits.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_vsock.h>
+#include <net/sock.h>
+#include <linux/mutex.h>
+#include <net/af_vsock.h>
+
+static struct workqueue_struct *virtio_vsock_workqueue;
+static struct virtio_vsock *the_virtio_vsock;
+static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */
+
+struct virtio_vsock {
+       struct virtio_device *vdev;
+       struct virtqueue *vqs[VSOCK_VQ_MAX];
+
+       /* Virtqueue processing is deferred to a workqueue */
+       struct work_struct tx_work;
+       struct work_struct rx_work;
+       struct work_struct event_work;
+
+       /* The following fields are protected by tx_lock.  vqs[VSOCK_VQ_TX]
+        * must be accessed with tx_lock held.
+        */
+       struct mutex tx_lock;
+
+       struct work_struct send_pkt_work;
+       spinlock_t send_pkt_list_lock;
+       struct list_head send_pkt_list;
+
+       atomic_t queued_replies;
+
+       /* The following fields are protected by rx_lock.  vqs[VSOCK_VQ_RX]
+        * must be accessed with rx_lock held.
+        */
+       struct mutex rx_lock;
+       int rx_buf_nr;
+       int rx_buf_max_nr;
+
+       /* The following fields are protected by event_lock.
+        * vqs[VSOCK_VQ_EVENT] must be accessed with event_lock held.
+        */
+       struct mutex event_lock;
+       struct virtio_vsock_event event_list[8];
+
+       u32 guest_cid;
+};
+
+static struct virtio_vsock *virtio_vsock_get(void)
+{
+       return the_virtio_vsock;
+}
+
+static u32 virtio_transport_get_local_cid(void)
+{
+       struct virtio_vsock *vsock = virtio_vsock_get();
+
+       return vsock->guest_cid;
+}
+
+static void
+virtio_transport_send_pkt_work(struct work_struct *work)
+{
+       struct virtio_vsock *vsock =
+               container_of(work, struct virtio_vsock, send_pkt_work);
+       struct virtqueue *vq;
+       bool added = false;
+       bool restart_rx = false;
+
+       mutex_lock(&vsock->tx_lock);
+
+       vq = vsock->vqs[VSOCK_VQ_TX];
+
+       /* Avoid unnecessary interrupts while we're processing the ring */
+       virtqueue_disable_cb(vq);
+
+       for (;;) {
+               struct virtio_vsock_pkt *pkt;
+               struct scatterlist hdr, buf, *sgs[2];
+               int ret, in_sg = 0, out_sg = 0;
+               bool reply;
+
+               spin_lock_bh(&vsock->send_pkt_list_lock);
+               if (list_empty(&vsock->send_pkt_list)) {
+                       spin_unlock_bh(&vsock->send_pkt_list_lock);
+                       virtqueue_enable_cb(vq);
+                       break;
+               }
+
+               pkt = list_first_entry(&vsock->send_pkt_list,
+                                      struct virtio_vsock_pkt, list);
+               list_del_init(&pkt->list);
+               spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+               reply = pkt->reply;
+
+               sg_init_one(&hdr, &pkt->hdr, sizeof(pkt->hdr));
+               sgs[out_sg++] = &hdr;
+               if (pkt->buf) {
+                       sg_init_one(&buf, pkt->buf, pkt->len);
+                       sgs[out_sg++] = &buf;
+               }
+
+               ret = virtqueue_add_sgs(vq, sgs, out_sg, in_sg, pkt, GFP_KERNEL);
+               if (ret < 0) {
+                       spin_lock_bh(&vsock->send_pkt_list_lock);
+                       list_add(&pkt->list, &vsock->send_pkt_list);
+                       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+                       if (!virtqueue_enable_cb(vq) && ret == -ENOSPC)
+                               continue; /* retry now that we have more space */
+                       break;
+               }
+
+               if (reply) {
+                       struct virtqueue *rx_vq = vsock->vqs[VSOCK_VQ_RX];
+                       int val;
+
+                       val = atomic_dec_return(&vsock->queued_replies);
+
+                       /* Do we now have resources to resume rx processing? */
+                       if (val + 1 == virtqueue_get_vring_size(rx_vq))
+                               restart_rx = true;
+               }
+
+               added = true;
+       }
+
+       if (added)
+               virtqueue_kick(vq);
+
+       mutex_unlock(&vsock->tx_lock);
+
+       if (restart_rx)
+               queue_work(virtio_vsock_workqueue, &vsock->rx_work);
+}
+
+static int
+virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt)
+{
+       struct virtio_vsock *vsock;
+       int len = pkt->len;
+
+       vsock = virtio_vsock_get();
+       if (!vsock) {
+               virtio_transport_free_pkt(pkt);
+               return -ENODEV;
+       }
+
+       if (pkt->reply)
+               atomic_inc(&vsock->queued_replies);
+
+       spin_lock_bh(&vsock->send_pkt_list_lock);
+       list_add_tail(&pkt->list, &vsock->send_pkt_list);
+       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+       queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
+       return len;
+}
+
+static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
+{
+       int buf_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE;
+       struct virtio_vsock_pkt *pkt;
+       struct scatterlist hdr, buf, *sgs[2];
+       struct virtqueue *vq;
+       int ret;
+
+       vq = vsock->vqs[VSOCK_VQ_RX];
+
+       do {
+               pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
+               if (!pkt)
+                       break;
+
+               pkt->buf = kmalloc(buf_len, GFP_KERNEL);
+               if (!pkt->buf) {
+                       virtio_transport_free_pkt(pkt);
+                       break;
+               }
+
+               pkt->len = buf_len;
+
+               sg_init_one(&hdr, &pkt->hdr, sizeof(pkt->hdr));
+               sgs[0] = &hdr;
+
+               sg_init_one(&buf, pkt->buf, buf_len);
+               sgs[1] = &buf;
+               ret = virtqueue_add_sgs(vq, sgs, 0, 2, pkt, GFP_KERNEL);
+               if (ret) {
+                       virtio_transport_free_pkt(pkt);
+                       break;
+               }
+               vsock->rx_buf_nr++;
+       } while (vq->num_free);
+       if (vsock->rx_buf_nr > vsock->rx_buf_max_nr)
+               vsock->rx_buf_max_nr = vsock->rx_buf_nr;
+       virtqueue_kick(vq);
+}
+
+static void virtio_transport_tx_work(struct work_struct *work)
+{
+       struct virtio_vsock *vsock =
+               container_of(work, struct virtio_vsock, tx_work);
+       struct virtqueue *vq;
+       bool added = false;
+
+       vq = vsock->vqs[VSOCK_VQ_TX];
+       mutex_lock(&vsock->tx_lock);
+       do {
+               struct virtio_vsock_pkt *pkt;
+               unsigned int len;
+
+               virtqueue_disable_cb(vq);
+               while ((pkt = virtqueue_get_buf(vq, &len)) != NULL) {
+                       virtio_transport_free_pkt(pkt);
+                       added = true;
+               }
+       } while (!virtqueue_enable_cb(vq));
+       mutex_unlock(&vsock->tx_lock);
+
+       if (added)
+               queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work);
+}
+
+/* Is there space left for replies to rx packets? */
+static bool virtio_transport_more_replies(struct virtio_vsock *vsock)
+{
+       struct virtqueue *vq = vsock->vqs[VSOCK_VQ_RX];
+       int val;
+
+       smp_rmb(); /* paired with atomic_inc() and atomic_dec_return() */
+       val = atomic_read(&vsock->queued_replies);
+
+       return val < virtqueue_get_vring_size(vq);
+}
+
+static void virtio_transport_rx_work(struct work_struct *work)
+{
+       struct virtio_vsock *vsock =
+               container_of(work, struct virtio_vsock, rx_work);
+       struct virtqueue *vq;
+
+       vq = vsock->vqs[VSOCK_VQ_RX];
+
+       mutex_lock(&vsock->rx_lock);
+
+       do {
+               virtqueue_disable_cb(vq);
+               for (;;) {
+                       struct virtio_vsock_pkt *pkt;
+                       unsigned int len;
+
+                       if (!virtio_transport_more_replies(vsock)) {
+                               /* Stop rx until the device processes already
+                                * pending replies.  Leave rx virtqueue
+                                * callbacks disabled.
+                                */
+                               goto out;
+                       }
+
+                       pkt = virtqueue_get_buf(vq, &len);
+                       if (!pkt) {
+                               break;
+                       }
+
+                       vsock->rx_buf_nr--;
+
+                       /* Drop short/long packets */
+                       if (unlikely(len < sizeof(pkt->hdr) ||
+                                    len > sizeof(pkt->hdr) + pkt->len)) {
+                               virtio_transport_free_pkt(pkt);
+                               continue;
+                       }
+
+                       pkt->len = len - sizeof(pkt->hdr);
+                       virtio_transport_recv_pkt(pkt);
+               }
+       } while (!virtqueue_enable_cb(vq));
+
+out:
+       if (vsock->rx_buf_nr < vsock->rx_buf_max_nr / 2)
+               virtio_vsock_rx_fill(vsock);
+       mutex_unlock(&vsock->rx_lock);
+}
+
+/* event_lock must be held */
+static int virtio_vsock_event_fill_one(struct virtio_vsock *vsock,
+                                      struct virtio_vsock_event *event)
+{
+       struct scatterlist sg;
+       struct virtqueue *vq;
+
+       vq = vsock->vqs[VSOCK_VQ_EVENT];
+
+       sg_init_one(&sg, event, sizeof(*event));
+
+       return virtqueue_add_inbuf(vq, &sg, 1, event, GFP_KERNEL);
+}
+
+/* event_lock must be held */
+static void virtio_vsock_event_fill(struct virtio_vsock *vsock)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(vsock->event_list); i++) {
+               struct virtio_vsock_event *event = &vsock->event_list[i];
+
+               virtio_vsock_event_fill_one(vsock, event);
+       }
+
+       virtqueue_kick(vsock->vqs[VSOCK_VQ_EVENT]);
+}
+
+static void virtio_vsock_reset_sock(struct sock *sk)
+{
+       lock_sock(sk);
+       sk->sk_state = SS_UNCONNECTED;
+       sk->sk_err = ECONNRESET;
+       sk->sk_error_report(sk);
+       release_sock(sk);
+}
+
+static void virtio_vsock_update_guest_cid(struct virtio_vsock *vsock)
+{
+       struct virtio_device *vdev = vsock->vdev;
+       u64 guest_cid;
+
+       vdev->config->get(vdev, offsetof(struct virtio_vsock_config, guest_cid),
+                         &guest_cid, sizeof(guest_cid));
+       vsock->guest_cid = le64_to_cpu(guest_cid);
+}
+
+/* event_lock must be held */
+static void virtio_vsock_event_handle(struct virtio_vsock *vsock,
+                                     struct virtio_vsock_event *event)
+{
+       switch (le32_to_cpu(event->id)) {
+       case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET:
+               virtio_vsock_update_guest_cid(vsock);
+               vsock_for_each_connected_socket(virtio_vsock_reset_sock);
+               break;
+       }
+}
+
+static void virtio_transport_event_work(struct work_struct *work)
+{
+       struct virtio_vsock *vsock =
+               container_of(work, struct virtio_vsock, event_work);
+       struct virtqueue *vq;
+
+       vq = vsock->vqs[VSOCK_VQ_EVENT];
+
+       mutex_lock(&vsock->event_lock);
+
+       do {
+               struct virtio_vsock_event *event;
+               unsigned int len;
+
+               virtqueue_disable_cb(vq);
+               while ((event = virtqueue_get_buf(vq, &len)) != NULL) {
+                       if (len == sizeof(*event))
+                               virtio_vsock_event_handle(vsock, event);
+
+                       virtio_vsock_event_fill_one(vsock, event);
+               }
+       } while (!virtqueue_enable_cb(vq));
+
+       virtqueue_kick(vsock->vqs[VSOCK_VQ_EVENT]);
+
+       mutex_unlock(&vsock->event_lock);
+}
+
+static void virtio_vsock_event_done(struct virtqueue *vq)
+{
+       struct virtio_vsock *vsock = vq->vdev->priv;
+
+       if (!vsock)
+               return;
+       queue_work(virtio_vsock_workqueue, &vsock->event_work);
+}
+
+static void virtio_vsock_tx_done(struct virtqueue *vq)
+{
+       struct virtio_vsock *vsock = vq->vdev->priv;
+
+       if (!vsock)
+               return;
+       queue_work(virtio_vsock_workqueue, &vsock->tx_work);
+}
+
+static void virtio_vsock_rx_done(struct virtqueue *vq)
+{
+       struct virtio_vsock *vsock = vq->vdev->priv;
+
+       if (!vsock)
+               return;
+       queue_work(virtio_vsock_workqueue, &vsock->rx_work);
+}
+
+static struct virtio_transport virtio_transport = {
+       .transport = {
+               .get_local_cid            = virtio_transport_get_local_cid,
+
+               .init                     = virtio_transport_do_socket_init,
+               .destruct                 = virtio_transport_destruct,
+               .release                  = virtio_transport_release,
+               .connect                  = virtio_transport_connect,
+               .shutdown                 = virtio_transport_shutdown,
+
+               .dgram_bind               = virtio_transport_dgram_bind,
+               .dgram_dequeue            = virtio_transport_dgram_dequeue,
+               .dgram_enqueue            = virtio_transport_dgram_enqueue,
+               .dgram_allow              = virtio_transport_dgram_allow,
+
+               .stream_dequeue           = virtio_transport_stream_dequeue,
+               .stream_enqueue           = virtio_transport_stream_enqueue,
+               .stream_has_data          = virtio_transport_stream_has_data,
+               .stream_has_space         = virtio_transport_stream_has_space,
+               .stream_rcvhiwat          = virtio_transport_stream_rcvhiwat,
+               .stream_is_active         = virtio_transport_stream_is_active,
+               .stream_allow             = virtio_transport_stream_allow,
+
+               .notify_poll_in           = virtio_transport_notify_poll_in,
+               .notify_poll_out          = virtio_transport_notify_poll_out,
+               .notify_recv_init         = virtio_transport_notify_recv_init,
+               .notify_recv_pre_block    = virtio_transport_notify_recv_pre_block,
+               .notify_recv_pre_dequeue  = virtio_transport_notify_recv_pre_dequeue,
+               .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue,
+               .notify_send_init         = virtio_transport_notify_send_init,
+               .notify_send_pre_block    = virtio_transport_notify_send_pre_block,
+               .notify_send_pre_enqueue  = virtio_transport_notify_send_pre_enqueue,
+               .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue,
+
+               .set_buffer_size          = virtio_transport_set_buffer_size,
+               .set_min_buffer_size      = virtio_transport_set_min_buffer_size,
+               .set_max_buffer_size      = virtio_transport_set_max_buffer_size,
+               .get_buffer_size          = virtio_transport_get_buffer_size,
+               .get_min_buffer_size      = virtio_transport_get_min_buffer_size,
+               .get_max_buffer_size      = virtio_transport_get_max_buffer_size,
+       },
+
+       .send_pkt = virtio_transport_send_pkt,
+};
+
+static int virtio_vsock_probe(struct virtio_device *vdev)
+{
+       vq_callback_t *callbacks[] = {
+               virtio_vsock_rx_done,
+               virtio_vsock_tx_done,
+               virtio_vsock_event_done,
+       };
+       static const char * const names[] = {
+               "rx",
+               "tx",
+               "event",
+       };
+       struct virtio_vsock *vsock = NULL;
+       int ret;
+
+       ret = mutex_lock_interruptible(&the_virtio_vsock_mutex);
+       if (ret)
+               return ret;
+
+       /* Only one virtio-vsock device per guest is supported */
+       if (the_virtio_vsock) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       vsock = kzalloc(sizeof(*vsock), GFP_KERNEL);
+       if (!vsock) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       vsock->vdev = vdev;
+
+       ret = vsock->vdev->config->find_vqs(vsock->vdev, VSOCK_VQ_MAX,
+                                           vsock->vqs, callbacks, names);
+       if (ret < 0)
+               goto out;
+
+       virtio_vsock_update_guest_cid(vsock);
+
+       ret = vsock_core_init(&virtio_transport.transport);
+       if (ret < 0)
+               goto out_vqs;
+
+       vsock->rx_buf_nr = 0;
+       vsock->rx_buf_max_nr = 0;
+       atomic_set(&vsock->queued_replies, 0);
+
+       vdev->priv = vsock;
+       the_virtio_vsock = vsock;
+       mutex_init(&vsock->tx_lock);
+       mutex_init(&vsock->rx_lock);
+       mutex_init(&vsock->event_lock);
+       spin_lock_init(&vsock->send_pkt_list_lock);
+       INIT_LIST_HEAD(&vsock->send_pkt_list);
+       INIT_WORK(&vsock->rx_work, virtio_transport_rx_work);
+       INIT_WORK(&vsock->tx_work, virtio_transport_tx_work);
+       INIT_WORK(&vsock->event_work, virtio_transport_event_work);
+       INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work);
+
+       mutex_lock(&vsock->rx_lock);
+       virtio_vsock_rx_fill(vsock);
+       mutex_unlock(&vsock->rx_lock);
+
+       mutex_lock(&vsock->event_lock);
+       virtio_vsock_event_fill(vsock);
+       mutex_unlock(&vsock->event_lock);
+
+       mutex_unlock(&the_virtio_vsock_mutex);
+       return 0;
+
+out_vqs:
+       vsock->vdev->config->del_vqs(vsock->vdev);
+out:
+       kfree(vsock);
+       mutex_unlock(&the_virtio_vsock_mutex);
+       return ret;
+}
+
+static void virtio_vsock_remove(struct virtio_device *vdev)
+{
+       struct virtio_vsock *vsock = vdev->priv;
+       struct virtio_vsock_pkt *pkt;
+
+       flush_work(&vsock->rx_work);
+       flush_work(&vsock->tx_work);
+       flush_work(&vsock->event_work);
+       flush_work(&vsock->send_pkt_work);
+
+       vdev->config->reset(vdev);
+
+       mutex_lock(&vsock->rx_lock);
+       while ((pkt = virtqueue_detach_unused_buf(vsock->vqs[VSOCK_VQ_RX])))
+               virtio_transport_free_pkt(pkt);
+       mutex_unlock(&vsock->rx_lock);
+
+       mutex_lock(&vsock->tx_lock);
+       while ((pkt = virtqueue_detach_unused_buf(vsock->vqs[VSOCK_VQ_TX])))
+               virtio_transport_free_pkt(pkt);
+       mutex_unlock(&vsock->tx_lock);
+
+       spin_lock_bh(&vsock->send_pkt_list_lock);
+       while (!list_empty(&vsock->send_pkt_list)) {
+               pkt = list_first_entry(&vsock->send_pkt_list,
+                                      struct virtio_vsock_pkt, list);
+               list_del(&pkt->list);
+               virtio_transport_free_pkt(pkt);
+       }
+       spin_unlock_bh(&vsock->send_pkt_list_lock);
+
+       mutex_lock(&the_virtio_vsock_mutex);
+       the_virtio_vsock = NULL;
+       vsock_core_exit();
+       mutex_unlock(&the_virtio_vsock_mutex);
+
+       vdev->config->del_vqs(vdev);
+
+       kfree(vsock);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_VSOCK, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static unsigned int features[] = {
+};
+
+static struct virtio_driver virtio_vsock_driver = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
+       .driver.name = KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table = id_table,
+       .probe = virtio_vsock_probe,
+       .remove = virtio_vsock_remove,
+};
+
+static int __init virtio_vsock_init(void)
+{
+       int ret;
+
+       virtio_vsock_workqueue = alloc_workqueue("virtio_vsock", 0, 0);
+       if (!virtio_vsock_workqueue)
+               return -ENOMEM;
+       ret = register_virtio_driver(&virtio_vsock_driver);
+       if (ret)
+               destroy_workqueue(virtio_vsock_workqueue);
+       return ret;
+}
+
+static void __exit virtio_vsock_exit(void)
+{
+       unregister_virtio_driver(&virtio_vsock_driver);
+       destroy_workqueue(virtio_vsock_workqueue);
+}
+
+module_init(virtio_vsock_init);
+module_exit(virtio_vsock_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Asias He");
+MODULE_DESCRIPTION("virtio transport for vsock");
+MODULE_DEVICE_TABLE(virtio, id_table);
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
new file mode 100644 (file)
index 0000000..a53b3a1
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+ * common code for virtio vsock
+ *
+ * Copyright (C) 2013-2015 Red Hat, Inc.
+ * Author: Asias He <asias@redhat.com>
+ *         Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_vsock.h>
+
+#include <net/sock.h>
+#include <net/af_vsock.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/vsock_virtio_transport_common.h>
+
+/* How long to wait for graceful shutdown of a connection */
+#define VSOCK_CLOSE_TIMEOUT (8 * HZ)
+
+static const struct virtio_transport *virtio_transport_get_ops(void)
+{
+       const struct vsock_transport *t = vsock_core_get_transport();
+
+       return container_of(t, struct virtio_transport, transport);
+}
+
+struct virtio_vsock_pkt *
+virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info,
+                          size_t len,
+                          u32 src_cid,
+                          u32 src_port,
+                          u32 dst_cid,
+                          u32 dst_port)
+{
+       struct virtio_vsock_pkt *pkt;
+       int err;
+
+       pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
+       if (!pkt)
+               return NULL;
+
+       pkt->hdr.type           = cpu_to_le16(info->type);
+       pkt->hdr.op             = cpu_to_le16(info->op);
+       pkt->hdr.src_cid        = cpu_to_le64(src_cid);
+       pkt->hdr.dst_cid        = cpu_to_le64(dst_cid);
+       pkt->hdr.src_port       = cpu_to_le32(src_port);
+       pkt->hdr.dst_port       = cpu_to_le32(dst_port);
+       pkt->hdr.flags          = cpu_to_le32(info->flags);
+       pkt->len                = len;
+       pkt->hdr.len            = cpu_to_le32(len);
+       pkt->reply              = info->reply;
+
+       if (info->msg && len > 0) {
+               pkt->buf = kmalloc(len, GFP_KERNEL);
+               if (!pkt->buf)
+                       goto out_pkt;
+               err = memcpy_from_msg(pkt->buf, info->msg, len);
+               if (err)
+                       goto out;
+       }
+
+       trace_virtio_transport_alloc_pkt(src_cid, src_port,
+                                        dst_cid, dst_port,
+                                        len,
+                                        info->type,
+                                        info->op,
+                                        info->flags);
+
+       return pkt;
+
+out:
+       kfree(pkt->buf);
+out_pkt:
+       kfree(pkt);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_alloc_pkt);
+
+static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+                                         struct virtio_vsock_pkt_info *info)
+{
+       u32 src_cid, src_port, dst_cid, dst_port;
+       struct virtio_vsock_sock *vvs;
+       struct virtio_vsock_pkt *pkt;
+       u32 pkt_len = info->pkt_len;
+
+       src_cid = vm_sockets_get_local_cid();
+       src_port = vsk->local_addr.svm_port;
+       if (!info->remote_cid) {
+               dst_cid = vsk->remote_addr.svm_cid;
+               dst_port = vsk->remote_addr.svm_port;
+       } else {
+               dst_cid = info->remote_cid;
+               dst_port = info->remote_port;
+       }
+
+       vvs = vsk->trans;
+
+       /* we can send less than pkt_len bytes */
+       if (pkt_len > VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE)
+               pkt_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE;
+
+       /* virtio_transport_get_credit might return less than pkt_len credit */
+       pkt_len = virtio_transport_get_credit(vvs, pkt_len);
+
+       /* Do not send zero length OP_RW pkt */
+       if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
+               return pkt_len;
+
+       pkt = virtio_transport_alloc_pkt(info, pkt_len,
+                                        src_cid, src_port,
+                                        dst_cid, dst_port);
+       if (!pkt) {
+               virtio_transport_put_credit(vvs, pkt_len);
+               return -ENOMEM;
+       }
+
+       virtio_transport_inc_tx_pkt(vvs, pkt);
+
+       return virtio_transport_get_ops()->send_pkt(pkt);
+}
+
+static void virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
+                                       struct virtio_vsock_pkt *pkt)
+{
+       vvs->rx_bytes += pkt->len;
+}
+
+static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs,
+                                       struct virtio_vsock_pkt *pkt)
+{
+       vvs->rx_bytes -= pkt->len;
+       vvs->fwd_cnt += pkt->len;
+}
+
+void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt)
+{
+       spin_lock_bh(&vvs->tx_lock);
+       pkt->hdr.fwd_cnt = cpu_to_le32(vvs->fwd_cnt);
+       pkt->hdr.buf_alloc = cpu_to_le32(vvs->buf_alloc);
+       spin_unlock_bh(&vvs->tx_lock);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt);
+
+u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit)
+{
+       u32 ret;
+
+       spin_lock_bh(&vvs->tx_lock);
+       ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
+       if (ret > credit)
+               ret = credit;
+       vvs->tx_cnt += ret;
+       spin_unlock_bh(&vvs->tx_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_get_credit);
+
+void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit)
+{
+       spin_lock_bh(&vvs->tx_lock);
+       vvs->tx_cnt -= credit;
+       spin_unlock_bh(&vvs->tx_lock);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_put_credit);
+
+static int virtio_transport_send_credit_update(struct vsock_sock *vsk,
+                                              int type,
+                                              struct virtio_vsock_hdr *hdr)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE,
+               .type = type,
+       };
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+
+static ssize_t
+virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
+                                  struct msghdr *msg,
+                                  size_t len)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       struct virtio_vsock_pkt *pkt;
+       size_t bytes, total = 0;
+       int err = -EFAULT;
+
+       spin_lock_bh(&vvs->rx_lock);
+       while (total < len && !list_empty(&vvs->rx_queue)) {
+               pkt = list_first_entry(&vvs->rx_queue,
+                                      struct virtio_vsock_pkt, list);
+
+               bytes = len - total;
+               if (bytes > pkt->len - pkt->off)
+                       bytes = pkt->len - pkt->off;
+
+               /* sk_lock is held by caller so no one else can dequeue.
+                * Unlock rx_lock since memcpy_to_msg() may sleep.
+                */
+               spin_unlock_bh(&vvs->rx_lock);
+
+               err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
+               if (err)
+                       goto out;
+
+               spin_lock_bh(&vvs->rx_lock);
+
+               total += bytes;
+               pkt->off += bytes;
+               if (pkt->off == pkt->len) {
+                       virtio_transport_dec_rx_pkt(vvs, pkt);
+                       list_del(&pkt->list);
+                       virtio_transport_free_pkt(pkt);
+               }
+       }
+       spin_unlock_bh(&vvs->rx_lock);
+
+       /* Send a credit pkt to peer */
+       virtio_transport_send_credit_update(vsk, VIRTIO_VSOCK_TYPE_STREAM,
+                                           NULL);
+
+       return total;
+
+out:
+       if (total)
+               err = total;
+       return err;
+}
+
+ssize_t
+virtio_transport_stream_dequeue(struct vsock_sock *vsk,
+                               struct msghdr *msg,
+                               size_t len, int flags)
+{
+       if (flags & MSG_PEEK)
+               return -EOPNOTSUPP;
+
+       return virtio_transport_stream_do_dequeue(vsk, msg, len);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue);
+
+int
+virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
+                              struct msghdr *msg,
+                              size_t len, int flags)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue);
+
+s64 virtio_transport_stream_has_data(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       s64 bytes;
+
+       spin_lock_bh(&vvs->rx_lock);
+       bytes = vvs->rx_bytes;
+       spin_unlock_bh(&vvs->rx_lock);
+
+       return bytes;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_has_data);
+
+static s64 virtio_transport_has_space(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       s64 bytes;
+
+       bytes = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
+       if (bytes < 0)
+               bytes = 0;
+
+       return bytes;
+}
+
+s64 virtio_transport_stream_has_space(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       s64 bytes;
+
+       spin_lock_bh(&vvs->tx_lock);
+       bytes = virtio_transport_has_space(vsk);
+       spin_unlock_bh(&vvs->tx_lock);
+
+       return bytes;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_has_space);
+
+int virtio_transport_do_socket_init(struct vsock_sock *vsk,
+                                   struct vsock_sock *psk)
+{
+       struct virtio_vsock_sock *vvs;
+
+       vvs = kzalloc(sizeof(*vvs), GFP_KERNEL);
+       if (!vvs)
+               return -ENOMEM;
+
+       vsk->trans = vvs;
+       vvs->vsk = vsk;
+       if (psk) {
+               struct virtio_vsock_sock *ptrans = psk->trans;
+
+               vvs->buf_size   = ptrans->buf_size;
+               vvs->buf_size_min = ptrans->buf_size_min;
+               vvs->buf_size_max = ptrans->buf_size_max;
+               vvs->peer_buf_alloc = ptrans->peer_buf_alloc;
+       } else {
+               vvs->buf_size = VIRTIO_VSOCK_DEFAULT_BUF_SIZE;
+               vvs->buf_size_min = VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE;
+               vvs->buf_size_max = VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE;
+       }
+
+       vvs->buf_alloc = vvs->buf_size;
+
+       spin_lock_init(&vvs->rx_lock);
+       spin_lock_init(&vvs->tx_lock);
+       INIT_LIST_HEAD(&vvs->rx_queue);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_do_socket_init);
+
+u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       return vvs->buf_size;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_get_buffer_size);
+
+u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       return vvs->buf_size_min;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_get_min_buffer_size);
+
+u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       return vvs->buf_size_max;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_get_max_buffer_size);
+
+void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       if (val > VIRTIO_VSOCK_MAX_BUF_SIZE)
+               val = VIRTIO_VSOCK_MAX_BUF_SIZE;
+       if (val < vvs->buf_size_min)
+               vvs->buf_size_min = val;
+       if (val > vvs->buf_size_max)
+               vvs->buf_size_max = val;
+       vvs->buf_size = val;
+       vvs->buf_alloc = val;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_set_buffer_size);
+
+void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       if (val > VIRTIO_VSOCK_MAX_BUF_SIZE)
+               val = VIRTIO_VSOCK_MAX_BUF_SIZE;
+       if (val > vvs->buf_size)
+               vvs->buf_size = val;
+       vvs->buf_size_min = val;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_set_min_buffer_size);
+
+void virtio_transport_set_max_buffer_size(struct vsock_sock *vsk, u64 val)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       if (val > VIRTIO_VSOCK_MAX_BUF_SIZE)
+               val = VIRTIO_VSOCK_MAX_BUF_SIZE;
+       if (val < vvs->buf_size)
+               vvs->buf_size = val;
+       vvs->buf_size_max = val;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_set_max_buffer_size);
+
+int
+virtio_transport_notify_poll_in(struct vsock_sock *vsk,
+                               size_t target,
+                               bool *data_ready_now)
+{
+       if (vsock_stream_has_data(vsk))
+               *data_ready_now = true;
+       else
+               *data_ready_now = false;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in);
+
+int
+virtio_transport_notify_poll_out(struct vsock_sock *vsk,
+                                size_t target,
+                                bool *space_avail_now)
+{
+       s64 free_space;
+
+       free_space = vsock_stream_has_space(vsk);
+       if (free_space > 0)
+               *space_avail_now = true;
+       else if (free_space == 0)
+               *space_avail_now = false;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out);
+
+int virtio_transport_notify_recv_init(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init);
+
+int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block);
+
+int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk,
+       size_t target, struct vsock_transport_recv_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue);
+
+int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk,
+       size_t target, ssize_t copied, bool data_read,
+       struct vsock_transport_recv_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue);
+
+int virtio_transport_notify_send_init(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_send_init);
+
+int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block);
+
+int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk,
+       struct vsock_transport_send_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue);
+
+int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk,
+       ssize_t written, struct vsock_transport_send_notify_data *data)
+{
+       return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue);
+
+u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       return vvs->buf_size;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat);
+
+bool virtio_transport_stream_is_active(struct vsock_sock *vsk)
+{
+       return true;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active);
+
+bool virtio_transport_stream_allow(u32 cid, u32 port)
+{
+       return true;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_allow);
+
+int virtio_transport_dgram_bind(struct vsock_sock *vsk,
+                               struct sockaddr_vm *addr)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind);
+
+bool virtio_transport_dgram_allow(u32 cid, u32 port)
+{
+       return false;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow);
+
+int virtio_transport_connect(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_REQUEST,
+               .type = VIRTIO_VSOCK_TYPE_STREAM,
+       };
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_connect);
+
+int virtio_transport_shutdown(struct vsock_sock *vsk, int mode)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_SHUTDOWN,
+               .type = VIRTIO_VSOCK_TYPE_STREAM,
+               .flags = (mode & RCV_SHUTDOWN ?
+                         VIRTIO_VSOCK_SHUTDOWN_RCV : 0) |
+                        (mode & SEND_SHUTDOWN ?
+                         VIRTIO_VSOCK_SHUTDOWN_SEND : 0),
+       };
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_shutdown);
+
+int
+virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
+                              struct sockaddr_vm *remote_addr,
+                              struct msghdr *msg,
+                              size_t dgram_len)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue);
+
+ssize_t
+virtio_transport_stream_enqueue(struct vsock_sock *vsk,
+                               struct msghdr *msg,
+                               size_t len)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_RW,
+               .type = VIRTIO_VSOCK_TYPE_STREAM,
+               .msg = msg,
+               .pkt_len = len,
+       };
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue);
+
+void virtio_transport_destruct(struct vsock_sock *vsk)
+{
+       struct virtio_vsock_sock *vvs = vsk->trans;
+
+       kfree(vvs);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_destruct);
+
+static int virtio_transport_reset(struct vsock_sock *vsk,
+                                 struct virtio_vsock_pkt *pkt)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_RST,
+               .type = VIRTIO_VSOCK_TYPE_STREAM,
+               .reply = !!pkt,
+       };
+
+       /* Send RST only if the original pkt is not a RST pkt */
+       if (pkt && le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
+               return 0;
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+
+/* Normally packets are associated with a socket.  There may be no socket if an
+ * attempt was made to connect to a socket that does not exist.
+ */
+static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_RST,
+               .type = le16_to_cpu(pkt->hdr.type),
+               .reply = true,
+       };
+
+       /* Send RST only if the original pkt is not a RST pkt */
+       if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
+               return 0;
+
+       pkt = virtio_transport_alloc_pkt(&info, 0,
+                                        le32_to_cpu(pkt->hdr.dst_cid),
+                                        le32_to_cpu(pkt->hdr.dst_port),
+                                        le32_to_cpu(pkt->hdr.src_cid),
+                                        le32_to_cpu(pkt->hdr.src_port));
+       if (!pkt)
+               return -ENOMEM;
+
+       return virtio_transport_get_ops()->send_pkt(pkt);
+}
+
+static void virtio_transport_wait_close(struct sock *sk, long timeout)
+{
+       if (timeout) {
+               DEFINE_WAIT(wait);
+
+               do {
+                       prepare_to_wait(sk_sleep(sk), &wait,
+                                       TASK_INTERRUPTIBLE);
+                       if (sk_wait_event(sk, &timeout,
+                                         sock_flag(sk, SOCK_DONE)))
+                               break;
+               } while (!signal_pending(current) && timeout);
+
+               finish_wait(sk_sleep(sk), &wait);
+       }
+}
+
+static void virtio_transport_do_close(struct vsock_sock *vsk,
+                                     bool cancel_timeout)
+{
+       struct sock *sk = sk_vsock(vsk);
+
+       sock_set_flag(sk, SOCK_DONE);
+       vsk->peer_shutdown = SHUTDOWN_MASK;
+       if (vsock_stream_has_data(vsk) <= 0)
+               sk->sk_state = SS_DISCONNECTING;
+       sk->sk_state_change(sk);
+
+       if (vsk->close_work_scheduled &&
+           (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
+               vsk->close_work_scheduled = false;
+
+               vsock_remove_sock(vsk);
+
+               /* Release refcnt obtained when we scheduled the timeout */
+               sock_put(sk);
+       }
+}
+
+static void virtio_transport_close_timeout(struct work_struct *work)
+{
+       struct vsock_sock *vsk =
+               container_of(work, struct vsock_sock, close_work.work);
+       struct sock *sk = sk_vsock(vsk);
+
+       sock_hold(sk);
+       lock_sock(sk);
+
+       if (!sock_flag(sk, SOCK_DONE)) {
+               (void)virtio_transport_reset(vsk, NULL);
+
+               virtio_transport_do_close(vsk, false);
+       }
+
+       vsk->close_work_scheduled = false;
+
+       release_sock(sk);
+       sock_put(sk);
+}
+
+/* User context, vsk->sk is locked */
+static bool virtio_transport_close(struct vsock_sock *vsk)
+{
+       struct sock *sk = &vsk->sk;
+
+       if (!(sk->sk_state == SS_CONNECTED ||
+             sk->sk_state == SS_DISCONNECTING))
+               return true;
+
+       /* Already received SHUTDOWN from peer, reply with RST */
+       if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) {
+               (void)virtio_transport_reset(vsk, NULL);
+               return true;
+       }
+
+       if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
+               (void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK);
+
+       if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING))
+               virtio_transport_wait_close(sk, sk->sk_lingertime);
+
+       if (sock_flag(sk, SOCK_DONE)) {
+               return true;
+       }
+
+       sock_hold(sk);
+       INIT_DELAYED_WORK(&vsk->close_work,
+                         virtio_transport_close_timeout);
+       vsk->close_work_scheduled = true;
+       schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT);
+       return false;
+}
+
+void virtio_transport_release(struct vsock_sock *vsk)
+{
+       struct sock *sk = &vsk->sk;
+       bool remove_sock = true;
+
+       lock_sock(sk);
+       if (sk->sk_type == SOCK_STREAM)
+               remove_sock = virtio_transport_close(vsk);
+       release_sock(sk);
+
+       if (remove_sock)
+               vsock_remove_sock(vsk);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_release);
+
+static int
+virtio_transport_recv_connecting(struct sock *sk,
+                                struct virtio_vsock_pkt *pkt)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+       int err;
+       int skerr;
+
+       switch (le16_to_cpu(pkt->hdr.op)) {
+       case VIRTIO_VSOCK_OP_RESPONSE:
+               sk->sk_state = SS_CONNECTED;
+               sk->sk_socket->state = SS_CONNECTED;
+               vsock_insert_connected(vsk);
+               sk->sk_state_change(sk);
+               break;
+       case VIRTIO_VSOCK_OP_INVALID:
+               break;
+       case VIRTIO_VSOCK_OP_RST:
+               skerr = ECONNRESET;
+               err = 0;
+               goto destroy;
+       default:
+               skerr = EPROTO;
+               err = -EINVAL;
+               goto destroy;
+       }
+       return 0;
+
+destroy:
+       virtio_transport_reset(vsk, pkt);
+       sk->sk_state = SS_UNCONNECTED;
+       sk->sk_err = skerr;
+       sk->sk_error_report(sk);
+       return err;
+}
+
+static int
+virtio_transport_recv_connected(struct sock *sk,
+                               struct virtio_vsock_pkt *pkt)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       int err = 0;
+
+       switch (le16_to_cpu(pkt->hdr.op)) {
+       case VIRTIO_VSOCK_OP_RW:
+               pkt->len = le32_to_cpu(pkt->hdr.len);
+               pkt->off = 0;
+
+               spin_lock_bh(&vvs->rx_lock);
+               virtio_transport_inc_rx_pkt(vvs, pkt);
+               list_add_tail(&pkt->list, &vvs->rx_queue);
+               spin_unlock_bh(&vvs->rx_lock);
+
+               sk->sk_data_ready(sk);
+               return err;
+       case VIRTIO_VSOCK_OP_CREDIT_UPDATE:
+               sk->sk_write_space(sk);
+               break;
+       case VIRTIO_VSOCK_OP_SHUTDOWN:
+               if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_RCV)
+                       vsk->peer_shutdown |= RCV_SHUTDOWN;
+               if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_SEND)
+                       vsk->peer_shutdown |= SEND_SHUTDOWN;
+               if (vsk->peer_shutdown == SHUTDOWN_MASK &&
+                   vsock_stream_has_data(vsk) <= 0)
+                       sk->sk_state = SS_DISCONNECTING;
+               if (le32_to_cpu(pkt->hdr.flags))
+                       sk->sk_state_change(sk);
+               break;
+       case VIRTIO_VSOCK_OP_RST:
+               virtio_transport_do_close(vsk, true);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       virtio_transport_free_pkt(pkt);
+       return err;
+}
+
+static void
+virtio_transport_recv_disconnecting(struct sock *sk,
+                                   struct virtio_vsock_pkt *pkt)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+
+       if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
+               virtio_transport_do_close(vsk, true);
+}
+
+static int
+virtio_transport_send_response(struct vsock_sock *vsk,
+                              struct virtio_vsock_pkt *pkt)
+{
+       struct virtio_vsock_pkt_info info = {
+               .op = VIRTIO_VSOCK_OP_RESPONSE,
+               .type = VIRTIO_VSOCK_TYPE_STREAM,
+               .remote_cid = le32_to_cpu(pkt->hdr.src_cid),
+               .remote_port = le32_to_cpu(pkt->hdr.src_port),
+               .reply = true,
+       };
+
+       return virtio_transport_send_pkt_info(vsk, &info);
+}
+
+/* Handle server socket */
+static int
+virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+       struct vsock_sock *vchild;
+       struct sock *child;
+
+       if (le16_to_cpu(pkt->hdr.op) != VIRTIO_VSOCK_OP_REQUEST) {
+               virtio_transport_reset(vsk, pkt);
+               return -EINVAL;
+       }
+
+       if (sk_acceptq_is_full(sk)) {
+               virtio_transport_reset(vsk, pkt);
+               return -ENOMEM;
+       }
+
+       child = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL,
+                              sk->sk_type, 0);
+       if (!child) {
+               virtio_transport_reset(vsk, pkt);
+               return -ENOMEM;
+       }
+
+       sk->sk_ack_backlog++;
+
+       lock_sock_nested(child, SINGLE_DEPTH_NESTING);
+
+       child->sk_state = SS_CONNECTED;
+
+       vchild = vsock_sk(child);
+       vsock_addr_init(&vchild->local_addr, le32_to_cpu(pkt->hdr.dst_cid),
+                       le32_to_cpu(pkt->hdr.dst_port));
+       vsock_addr_init(&vchild->remote_addr, le32_to_cpu(pkt->hdr.src_cid),
+                       le32_to_cpu(pkt->hdr.src_port));
+
+       vsock_insert_connected(vchild);
+       vsock_enqueue_accept(sk, child);
+       virtio_transport_send_response(vchild, pkt);
+
+       release_sock(child);
+
+       sk->sk_data_ready(sk);
+       return 0;
+}
+
+static bool virtio_transport_space_update(struct sock *sk,
+                                         struct virtio_vsock_pkt *pkt)
+{
+       struct vsock_sock *vsk = vsock_sk(sk);
+       struct virtio_vsock_sock *vvs = vsk->trans;
+       bool space_available;
+
+       /* buf_alloc and fwd_cnt is always included in the hdr */
+       spin_lock_bh(&vvs->tx_lock);
+       vvs->peer_buf_alloc = le32_to_cpu(pkt->hdr.buf_alloc);
+       vvs->peer_fwd_cnt = le32_to_cpu(pkt->hdr.fwd_cnt);
+       space_available = virtio_transport_has_space(vsk);
+       spin_unlock_bh(&vvs->tx_lock);
+       return space_available;
+}
+
+/* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex
+ * lock.
+ */
+void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt)
+{
+       struct sockaddr_vm src, dst;
+       struct vsock_sock *vsk;
+       struct sock *sk;
+       bool space_available;
+
+       vsock_addr_init(&src, le32_to_cpu(pkt->hdr.src_cid),
+                       le32_to_cpu(pkt->hdr.src_port));
+       vsock_addr_init(&dst, le32_to_cpu(pkt->hdr.dst_cid),
+                       le32_to_cpu(pkt->hdr.dst_port));
+
+       trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port,
+                                       dst.svm_cid, dst.svm_port,
+                                       le32_to_cpu(pkt->hdr.len),
+                                       le16_to_cpu(pkt->hdr.type),
+                                       le16_to_cpu(pkt->hdr.op),
+                                       le32_to_cpu(pkt->hdr.flags),
+                                       le32_to_cpu(pkt->hdr.buf_alloc),
+                                       le32_to_cpu(pkt->hdr.fwd_cnt));
+
+       if (le16_to_cpu(pkt->hdr.type) != VIRTIO_VSOCK_TYPE_STREAM) {
+               (void)virtio_transport_reset_no_sock(pkt);
+               goto free_pkt;
+       }
+
+       /* The socket must be in connected or bound table
+        * otherwise send reset back
+        */
+       sk = vsock_find_connected_socket(&src, &dst);
+       if (!sk) {
+               sk = vsock_find_bound_socket(&dst);
+               if (!sk) {
+                       (void)virtio_transport_reset_no_sock(pkt);
+                       goto free_pkt;
+               }
+       }
+
+       vsk = vsock_sk(sk);
+
+       space_available = virtio_transport_space_update(sk, pkt);
+
+       lock_sock(sk);
+
+       /* Update CID in case it has changed after a transport reset event */
+       vsk->local_addr.svm_cid = dst.svm_cid;
+
+       if (space_available)
+               sk->sk_write_space(sk);
+
+       switch (sk->sk_state) {
+       case VSOCK_SS_LISTEN:
+               virtio_transport_recv_listen(sk, pkt);
+               virtio_transport_free_pkt(pkt);
+               break;
+       case SS_CONNECTING:
+               virtio_transport_recv_connecting(sk, pkt);
+               virtio_transport_free_pkt(pkt);
+               break;
+       case SS_CONNECTED:
+               virtio_transport_recv_connected(sk, pkt);
+               break;
+       case SS_DISCONNECTING:
+               virtio_transport_recv_disconnecting(sk, pkt);
+               virtio_transport_free_pkt(pkt);
+               break;
+       default:
+               virtio_transport_free_pkt(pkt);
+               break;
+       }
+       release_sock(sk);
+
+       /* Release refcnt obtained when we fetched this socket out of the
+        * bound or connected list.
+        */
+       sock_put(sk);
+       return;
+
+free_pkt:
+       virtio_transport_free_pkt(pkt);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_recv_pkt);
+
+void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt)
+{
+       kfree(pkt->buf);
+       kfree(pkt);
+}
+EXPORT_SYMBOL_GPL(virtio_transport_free_pkt);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Asias He");
+MODULE_DESCRIPTION("common code for virtio vsock");
index 4120b7a..4be4fbb 100644 (file)
@@ -1644,6 +1644,8 @@ static void vmci_transport_destruct(struct vsock_sock *vsk)
 
 static void vmci_transport_release(struct vsock_sock *vsk)
 {
+       vsock_remove_sock(vsk);
+
        if (!vmci_handle_is_invalid(vmci_trans(vsk)->dg_handle)) {
                vmci_datagram_destroy_handle(vmci_trans(vsk)->dg_handle);
                vmci_trans(vsk)->dg_handle = VMCI_INVALID_HANDLE;
index da49c0b..b0e11b6 100644 (file)
@@ -715,7 +715,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
 
        ASSERT_RTNL();
 
-       if (!config_enabled(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
+       if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
            !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
                return false;
 
index c3108bb..e3c0a40 100644 (file)
@@ -48,10 +48,10 @@ static int __init jprobe_init(void)
 
        ret = register_jprobe(&my_jprobe);
        if (ret < 0) {
-               printk(KERN_INFO "register_jprobe failed, returned %d\n", ret);
+               pr_err("register_jprobe failed, returned %d\n", ret);
                return -1;
        }
-       printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n",
+       pr_info("Planted jprobe at %p, handler addr %p\n",
               my_jprobe.kp.addr, my_jprobe.entry);
        return 0;
 }
@@ -59,7 +59,7 @@ static int __init jprobe_init(void)
 static void __exit jprobe_exit(void)
 {
        unregister_jprobe(&my_jprobe);
-       printk(KERN_INFO "jprobe at %p unregistered\n", my_jprobe.kp.addr);
+       pr_info("jprobe at %p unregistered\n", my_jprobe.kp.addr);
 }
 
 module_init(jprobe_init)
index f3b61b4..88b3e2d 100644 (file)
@@ -27,23 +27,19 @@ static struct kprobe kp = {
 static int handler_pre(struct kprobe *p, struct pt_regs *regs)
 {
 #ifdef CONFIG_X86
-       printk(KERN_INFO "<%s> pre_handler: p->addr = 0x%p, ip = %lx,"
-                       " flags = 0x%lx\n",
+       pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->ip, regs->flags);
 #endif
 #ifdef CONFIG_PPC
-       printk(KERN_INFO "<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx,"
-                       " msr = 0x%lx\n",
+       pr_info("<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",
                p->symbol_name, p->addr, regs->nip, regs->msr);
 #endif
 #ifdef CONFIG_MIPS
-       printk(KERN_INFO "<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx,"
-                       " status = 0x%lx\n",
+       pr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
 #endif
 #ifdef CONFIG_TILEGX
-       printk(KERN_INFO "<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"
-                       " ex1 = 0x%lx\n",
+       pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx, ex1 = 0x%lx\n",
                p->symbol_name, p->addr, regs->pc, regs->ex1);
 #endif
 #ifdef CONFIG_ARM64
@@ -61,19 +57,19 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
                                unsigned long flags)
 {
 #ifdef CONFIG_X86
-       printk(KERN_INFO "<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",
+       pr_info("<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",
                p->symbol_name, p->addr, regs->flags);
 #endif
 #ifdef CONFIG_PPC
-       printk(KERN_INFO "<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",
+       pr_info("<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",
                p->symbol_name, p->addr, regs->msr);
 #endif
 #ifdef CONFIG_MIPS
-       printk(KERN_INFO "<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
+       pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",
                p->symbol_name, p->addr, regs->cp0_status);
 #endif
 #ifdef CONFIG_TILEGX
-       printk(KERN_INFO "<%s> post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
+       pr_info("<%s> post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
                p->symbol_name, p->addr, regs->ex1);
 #endif
 #ifdef CONFIG_ARM64
@@ -89,8 +85,7 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
  */
 static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
 {
-       printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
-               p->addr, trapnr);
+       pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
        /* Return 0 because we don't handle the fault. */
        return 0;
 }
@@ -104,17 +99,17 @@ static int __init kprobe_init(void)
 
        ret = register_kprobe(&kp);
        if (ret < 0) {
-               printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
+               pr_err("register_kprobe failed, returned %d\n", ret);
                return ret;
        }
-       printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
+       pr_info("Planted kprobe at %p\n", kp.addr);
        return 0;
 }
 
 static void __exit kprobe_exit(void)
 {
        unregister_kprobe(&kp);
-       printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
+       pr_info("kprobe at %p unregistered\n", kp.addr);
 }
 
 module_init(kprobe_init)
index ebb1d1a..7f9060f 100644 (file)
@@ -55,14 +55,14 @@ static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
  */
 static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
-       int retval = regs_return_value(regs);
+       unsigned long retval = regs_return_value(regs);
        struct my_data *data = (struct my_data *)ri->data;
        s64 delta;
        ktime_t now;
 
        now = ktime_get();
        delta = ktime_to_ns(ktime_sub(now, data->entry_stamp));
-       printk(KERN_INFO "%s returned %d and took %lld ns to execute\n",
+       pr_info("%s returned %lu and took %lld ns to execute\n",
                        func_name, retval, (long long)delta);
        return 0;
 }
@@ -82,11 +82,10 @@ static int __init kretprobe_init(void)
        my_kretprobe.kp.symbol_name = func_name;
        ret = register_kretprobe(&my_kretprobe);
        if (ret < 0) {
-               printk(KERN_INFO "register_kretprobe failed, returned %d\n",
-                               ret);
+               pr_err("register_kretprobe failed, returned %d\n", ret);
                return -1;
        }
-       printk(KERN_INFO "Planted return probe at %s: %p\n",
+       pr_info("Planted return probe at %s: %p\n",
                        my_kretprobe.kp.symbol_name, my_kretprobe.kp.addr);
        return 0;
 }
@@ -94,11 +93,10 @@ static int __init kretprobe_init(void)
 static void __exit kretprobe_exit(void)
 {
        unregister_kretprobe(&my_kretprobe);
-       printk(KERN_INFO "kretprobe at %p unregistered\n",
-                       my_kretprobe.kp.addr);
+       pr_info("kretprobe at %p unregistered\n", my_kretprobe.kp.addr);
 
        /* nmissed > 0 suggests that maxactive was set too low. */
-       printk(KERN_INFO "Missed probing %d instances of %s\n",
+       pr_info("Missed probing %d instances of %s\n",
                my_kretprobe.nmissed, my_kretprobe.kp.symbol_name);
 }
 
index 0f82314..1792198 100644 (file)
@@ -108,16 +108,20 @@ as-option = $(call try-run,\
 as-instr = $(call try-run,\
        printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
 
+# Do not attempt to build with gcc plugins during cc-option tests.
+# (And this uses delayed resolution so the flags will be up to date.)
+CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS))
+
 # cc-option
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
 
 cc-option = $(call try-run,\
-       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+       $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
 
 # cc-option-yn
 # Usage: flag := $(call cc-option-yn,-march=winchip-c6)
 cc-option-yn = $(call try-run,\
-       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
+       $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
 
 # cc-option-align
 # Prefix align with either -falign or -malign
@@ -127,7 +131,7 @@ cc-option-align = $(subst -functions=0,,\
 # cc-disable-warning
 # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
 cc-disable-warning = $(call try-run,\
-       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+       $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
 
 # cc-name
 # Expands to either gcc or clang
@@ -202,7 +206,7 @@ hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
 # Prefix -I with $(srctree) if it is not an absolute path.
 # skip if -I has no parameter
 addtree = $(if $(patsubst -I%,%,$(1)), \
-$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
+$(if $(filter-out -I/% -I./% -I../%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1)),$(1)))
 
 # Find all -I options and call addtree
 flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
index 822ab4a..1d80897 100644 (file)
@@ -47,4 +47,4 @@ subdir-$(CONFIG_DTC)         += dtc
 subdir-$(CONFIG_GDB_SCRIPTS) += gdb
 
 # Let clean descend into subdirs
-subdir-        += basic kconfig package
+subdir-        += basic kconfig package gcc-plugins
index 0d1ca5b..11602e5 100644 (file)
@@ -60,7 +60,7 @@ endif
 endif
 
 # Do not include host rules unless needed
-ifneq ($(hostprogs-y)$(hostprogs-m),)
+ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),)
 include scripts/Makefile.host
 endif
 
index 55c96cb..50616ea 100644 (file)
@@ -38,7 +38,9 @@ subdir-ymn    := $(addprefix $(obj)/,$(subdir-ymn))
 __clean-files  := $(extra-y) $(extra-m) $(extra-)       \
                   $(always) $(targets) $(clean-files)   \
                   $(host-progs)                         \
-                  $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
+                  $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
+                  $(hostlibs-y) $(hostlibs-m) $(hostlibs-) \
+                  $(hostcxxlibs-y) $(hostcxxlibs-m)
 
 __clean-files   := $(filter-out $(no-clean-files), $(__clean-files))
 
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
new file mode 100644 (file)
index 0000000..61f0e6d
--- /dev/null
@@ -0,0 +1,60 @@
+ifdef CONFIG_GCC_PLUGINS
+  __PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC))
+  PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)")
+
+  SANCOV_PLUGIN := -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so
+
+  gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY)       += cyc_complexity_plugin.so
+
+  ifdef CONFIG_GCC_PLUGIN_SANCOV
+    ifeq ($(CFLAGS_KCOV),)
+      # It is needed because of the gcc-plugin.sh and gcc version checks.
+      gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV)           += sancov_plugin.so
+
+      ifneq ($(PLUGINCC),)
+        CFLAGS_KCOV := $(SANCOV_PLUGIN)
+      else
+        $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler)
+      endif
+    endif
+  endif
+
+  GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
+
+  export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR SANCOV_PLUGIN
+
+  ifneq ($(PLUGINCC),)
+    # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication.
+    GCC_PLUGINS_CFLAGS := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGINS_CFLAGS))
+  endif
+
+  KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS)
+  GCC_PLUGIN := $(gcc-plugin-y)
+  GCC_PLUGIN_SUBDIR := $(gcc-plugin-subdir-y)
+endif
+
+# If plugins aren't supported, abort the build before hard-to-read compiler
+# errors start getting spewed by the main build.
+PHONY += gcc-plugins-check
+gcc-plugins-check: FORCE
+ifdef CONFIG_GCC_PLUGINS
+  ifeq ($(PLUGINCC),)
+    ifneq ($(GCC_PLUGINS_CFLAGS),)
+      ifeq ($(call cc-ifversion, -ge, 0405, y), y)
+       $(Q)$(srctree)/scripts/gcc-plugin.sh --show-error "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)" || true
+       @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc installation does not support plugins, perhaps the necessary headers are missing?" >&2 && exit 1
+      else
+       @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc version does not support plugins, you should upgrade it to at least gcc 4.5" >&2 && exit 1
+      endif
+    endif
+  endif
+endif
+       @:
+
+# Actually do the build, if requested.
+PHONY += gcc-plugins
+gcc-plugins: scripts_basic gcc-plugins-check
+ifdef CONFIG_GCC_PLUGINS
+       $(Q)$(MAKE) $(build)=scripts/gcc-plugins
+endif
+       @:
index 133edfa..45b5b1a 100644 (file)
 # Will compile qconf as a C++ program, and menu as a C program.
 # They are linked as C++ code to the executable qconf
 
+# hostcc-option
+# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586)
+
+hostcc-option = $(call try-run,\
+       $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+
 __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
+host-cshlib := $(sort $(hostlibs-y) $(hostlibs-m))
+host-cxxshlib := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m))
 
 # C code
 # Executables compiled from a single .c file
@@ -42,6 +50,10 @@ host-cxxmulti        := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
 # C++ Object (.o) files compiled from .cc files
 host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
 
+# Object (.o) files used by the shared libaries
+host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
+
 # output directory for programs/.o files
 # hostprogs-y := tools/build may have been specified.
 # Retrieve also directory of .o files from prog-objs or prog-cxxobjs notation
@@ -56,6 +68,10 @@ host-cmulti  := $(addprefix $(obj)/,$(host-cmulti))
 host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
 host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
 host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
+host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
+host-cxxshlib  := $(addprefix $(obj)/,$(host-cxxshlib))
+host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
+host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
 host-objdirs    := $(addprefix $(obj)/,$(host-objdirs))
 
 obj-dirs += $(host-objdirs)
@@ -124,5 +140,42 @@ quiet_cmd_host-cxxobjs     = HOSTCXX $@
 $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
        $(call if_changed_dep,host-cxxobjs)
 
+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
+      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
+       $(call if_changed_dep,host-cshobjs)
+
+# Compile .c file, create position independent .o file
+# Note that plugin capable gcc versions can be either C or C++ based
+# therefore plugin source files have to be compilable in both C and C++ mode.
+# This is why a C++ compiler is invoked on a .c file.
+# host-cxxshobjs -> .o
+quiet_cmd_host-cxxshobjs       = HOSTCXX -fPIC $@
+      cmd_host-cxxshobjs       = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $<
+$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE
+       $(call if_changed_dep,host-cxxshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib  = HOSTLLD -shared $@
+      cmd_host-cshlib  = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): FORCE
+       $(call if_changed,host-cshlib)
+$(call multi_depend, $(host-cshlib), .so, -objs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cxxshlib)
+quiet_cmd_host-cxxshlib        = HOSTLLD -shared $@
+      cmd_host-cxxshlib        = $(HOSTCXX) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxshlib): FORCE
+       $(call if_changed,host-cxxshlib)
+$(call multi_depend, $(host-cxxshlib), .so, -objs)
+
 targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
-          $(host-cxxmulti) $(host-cxxobjs)
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) $(host-cxxshlib) $(host-cxxshobjs)
index e7df0f5..0a07f90 100644 (file)
@@ -138,7 +138,7 @@ endif
 
 ifeq ($(CONFIG_KCOV),y)
 _c_flags += $(if $(patsubst n%,, \
-       $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)y), \
+       $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \
        $(CFLAGS_KCOV))
 endif
 
@@ -155,9 +155,10 @@ else
 # $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
 #   and locates generated .h files
 # FIXME: Replace both with specific CFLAGS* statements in the makefiles
-__c_flags      = $(call addtree,-I$(obj)) $(call flags,_c_flags)
-__a_flags      =                          $(call flags,_a_flags)
-__cpp_flags     =                          $(call flags,_cpp_flags)
+__c_flags      = $(if $(obj),-I$(srctree)/$(src) -I$(obj)) \
+                 $(call flags,_c_flags)
+__a_flags      = $(call flags,_a_flags)
+__cpp_flags     = $(call flags,_cpp_flags)
 endif
 
 c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
index af187e6..c3d7eef 100644 (file)
@@ -29,7 +29,8 @@ int main(int argc, char *argv[])
        } while (ch != EOF);
 
        if (argc > 1)
-               printf("\t;\n\nconst int %s_size = %d;\n", argv[1], total);
+               printf("\t;\n\n#include <linux/types.h>\n\nconst size_t %s_size = %d;\n",
+                      argv[1], total);
 
        return 0;
 }
index 24a0836..4de3cc4 100755 (executable)
@@ -55,6 +55,7 @@ my $spelling_file = "$D/spelling.txt";
 my $codespell = 0;
 my $codespellfile = "/usr/share/codespell/dictionary.txt";
 my $color = 1;
+my $allow_c99_comments = 1;
 
 sub help {
        my ($exitcode) = @_;
@@ -227,9 +228,9 @@ if ($^V && $^V lt $minimum_perl_version) {
        }
 }
 
+#if no filenames are given, push '-' to read patch from stdin
 if ($#ARGV < 0) {
-       print "$P: no input files\n";
-       exit(1);
+       push(@ARGV, '-');
 }
 
 sub hash_save_array_words {
@@ -1144,6 +1145,11 @@ sub sanitise_line {
                $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
        }
 
+       if ($allow_c99_comments && $res =~ m@(//.*$)@) {
+               my $match = $1;
+               $res =~ s/\Q$match\E/"$;" x length($match)/e;
+       }
+
        return $res;
 }
 
@@ -2063,6 +2069,7 @@ sub process {
        my $is_patch = 0;
        my $in_header_lines = $file ? 0 : 1;
        my $in_commit_log = 0;          #Scanning lines before patch
+       my $has_commit_log = 0;         #Encountered lines before patch
        my $commit_log_possible_stack_dump = 0;
        my $commit_log_long_line = 0;
        my $commit_log_has_diff = 0;
@@ -2453,9 +2460,9 @@ sub process {
 
 # Check for git id commit length and improperly formed commit descriptions
                if ($in_commit_log && !$commit_log_possible_stack_dump &&
-                   $line !~ /^\s*(?:Link|Patchwork|http|BugLink):/i &&
+                   $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i &&
                    ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i ||
-                    ($line =~ /\b[0-9a-f]{12,40}\b/i &&
+                    ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i &&
                      $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i &&
                      $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) {
                        my $init_char = "c";
@@ -2560,6 +2567,7 @@ sub process {
                      $rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
                        $in_header_lines = 0;
                        $in_commit_log = 1;
+                       $has_commit_log = 1;
                }
 
 # Check if there is UTF-8 in a commit log when a mail header has explicitly
@@ -2763,6 +2771,10 @@ sub process {
                                 $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
                                $msg_type = "";
 
+                       # EFI_GUID is another special case
+                       } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) {
+                               $msg_type = "";
+
                        # Otherwise set the alternate message types
 
                        # a comment starts before $max_line_length
@@ -3337,7 +3349,7 @@ sub process {
                next if ($line =~ /^[^\+]/);
 
 # check for declarations of signed or unsigned without int
-               while ($line =~ m{($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
+               while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
                        my $type = $1;
                        my $var = $2;
                        $var = "" if (!defined $var);
@@ -5722,8 +5734,9 @@ sub process {
                        }
                }
 
-# check for #defines like: 1 << <digit> that could be BIT(digit)
-               if ($line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
+# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi
+               if ($realfile !~ m@^include/uapi/@ &&
+                   $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
                        my $ull = "";
                        $ull = "_ULL" if (defined($1) && $1 =~ /ll/i);
                        if (CHK("BIT_MACRO",
@@ -6044,7 +6057,7 @@ sub process {
                ERROR("NOT_UNIFIED_DIFF",
                      "Does not appear to be a unified-diff format patch\n");
        }
-       if ($is_patch && $filename ne '-' && $chk_signoff && $signoff == 0) {
+       if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) {
                ERROR("MISSING_SIGN_OFF",
                      "Missing Signed-off-by: line(s)\n");
        }
index dd85a45..c92c152 100755 (executable)
@@ -1,14 +1,24 @@
 #!/bin/bash
-
+# Linux kernel coccicheck
+#
+# Read Documentation/coccinelle.txt
 #
 # This script requires at least spatch
 # version 1.0.0-rc11.
-#
 
+DIR="$(dirname $(readlink -f $0))/.."
 SPATCH="`which ${SPATCH:=spatch}`"
 
-trap kill_running SIGTERM SIGINT
-declare -a SPATCH_PID
+if [ ! -x "$SPATCH" ]; then
+    echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
+    exit 1
+fi
+
+SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
+SPATCH_VERSION_NUM=$(echo $SPATCH_VERSION | ${DIR}/scripts/ld-version.sh)
+
+USE_JOBS="no"
+$SPATCH --help | grep "\-\-jobs" > /dev/null && USE_JOBS="yes"
 
 # The verbosity may be set by the environmental parameter V=
 # as for example with 'make V=1 coccicheck'
@@ -25,7 +35,28 @@ else
        NPROC="$J"
 fi
 
-FLAGS="$SPFLAGS --very-quiet"
+FLAGS="--very-quiet"
+
+# You can use SPFLAGS to append extra arguments to coccicheck or override any
+# heuristics done in this file as Coccinelle accepts the last options when
+# options conflict.
+#
+# A good example for use of SPFLAGS is if you want to debug your cocci script,
+# you can for instance use the following:
+#
+# $ export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
+# $ make coccicheck MODE=report DEBUG_FILE="all.err" SPFLAGS="--profile --show-trying" M=./drivers/mfd/arizona-irq.c
+#
+# "--show-trying" should show you what rule is being processed as it goes to
+# stdout, you do not need a debug file for that. The profile output will be
+# be sent to stdout, if you provide a DEBUG_FILE the profiling data can be
+# inspected there.
+#
+# --profile will not output if --very-quiet is used, so avoid it.
+echo $SPFLAGS | egrep -e "--profile|--show-trying" 2>&1 > /dev/null
+if [ $? -eq 0 ]; then
+       FLAGS="--quiet"
+fi
 
 # spatch only allows include directories with the syntax "-I include"
 # while gcc also allows "-Iinclude" and "-include include"
@@ -51,9 +82,14 @@ if [ "$KBUILD_EXTMOD" != "" ] ; then
     OPTIONS="--patch $srctree $OPTIONS"
 fi
 
-if [ ! -x "$SPATCH" ]; then
-    echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
-    exit 1
+# You can override by using SPFLAGS
+if [ "$USE_JOBS" = "no" ]; then
+       trap kill_running SIGTERM SIGINT
+       declare -a SPATCH_PID
+elif [ "$NPROC" != "1" ]; then
+       # Using 0 should work as well, refer to _SC_NPROCESSORS_ONLN use on
+       # https://github.com/rdicosmo/parmap/blob/master/setcore_stubs.c
+       OPTIONS="$OPTIONS --jobs $NPROC --chunksize 1"
 fi
 
 if [ "$MODE" = "" ] ; then
@@ -72,7 +108,7 @@ if [ "$MODE" = "chain" ] ; then
        echo 'All available modes will be tried (in that order): patch, report, context, org'
     fi
 elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
-    FLAGS="$FLAGS --no-show-diff"
+    FLAGS="--no-show-diff $FLAGS"
 fi
 
 if [ "$ONLINE" = "0" ] ; then
@@ -82,7 +118,26 @@ if [ "$ONLINE" = "0" ] ; then
     echo ''
 fi
 
-run_cmd() {
+run_cmd_parmap() {
+       if [ $VERBOSE -ne 0 ] ; then
+               echo "Running ($NPROC in parallel): $@"
+       fi
+       if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
+               if [ -f $DEBUG_FILE ]; then
+                       echo "Debug file $DEBUG_FILE exists, bailing"
+                       exit
+               fi
+       else
+               DEBUG_FILE="/dev/null"
+       fi
+       $@ 2>$DEBUG_FILE
+       if [[ $? -ne 0 ]]; then
+               echo "coccicheck failed"
+               exit $?
+       fi
+}
+
+run_cmd_old() {
        local i
        if [ $VERBOSE -ne 0 ] ; then
                echo "Running ($NPROC in parallel): $@"
@@ -97,6 +152,14 @@ run_cmd() {
        wait
 }
 
+run_cmd() {
+       if [ "$USE_JOBS" = "yes" ]; then
+               run_cmd_parmap $@
+       else
+               run_cmd_old $@
+       fi
+}
+
 kill_running() {
        for i in $(seq 0 $(( NPROC - 1 )) ); do
                if [ $VERBOSE -eq 2 ] ; then
@@ -106,10 +169,23 @@ kill_running() {
        done
 }
 
+# You can override heuristics with SPFLAGS, these must always go last
+OPTIONS="$OPTIONS $SPFLAGS"
+
 coccinelle () {
     COCCI="$1"
 
     OPT=`grep "Option" $COCCI | cut -d':' -f2`
+    REQ=`grep "Requires" $COCCI | cut -d':' -f2 | sed "s| ||"`
+    REQ_NUM=$(echo $REQ | ${DIR}/scripts/ld-version.sh)
+    if [ "$REQ_NUM" != "0" ] ; then
+           if [ "$SPATCH_VERSION_NUM" -lt "$REQ_NUM" ] ; then
+                   echo "Skipping coccinele SmPL patch: $COCCI"
+                   echo "You have coccinelle:           $SPATCH_VERSION"
+                   echo "This SmPL patch requires:      $REQ"
+                   return
+           fi
+    fi
 
 #   The option '--parse-cocci' can be used to syntactically check the SmPL files.
 #
index 3d93490..c990d2c 100644 (file)
@@ -29,7 +29,23 @@ expression x;
 @@
 
 (
+ x = devm_kmalloc(...)
+|
+ x = devm_kvasprintf(...)
+|
+ x = devm_kasprintf(...)
+|
  x = devm_kzalloc(...)
+|
+ x = devm_kmalloc_array(...)
+|
+ x = devm_kcalloc(...)
+|
+ x = devm_kstrdup(...)
+|
+ x = devm_kmemdup(...)
+|
+ x = devm_get_free_pages(...)
 |
  x = devm_request_irq(...)
 |
@@ -48,6 +64,16 @@ position p;
 (
 * kfree@p(x)
 |
+* kzfree@p(x)
+|
+* __krealloc@p(x, ...)
+|
+* krealloc@p(x, ...)
+|
+* free_pages@p(x, ...)
+|
+* free_page@p(x)
+|
 * free_irq@p(x)
 |
 * iounmap@p(x)
index 52bd235..14a4cd9 100644 (file)
@@ -19,6 +19,8 @@ expression E;
 - if (E != NULL)
 (
   kfree(E);
+|
+  kzfree(E);
 |
   debugfs_remove(E);
 |
@@ -39,7 +41,7 @@ position p;
 @@
 
 * if (E != NULL)
-*      \(kfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
+*      \(kfree@p\|kzfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
 *         usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
 *         dma_pool_destroy@p\)(E);
 
index 577b780..ac438da 100644 (file)
@@ -20,7 +20,11 @@ expression E;
 position p1;
 @@
 
-kfree@p1(E)
+(
+* kfree@p1(E)
+|
+* kzfree@p1(E)
+)
 
 @print expression@
 constant char [] c;
@@ -60,7 +64,11 @@ position ok;
 @@
 
 while (1) { ...
-  kfree@ok(E)
+(
+* kfree@ok(E)
+|
+* kzfree@ok(E)
+)
   ... when != break;
       when != goto l;
       when forall
@@ -74,7 +82,11 @@ statement S;
 position free.p1!=loop.ok,p2!={print.p,sz.p};
 @@
 
-kfree@p1(E,...)
+(
+* kfree@p1(E,...)
+|
+* kzfree@p1(E,...)
+)
 ...
 (
  iter(...,subE,...) S // no use
index ce8aacc..d46063b 100644 (file)
@@ -16,7 +16,11 @@ identifier f;
 position p;
 @@
 
+(
 * kfree@p(&e->f)
+|
+* kzfree@p(&e->f)
+)
 
 @script:python depends on org@
 p << r.p;
@@ -28,5 +32,5 @@ cocci.print_main("kfree",p)
 p << r.p;
 @@
 
-msg = "ERROR: kfree of structure field"
+msg = "ERROR: invalid free of structure field"
 coccilib.report.print_report(p[0],msg)
index 38ab744..a36c16d 100644 (file)
@@ -5,8 +5,11 @@
 // Copyright: (C) 2015 Julia Lawall, Inria. GPLv2.
 // URL: http://coccinelle.lip6.fr/
 // Options: --no-includes --include-headers
+// Requires: 1.0.4
 // Keywords: for_each_child_of_node, etc.
 
+// This uses a conjunction, which requires at least coccinelle >= 1.0.4
+
 virtual patch
 virtual context
 virtual org
index 80a831c..007f0de 100644 (file)
@@ -16,6 +16,7 @@ virtual patch
 @depends on patch@
 expression *x;
 expression f;
+expression i;
 type T;
 @@
 
@@ -30,15 +31,26 @@ f(...,(T)(x),...,sizeof(
 + *x
    ),...)
 |
-f(...,sizeof(x),...,(T)(
+f(...,sizeof(
+- x
++ *x
+   ),...,(T)(x),...)
+|
+f(...,(T)(x),...,i*sizeof(
 - x
 + *x
    ),...)
+|
+f(...,i*sizeof(
+- x
++ *x
+   ),...,(T)(x),...)
 )
 
 @r depends on !patch@
 expression *x;
 expression f;
+expression i;
 position p;
 type T;
 @@
@@ -49,6 +61,10 @@ type T;
 *f(...,(T)(x),...,sizeof@p(x),...)
 |
 *f(...,sizeof@p(x),...,(T)(x),...)
+|
+*f(...,(T)(x),...,i*sizeof@p(x),...)
+|
+*f(...,i*sizeof@p(x),...,(T)(x),...)
 )
 
 @script:python depends on org@
diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh
new file mode 100755 (executable)
index 0000000..b65224b
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+srctree=$(dirname "$0")
+
+SHOW_ERROR=
+if [ "$1" = "--show-error" ] ; then
+       SHOW_ERROR=1
+       shift || true
+fi
+
+gccplugins_dir=$($3 -print-file-name=plugin)
+plugincc=$($1 -E -x c++ - -o /dev/null -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
+#include "gcc-common.h"
+#if BUILDING_GCC_VERSION >= 4008 || defined(ENABLE_BUILD_WITH_CXX)
+#warning $2 CXX
+#else
+#warning $1 CC
+#endif
+EOF
+)
+
+if [ $? -ne 0 ]
+then
+       if [ -n "$SHOW_ERROR" ] ; then
+               echo "${plugincc}" >&2
+       fi
+       exit 1
+fi
+
+case "$plugincc" in
+       *"$1 CC"*)
+               echo "$1"
+               exit 0
+               ;;
+
+       *"$2 CXX"*)
+               # the c++ compiler needs another test, see below
+               ;;
+
+       *)
+               exit 1
+               ;;
+esac
+
+# we need a c++ compiler that supports the designated initializer GNU extension
+plugincc=$($2 -c -x c++ -std=gnu++98 - -fsyntax-only -I"${srctree}"/gcc-plugins -I"${gccplugins_dir}"/include 2>&1 <<EOF
+#include "gcc-common.h"
+class test {
+public:
+       int test;
+} test = {
+       .test = 1
+};
+EOF
+)
+
+if [ $? -eq 0 ]
+then
+       echo "$2"
+       exit 0
+fi
+
+if [ -n "$SHOW_ERROR" ] ; then
+       echo "${plugincc}" >&2
+fi
+exit 1
diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile
new file mode 100644 (file)
index 0000000..8b29dc1
--- /dev/null
@@ -0,0 +1,29 @@
+GCC_PLUGINS_DIR := $(shell $(CC) -print-file-name=plugin)
+
+ifeq ($(PLUGINCC),$(HOSTCC))
+  HOSTLIBS := hostlibs
+  HOST_EXTRACFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu99 -ggdb
+  export HOST_EXTRACFLAGS
+else
+  HOSTLIBS := hostcxxlibs
+  HOST_EXTRACXXFLAGS += -I$(GCC_PLUGINS_DIR)/include -I$(src) -std=gnu++98 -fno-rtti
+  HOST_EXTRACXXFLAGS += -fno-exceptions -fasynchronous-unwind-tables -ggdb
+  HOST_EXTRACXXFLAGS += -Wno-narrowing -Wno-unused-variable
+  export HOST_EXTRACXXFLAGS
+endif
+
+ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN))
+  GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN))
+endif
+
+export HOSTLIBS
+
+$(HOSTLIBS)-y := $(foreach p,$(GCC_PLUGIN),$(if $(findstring /,$(p)),,$(p)))
+always := $($(HOSTLIBS)-y)
+
+$(foreach p,$($(HOSTLIBS)-y:%.so=%),$(eval $(p)-objs := $(p).o))
+
+subdir-y := $(GCC_PLUGIN_SUBDIR)
+subdir-  += $(GCC_PLUGIN_SUBDIR)
+
+clean-files += *.so
diff --git a/scripts/gcc-plugins/cyc_complexity_plugin.c b/scripts/gcc-plugins/cyc_complexity_plugin.c
new file mode 100644 (file)
index 0000000..34df974
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
+ *
+ * http://en.wikipedia.org/wiki/Cyclomatic_complexity
+ * The complexity M is then defined as:
+ * M = E - N + 2P
+ * where
+ *
+ *  E = the number of edges of the graph
+ *  N = the number of nodes of the graph
+ *  P = the number of connected components (exit nodes).
+ *
+ * Usage (4.5 - 5):
+ * $ make clean; make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info cyc_complexity_plugin_info = {
+       .version        = "20160225",
+       .help           = "Cyclomatic Complexity\n",
+};
+
+static unsigned int cyc_complexity_execute(void)
+{
+       int complexity;
+       expanded_location xloc;
+
+       /* M = E - N + 2P */
+       complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
+
+       xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+       fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity,
+               xloc.file, DECL_NAME_POINTER(current_function_decl));
+
+       return 0;
+}
+
+#define PASS_NAME cyc_complexity
+
+#define NO_GATE
+#define TODO_FLAGS_FINISH TODO_dump_func
+
+#include "gcc-generate-gimple-pass.h"
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+       const char * const plugin_name = plugin_info->base_name;
+       struct register_pass_info cyc_complexity_pass_info;
+
+       cyc_complexity_pass_info.pass                           = make_cyc_complexity_pass();
+       cyc_complexity_pass_info.reference_pass_name            = "ssa";
+       cyc_complexity_pass_info.ref_pass_instance_number       = 1;
+       cyc_complexity_pass_info.pos_op                         = PASS_POS_INSERT_AFTER;
+
+       if (!plugin_default_version_check(version, &gcc_version)) {
+               error(G_("incompatible gcc/plugin versions"));
+               return 1;
+       }
+
+       register_callback(plugin_name, PLUGIN_INFO, NULL,
+                               &cyc_complexity_plugin_info);
+       register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+                               &cyc_complexity_pass_info);
+
+       return 0;
+}
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
new file mode 100644 (file)
index 0000000..172850b
--- /dev/null
@@ -0,0 +1,830 @@
+#ifndef GCC_COMMON_H_INCLUDED
+#define GCC_COMMON_H_INCLUDED
+
+#include "bversion.h"
+#if BUILDING_GCC_VERSION >= 6000
+#include "gcc-plugin.h"
+#else
+#include "plugin.h"
+#endif
+#include "plugin-version.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "line-map.h"
+#include "input.h"
+#include "tree.h"
+
+#include "tree-inline.h"
+#include "version.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "hard-reg-set.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "intl.h"
+#include "ggc.h"
+#include "timevar.h"
+
+#include "params.h"
+
+#if BUILDING_GCC_VERSION <= 4009
+#include "pointer-set.h"
+#else
+#include "hash-map.h"
+#endif
+
+#include "emit-rtl.h"
+#include "debug.h"
+#include "target.h"
+#include "langhooks.h"
+#include "cfgloop.h"
+#include "cgraph.h"
+#include "opts.h"
+
+#if BUILDING_GCC_VERSION == 4005
+#include <sys/mman.h>
+#endif
+
+#if BUILDING_GCC_VERSION >= 4007
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4006
+#include "c-family/c-common.h"
+#else
+#include "c-common.h"
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#include "tree-flow.h"
+#else
+#include "tree-cfgcleanup.h"
+#include "tree-ssa-operands.h"
+#include "tree-into-ssa.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#include "is-a.h"
+#endif
+
+#include "diagnostic.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "predict.h"
+#include "ipa-utils.h"
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "attribs.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple-fold.h"
+#include "context.h"
+#include "tree-ssa-alias.h"
+#include "tree-ssa.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "print-tree.h"
+#include "tree-eh.h"
+#include "stmt.h"
+#include "gimplify.h"
+#endif
+
+#include "gimple.h"
+
+#if BUILDING_GCC_VERSION >= 4009
+#include "tree-ssa-operands.h"
+#include "tree-phinodes.h"
+#include "tree-cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "ssa-iterators.h"
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#include "builtins.h"
+#endif
+
+/* #include "expr.h" where are you... */
+extern rtx emit_move_insn(rtx x, rtx y);
+
+/* missing from basic_block.h... */
+extern void debug_dominance_info(enum cdi_direction dir);
+extern void debug_dominance_tree(enum cdi_direction dir, basic_block root);
+
+#if BUILDING_GCC_VERSION == 4006
+extern void debug_gimple_stmt(gimple);
+extern void debug_gimple_seq(gimple_seq);
+extern void print_gimple_seq(FILE *, gimple_seq, int, int);
+extern void print_gimple_stmt(FILE *, gimple, int, int);
+extern void print_gimple_expr(FILE *, gimple, int, int);
+extern void dump_gimple_stmt(pretty_printer *, gimple, int, int);
+#endif
+
+#define __unused __attribute__((__unused__))
+
+#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node))
+#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node))
+#define TYPE_NAME_POINTER(node) IDENTIFIER_POINTER(TYPE_NAME(node))
+#define TYPE_NAME_LENGTH(node) IDENTIFIER_LENGTH(TYPE_NAME(node))
+
+/* should come from c-tree.h if only it were installed for gcc 4.5... */
+#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1(TYPE)
+
+#if BUILDING_GCC_VERSION == 4005
+#define FOR_EACH_LOCAL_DECL(FUN, I, D)                 \
+       for (tree vars = (FUN)->local_decls, (I) = 0;   \
+               vars && ((D) = TREE_VALUE(vars));       \
+               vars = TREE_CHAIN(vars), (I)++)
+#define DECL_CHAIN(NODE) (TREE_CHAIN(DECL_MINIMAL_CHECK(NODE)))
+#define FOR_EACH_VEC_ELT(T, V, I, P) \
+       for (I = 0; VEC_iterate(T, (V), (I), (P)); ++(I))
+#define TODO_rebuild_cgraph_edges 0
+#define SCOPE_FILE_SCOPE_P(EXP) (!(EXP))
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline bool gimple_call_builtin_p(gimple stmt, enum built_in_function code)
+{
+       tree fndecl;
+
+       if (!is_gimple_call(stmt))
+               return false;
+       fndecl = gimple_call_fndecl(stmt);
+       if (!fndecl || DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_NORMAL)
+               return false;
+       return DECL_FUNCTION_CODE(fndecl) == code;
+}
+
+static inline bool is_simple_builtin(tree decl)
+{
+       if (decl && DECL_BUILT_IN_CLASS(decl) != BUILT_IN_NORMAL)
+               return false;
+
+       switch (DECL_FUNCTION_CODE(decl)) {
+       /* Builtins that expand to constants. */
+       case BUILT_IN_CONSTANT_P:
+       case BUILT_IN_EXPECT:
+       case BUILT_IN_OBJECT_SIZE:
+       case BUILT_IN_UNREACHABLE:
+       /* Simple register moves or loads from stack. */
+       case BUILT_IN_RETURN_ADDRESS:
+       case BUILT_IN_EXTRACT_RETURN_ADDR:
+       case BUILT_IN_FROB_RETURN_ADDR:
+       case BUILT_IN_RETURN:
+       case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+       case BUILT_IN_FRAME_ADDRESS:
+       case BUILT_IN_VA_END:
+       case BUILT_IN_STACK_SAVE:
+       case BUILT_IN_STACK_RESTORE:
+       /* Exception state returns or moves registers around. */
+       case BUILT_IN_EH_FILTER:
+       case BUILT_IN_EH_POINTER:
+       case BUILT_IN_EH_COPY_VALUES:
+       return true;
+
+       default:
+       return false;
+       }
+}
+
+static inline void add_local_decl(struct function *fun, tree d)
+{
+       gcc_assert(TREE_CODE(d) == VAR_DECL);
+       fun->local_decls = tree_cons(NULL_TREE, d, fun->local_decls);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4006
+#define ANY_RETURN_P(rtx) (GET_CODE(rtx) == RETURN)
+#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4(EXP)
+#define EDGE_PRESERVE 0ULL
+#define HOST_WIDE_INT_PRINT_HEX_PURE "%" HOST_WIDE_INT_PRINT "x"
+#define flag_fat_lto_objects true
+
+#define get_random_seed(noinit) ({                                             \
+       unsigned HOST_WIDE_INT seed;                                            \
+       sscanf(get_random_seed(noinit), "%" HOST_WIDE_INT_PRINT "x", &seed);    \
+       seed * seed; })
+
+#define int_const_binop(code, arg1, arg2)      \
+       int_const_binop((code), (arg1), (arg2), 0)
+
+static inline bool gimple_clobber_p(gimple s __unused)
+{
+       return false;
+}
+
+static inline bool gimple_asm_clobbers_memory_p(const_gimple stmt)
+{
+       unsigned i;
+
+       for (i = 0; i < gimple_asm_nclobbers(stmt); i++) {
+               tree op = gimple_asm_clobber_op(stmt, i);
+
+               if (!strcmp(TREE_STRING_POINTER(TREE_VALUE(op)), "memory"))
+                       return true;
+       }
+
+       return false;
+}
+
+static inline tree builtin_decl_implicit(enum built_in_function fncode)
+{
+       return implicit_built_in_decls[fncode];
+}
+
+static inline int ipa_reverse_postorder(struct cgraph_node **order)
+{
+       return cgraph_postorder(order);
+}
+
+static inline struct cgraph_node *cgraph_create_node(tree decl)
+{
+       return cgraph_node(decl);
+}
+
+static inline struct cgraph_node *cgraph_get_create_node(tree decl)
+{
+       struct cgraph_node *node = cgraph_get_node(decl);
+
+       return node ? node : cgraph_node(decl);
+}
+
+static inline bool cgraph_function_with_gimple_body_p(struct cgraph_node *node)
+{
+       return node->analyzed && !node->thunk.thunk_p && !node->alias;
+}
+
+static inline struct cgraph_node *cgraph_first_function_with_gimple_body(void)
+{
+       struct cgraph_node *node;
+
+       for (node = cgraph_nodes; node; node = node->next)
+               if (cgraph_function_with_gimple_body_p(node))
+                       return node;
+       return NULL;
+}
+
+static inline struct cgraph_node *cgraph_next_function_with_gimple_body(struct cgraph_node *node)
+{
+       for (node = node->next; node; node = node->next)
+               if (cgraph_function_with_gimple_body_p(node))
+                       return node;
+       return NULL;
+}
+
+#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \
+       for ((node) = cgraph_first_function_with_gimple_body(); (node); \
+               (node) = cgraph_next_function_with_gimple_body(node))
+
+static inline void varpool_add_new_variable(tree decl)
+{
+       varpool_finalize_decl(decl);
+}
+#endif
+
+#if BUILDING_GCC_VERSION <= 4007
+#define FOR_EACH_FUNCTION(node)        \
+       for (node = cgraph_nodes; node; node = node->next)
+#define FOR_EACH_VARIABLE(node)        \
+       for (node = varpool_nodes; node; node = node->next)
+#define PROP_loops 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define INSN_LOCATION(INSN) RTL_LOCATION(INSN)
+#define vNULL NULL
+
+static inline int bb_loop_depth(const_basic_block bb)
+{
+       return bb->loop_father ? loop_depth(bb->loop_father) : 0;
+}
+
+static inline bool gimple_store_p(gimple gs)
+{
+       tree lhs = gimple_get_lhs(gs);
+
+       return lhs && !is_gimple_reg(lhs);
+}
+
+static inline void gimple_init_singleton(gimple g __unused)
+{
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4007 || BUILDING_GCC_VERSION == 4008
+static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n)
+{
+       return cgraph_alias_aliased_node(n);
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION <= 4009
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \
+       cgraph_create_edge((caller), (callee), (call_stmt), (count), (freq))
+#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \
+       cgraph_create_edge_including_clones((caller), (callee), (old_call_stmt), (call_stmt), (count), (freq), (reason))
+#endif
+
+#if BUILDING_GCC_VERSION <= 4008
+#define ENTRY_BLOCK_PTR_FOR_FN(FN)     ENTRY_BLOCK_PTR_FOR_FUNCTION(FN)
+#define EXIT_BLOCK_PTR_FOR_FN(FN)      EXIT_BLOCK_PTR_FOR_FUNCTION(FN)
+#define basic_block_info_for_fn(FN)    ((FN)->cfg->x_basic_block_info)
+#define n_basic_blocks_for_fn(FN)      ((FN)->cfg->x_n_basic_blocks)
+#define n_edges_for_fn(FN)             ((FN)->cfg->x_n_edges)
+#define last_basic_block_for_fn(FN)    ((FN)->cfg->x_last_basic_block)
+#define label_to_block_map_for_fn(FN)  ((FN)->cfg->x_label_to_block_map)
+#define profile_status_for_fn(FN)      ((FN)->cfg->x_profile_status)
+#define BASIC_BLOCK_FOR_FN(FN, N)      BASIC_BLOCK_FOR_FUNCTION((FN), (N))
+#define NODE_IMPLICIT_ALIAS(node)      (node)->same_body_alias
+#define VAR_P(NODE)                    (TREE_CODE(NODE) == VAR_DECL)
+
+static inline bool tree_fits_shwi_p(const_tree t)
+{
+       if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+               return false;
+
+       if (TREE_INT_CST_HIGH(t) == 0 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) >= 0)
+               return true;
+
+       if (TREE_INT_CST_HIGH(t) == -1 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) < 0 && !TYPE_UNSIGNED(TREE_TYPE(t)))
+               return true;
+
+       return false;
+}
+
+static inline bool tree_fits_uhwi_p(const_tree t)
+{
+       if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST)
+               return false;
+
+       return TREE_INT_CST_HIGH(t) == 0;
+}
+
+static inline HOST_WIDE_INT tree_to_shwi(const_tree t)
+{
+       gcc_assert(tree_fits_shwi_p(t));
+       return TREE_INT_CST_LOW(t);
+}
+
+static inline unsigned HOST_WIDE_INT tree_to_uhwi(const_tree t)
+{
+       gcc_assert(tree_fits_uhwi_p(t));
+       return TREE_INT_CST_LOW(t);
+}
+
+static inline const char *get_tree_code_name(enum tree_code code)
+{
+       gcc_assert(code < MAX_TREE_CODES);
+       return tree_code_name[code];
+}
+
+#define ipa_remove_stmt_references(cnode, stmt)
+
+typedef union gimple_statement_d gasm;
+typedef union gimple_statement_d gassign;
+typedef union gimple_statement_d gcall;
+typedef union gimple_statement_d gcond;
+typedef union gimple_statement_d gdebug;
+typedef union gimple_statement_d gphi;
+typedef union gimple_statement_d greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+       return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4008
+#define NODE_SYMBOL(node) (&(node)->symbol)
+#define NODE_DECL(node) (node)->symbol.decl
+#endif
+
+#if BUILDING_GCC_VERSION >= 4008
+#define add_referenced_var(var)
+#define mark_sym_for_renaming(var)
+#define varpool_mark_needed_node(node)
+#define create_var_ann(var)
+#define TODO_dump_func 0
+#define TODO_dump_cgraph 0
+#endif
+
+#if BUILDING_GCC_VERSION <= 4009
+#define TODO_verify_il 0
+#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE
+
+#define section_name_prefix LTO_SECTION_NAME_PREFIX
+#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__)
+
+typedef struct rtx_def rtx_insn;
+
+static inline void set_decl_section_name(tree node, const char *value)
+{
+       if (value)
+               DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value);
+       else
+               DECL_SECTION_NAME(node) = NULL;
+}
+#endif
+
+#if BUILDING_GCC_VERSION == 4009
+typedef struct gimple_statement_asm gasm;
+typedef struct gimple_statement_base gassign;
+typedef struct gimple_statement_call gcall;
+typedef struct gimple_statement_base gcond;
+typedef struct gimple_statement_base gdebug;
+typedef struct gimple_statement_phi gphi;
+typedef struct gimple_statement_base greturn;
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+       return as_a<gasm>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+       return as_a<const gasm>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+       return as_a<gcall>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+       return as_a<const gcall>(stmt);
+}
+
+static inline gcond *as_a_gcond(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gcond *as_a_const_gcond(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gdebug *as_a_gdebug(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const gdebug *as_a_const_gdebug(const_gimple stmt)
+{
+       return stmt;
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+       return as_a<gphi>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+       return as_a<const gphi>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+       return stmt;
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+       return stmt;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+#define TODO_ggc_collect 0
+#define NODE_SYMBOL(node) (node)
+#define NODE_DECL(node) (node)->decl
+#define cgraph_node_name(node) (node)->name()
+#define NODE_IMPLICIT_ALIAS(node) (node)->cpp_implicit_alias
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000
+/* gimple related */
+template <>
+template <>
+inline bool is_a_helper<const gassign *>::test(const_gimple gs)
+{
+       return gs->code == GIMPLE_ASSIGN;
+}
+#endif
+
+#if BUILDING_GCC_VERSION >= 5000
+#define TODO_verify_ssa TODO_verify_il
+#define TODO_verify_flow TODO_verify_il
+#define TODO_verify_stmts TODO_verify_il
+#define TODO_verify_rtl_sharing TODO_verify_il
+
+#define INSN_DELETED_P(insn) (insn)->deleted()
+
+/* symtab/cgraph related */
+#define debug_cgraph_node(node) (node)->debug()
+#define cgraph_get_node(decl) cgraph_node::get(decl)
+#define cgraph_get_create_node(decl) cgraph_node::get_create(decl)
+#define cgraph_create_node(decl) cgraph_node::create(decl)
+#define cgraph_n_nodes symtab->cgraph_count
+#define cgraph_max_uid symtab->cgraph_max_uid
+#define varpool_get_node(decl) varpool_node::get(decl)
+
+#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \
+       (caller)->create_edge((callee), (call_stmt), (count), (freq))
+#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \
+       (caller)->create_edge_including_clones((callee), (old_call_stmt), (call_stmt), (count), (freq), (reason))
+
+typedef struct cgraph_node *cgraph_node_ptr;
+typedef struct cgraph_edge *cgraph_edge_p;
+typedef struct varpool_node *varpool_node_ptr;
+
+static inline void change_decl_assembler_name(tree decl, tree name)
+{
+       symtab->change_decl_assembler_name(decl, name);
+}
+
+static inline void varpool_finalize_decl(tree decl)
+{
+       varpool_node::finalize_decl(decl);
+}
+
+static inline void varpool_add_new_variable(tree decl)
+{
+       varpool_node::add(decl);
+}
+
+static inline unsigned int rebuild_cgraph_edges(void)
+{
+       return cgraph_edge::rebuild_edges();
+}
+
+static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability)
+{
+       return node->function_symbol(availability);
+}
+
+static inline cgraph_node_ptr cgraph_function_or_thunk_node(cgraph_node_ptr node, enum availability *availability = NULL)
+{
+       return node->ultimate_alias_target(availability);
+}
+
+static inline bool cgraph_only_called_directly_p(cgraph_node_ptr node)
+{
+       return node->only_called_directly_p();
+}
+
+static inline enum availability cgraph_function_body_availability(cgraph_node_ptr node)
+{
+       return node->get_availability();
+}
+
+static inline cgraph_node_ptr cgraph_alias_target(cgraph_node_ptr node)
+{
+       return node->get_alias_target();
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_function_insertion_hook(cgraph_node_hook hook, void *data)
+{
+       return symtab->add_cgraph_insertion_hook(hook, data);
+}
+
+static inline void cgraph_remove_function_insertion_hook(struct cgraph_node_hook_list *entry)
+{
+       symtab->remove_cgraph_insertion_hook(entry);
+}
+
+static inline struct cgraph_node_hook_list *cgraph_add_node_removal_hook(cgraph_node_hook hook, void *data)
+{
+       return symtab->add_cgraph_removal_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_removal_hook(struct cgraph_node_hook_list *entry)
+{
+       symtab->remove_cgraph_removal_hook(entry);
+}
+
+static inline struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook(cgraph_2node_hook hook, void *data)
+{
+       return symtab->add_cgraph_duplication_hook(hook, data);
+}
+
+static inline void cgraph_remove_node_duplication_hook(struct cgraph_2node_hook_list *entry)
+{
+       symtab->remove_cgraph_duplication_hook(entry);
+}
+
+static inline void cgraph_call_node_duplication_hooks(cgraph_node_ptr node, cgraph_node_ptr node2)
+{
+       symtab->call_cgraph_duplication_hooks(node, node2);
+}
+
+static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_edge *cs2)
+{
+       symtab->call_edge_duplication_hooks(cs1, cs2);
+}
+
+#if BUILDING_GCC_VERSION >= 6000
+typedef gimple *gimple_ptr;
+typedef const gimple *const_gimple_ptr;
+#define gimple gimple_ptr
+#define const_gimple const_gimple_ptr
+#undef CONST_CAST_GIMPLE
+#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X))
+#endif
+
+/* gimple related */
+static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL)
+{
+       return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT);
+}
+
+template <>
+template <>
+inline bool is_a_helper<const greturn *>::test(const_gimple gs)
+{
+       return gs->code == GIMPLE_RETURN;
+}
+
+static inline gasm *as_a_gasm(gimple stmt)
+{
+       return as_a<gasm *>(stmt);
+}
+
+static inline const gasm *as_a_const_gasm(const_gimple stmt)
+{
+       return as_a<const gasm *>(stmt);
+}
+
+static inline gassign *as_a_gassign(gimple stmt)
+{
+       return as_a<gassign *>(stmt);
+}
+
+static inline const gassign *as_a_const_gassign(const_gimple stmt)
+{
+       return as_a<const gassign *>(stmt);
+}
+
+static inline gcall *as_a_gcall(gimple stmt)
+{
+       return as_a<gcall *>(stmt);
+}
+
+static inline const gcall *as_a_const_gcall(const_gimple stmt)
+{
+       return as_a<const gcall *>(stmt);
+}
+
+static inline gphi *as_a_gphi(gimple stmt)
+{
+       return as_a<gphi *>(stmt);
+}
+
+static inline const gphi *as_a_const_gphi(const_gimple stmt)
+{
+       return as_a<const gphi *>(stmt);
+}
+
+static inline greturn *as_a_greturn(gimple stmt)
+{
+       return as_a<greturn *>(stmt);
+}
+
+static inline const greturn *as_a_const_greturn(const_gimple stmt)
+{
+       return as_a<const greturn *>(stmt);
+}
+
+/* IPA/LTO related */
+#define ipa_ref_list_referring_iterate(L, I, P)        \
+       (L)->referring.iterate((I), &(P))
+#define ipa_ref_list_reference_iterate(L, I, P)        \
+       (L)->reference.iterate((I), &(P))
+
+static inline cgraph_node_ptr ipa_ref_referring_node(struct ipa_ref *ref)
+{
+       return dyn_cast<cgraph_node_ptr>(ref->referring);
+}
+
+static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimple stmt)
+{
+       referring_node->remove_stmt_references(stmt);
+}
+#endif
+
+#if BUILDING_GCC_VERSION < 6000
+#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning)  \
+       get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning)
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1))
+#endif
+
+#if BUILDING_GCC_VERSION >= 6000
+#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1))
+#endif
+
+#ifdef __cplusplus
+static inline void debug_tree(const_tree t)
+{
+       debug_tree(CONST_CAST_TREE(t));
+}
+
+static inline void debug_gimple_stmt(const_gimple s)
+{
+       debug_gimple_stmt(CONST_CAST_GIMPLE(s));
+}
+#else
+#define debug_tree(t) debug_tree(CONST_CAST_TREE(t))
+#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s))
+#endif
+
+#endif
diff --git a/scripts/gcc-plugins/gcc-generate-gimple-pass.h b/scripts/gcc-plugins/gcc-generate-gimple-pass.h
new file mode 100644 (file)
index 0000000..526c3c7
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Generator for GIMPLE pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ *    NO_GATE
+ *    NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ *    the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n)      #n
+#define _GCC_PLUGIN_STRINGIFY(n)       __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y)      x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z)   x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n)       _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA           __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n)            _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS                        __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME                        _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n)       _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS           __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n)                      _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE                          __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n)                   _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE                       __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct gimple_opt_pass _PASS_NAME_PASS = {
+       .pass = {
+#endif
+               .type                   = GIMPLE_PASS,
+               .name                   = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+               .optinfo_flags          = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+               .has_gate               = _HAS_GATE,
+               .has_execute            = _HAS_EXECUTE,
+#else
+               .gate                   = _GATE,
+               .execute                = _EXECUTE,
+               .sub                    = NULL,
+               .next                   = NULL,
+               .static_pass_number     = 0,
+#endif
+               .tv_id                  = TV_NONE,
+               .properties_required    = PROPERTIES_REQUIRED,
+               .properties_provided    = PROPERTIES_PROVIDED,
+               .properties_destroyed   = PROPERTIES_DESTROYED,
+               .todo_flags_start       = TODO_FLAGS_START,
+               .todo_flags_finish      = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+       }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public gimple_opt_pass {
+public:
+       _PASS_NAME_PASS() : gimple_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual bool gate(function *) { return _GATE(); }
+#else
+       virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+       virtual opt_pass * clone () { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+       virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
diff --git a/scripts/gcc-plugins/gcc-generate-ipa-pass.h b/scripts/gcc-plugins/gcc-generate-ipa-pass.h
new file mode 100644 (file)
index 0000000..9bd926e
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Generator for IPA pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ *    NO_GENERATE_SUMMARY
+ *    NO_READ_SUMMARY
+ *    NO_WRITE_SUMMARY
+ *    NO_READ_OPTIMIZATION_SUMMARY
+ *    NO_WRITE_OPTIMIZATION_SUMMARY
+ *    NO_STMT_FIXUP
+ *    NO_FUNCTION_TRANSFORM
+ *    NO_VARIABLE_TRANSFORM
+ *    NO_GATE
+ *    NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and *TODO_FLAGS_* to override
+ *    the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n)      #n
+#define _GCC_PLUGIN_STRINGIFY(n)       __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y)      x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z)   x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n)       _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA           __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n)            _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS                        __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME                        _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n)       _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS           __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GENERATE_SUMMARY
+#define _GENERATE_SUMMARY NULL
+#else
+#define __GENERATE_SUMMARY(n)          _GCC_PLUGIN_CONCAT2(n, _generate_summary)
+#define _GENERATE_SUMMARY              __GENERATE_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_READ_SUMMARY
+#define _READ_SUMMARY NULL
+#else
+#define __READ_SUMMARY(n)              _GCC_PLUGIN_CONCAT2(n, _read_summary)
+#define _READ_SUMMARY                  __READ_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_WRITE_SUMMARY
+#define _WRITE_SUMMARY NULL
+#else
+#define __WRITE_SUMMARY(n)             _GCC_PLUGIN_CONCAT2(n, _write_summary)
+#define _WRITE_SUMMARY                 __WRITE_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_READ_OPTIMIZATION_SUMMARY
+#define _READ_OPTIMIZATION_SUMMARY NULL
+#else
+#define __READ_OPTIMIZATION_SUMMARY(n) _GCC_PLUGIN_CONCAT2(n, _read_optimization_summary)
+#define _READ_OPTIMIZATION_SUMMARY     __READ_OPTIMIZATION_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_WRITE_OPTIMIZATION_SUMMARY
+#define _WRITE_OPTIMIZATION_SUMMARY NULL
+#else
+#define __WRITE_OPTIMIZATION_SUMMARY(n)        _GCC_PLUGIN_CONCAT2(n, _write_optimization_summary)
+#define _WRITE_OPTIMIZATION_SUMMARY    __WRITE_OPTIMIZATION_SUMMARY(PASS_NAME)
+#endif
+
+#ifdef NO_STMT_FIXUP
+#define _STMT_FIXUP NULL
+#else
+#define __STMT_FIXUP(n)                        _GCC_PLUGIN_CONCAT2(n, _stmt_fixup)
+#define _STMT_FIXUP                    __STMT_FIXUP(PASS_NAME)
+#endif
+
+#ifdef NO_FUNCTION_TRANSFORM
+#define _FUNCTION_TRANSFORM NULL
+#else
+#define __FUNCTION_TRANSFORM(n)                _GCC_PLUGIN_CONCAT2(n, _function_transform)
+#define _FUNCTION_TRANSFORM            __FUNCTION_TRANSFORM(PASS_NAME)
+#endif
+
+#ifdef NO_VARIABLE_TRANSFORM
+#define _VARIABLE_TRANSFORM NULL
+#else
+#define __VARIABLE_TRANSFORM(n)                _GCC_PLUGIN_CONCAT2(n, _variable_transform)
+#define _VARIABLE_TRANSFORM            __VARIABLE_TRANSFORM(PASS_NAME)
+#endif
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n)                      _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE                          __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n)                   _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE                       __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#ifndef FUNCTION_TRANSFORM_TODO_FLAGS_START
+#define FUNCTION_TRANSFORM_TODO_FLAGS_START 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct ipa_opt_pass_d _PASS_NAME_PASS = {
+       .pass = {
+#endif
+               .type                   = IPA_PASS,
+               .name                   = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+               .optinfo_flags          = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+               .has_gate               = _HAS_GATE,
+               .has_execute            = _HAS_EXECUTE,
+#else
+               .gate                   = _GATE,
+               .execute                = _EXECUTE,
+               .sub                    = NULL,
+               .next                   = NULL,
+               .static_pass_number     = 0,
+#endif
+               .tv_id                  = TV_NONE,
+               .properties_required    = PROPERTIES_REQUIRED,
+               .properties_provided    = PROPERTIES_PROVIDED,
+               .properties_destroyed   = PROPERTIES_DESTROYED,
+               .todo_flags_start       = TODO_FLAGS_START,
+               .todo_flags_finish      = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+       },
+       .generate_summary               = _GENERATE_SUMMARY,
+       .write_summary                  = _WRITE_SUMMARY,
+       .read_summary                   = _READ_SUMMARY,
+#if BUILDING_GCC_VERSION >= 4006
+       .write_optimization_summary     = _WRITE_OPTIMIZATION_SUMMARY,
+       .read_optimization_summary      = _READ_OPTIMIZATION_SUMMARY,
+#endif
+       .stmt_fixup                     = _STMT_FIXUP,
+       .function_transform_todo_flags_start    = FUNCTION_TRANSFORM_TODO_FLAGS_START,
+       .function_transform             = _FUNCTION_TRANSFORM,
+       .variable_transform             = _VARIABLE_TRANSFORM,
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public ipa_opt_pass_d {
+public:
+       _PASS_NAME_PASS() : ipa_opt_pass_d(_PASS_NAME_PASS_DATA,
+                        g,
+                        _GENERATE_SUMMARY,
+                        _WRITE_SUMMARY,
+                        _READ_SUMMARY,
+                        _WRITE_OPTIMIZATION_SUMMARY,
+                        _READ_OPTIMIZATION_SUMMARY,
+                        _STMT_FIXUP,
+                        FUNCTION_TRANSFORM_TODO_FLAGS_START,
+                        _FUNCTION_TRANSFORM,
+                        _VARIABLE_TRANSFORM) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual bool gate(function *) { return _GATE(); }
+#else
+       virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+       virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+       virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GENERATE_SUMMARY
+#undef NO_WRITE_SUMMARY
+#undef NO_READ_SUMMARY
+#undef NO_WRITE_OPTIMIZATION_SUMMARY
+#undef NO_READ_OPTIMIZATION_SUMMARY
+#undef NO_STMT_FIXUP
+#undef NO_FUNCTION_TRANSFORM
+#undef NO_VARIABLE_TRANSFORM
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef FUNCTION_TRANSFORM_TODO_FLAGS_START
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _FUNCTION_TRANSFORM
+#undef __FUNCTION_TRANSFORM
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _GENERATE_SUMMARY
+#undef __GENERATE_SUMMARY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+#undef _READ_OPTIMIZATION_SUMMARY
+#undef __READ_OPTIMIZATION_SUMMARY
+#undef _READ_SUMMARY
+#undef __READ_SUMMARY
+#undef _STMT_FIXUP
+#undef __STMT_FIXUP
+#undef _VARIABLE_TRANSFORM
+#undef __VARIABLE_TRANSFORM
+#undef _WRITE_OPTIMIZATION_SUMMARY
+#undef __WRITE_OPTIMIZATION_SUMMARY
+#undef _WRITE_SUMMARY
+#undef __WRITE_SUMMARY
+
+#endif /* PASS_NAME */
diff --git a/scripts/gcc-plugins/gcc-generate-rtl-pass.h b/scripts/gcc-plugins/gcc-generate-rtl-pass.h
new file mode 100644 (file)
index 0000000..1dc67a5
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Generator for RTL pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ *    NO_GATE
+ *    NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ *    the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n)      #n
+#define _GCC_PLUGIN_STRINGIFY(n)       __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y)      x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z)   x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n)       _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA           __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n)            _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS                        __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME                        _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n)       _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS           __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n)                      _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE                          __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n)                   _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE                       __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct rtl_opt_pass _PASS_NAME_PASS = {
+       .pass = {
+#endif
+               .type                   = RTL_PASS,
+               .name                   = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+               .optinfo_flags          = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+               .has_gate               = _HAS_GATE,
+               .has_execute            = _HAS_EXECUTE,
+#else
+               .gate                   = _GATE,
+               .execute                = _EXECUTE,
+               .sub                    = NULL,
+               .next                   = NULL,
+               .static_pass_number     = 0,
+#endif
+               .tv_id                  = TV_NONE,
+               .properties_required    = PROPERTIES_REQUIRED,
+               .properties_provided    = PROPERTIES_PROVIDED,
+               .properties_destroyed   = PROPERTIES_DESTROYED,
+               .todo_flags_start       = TODO_FLAGS_START,
+               .todo_flags_finish      = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+       }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public rtl_opt_pass {
+public:
+       _PASS_NAME_PASS() : rtl_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual bool gate(function *) { return _GATE(); }
+#else
+       virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+       virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+       virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
diff --git a/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h b/scripts/gcc-plugins/gcc-generate-simple_ipa-pass.h
new file mode 100644 (file)
index 0000000..a27e2b3
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Generator for SIMPLE_IPA pass related boilerplate code/data
+ *
+ * Supports gcc 4.5-6
+ *
+ * Usage:
+ *
+ * 1. before inclusion define PASS_NAME
+ * 2. before inclusion define NO_* for unimplemented callbacks
+ *    NO_GATE
+ *    NO_EXECUTE
+ * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override
+ *    the default 0 values
+ * 4. for convenience, all the above will be undefined after inclusion!
+ * 5. the only exported name is make_PASS_NAME_pass() to register with gcc
+ */
+
+#ifndef PASS_NAME
+#error at least PASS_NAME must be defined
+#else
+#define __GCC_PLUGIN_STRINGIFY(n)      #n
+#define _GCC_PLUGIN_STRINGIFY(n)       __GCC_PLUGIN_STRINGIFY(n)
+#define _GCC_PLUGIN_CONCAT2(x, y)      x ## y
+#define _GCC_PLUGIN_CONCAT3(x, y, z)   x ## y ## z
+
+#define __PASS_NAME_PASS_DATA(n)       _GCC_PLUGIN_CONCAT2(n, _pass_data)
+#define _PASS_NAME_PASS_DATA           __PASS_NAME_PASS_DATA(PASS_NAME)
+
+#define __PASS_NAME_PASS(n)            _GCC_PLUGIN_CONCAT2(n, _pass)
+#define _PASS_NAME_PASS                        __PASS_NAME_PASS(PASS_NAME)
+
+#define _PASS_NAME_NAME                        _GCC_PLUGIN_STRINGIFY(PASS_NAME)
+
+#define __MAKE_PASS_NAME_PASS(n)       _GCC_PLUGIN_CONCAT3(make_, n, _pass)
+#define _MAKE_PASS_NAME_PASS           __MAKE_PASS_NAME_PASS(PASS_NAME)
+
+#ifdef NO_GATE
+#define _GATE NULL
+#define _HAS_GATE false
+#else
+#define __GATE(n)                      _GCC_PLUGIN_CONCAT2(n, _gate)
+#define _GATE                          __GATE(PASS_NAME)
+#define _HAS_GATE true
+#endif
+
+#ifdef NO_EXECUTE
+#define _EXECUTE NULL
+#define _HAS_EXECUTE false
+#else
+#define __EXECUTE(n)                   _GCC_PLUGIN_CONCAT2(n, _execute)
+#define _EXECUTE                       __EXECUTE(PASS_NAME)
+#define _HAS_EXECUTE true
+#endif
+
+#ifndef PROPERTIES_REQUIRED
+#define PROPERTIES_REQUIRED 0
+#endif
+
+#ifndef PROPERTIES_PROVIDED
+#define PROPERTIES_PROVIDED 0
+#endif
+
+#ifndef PROPERTIES_DESTROYED
+#define PROPERTIES_DESTROYED 0
+#endif
+
+#ifndef TODO_FLAGS_START
+#define TODO_FLAGS_START 0
+#endif
+
+#ifndef TODO_FLAGS_FINISH
+#define TODO_FLAGS_FINISH 0
+#endif
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const pass_data _PASS_NAME_PASS_DATA = {
+#else
+static struct simple_ipa_opt_pass _PASS_NAME_PASS = {
+       .pass = {
+#endif
+               .type                   = SIMPLE_IPA_PASS,
+               .name                   = _PASS_NAME_NAME,
+#if BUILDING_GCC_VERSION >= 4008
+               .optinfo_flags          = OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION == 4009
+               .has_gate               = _HAS_GATE,
+               .has_execute            = _HAS_EXECUTE,
+#else
+               .gate                   = _GATE,
+               .execute                = _EXECUTE,
+               .sub                    = NULL,
+               .next                   = NULL,
+               .static_pass_number     = 0,
+#endif
+               .tv_id                  = TV_NONE,
+               .properties_required    = PROPERTIES_REQUIRED,
+               .properties_provided    = PROPERTIES_PROVIDED,
+               .properties_destroyed   = PROPERTIES_DESTROYED,
+               .todo_flags_start       = TODO_FLAGS_START,
+               .todo_flags_finish      = TODO_FLAGS_FINISH,
+#if BUILDING_GCC_VERSION < 4009
+       }
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class _PASS_NAME_PASS : public simple_ipa_opt_pass {
+public:
+       _PASS_NAME_PASS() : simple_ipa_opt_pass(_PASS_NAME_PASS_DATA, g) {}
+
+#ifndef NO_GATE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual bool gate(function *) { return _GATE(); }
+#else
+       virtual bool gate(void) { return _GATE(); }
+#endif
+#endif
+
+       virtual opt_pass *clone() { return new _PASS_NAME_PASS(); }
+
+#ifndef NO_EXECUTE
+#if BUILDING_GCC_VERSION >= 5000
+       virtual unsigned int execute(function *) { return _EXECUTE(); }
+#else
+       virtual unsigned int execute(void) { return _EXECUTE(); }
+#endif
+#endif
+};
+}
+
+opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return new _PASS_NAME_PASS();
+}
+#else
+struct opt_pass *_MAKE_PASS_NAME_PASS(void)
+{
+       return &_PASS_NAME_PASS.pass;
+}
+#endif
+
+/* clean up user provided defines */
+#undef PASS_NAME
+#undef NO_GATE
+#undef NO_EXECUTE
+
+#undef PROPERTIES_DESTROYED
+#undef PROPERTIES_PROVIDED
+#undef PROPERTIES_REQUIRED
+#undef TODO_FLAGS_FINISH
+#undef TODO_FLAGS_START
+
+/* clean up generated defines */
+#undef _EXECUTE
+#undef __EXECUTE
+#undef _GATE
+#undef __GATE
+#undef _GCC_PLUGIN_CONCAT2
+#undef _GCC_PLUGIN_CONCAT3
+#undef _GCC_PLUGIN_STRINGIFY
+#undef __GCC_PLUGIN_STRINGIFY
+#undef _HAS_EXECUTE
+#undef _HAS_GATE
+#undef _MAKE_PASS_NAME_PASS
+#undef __MAKE_PASS_NAME_PASS
+#undef _PASS_NAME_NAME
+#undef _PASS_NAME_PASS
+#undef __PASS_NAME_PASS
+#undef _PASS_NAME_PASS_DATA
+#undef __PASS_NAME_PASS_DATA
+
+#endif /* PASS_NAME */
diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c
new file mode 100644 (file)
index 0000000..aedd611
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/sancov
+ *
+ * This plugin inserts a __sanitizer_cov_trace_pc() call at the start of basic blocks.
+ * It supports all gcc versions with plugin support (from gcc-4.5 on).
+ * It is based on the commit "Add fuzzing coverage support" by Dmitry Vyukov <dvyukov@google.com>.
+ *
+ * You can read about it more here:
+ *  https://gcc.gnu.org/viewcvs/gcc?limit_changes=0&view=revision&revision=231296
+ *  http://lwn.net/Articles/674854/
+ *  https://github.com/google/syzkaller
+ *  https://lwn.net/Articles/677764/
+ *
+ * Usage:
+ * make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+tree sancov_fndecl;
+
+static struct plugin_info sancov_plugin_info = {
+       .version        = "20160402",
+       .help           = "sancov plugin\n",
+};
+
+static unsigned int sancov_execute(void)
+{
+       basic_block bb;
+
+       /* Remove this line when this plugin and kcov will be in the kernel.
+       if (!strcmp(DECL_NAME_POINTER(current_function_decl), DECL_NAME_POINTER(sancov_fndecl)))
+               return 0;
+       */
+
+       FOR_EACH_BB_FN(bb, cfun) {
+               const_gimple stmt;
+               gcall *gcall;
+               gimple_stmt_iterator gsi = gsi_after_labels(bb);
+
+               if (gsi_end_p(gsi))
+                       continue;
+
+               stmt = gsi_stmt(gsi);
+               gcall = as_a_gcall(gimple_build_call(sancov_fndecl, 0));
+               gimple_set_location(gcall, gimple_location(stmt));
+               gsi_insert_before(&gsi, gcall, GSI_SAME_STMT);
+       }
+       return 0;
+}
+
+#define PASS_NAME sancov
+
+#define NO_GATE
+#define TODO_FLAGS_FINISH TODO_dump_func | TODO_verify_stmts | TODO_update_ssa_no_phi | TODO_verify_flow
+
+#include "gcc-generate-gimple-pass.h"
+
+static void sancov_start_unit(void __unused *gcc_data, void __unused *user_data)
+{
+       tree leaf_attr, nothrow_attr;
+       tree BT_FN_VOID = build_function_type_list(void_type_node, NULL_TREE);
+
+       sancov_fndecl = build_fn_decl("__sanitizer_cov_trace_pc", BT_FN_VOID);
+
+       DECL_ASSEMBLER_NAME(sancov_fndecl);
+       TREE_PUBLIC(sancov_fndecl) = 1;
+       DECL_EXTERNAL(sancov_fndecl) = 1;
+       DECL_ARTIFICIAL(sancov_fndecl) = 1;
+       DECL_PRESERVE_P(sancov_fndecl) = 1;
+       DECL_UNINLINABLE(sancov_fndecl) = 1;
+       TREE_USED(sancov_fndecl) = 1;
+
+       nothrow_attr = tree_cons(get_identifier("nothrow"), NULL, NULL);
+       decl_attributes(&sancov_fndecl, nothrow_attr, 0);
+       gcc_assert(TREE_NOTHROW(sancov_fndecl));
+#if BUILDING_GCC_VERSION > 4005
+       leaf_attr = tree_cons(get_identifier("leaf"), NULL, NULL);
+       decl_attributes(&sancov_fndecl, leaf_attr, 0);
+#endif
+}
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+       int i;
+       struct register_pass_info sancov_plugin_pass_info;
+       const char * const plugin_name = plugin_info->base_name;
+       const int argc = plugin_info->argc;
+       const struct plugin_argument * const argv = plugin_info->argv;
+       bool enable = true;
+
+       static const struct ggc_root_tab gt_ggc_r_gt_sancov[] = {
+               {
+                       .base = &sancov_fndecl,
+                       .nelt = 1,
+                       .stride = sizeof(sancov_fndecl),
+                       .cb = &gt_ggc_mx_tree_node,
+                       .pchw = &gt_pch_nx_tree_node
+               },
+               LAST_GGC_ROOT_TAB
+       };
+
+       /* BBs can be split afterwards?? */
+       sancov_plugin_pass_info.pass                            = make_sancov_pass();
+#if BUILDING_GCC_VERSION >= 4009
+       sancov_plugin_pass_info.reference_pass_name             = "asan";
+#else
+       sancov_plugin_pass_info.reference_pass_name             = "nrv";
+#endif
+       sancov_plugin_pass_info.ref_pass_instance_number        = 0;
+       sancov_plugin_pass_info.pos_op                          = PASS_POS_INSERT_BEFORE;
+
+       if (!plugin_default_version_check(version, &gcc_version)) {
+               error(G_("incompatible gcc/plugin versions"));
+               return 1;
+       }
+
+       for (i = 0; i < argc; ++i) {
+               if (!strcmp(argv[i].key, "no-sancov")) {
+                       enable = false;
+                       continue;
+               }
+               error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key);
+       }
+
+       register_callback(plugin_name, PLUGIN_INFO, NULL, &sancov_plugin_info);
+
+       if (!enable)
+               return 0;
+
+#if BUILDING_GCC_VERSION < 6000
+       register_callback(plugin_name, PLUGIN_START_UNIT, &sancov_start_unit, NULL);
+       register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)&gt_ggc_r_gt_sancov);
+       register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_plugin_pass_info);
+#endif
+
+       return 0;
+}
index 1873421..49a00d5 100755 (executable)
@@ -133,6 +133,7 @@ my %VCS_cmds_git = (
     "author_pattern" => "^GitAuthor: (.*)",
     "subject_pattern" => "^GitSubject: (.*)",
     "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$",
+    "file_exists_cmd" => "git ls-files \$file",
 );
 
 my %VCS_cmds_hg = (
@@ -161,6 +162,7 @@ my %VCS_cmds_hg = (
     "author_pattern" => "^HgAuthor: (.*)",
     "subject_pattern" => "^HgSubject: (.*)",
     "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$",
+    "file_exists_cmd" => "hg files \$file",
 );
 
 my $conf = which_conf(".get_maintainer.conf");
@@ -430,7 +432,7 @@ foreach my $file (@ARGV) {
            die "$P: file '${file}' not found\n";
        }
     }
-    if ($from_filename) {
+    if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) {
        $file =~ s/^\Q${cur_path}\E//;  #strip any absolute path
        $file =~ s/^\Q${lk_path}\E//;   #or the path to the lk tree
        push(@files, $file);
@@ -2124,6 +2126,22 @@ sub vcs_file_blame {
     }
 }
 
+sub vcs_file_exists {
+    my ($file) = @_;
+
+    my $exists;
+
+    my $vcs_used = vcs_exists();
+    return 0 if (!$vcs_used);
+
+    my $cmd = $VCS_cmds{"file_exists_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;          # interpolate $cmd
+
+    $exists = &{$VCS_cmds{"execute_cmd"}}($cmd);
+
+    return $exists;
+}
+
 sub uniq {
     my (@parms) = @_;
 
index f0f6d9d..4f727eb 100755 (executable)
@@ -180,7 +180,7 @@ else
 fi;
 
 # final build of init/
-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init
+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}"
 
 kallsymso=""
 kallsyms_vmlinux=""
index 86e56fe..e1c09e2 100755 (executable)
@@ -26,6 +26,8 @@ create_package() {
        # Fix ownership and permissions
        chown -R root:root "$pdir"
        chmod -R go-w "$pdir"
+       # in case we are in a restrictive umask environment like 0077
+       chmod -R a+rX "$pdir"
 
        # Create the package
        dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch}" -p$pname -P"$pdir"
@@ -238,7 +240,8 @@ maintainer="$name <$email>"
 # Try to determine distribution
 if [ -n "$KDEB_CHANGELOG_DIST" ]; then
         distribution=$KDEB_CHANGELOG_DIST
-elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ]; then
+# In some cases lsb_release returns the codename as n/a, which breaks dpkg-parsechangelog
+elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ] && [ "$distribution" != "n/a" ]; then
         : # nothing to do in this case
 else
         distribution="unstable"
@@ -322,13 +325,14 @@ fi
 
 # Build kernel header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles"
-if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
-       (cd $srctree; find tools/objtool -type f -executable) >> "$objtree/debian/hdrsrcfiles"
-fi
 (cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
+if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
+       (cd $objtree; find tools/objtool -type f -executable) >> "$objtree/debian/hdrobjfiles"
+fi
 (cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles"
+(cd $objtree; find scripts/gcc-plugins -name \*.so -o -name gcc-common.h) >> "$objtree/debian/hdrobjfiles"
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
 (cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)
index e167592..42396a7 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
+/*
+ * glibc synced up and added the metag number but didn't add the relocations.
+ * Work around this in a crude manner for now.
+ */
 #ifndef EM_METAG
-/* Remove this when these make it to the standard system elf.h. */
 #define EM_METAG      174
+#endif
+#ifndef R_METAG_ADDR32
 #define R_METAG_ADDR32                   2
+#endif
+#ifndef R_METAG_NONE
 #define R_METAG_NONE                     3
 #endif
 
index 63d91e2..966dd39 100755 (executable)
@@ -143,7 +143,7 @@ fi
 if test -e include/config/auto.conf; then
        . include/config/auto.conf
 else
-       echo "Error: kernelrelease not valid - run 'make prepare' to update it"
+       echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2
        exit 1
 fi
 
index 176758c..df28f2b 100644 (file)
@@ -118,6 +118,34 @@ config LSM_MMAP_MIN_ADDR
          this low address space will need the permission specific to the
          systems running LSM.
 
+config HAVE_HARDENED_USERCOPY_ALLOCATOR
+       bool
+       help
+         The heap allocator implements __check_heap_object() for
+         validating memory ranges against heap object sizes in
+         support of CONFIG_HARDENED_USERCOPY.
+
+config HAVE_ARCH_HARDENED_USERCOPY
+       bool
+       help
+         The architecture supports CONFIG_HARDENED_USERCOPY by
+         calling check_object_size() just before performing the
+         userspace copies in the low level implementation of
+         copy_to_user() and copy_from_user().
+
+config HARDENED_USERCOPY
+       bool "Harden memory copies between kernel and userspace"
+       depends on HAVE_ARCH_HARDENED_USERCOPY
+       select BUG
+       help
+         This option checks for obviously wrong memory regions when
+         copying memory to/from the kernel (via copy_to_user() and
+         copy_from_user() functions) by rejecting memory ranges that
+         are larger than the specified heap object, span multiple
+         separately allocates pages, are not on the process stack,
+         or are part of the kernel text. This kills entire classes
+         of heap overflow exploits and similar kernel memory exposures.
+
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
index c4bb47d..4838e7f 100644 (file)
@@ -356,7 +356,7 @@ void security_inode_free(struct inode *inode)
 }
 
 int security_dentry_init_security(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen)
 {
        return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
index ec30880..13185a6 100644 (file)
@@ -2832,7 +2832,7 @@ static void selinux_inode_free_security(struct inode *inode)
 }
 
 static int selinux_dentry_init_security(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen)
 {
        u32 newsid;
index e040621..65171f6 100644 (file)
@@ -9,14 +9,6 @@ menuconfig SND_ARM
          Drivers that are implemented on ASoC can be found in
          "ALSA for SoC audio support" section.
 
-config SND_PXA2XX_LIB
-       tristate
-       select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
-       select SND_DMAENGINE_PCM
-
-config SND_PXA2XX_LIB_AC97
-       bool
-
 if SND_ARM
 
 config SND_ARMAACI
@@ -42,3 +34,10 @@ config SND_PXA2XX_AC97
 
 endif  # SND_ARM
 
+config SND_PXA2XX_LIB
+       tristate
+       select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
+       select SND_DMAENGINE_PCM
+
+config SND_PXA2XX_LIB_AC97
+       bool
index 516795b..5dfa610 100644 (file)
@@ -21,13 +21,15 @@ void *snd_array_new(struct snd_array *array)
                return NULL;
        if (array->used >= array->alloced) {
                int num = array->alloced + array->alloc_align;
+               int oldsize = array->alloced * array->elem_size;
                int size = (num + 1) * array->elem_size;
                void *nlist;
                if (snd_BUG_ON(num >= 4096))
                        return NULL;
-               nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
+               nlist = krealloc(array->list, size, GFP_KERNEL);
                if (!nlist)
                        return NULL;
+               memset(nlist + oldsize, 0, size - oldsize);
                array->list = nlist;
                array->alloced = num;
        }
index 6f8ea13..89dacf9 100644 (file)
@@ -2265,6 +2265,8 @@ static const struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x1022, 0x780d),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
+       { PCI_DEVICE(0x1002, 0x0002),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x1308),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x157a),
index ddd29b9..574b1b4 100644 (file)
@@ -4689,6 +4689,22 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec,
        }
 }
 
+static void alc298_fixup_speaker_volume(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* The speaker is routed to the Node 0x06 by a mistake, as a result
+                  we can't adjust the speaker's volume since this node does not has
+                  Amp-out capability. we change the speaker's route to:
+                  Node 0x02 (Audio Output) -> Node 0x0c (Audio Mixer) -> Node 0x17 (
+                  Pin Complex), since Node 0x02 has Amp-out caps, we can adjust
+                  speaker's volume now. */
+
+               hda_nid_t conn1[1] = { 0x0c };
+               snd_hda_override_conn_list(codec, 0x17, 1, conn1);
+       }
+}
+
 /* Hook to update amp GPIO4 for automute */
 static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
                                          struct hda_jack_callback *jack)
@@ -4838,6 +4854,7 @@ enum {
        ALC280_FIXUP_HP_HEADSET_MIC,
        ALC221_FIXUP_HP_FRONT_MIC,
        ALC292_FIXUP_TPT460,
+       ALC298_FIXUP_SPK_VOLUME,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5493,6 +5510,12 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE,
        },
+       [ALC298_FIXUP_SPK_VOLUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_speaker_volume,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5539,6 +5562,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
        SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
        SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5813,6 +5837,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x14, 0x90170130},
                {0x1b, 0x01014020},
                {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221103f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x14, 0x90170150},
                {0x1b, 0x02011020},
@@ -6549,6 +6577,7 @@ enum {
        ALC668_FIXUP_ASUS_Nx51,
        ALC891_FIXUP_HEADSET_MODE,
        ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC662_FIXUP_ACER_VERITON,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -6818,6 +6847,13 @@ static const struct hda_fixup alc662_fixups[] = {
                .chained = true,
                .chain_id = ALC891_FIXUP_HEADSET_MODE
        },
+       [ALC662_FIXUP_ACER_VERITON] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x50170120 }, /* no internal speaker */
+                       { }
+               }
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6856,6 +6892,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
+       SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
        SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
 
 #if 0
index 28f5493..43c1c50 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <string.h>
 #include <linux/bitops.h>
+#include <stdlib.h>
 
 #define DECLARE_BITMAP(name,bits) \
        unsigned long name[BITS_TO_LONGS(bits)]
@@ -10,6 +11,8 @@
 int __bitmap_weight(const unsigned long *bitmap, int bits);
 void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
                 const unsigned long *bitmap2, int bits);
+int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                const unsigned long *bitmap2, unsigned int bits);
 
 #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
 
@@ -65,4 +68,38 @@ static inline int test_and_set_bit(int nr, unsigned long *addr)
        return (old & mask) != 0;
 }
 
+/**
+ * bitmap_alloc - Allocate bitmap
+ * @nr: Bit to set
+ */
+static inline unsigned long *bitmap_alloc(int nbits)
+{
+       return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long));
+}
+
+/*
+ * bitmap_scnprintf - print bitmap list into buffer
+ * @bitmap: bitmap
+ * @nbits: size of bitmap
+ * @buf: buffer to store output
+ * @size: size of @buf
+ */
+size_t bitmap_scnprintf(unsigned long *bitmap, int nbits,
+                       char *buf, size_t size);
+
+/**
+ * bitmap_and - Do logical and on bitmaps
+ * @dst: resulting bitmap
+ * @src1: operand 1
+ * @src2: operand 2
+ * @nbits: size of bitmap
+ */
+static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
+                            const unsigned long *src2, unsigned int nbits)
+{
+       if (small_const_nbits(nbits))
+               return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+       return __bitmap_and(dst, src1, src2, nbits);
+}
+
 #endif /* _PERF_BITOPS_H */
index 0a1adc1..38748b0 100644 (file)
@@ -29,3 +29,47 @@ void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
        for (k = 0; k < nr; k++)
                dst[k] = bitmap1[k] | bitmap2[k];
 }
+
+size_t bitmap_scnprintf(unsigned long *bitmap, int nbits,
+                       char *buf, size_t size)
+{
+       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+       int cur, rbot, rtop;
+       bool first = true;
+       size_t ret = 0;
+
+       rbot = cur = find_first_bit(bitmap, nbits);
+       while (cur < nbits) {
+               rtop = cur;
+               cur = find_next_bit(bitmap, nbits, cur + 1);
+               if (cur < nbits && cur <= rtop + 1)
+                       continue;
+
+               if (!first)
+                       ret += scnprintf(buf + ret, size - ret, ",");
+
+               first = false;
+
+               ret += scnprintf(buf + ret, size - ret, "%d", rbot);
+               if (rbot < rtop)
+                       ret += scnprintf(buf + ret, size - ret, "-%d", rtop);
+
+               rbot = cur;
+       }
+       return ret;
+}
+
+int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+                const unsigned long *bitmap2, unsigned int bits)
+{
+       unsigned int k;
+       unsigned int lim = bits/BITS_PER_LONG;
+       unsigned long result = 0;
+
+       for (k = 0; k < lim; k++)
+               result |= (dst[k] = bitmap1[k] & bitmap2[k]);
+       if (bits % BITS_PER_LONG)
+               result |= (dst[k] = bitmap1[k] & bitmap2[k] &
+                          BITMAP_LAST_WORD_MASK(bits));
+       return result != 0;
+}
index 3c60335..9e9f25f 100644 (file)
@@ -1,2 +1,3 @@
 TRACEEVENT-CFLAGS
 libtraceevent-dynamic-list
+libtraceevent.so.*
index 69966ab..379a2be 100644 (file)
@@ -192,6 +192,9 @@ OPTIONS
 --period::
        Record the sample period.
 
+--sample-cpu::
+       Record the sample cpu.
+
 -n::
 --no-samples::
        Don't sample.
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
new file mode 100644 (file)
index 0000000..24803c5
--- /dev/null
@@ -0,0 +1,874 @@
+
+ifeq ($(src-perf),)
+src-perf := $(srctree)/tools/perf
+endif
+
+ifeq ($(obj-perf),)
+obj-perf := $(OUTPUT)
+endif
+
+ifneq ($(obj-perf),)
+obj-perf := $(abspath $(obj-perf))/
+endif
+
+$(shell printf "" > $(OUTPUT).config-detected)
+detected     = $(shell echo "$(1)=y"       >> $(OUTPUT).config-detected)
+detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
+
+CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
+
+include $(srctree)/tools/scripts/Makefile.arch
+
+$(call detected_var,ARCH)
+
+NO_PERF_REGS := 1
+
+# Additional ARCH settings for ppc
+ifeq ($(ARCH),powerpc)
+  NO_PERF_REGS := 0
+  LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
+endif
+
+# Additional ARCH settings for x86
+ifeq ($(ARCH),x86)
+  $(call detected,CONFIG_X86)
+  ifeq (${IS_64_BIT}, 1)
+    CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated
+    ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
+    LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
+    $(call detected,CONFIG_X86_64)
+  else
+    LIBUNWIND_LIBS = -lunwind-x86 -llzma -lunwind
+  endif
+  NO_PERF_REGS := 0
+endif
+
+ifeq ($(ARCH),arm)
+  NO_PERF_REGS := 0
+  LIBUNWIND_LIBS = -lunwind -lunwind-arm
+endif
+
+ifeq ($(ARCH),arm64)
+  NO_PERF_REGS := 0
+  LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
+endif
+
+ifeq ($(NO_PERF_REGS),0)
+  $(call detected,CONFIG_PERF_REGS)
+endif
+
+# So far there's only x86 and arm libdw unwind support merged in perf.
+# Disable it on all other architectures in case libdw unwind
+# support is detected in system. Add supported architectures
+# to the check.
+ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
+  NO_LIBDW_DWARF_UNWIND := 1
+endif
+
+ifeq ($(LIBUNWIND_LIBS),)
+  NO_LIBUNWIND := 1
+endif
+#
+# For linking with debug library, run like:
+#
+#   make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
+#
+
+libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code))
+define libunwind_arch_set_flags_code
+  FEATURE_CHECK_CFLAGS-libunwind-$(1)  = -I$(LIBUNWIND_DIR)/include
+  FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
+endef
+
+ifdef LIBUNWIND_DIR
+  LIBUNWIND_CFLAGS  = -I$(LIBUNWIND_DIR)/include
+  LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
+  LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64
+  $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch)))
+endif
+
+# Set per-feature check compilation flags
+FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
+FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
+
+ifeq ($(NO_PERF_REGS),0)
+  CFLAGS += -DHAVE_PERF_REGS_SUPPORT
+endif
+
+# for linking with debug library, run like:
+# make DEBUG=1 LIBDW_DIR=/opt/libdw/
+ifdef LIBDW_DIR
+  LIBDW_CFLAGS  := -I$(LIBDW_DIR)/include
+  LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
+endif
+FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
+
+# for linking with debug library, run like:
+# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
+ifdef LIBBABELTRACE_DIR
+  LIBBABELTRACE_CFLAGS  := -I$(LIBBABELTRACE_DIR)/include
+  LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
+endif
+FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
+FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
+
+FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi
+# include ARCH specific config
+-include $(src-perf)/arch/$(ARCH)/Makefile
+
+ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+  CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+endif
+
+include $(srctree)/tools/scripts/utilities.mak
+
+ifeq ($(call get-executable,$(FLEX)),)
+  dummy := $(error Error: $(FLEX) is missing on this system, please install it)
+endif
+
+ifeq ($(call get-executable,$(BISON)),)
+  dummy := $(error Error: $(BISON) is missing on this system, please install it)
+endif
+
+# Treat warnings as errors unless directed not to
+ifneq ($(WERROR),0)
+  CFLAGS += -Werror
+endif
+
+ifndef DEBUG
+  DEBUG := 0
+endif
+
+ifeq ($(DEBUG),0)
+  CFLAGS += -O6
+endif
+
+ifdef PARSER_DEBUG
+  PARSER_DEBUG_BISON := -t
+  PARSER_DEBUG_FLEX  := -d
+  CFLAGS             += -DPARSER_DEBUG
+  $(call detected_var,PARSER_DEBUG_BISON)
+  $(call detected_var,PARSER_DEBUG_FLEX)
+endif
+
+# Try different combinations to accommodate systems that only have
+# python[2][-config] in weird combinations but always preferring
+# python2 and python2-config as per pep-0394. If we catch a
+# python[-config] in version 3, the version check will kill it.
+PYTHON2 := $(if $(call get-executable,python2),python2,python)
+override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
+PYTHON2_CONFIG := \
+  $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
+override PYTHON_CONFIG := \
+  $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
+
+PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
+
+PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
+PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
+
+FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
+FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
+FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
+FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
+
+CFLAGS += -fno-omit-frame-pointer
+CFLAGS += -ggdb3
+CFLAGS += -funwind-tables
+CFLAGS += -Wall
+CFLAGS += -Wextra
+CFLAGS += -std=gnu99
+
+# Enforce a non-executable stack, as we may regress (again) in the future by
+# adding assembler files missing the .GNU-stack linker note.
+LDFLAGS += -Wl,-z,noexecstack
+
+EXTLIBS = -lpthread -lrt -lm -ldl
+
+ifeq ($(FEATURES_DUMP),)
+include $(srctree)/tools/build/Makefile.feature
+else
+include $(FEATURES_DUMP)
+endif
+
+ifeq ($(feature-stackprotector-all), 1)
+  CFLAGS += -fstack-protector-all
+endif
+
+ifeq ($(DEBUG),0)
+  ifeq ($(feature-fortify-source), 1)
+    CFLAGS += -D_FORTIFY_SOURCE=2
+  endif
+endif
+
+CFLAGS += -I$(src-perf)/util/include
+CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
+CFLAGS += -I$(srctree)/tools/include/uapi
+CFLAGS += -I$(srctree)/tools/include/
+CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi
+CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/
+CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/
+
+# $(obj-perf)      for generated common-cmds.h
+# $(obj-perf)/util for generated bison/flex headers
+ifneq ($(OUTPUT),)
+CFLAGS += -I$(obj-perf)/util
+CFLAGS += -I$(obj-perf)
+endif
+
+CFLAGS += -I$(src-perf)/util
+CFLAGS += -I$(src-perf)
+CFLAGS += -I$(srctree)/tools/lib/
+
+CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+
+ifeq ($(feature-sync-compare-and-swap), 1)
+  CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
+endif
+
+ifeq ($(feature-pthread-attr-setaffinity-np), 1)
+  CFLAGS += -DHAVE_PTHREAD_ATTR_SETAFFINITY_NP
+endif
+
+ifndef NO_BIONIC
+  $(call feature_check,bionic)
+  ifeq ($(feature-bionic), 1)
+    BIONIC := 1
+    EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
+    EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
+  endif
+endif
+
+ifdef NO_LIBELF
+  NO_DWARF := 1
+  NO_DEMANGLE := 1
+  NO_LIBUNWIND := 1
+  NO_LIBDW_DWARF_UNWIND := 1
+  NO_LIBBPF := 1
+else
+  ifeq ($(feature-libelf), 0)
+    ifeq ($(feature-glibc), 1)
+      LIBC_SUPPORT := 1
+    endif
+    ifeq ($(BIONIC),1)
+      LIBC_SUPPORT := 1
+    endif
+    ifeq ($(LIBC_SUPPORT),1)
+      msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install libelf-dev, libelf-devel or elfutils-libelf-devel);
+
+      NO_LIBELF := 1
+      NO_DWARF := 1
+      NO_DEMANGLE := 1
+      NO_LIBUNWIND := 1
+      NO_LIBDW_DWARF_UNWIND := 1
+      NO_LIBBPF := 1
+    else
+      ifneq ($(filter s% -static%,$(LDFLAGS),),)
+        msg := $(error No static glibc found, please install glibc-static);
+      else
+        msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
+      endif
+    endif
+  else
+    ifndef NO_LIBDW_DWARF_UNWIND
+      ifneq ($(feature-libdw-dwarf-unwind),1)
+        NO_LIBDW_DWARF_UNWIND := 1
+        msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
+      endif
+    endif
+    ifneq ($(feature-dwarf), 1)
+      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
+    else
+      ifneq ($(feature-dwarf_getlocations), 1)
+        msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157);
+      else
+        CFLAGS += -DHAVE_DWARF_GETLOCATIONS
+      endif # dwarf_getlocations
+    endif # Dwarf support
+  endif # libelf support
+endif # NO_LIBELF
+
+ifdef NO_DWARF
+  NO_LIBDW_DWARF_UNWIND := 1
+endif
+
+ifndef NO_LIBELF
+  CFLAGS += -DHAVE_LIBELF_SUPPORT
+  EXTLIBS += -lelf
+  $(call detected,CONFIG_LIBELF)
+
+  ifeq ($(feature-libelf-mmap), 1)
+    CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
+  endif
+
+  ifeq ($(feature-libelf-getphdrnum), 1)
+    CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
+  endif
+
+  ifeq ($(feature-libelf-gelf_getnote), 1)
+    CFLAGS += -DHAVE_GELF_GETNOTE_SUPPORT
+  else
+    msg := $(warning gelf_getnote() not found on libelf, SDT support disabled);
+  endif
+
+  ifeq ($(feature-libelf-getshdrstrndx), 1)
+    CFLAGS += -DHAVE_ELF_GETSHDRSTRNDX_SUPPORT
+  endif
+
+  ifndef NO_DWARF
+    ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
+      msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
+      NO_DWARF := 1
+    else
+      CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
+      LDFLAGS += $(LIBDW_LDFLAGS)
+      DWARFLIBS := -ldw
+      ifeq ($(findstring -static,${LDFLAGS}),-static)
+       DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
+      endif
+      EXTLIBS += ${DWARFLIBS}
+      $(call detected,CONFIG_DWARF)
+    endif # PERF_HAVE_DWARF_REGS
+  endif # NO_DWARF
+
+  ifndef NO_LIBBPF
+    ifeq ($(feature-bpf), 1)
+      CFLAGS += -DHAVE_LIBBPF_SUPPORT
+      $(call detected,CONFIG_LIBBPF)
+    endif
+
+    ifndef NO_DWARF
+      ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+        CFLAGS += -DHAVE_BPF_PROLOGUE
+        $(call detected,CONFIG_BPF_PROLOGUE)
+      else
+        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+      endif
+    else
+      msg := $(warning DWARF support is off, BPF prologue is disabled);
+    endif
+
+  endif # NO_LIBBPF
+endif # NO_LIBELF
+
+ifndef NO_SDT
+  ifneq ($(feature-sdt), 1)
+    msg := $(warning No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev);
+    NO_SDT := 1;
+  else
+    CFLAGS += -DHAVE_SDT_EVENT
+    $(call detected,CONFIG_SDT_EVENT)
+  endif
+endif
+
+ifdef PERF_HAVE_JITDUMP
+  ifndef NO_DWARF
+    $(call detected,CONFIG_JITDUMP)
+    CFLAGS += -DHAVE_JITDUMP
+  endif
+endif
+
+ifeq ($(ARCH),powerpc)
+  ifndef NO_DWARF
+    CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
+  endif
+endif
+
+ifndef NO_LIBUNWIND
+  have_libunwind :=
+
+  ifeq ($(feature-libunwind-x86), 1)
+    $(call detected,CONFIG_LIBUNWIND_X86)
+    CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
+    LDFLAGS += -lunwind-x86
+    EXTLIBS_LIBUNWIND += -lunwind-x86
+    have_libunwind = 1
+  endif
+
+  ifeq ($(feature-libunwind-aarch64), 1)
+    $(call detected,CONFIG_LIBUNWIND_AARCH64)
+    CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
+    LDFLAGS += -lunwind-aarch64
+    EXTLIBS_LIBUNWIND += -lunwind-aarch64
+    have_libunwind = 1
+    $(call feature_check,libunwind-debug-frame-aarch64)
+    ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
+      msg := $(warning No debug_frame support found in libunwind-aarch64);
+      CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64
+    endif
+  endif
+
+  ifneq ($(feature-libunwind), 1)
+    msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
+    NO_LOCAL_LIBUNWIND := 1
+  else
+    have_libunwind := 1
+    $(call detected,CONFIG_LOCAL_LIBUNWIND)
+  endif
+
+  ifneq ($(have_libunwind), 1)
+    NO_LIBUNWIND := 1
+  endif
+else
+  NO_LOCAL_LIBUNWIND := 1
+endif
+
+ifndef NO_LIBBPF
+  ifneq ($(feature-bpf), 1)
+    msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.)
+    NO_LIBBPF := 1
+  endif
+endif
+
+dwarf-post-unwind := 1
+dwarf-post-unwind-text := BUG
+
+# setup DWARF post unwinder
+ifdef NO_LIBUNWIND
+  ifdef NO_LIBDW_DWARF_UNWIND
+    msg := $(warning Disabling post unwind, no support found.);
+    dwarf-post-unwind := 0
+  else
+    dwarf-post-unwind-text := libdw
+    $(call detected,CONFIG_LIBDW_DWARF_UNWIND)
+  endif
+else
+  dwarf-post-unwind-text := libunwind
+  $(call detected,CONFIG_LIBUNWIND)
+  # Enable libunwind support by default.
+  ifndef NO_LIBDW_DWARF_UNWIND
+    NO_LIBDW_DWARF_UNWIND := 1
+  endif
+endif
+
+ifeq ($(dwarf-post-unwind),1)
+  CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
+  $(call detected,CONFIG_DWARF_UNWIND)
+else
+  NO_DWARF_UNWIND := 1
+endif
+
+ifndef NO_LOCAL_LIBUNWIND
+  ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
+    $(call feature_check,libunwind-debug-frame)
+    ifneq ($(feature-libunwind-debug-frame), 1)
+      msg := $(warning No debug_frame support found in libunwind);
+      CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+    endif
+  else
+    # non-ARM has no dwarf_find_debug_frame() function:
+    CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+  endif
+  EXTLIBS += $(LIBUNWIND_LIBS)
+  LDFLAGS += $(LIBUNWIND_LIBS)
+endif
+
+ifndef NO_LIBUNWIND
+  CFLAGS  += -DHAVE_LIBUNWIND_SUPPORT
+  CFLAGS  += $(LIBUNWIND_CFLAGS)
+  LDFLAGS += $(LIBUNWIND_LDFLAGS)
+  EXTLIBS += $(EXTLIBS_LIBUNWIND)
+endif
+
+ifndef NO_LIBAUDIT
+  ifneq ($(feature-libaudit), 1)
+    msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
+    NO_LIBAUDIT := 1
+  else
+    CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
+    EXTLIBS += -laudit
+    $(call detected,CONFIG_AUDIT)
+  endif
+endif
+
+ifndef NO_LIBCRYPTO
+  ifneq ($(feature-libcrypto), 1)
+    msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
+    NO_LIBCRYPTO := 1
+  else
+    CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
+    EXTLIBS += -lcrypto
+    $(call detected,CONFIG_CRYPTO)
+  endif
+endif
+
+ifdef NO_NEWT
+  NO_SLANG=1
+endif
+
+ifndef NO_SLANG
+  ifneq ($(feature-libslang), 1)
+    msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
+    NO_SLANG := 1
+  else
+    # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
+    CFLAGS += -I/usr/include/slang
+    CFLAGS += -DHAVE_SLANG_SUPPORT
+    EXTLIBS += -lslang
+    $(call detected,CONFIG_SLANG)
+  endif
+endif
+
+ifndef NO_GTK2
+  FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
+  ifneq ($(feature-gtk2), 1)
+    msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
+    NO_GTK2 := 1
+  else
+    ifeq ($(feature-gtk2-infobar), 1)
+      GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
+    endif
+    CFLAGS += -DHAVE_GTK2_SUPPORT
+    GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null)
+    GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null)
+    EXTLIBS += -ldl
+  endif
+endif
+
+grep-libs  = $(filter -l%,$(1))
+strip-libs = $(filter-out -l%,$(1))
+
+ifdef NO_LIBPERL
+  CFLAGS += -DNO_LIBPERL
+else
+  PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
+  PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
+  PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
+  PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
+  FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
+
+  ifneq ($(feature-libperl), 1)
+    CFLAGS += -DNO_LIBPERL
+    NO_LIBPERL := 1
+    msg := $(warning Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev);
+  else
+    LDFLAGS += $(PERL_EMBED_LDFLAGS)
+    EXTLIBS += $(PERL_EMBED_LIBADD)
+    $(call detected,CONFIG_LIBPERL)
+  endif
+endif
+
+ifeq ($(feature-timerfd), 1)
+  CFLAGS += -DHAVE_TIMERFD_SUPPORT
+else
+  msg := $(warning No timerfd support. Disables 'perf kvm stat live');
+endif
+
+disable-python = $(eval $(disable-python_code))
+define disable-python_code
+  CFLAGS += -DNO_LIBPYTHON
+  $(warning $1)
+  NO_LIBPYTHON := 1
+endef
+
+ifdef NO_LIBPYTHON
+  $(call disable-python,Python support disabled by user)
+else
+
+  ifndef PYTHON
+    $(call disable-python,No python interpreter was found: disables Python support - please install python-devel/python-dev)
+  else
+    PYTHON_WORD := $(call shell-wordify,$(PYTHON))
+
+    ifndef PYTHON_CONFIG
+      $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
+    else
+
+      PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
+
+      PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
+      PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
+      PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
+      PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
+      FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
+
+      ifneq ($(feature-libpython), 1)
+        $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev)
+      else
+
+        ifneq ($(feature-libpython-version), 1)
+          $(warning Python 3 is not yet supported; please set)
+          $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
+          $(warning If you also have Python 2 installed, then)
+          $(warning try something like:)
+          $(warning $(and ,))
+          $(warning $(and ,)  make PYTHON=python2)
+          $(warning $(and ,))
+          $(warning Otherwise, disable Python support entirely:)
+          $(warning $(and ,))
+          $(warning $(and ,)  make NO_LIBPYTHON=1)
+          $(warning $(and ,))
+          $(error   $(and ,))
+        else
+          LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
+          EXTLIBS += $(PYTHON_EMBED_LIBADD)
+          LANG_BINDINGS += $(obj-perf)python/perf.so
+          $(call detected,CONFIG_LIBPYTHON)
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifeq ($(feature-libbfd), 1)
+  EXTLIBS += -lbfd
+
+  # call all detections now so we get correct
+  # status in VF output
+  $(call feature_check,liberty)
+  $(call feature_check,liberty-z)
+  $(call feature_check,cplus-demangle)
+
+  ifeq ($(feature-liberty), 1)
+    EXTLIBS += -liberty
+  else
+    ifeq ($(feature-liberty-z), 1)
+      EXTLIBS += -liberty -lz
+    endif
+  endif
+endif
+
+ifdef NO_DEMANGLE
+  CFLAGS += -DNO_DEMANGLE
+else
+  ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
+    EXTLIBS += -liberty
+    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
+  else
+    ifneq ($(feature-libbfd), 1)
+      ifneq ($(feature-liberty), 1)
+        ifneq ($(feature-liberty-z), 1)
+          # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
+          # or any of 'bfd iberty z' trinity
+          ifeq ($(feature-cplus-demangle), 1)
+            EXTLIBS += -liberty
+            CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
+          else
+            msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
+            CFLAGS += -DNO_DEMANGLE
+          endif
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifneq ($(filter -lbfd,$(EXTLIBS)),)
+  CFLAGS += -DHAVE_LIBBFD_SUPPORT
+endif
+
+ifndef NO_ZLIB
+  ifeq ($(feature-zlib), 1)
+    CFLAGS += -DHAVE_ZLIB_SUPPORT
+    EXTLIBS += -lz
+    $(call detected,CONFIG_ZLIB)
+  else
+    NO_ZLIB := 1
+  endif
+endif
+
+ifndef NO_LZMA
+  ifeq ($(feature-lzma), 1)
+    CFLAGS += -DHAVE_LZMA_SUPPORT
+    EXTLIBS += -llzma
+    $(call detected,CONFIG_LZMA)
+  else
+    msg := $(warning No liblzma found, disables xz kernel module decompression, please install xz-devel/liblzma-dev);
+    NO_LZMA := 1
+  endif
+endif
+
+ifndef NO_BACKTRACE
+  ifeq ($(feature-backtrace), 1)
+    CFLAGS += -DHAVE_BACKTRACE_SUPPORT
+  endif
+endif
+
+ifndef NO_LIBNUMA
+  ifeq ($(feature-libnuma), 0)
+    msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev);
+    NO_LIBNUMA := 1
+  else
+    ifeq ($(feature-numa_num_possible_cpus), 0)
+      msg := $(warning Old numa library found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev >= 2.0.8);
+      NO_LIBNUMA := 1
+    else
+      CFLAGS += -DHAVE_LIBNUMA_SUPPORT
+      EXTLIBS += -lnuma
+      $(call detected,CONFIG_NUMA)
+    endif
+  endif
+endif
+
+ifdef HAVE_KVM_STAT_SUPPORT
+    CFLAGS += -DHAVE_KVM_STAT_SUPPORT
+endif
+
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    $(call feature_check,compile-32)
+    ifeq ($(feature-compile-32), 1)
+      CFLAGS += -DHAVE_PERF_READ_VDSO32
+    else
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq ($(ARCH), x86)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
+  ifndef NO_PERF_READ_VDSOX32
+    $(call feature_check,compile-x32)
+    ifeq ($(feature-compile-x32), 1)
+      CFLAGS += -DHAVE_PERF_READ_VDSOX32
+    else
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif
+else
+  NO_PERF_READ_VDSO32 := 1
+  NO_PERF_READ_VDSOX32 := 1
+endif
+
+ifdef LIBBABELTRACE
+  $(call feature_check,libbabeltrace)
+  ifeq ($(feature-libbabeltrace), 1)
+    CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS)
+    LDFLAGS += $(LIBBABELTRACE_LDFLAGS)
+    EXTLIBS += -lbabeltrace-ctf
+    $(call detected,CONFIG_LIBBABELTRACE)
+  else
+    msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev);
+  endif
+endif
+
+ifndef NO_AUXTRACE
+  ifeq ($(feature-get_cpuid), 0)
+    msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc);
+    NO_AUXTRACE := 1
+  else
+    $(call detected,CONFIG_AUXTRACE)
+    CFLAGS += -DHAVE_AUXTRACE_SUPPORT
+  endif
+endif
+
+# Among the variables below, these:
+#   perfexecdir
+#   template_dir
+#   mandir
+#   infodir
+#   htmldir
+#   ETC_PERFCONFIG (but not sysconfdir)
+# can be specified as a relative path some/where/else;
+# this is interpreted as relative to $(prefix) and "perf" at
+# runtime figures out where they are based on the path to the executable.
+# This can help installing the suite in a relocatable way.
+
+# Make the path relative to DESTDIR, not to prefix
+ifndef DESTDIR
+prefix ?= $(HOME)
+endif
+bindir_relative = bin
+bindir = $(abspath $(prefix)/$(bindir_relative))
+mandir = share/man
+infodir = share/info
+perfexecdir = libexec/perf-core
+sharedir = $(prefix)/share
+template_dir = share/perf-core/templates
+STRACE_GROUPS_DIR = share/perf-core/strace/groups
+htmldir = share/doc/perf-doc
+tipdir = share/doc/perf-tip
+srcdir = $(srctree)/tools/perf
+ifeq ($(prefix),/usr)
+sysconfdir = /etc
+ETC_PERFCONFIG = $(sysconfdir)/perfconfig
+else
+sysconfdir = $(prefix)/etc
+ETC_PERFCONFIG = etc/perfconfig
+endif
+ifndef lib
+ifeq ($(ARCH)$(IS_64_BIT), x861)
+lib = lib64
+else
+lib = lib
+endif
+endif # lib
+libdir = $(prefix)/$(lib)
+
+# Shell quote (do not use $(call) to accommodate ancient setups);
+ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
+STRACE_GROUPS_DIR_SQ = $(subst ','\'',$(STRACE_GROUPS_DIR))
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
+bindir_SQ = $(subst ','\'',$(bindir))
+mandir_SQ = $(subst ','\'',$(mandir))
+infodir_SQ = $(subst ','\'',$(infodir))
+perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
+template_dir_SQ = $(subst ','\'',$(template_dir))
+htmldir_SQ = $(subst ','\'',$(htmldir))
+tipdir_SQ = $(subst ','\'',$(tipdir))
+prefix_SQ = $(subst ','\'',$(prefix))
+sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
+libdir_SQ = $(subst ','\'',$(libdir))
+srcdir_SQ = $(subst ','\'',$(srcdir))
+
+ifneq ($(filter /%,$(firstword $(perfexecdir))),)
+perfexec_instdir = $(perfexecdir)
+STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
+tip_instdir = $(tipdir)
+else
+perfexec_instdir = $(prefix)/$(perfexecdir)
+STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
+tip_instdir = $(prefix)/$(tipdir)
+endif
+perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
+STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
+tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
+
+# If we install to $(HOME) we keep the traceevent default:
+# $(HOME)/.traceevent/plugins
+# Otherwise we install plugins into the global $(libdir).
+ifdef DESTDIR
+plugindir=$(libdir)/traceevent/plugins
+plugindir_SQ= $(subst ','\'',$(plugindir))
+endif
+
+print_var = $(eval $(print_var_code)) $(info $(MSG))
+define print_var_code
+    MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
+endef
+
+ifeq ($(VF),1)
+  $(call print_var,prefix)
+  $(call print_var,bindir)
+  $(call print_var,libdir)
+  $(call print_var,sysconfdir)
+  $(call print_var,LIBUNWIND_DIR)
+  $(call print_var,LIBDW_DIR)
+
+  ifeq ($(dwarf-post-unwind),1)
+    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+  endif
+  $(info )
+endif
+
+$(call detected_var,bindir_SQ)
+$(call detected_var,PYTHON_WORD)
+ifneq ($(OUTPUT),)
+$(call detected_var,OUTPUT)
+endif
+$(call detected_var,htmldir_SQ)
+$(call detected_var,infodir_SQ)
+$(call detected_var,mandir_SQ)
+$(call detected_var,ETC_PERFCONFIG_SQ)
+$(call detected_var,STRACE_GROUPS_DIR_SQ)
+$(call detected_var,prefix_SQ)
+$(call detected_var,perfexecdir_SQ)
+$(call detected_var,tipdir_SQ)
+$(call detected_var,srcdir_SQ)
+$(call detected_var,LIBDIR)
+$(call detected_var,GTK_CFLAGS)
+$(call detected_var,PERL_EMBED_CCOPTS)
+$(call detected_var,PYTHON_EMBED_CCOPTS)
index 6641abb..2d90875 100644 (file)
@@ -161,7 +161,7 @@ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
 BPF_DIR                = $(srctree)/tools/lib/bpf/
 SUBCMD_DIR     = $(srctree)/tools/lib/subcmd/
 
-# include config/Makefile by default and rule out
+# include Makefile.config by default and rule out
 # non-config cases
 config := 1
 
@@ -183,7 +183,7 @@ ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
 FEATURE_TESTS := all
 endif
 endif
-include config/Makefile
+include Makefile.config
 endif
 
 ifeq ($(config),0)
@@ -706,7 +706,7 @@ $(INSTALL_DOC_TARGETS):
 ### Cleaning rules
 
 #
-# This is here, not in config/Makefile, because config/Makefile does
+# This is here, not in Makefile.config, because Makefile.config does
 # not get included for the clean target:
 #
 config-clean:
index 8f2c16d..6355902 100644 (file)
@@ -1434,6 +1434,7 @@ struct option __record_options[] = {
        OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
                    "per thread counts"),
        OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
+       OPT_BOOLEAN(0, "sample-cpu", &record.opts.sample_cpu, "Record the sample cpu"),
        OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
                        &record.opts.sample_time_set,
                        "Record the sample timestamps"),
index bd10868..418ed94 100644 (file)
@@ -128,10 +128,14 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
                return err;
        }
 
-       err = symbol__annotate(sym, map, 0);
+       err = symbol__disassemble(sym, map, 0);
        if (err == 0) {
 out_assign:
                top->sym_filter_entry = he;
+       } else {
+               char msg[BUFSIZ];
+               symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
+               pr_err("Couldn't annotate %s: %s\n", sym->name, msg);
        }
 
        pthread_mutex_unlock(&notes->lock);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
deleted file mode 100644 (file)
index 24803c5..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-
-ifeq ($(src-perf),)
-src-perf := $(srctree)/tools/perf
-endif
-
-ifeq ($(obj-perf),)
-obj-perf := $(OUTPUT)
-endif
-
-ifneq ($(obj-perf),)
-obj-perf := $(abspath $(obj-perf))/
-endif
-
-$(shell printf "" > $(OUTPUT).config-detected)
-detected     = $(shell echo "$(1)=y"       >> $(OUTPUT).config-detected)
-detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
-
-CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
-
-include $(srctree)/tools/scripts/Makefile.arch
-
-$(call detected_var,ARCH)
-
-NO_PERF_REGS := 1
-
-# Additional ARCH settings for ppc
-ifeq ($(ARCH),powerpc)
-  NO_PERF_REGS := 0
-  LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
-endif
-
-# Additional ARCH settings for x86
-ifeq ($(ARCH),x86)
-  $(call detected,CONFIG_X86)
-  ifeq (${IS_64_BIT}, 1)
-    CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated
-    ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
-    LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
-    $(call detected,CONFIG_X86_64)
-  else
-    LIBUNWIND_LIBS = -lunwind-x86 -llzma -lunwind
-  endif
-  NO_PERF_REGS := 0
-endif
-
-ifeq ($(ARCH),arm)
-  NO_PERF_REGS := 0
-  LIBUNWIND_LIBS = -lunwind -lunwind-arm
-endif
-
-ifeq ($(ARCH),arm64)
-  NO_PERF_REGS := 0
-  LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
-endif
-
-ifeq ($(NO_PERF_REGS),0)
-  $(call detected,CONFIG_PERF_REGS)
-endif
-
-# So far there's only x86 and arm libdw unwind support merged in perf.
-# Disable it on all other architectures in case libdw unwind
-# support is detected in system. Add supported architectures
-# to the check.
-ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
-  NO_LIBDW_DWARF_UNWIND := 1
-endif
-
-ifeq ($(LIBUNWIND_LIBS),)
-  NO_LIBUNWIND := 1
-endif
-#
-# For linking with debug library, run like:
-#
-#   make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
-#
-
-libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code))
-define libunwind_arch_set_flags_code
-  FEATURE_CHECK_CFLAGS-libunwind-$(1)  = -I$(LIBUNWIND_DIR)/include
-  FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
-endef
-
-ifdef LIBUNWIND_DIR
-  LIBUNWIND_CFLAGS  = -I$(LIBUNWIND_DIR)/include
-  LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
-  LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64
-  $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch)))
-endif
-
-# Set per-feature check compilation flags
-FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
-FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
-FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
-FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
-
-ifeq ($(NO_PERF_REGS),0)
-  CFLAGS += -DHAVE_PERF_REGS_SUPPORT
-endif
-
-# for linking with debug library, run like:
-# make DEBUG=1 LIBDW_DIR=/opt/libdw/
-ifdef LIBDW_DIR
-  LIBDW_CFLAGS  := -I$(LIBDW_DIR)/include
-  LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
-endif
-FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
-FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
-
-# for linking with debug library, run like:
-# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
-ifdef LIBBABELTRACE_DIR
-  LIBBABELTRACE_CFLAGS  := -I$(LIBBABELTRACE_DIR)/include
-  LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
-endif
-FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
-FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
-
-FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi
-# include ARCH specific config
--include $(src-perf)/arch/$(ARCH)/Makefile
-
-ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
-  CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
-endif
-
-include $(srctree)/tools/scripts/utilities.mak
-
-ifeq ($(call get-executable,$(FLEX)),)
-  dummy := $(error Error: $(FLEX) is missing on this system, please install it)
-endif
-
-ifeq ($(call get-executable,$(BISON)),)
-  dummy := $(error Error: $(BISON) is missing on this system, please install it)
-endif
-
-# Treat warnings as errors unless directed not to
-ifneq ($(WERROR),0)
-  CFLAGS += -Werror
-endif
-
-ifndef DEBUG
-  DEBUG := 0
-endif
-
-ifeq ($(DEBUG),0)
-  CFLAGS += -O6
-endif
-
-ifdef PARSER_DEBUG
-  PARSER_DEBUG_BISON := -t
-  PARSER_DEBUG_FLEX  := -d
-  CFLAGS             += -DPARSER_DEBUG
-  $(call detected_var,PARSER_DEBUG_BISON)
-  $(call detected_var,PARSER_DEBUG_FLEX)
-endif
-
-# Try different combinations to accommodate systems that only have
-# python[2][-config] in weird combinations but always preferring
-# python2 and python2-config as per pep-0394. If we catch a
-# python[-config] in version 3, the version check will kill it.
-PYTHON2 := $(if $(call get-executable,python2),python2,python)
-override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
-PYTHON2_CONFIG := \
-  $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
-override PYTHON_CONFIG := \
-  $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
-
-PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
-
-PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
-PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-
-FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
-FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
-FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
-FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
-
-CFLAGS += -fno-omit-frame-pointer
-CFLAGS += -ggdb3
-CFLAGS += -funwind-tables
-CFLAGS += -Wall
-CFLAGS += -Wextra
-CFLAGS += -std=gnu99
-
-# Enforce a non-executable stack, as we may regress (again) in the future by
-# adding assembler files missing the .GNU-stack linker note.
-LDFLAGS += -Wl,-z,noexecstack
-
-EXTLIBS = -lpthread -lrt -lm -ldl
-
-ifeq ($(FEATURES_DUMP),)
-include $(srctree)/tools/build/Makefile.feature
-else
-include $(FEATURES_DUMP)
-endif
-
-ifeq ($(feature-stackprotector-all), 1)
-  CFLAGS += -fstack-protector-all
-endif
-
-ifeq ($(DEBUG),0)
-  ifeq ($(feature-fortify-source), 1)
-    CFLAGS += -D_FORTIFY_SOURCE=2
-  endif
-endif
-
-CFLAGS += -I$(src-perf)/util/include
-CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
-CFLAGS += -I$(srctree)/tools/include/uapi
-CFLAGS += -I$(srctree)/tools/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/
-
-# $(obj-perf)      for generated common-cmds.h
-# $(obj-perf)/util for generated bison/flex headers
-ifneq ($(OUTPUT),)
-CFLAGS += -I$(obj-perf)/util
-CFLAGS += -I$(obj-perf)
-endif
-
-CFLAGS += -I$(src-perf)/util
-CFLAGS += -I$(src-perf)
-CFLAGS += -I$(srctree)/tools/lib/
-
-CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
-
-ifeq ($(feature-sync-compare-and-swap), 1)
-  CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
-endif
-
-ifeq ($(feature-pthread-attr-setaffinity-np), 1)
-  CFLAGS += -DHAVE_PTHREAD_ATTR_SETAFFINITY_NP
-endif
-
-ifndef NO_BIONIC
-  $(call feature_check,bionic)
-  ifeq ($(feature-bionic), 1)
-    BIONIC := 1
-    EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
-    EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
-  endif
-endif
-
-ifdef NO_LIBELF
-  NO_DWARF := 1
-  NO_DEMANGLE := 1
-  NO_LIBUNWIND := 1
-  NO_LIBDW_DWARF_UNWIND := 1
-  NO_LIBBPF := 1
-else
-  ifeq ($(feature-libelf), 0)
-    ifeq ($(feature-glibc), 1)
-      LIBC_SUPPORT := 1
-    endif
-    ifeq ($(BIONIC),1)
-      LIBC_SUPPORT := 1
-    endif
-    ifeq ($(LIBC_SUPPORT),1)
-      msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install libelf-dev, libelf-devel or elfutils-libelf-devel);
-
-      NO_LIBELF := 1
-      NO_DWARF := 1
-      NO_DEMANGLE := 1
-      NO_LIBUNWIND := 1
-      NO_LIBDW_DWARF_UNWIND := 1
-      NO_LIBBPF := 1
-    else
-      ifneq ($(filter s% -static%,$(LDFLAGS),),)
-        msg := $(error No static glibc found, please install glibc-static);
-      else
-        msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
-      endif
-    endif
-  else
-    ifndef NO_LIBDW_DWARF_UNWIND
-      ifneq ($(feature-libdw-dwarf-unwind),1)
-        NO_LIBDW_DWARF_UNWIND := 1
-        msg := $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR);
-      endif
-    endif
-    ifneq ($(feature-dwarf), 1)
-      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
-    else
-      ifneq ($(feature-dwarf_getlocations), 1)
-        msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157);
-      else
-        CFLAGS += -DHAVE_DWARF_GETLOCATIONS
-      endif # dwarf_getlocations
-    endif # Dwarf support
-  endif # libelf support
-endif # NO_LIBELF
-
-ifdef NO_DWARF
-  NO_LIBDW_DWARF_UNWIND := 1
-endif
-
-ifndef NO_LIBELF
-  CFLAGS += -DHAVE_LIBELF_SUPPORT
-  EXTLIBS += -lelf
-  $(call detected,CONFIG_LIBELF)
-
-  ifeq ($(feature-libelf-mmap), 1)
-    CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
-  endif
-
-  ifeq ($(feature-libelf-getphdrnum), 1)
-    CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
-  endif
-
-  ifeq ($(feature-libelf-gelf_getnote), 1)
-    CFLAGS += -DHAVE_GELF_GETNOTE_SUPPORT
-  else
-    msg := $(warning gelf_getnote() not found on libelf, SDT support disabled);
-  endif
-
-  ifeq ($(feature-libelf-getshdrstrndx), 1)
-    CFLAGS += -DHAVE_ELF_GETSHDRSTRNDX_SUPPORT
-  endif
-
-  ifndef NO_DWARF
-    ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
-      msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
-      NO_DWARF := 1
-    else
-      CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
-      LDFLAGS += $(LIBDW_LDFLAGS)
-      DWARFLIBS := -ldw
-      ifeq ($(findstring -static,${LDFLAGS}),-static)
-       DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
-      endif
-      EXTLIBS += ${DWARFLIBS}
-      $(call detected,CONFIG_DWARF)
-    endif # PERF_HAVE_DWARF_REGS
-  endif # NO_DWARF
-
-  ifndef NO_LIBBPF
-    ifeq ($(feature-bpf), 1)
-      CFLAGS += -DHAVE_LIBBPF_SUPPORT
-      $(call detected,CONFIG_LIBBPF)
-    endif
-
-    ifndef NO_DWARF
-      ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
-        CFLAGS += -DHAVE_BPF_PROLOGUE
-        $(call detected,CONFIG_BPF_PROLOGUE)
-      else
-        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
-      endif
-    else
-      msg := $(warning DWARF support is off, BPF prologue is disabled);
-    endif
-
-  endif # NO_LIBBPF
-endif # NO_LIBELF
-
-ifndef NO_SDT
-  ifneq ($(feature-sdt), 1)
-    msg := $(warning No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev);
-    NO_SDT := 1;
-  else
-    CFLAGS += -DHAVE_SDT_EVENT
-    $(call detected,CONFIG_SDT_EVENT)
-  endif
-endif
-
-ifdef PERF_HAVE_JITDUMP
-  ifndef NO_DWARF
-    $(call detected,CONFIG_JITDUMP)
-    CFLAGS += -DHAVE_JITDUMP
-  endif
-endif
-
-ifeq ($(ARCH),powerpc)
-  ifndef NO_DWARF
-    CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
-  endif
-endif
-
-ifndef NO_LIBUNWIND
-  have_libunwind :=
-
-  ifeq ($(feature-libunwind-x86), 1)
-    $(call detected,CONFIG_LIBUNWIND_X86)
-    CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
-    LDFLAGS += -lunwind-x86
-    EXTLIBS_LIBUNWIND += -lunwind-x86
-    have_libunwind = 1
-  endif
-
-  ifeq ($(feature-libunwind-aarch64), 1)
-    $(call detected,CONFIG_LIBUNWIND_AARCH64)
-    CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
-    LDFLAGS += -lunwind-aarch64
-    EXTLIBS_LIBUNWIND += -lunwind-aarch64
-    have_libunwind = 1
-    $(call feature_check,libunwind-debug-frame-aarch64)
-    ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
-      msg := $(warning No debug_frame support found in libunwind-aarch64);
-      CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64
-    endif
-  endif
-
-  ifneq ($(feature-libunwind), 1)
-    msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
-    NO_LOCAL_LIBUNWIND := 1
-  else
-    have_libunwind := 1
-    $(call detected,CONFIG_LOCAL_LIBUNWIND)
-  endif
-
-  ifneq ($(have_libunwind), 1)
-    NO_LIBUNWIND := 1
-  endif
-else
-  NO_LOCAL_LIBUNWIND := 1
-endif
-
-ifndef NO_LIBBPF
-  ifneq ($(feature-bpf), 1)
-    msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.)
-    NO_LIBBPF := 1
-  endif
-endif
-
-dwarf-post-unwind := 1
-dwarf-post-unwind-text := BUG
-
-# setup DWARF post unwinder
-ifdef NO_LIBUNWIND
-  ifdef NO_LIBDW_DWARF_UNWIND
-    msg := $(warning Disabling post unwind, no support found.);
-    dwarf-post-unwind := 0
-  else
-    dwarf-post-unwind-text := libdw
-    $(call detected,CONFIG_LIBDW_DWARF_UNWIND)
-  endif
-else
-  dwarf-post-unwind-text := libunwind
-  $(call detected,CONFIG_LIBUNWIND)
-  # Enable libunwind support by default.
-  ifndef NO_LIBDW_DWARF_UNWIND
-    NO_LIBDW_DWARF_UNWIND := 1
-  endif
-endif
-
-ifeq ($(dwarf-post-unwind),1)
-  CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
-  $(call detected,CONFIG_DWARF_UNWIND)
-else
-  NO_DWARF_UNWIND := 1
-endif
-
-ifndef NO_LOCAL_LIBUNWIND
-  ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
-    $(call feature_check,libunwind-debug-frame)
-    ifneq ($(feature-libunwind-debug-frame), 1)
-      msg := $(warning No debug_frame support found in libunwind);
-      CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
-    endif
-  else
-    # non-ARM has no dwarf_find_debug_frame() function:
-    CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
-  endif
-  EXTLIBS += $(LIBUNWIND_LIBS)
-  LDFLAGS += $(LIBUNWIND_LIBS)
-endif
-
-ifndef NO_LIBUNWIND
-  CFLAGS  += -DHAVE_LIBUNWIND_SUPPORT
-  CFLAGS  += $(LIBUNWIND_CFLAGS)
-  LDFLAGS += $(LIBUNWIND_LDFLAGS)
-  EXTLIBS += $(EXTLIBS_LIBUNWIND)
-endif
-
-ifndef NO_LIBAUDIT
-  ifneq ($(feature-libaudit), 1)
-    msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
-    NO_LIBAUDIT := 1
-  else
-    CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
-    EXTLIBS += -laudit
-    $(call detected,CONFIG_AUDIT)
-  endif
-endif
-
-ifndef NO_LIBCRYPTO
-  ifneq ($(feature-libcrypto), 1)
-    msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
-    NO_LIBCRYPTO := 1
-  else
-    CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
-    EXTLIBS += -lcrypto
-    $(call detected,CONFIG_CRYPTO)
-  endif
-endif
-
-ifdef NO_NEWT
-  NO_SLANG=1
-endif
-
-ifndef NO_SLANG
-  ifneq ($(feature-libslang), 1)
-    msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev);
-    NO_SLANG := 1
-  else
-    # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
-    CFLAGS += -I/usr/include/slang
-    CFLAGS += -DHAVE_SLANG_SUPPORT
-    EXTLIBS += -lslang
-    $(call detected,CONFIG_SLANG)
-  endif
-endif
-
-ifndef NO_GTK2
-  FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
-  ifneq ($(feature-gtk2), 1)
-    msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
-    NO_GTK2 := 1
-  else
-    ifeq ($(feature-gtk2-infobar), 1)
-      GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
-    endif
-    CFLAGS += -DHAVE_GTK2_SUPPORT
-    GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null)
-    GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null)
-    EXTLIBS += -ldl
-  endif
-endif
-
-grep-libs  = $(filter -l%,$(1))
-strip-libs = $(filter-out -l%,$(1))
-
-ifdef NO_LIBPERL
-  CFLAGS += -DNO_LIBPERL
-else
-  PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
-  PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
-  PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
-  PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
-  FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
-
-  ifneq ($(feature-libperl), 1)
-    CFLAGS += -DNO_LIBPERL
-    NO_LIBPERL := 1
-    msg := $(warning Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev);
-  else
-    LDFLAGS += $(PERL_EMBED_LDFLAGS)
-    EXTLIBS += $(PERL_EMBED_LIBADD)
-    $(call detected,CONFIG_LIBPERL)
-  endif
-endif
-
-ifeq ($(feature-timerfd), 1)
-  CFLAGS += -DHAVE_TIMERFD_SUPPORT
-else
-  msg := $(warning No timerfd support. Disables 'perf kvm stat live');
-endif
-
-disable-python = $(eval $(disable-python_code))
-define disable-python_code
-  CFLAGS += -DNO_LIBPYTHON
-  $(warning $1)
-  NO_LIBPYTHON := 1
-endef
-
-ifdef NO_LIBPYTHON
-  $(call disable-python,Python support disabled by user)
-else
-
-  ifndef PYTHON
-    $(call disable-python,No python interpreter was found: disables Python support - please install python-devel/python-dev)
-  else
-    PYTHON_WORD := $(call shell-wordify,$(PYTHON))
-
-    ifndef PYTHON_CONFIG
-      $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
-    else
-
-      PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
-
-      PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
-      PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
-      PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
-      PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-      FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
-
-      ifneq ($(feature-libpython), 1)
-        $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev)
-      else
-
-        ifneq ($(feature-libpython-version), 1)
-          $(warning Python 3 is not yet supported; please set)
-          $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
-          $(warning If you also have Python 2 installed, then)
-          $(warning try something like:)
-          $(warning $(and ,))
-          $(warning $(and ,)  make PYTHON=python2)
-          $(warning $(and ,))
-          $(warning Otherwise, disable Python support entirely:)
-          $(warning $(and ,))
-          $(warning $(and ,)  make NO_LIBPYTHON=1)
-          $(warning $(and ,))
-          $(error   $(and ,))
-        else
-          LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
-          EXTLIBS += $(PYTHON_EMBED_LIBADD)
-          LANG_BINDINGS += $(obj-perf)python/perf.so
-          $(call detected,CONFIG_LIBPYTHON)
-        endif
-      endif
-    endif
-  endif
-endif
-
-ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
-
-  # call all detections now so we get correct
-  # status in VF output
-  $(call feature_check,liberty)
-  $(call feature_check,liberty-z)
-  $(call feature_check,cplus-demangle)
-
-  ifeq ($(feature-liberty), 1)
-    EXTLIBS += -liberty
-  else
-    ifeq ($(feature-liberty-z), 1)
-      EXTLIBS += -liberty -lz
-    endif
-  endif
-endif
-
-ifdef NO_DEMANGLE
-  CFLAGS += -DNO_DEMANGLE
-else
-  ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
-    EXTLIBS += -liberty
-    CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
-  else
-    ifneq ($(feature-libbfd), 1)
-      ifneq ($(feature-liberty), 1)
-        ifneq ($(feature-liberty-z), 1)
-          # we dont have neither HAVE_CPLUS_DEMANGLE_SUPPORT
-          # or any of 'bfd iberty z' trinity
-          ifeq ($(feature-cplus-demangle), 1)
-            EXTLIBS += -liberty
-            CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
-          else
-            msg := $(warning No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling)
-            CFLAGS += -DNO_DEMANGLE
-          endif
-        endif
-      endif
-    endif
-  endif
-endif
-
-ifneq ($(filter -lbfd,$(EXTLIBS)),)
-  CFLAGS += -DHAVE_LIBBFD_SUPPORT
-endif
-
-ifndef NO_ZLIB
-  ifeq ($(feature-zlib), 1)
-    CFLAGS += -DHAVE_ZLIB_SUPPORT
-    EXTLIBS += -lz
-    $(call detected,CONFIG_ZLIB)
-  else
-    NO_ZLIB := 1
-  endif
-endif
-
-ifndef NO_LZMA
-  ifeq ($(feature-lzma), 1)
-    CFLAGS += -DHAVE_LZMA_SUPPORT
-    EXTLIBS += -llzma
-    $(call detected,CONFIG_LZMA)
-  else
-    msg := $(warning No liblzma found, disables xz kernel module decompression, please install xz-devel/liblzma-dev);
-    NO_LZMA := 1
-  endif
-endif
-
-ifndef NO_BACKTRACE
-  ifeq ($(feature-backtrace), 1)
-    CFLAGS += -DHAVE_BACKTRACE_SUPPORT
-  endif
-endif
-
-ifndef NO_LIBNUMA
-  ifeq ($(feature-libnuma), 0)
-    msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev);
-    NO_LIBNUMA := 1
-  else
-    ifeq ($(feature-numa_num_possible_cpus), 0)
-      msg := $(warning Old numa library found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev >= 2.0.8);
-      NO_LIBNUMA := 1
-    else
-      CFLAGS += -DHAVE_LIBNUMA_SUPPORT
-      EXTLIBS += -lnuma
-      $(call detected,CONFIG_NUMA)
-    endif
-  endif
-endif
-
-ifdef HAVE_KVM_STAT_SUPPORT
-    CFLAGS += -DHAVE_KVM_STAT_SUPPORT
-endif
-
-ifeq (${IS_64_BIT}, 1)
-  ifndef NO_PERF_READ_VDSO32
-    $(call feature_check,compile-32)
-    ifeq ($(feature-compile-32), 1)
-      CFLAGS += -DHAVE_PERF_READ_VDSO32
-    else
-      NO_PERF_READ_VDSO32 := 1
-    endif
-  endif
-  ifneq ($(ARCH), x86)
-    NO_PERF_READ_VDSOX32 := 1
-  endif
-  ifndef NO_PERF_READ_VDSOX32
-    $(call feature_check,compile-x32)
-    ifeq ($(feature-compile-x32), 1)
-      CFLAGS += -DHAVE_PERF_READ_VDSOX32
-    else
-      NO_PERF_READ_VDSOX32 := 1
-    endif
-  endif
-else
-  NO_PERF_READ_VDSO32 := 1
-  NO_PERF_READ_VDSOX32 := 1
-endif
-
-ifdef LIBBABELTRACE
-  $(call feature_check,libbabeltrace)
-  ifeq ($(feature-libbabeltrace), 1)
-    CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS)
-    LDFLAGS += $(LIBBABELTRACE_LDFLAGS)
-    EXTLIBS += -lbabeltrace-ctf
-    $(call detected,CONFIG_LIBBABELTRACE)
-  else
-    msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev);
-  endif
-endif
-
-ifndef NO_AUXTRACE
-  ifeq ($(feature-get_cpuid), 0)
-    msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc);
-    NO_AUXTRACE := 1
-  else
-    $(call detected,CONFIG_AUXTRACE)
-    CFLAGS += -DHAVE_AUXTRACE_SUPPORT
-  endif
-endif
-
-# Among the variables below, these:
-#   perfexecdir
-#   template_dir
-#   mandir
-#   infodir
-#   htmldir
-#   ETC_PERFCONFIG (but not sysconfdir)
-# can be specified as a relative path some/where/else;
-# this is interpreted as relative to $(prefix) and "perf" at
-# runtime figures out where they are based on the path to the executable.
-# This can help installing the suite in a relocatable way.
-
-# Make the path relative to DESTDIR, not to prefix
-ifndef DESTDIR
-prefix ?= $(HOME)
-endif
-bindir_relative = bin
-bindir = $(abspath $(prefix)/$(bindir_relative))
-mandir = share/man
-infodir = share/info
-perfexecdir = libexec/perf-core
-sharedir = $(prefix)/share
-template_dir = share/perf-core/templates
-STRACE_GROUPS_DIR = share/perf-core/strace/groups
-htmldir = share/doc/perf-doc
-tipdir = share/doc/perf-tip
-srcdir = $(srctree)/tools/perf
-ifeq ($(prefix),/usr)
-sysconfdir = /etc
-ETC_PERFCONFIG = $(sysconfdir)/perfconfig
-else
-sysconfdir = $(prefix)/etc
-ETC_PERFCONFIG = etc/perfconfig
-endif
-ifndef lib
-ifeq ($(ARCH)$(IS_64_BIT), x861)
-lib = lib64
-else
-lib = lib
-endif
-endif # lib
-libdir = $(prefix)/$(lib)
-
-# Shell quote (do not use $(call) to accommodate ancient setups);
-ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
-STRACE_GROUPS_DIR_SQ = $(subst ','\'',$(STRACE_GROUPS_DIR))
-DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
-bindir_SQ = $(subst ','\'',$(bindir))
-mandir_SQ = $(subst ','\'',$(mandir))
-infodir_SQ = $(subst ','\'',$(infodir))
-perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
-template_dir_SQ = $(subst ','\'',$(template_dir))
-htmldir_SQ = $(subst ','\'',$(htmldir))
-tipdir_SQ = $(subst ','\'',$(tipdir))
-prefix_SQ = $(subst ','\'',$(prefix))
-sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
-libdir_SQ = $(subst ','\'',$(libdir))
-srcdir_SQ = $(subst ','\'',$(srcdir))
-
-ifneq ($(filter /%,$(firstword $(perfexecdir))),)
-perfexec_instdir = $(perfexecdir)
-STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
-tip_instdir = $(tipdir)
-else
-perfexec_instdir = $(prefix)/$(perfexecdir)
-STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
-tip_instdir = $(prefix)/$(tipdir)
-endif
-perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
-STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
-tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
-
-# If we install to $(HOME) we keep the traceevent default:
-# $(HOME)/.traceevent/plugins
-# Otherwise we install plugins into the global $(libdir).
-ifdef DESTDIR
-plugindir=$(libdir)/traceevent/plugins
-plugindir_SQ= $(subst ','\'',$(plugindir))
-endif
-
-print_var = $(eval $(print_var_code)) $(info $(MSG))
-define print_var_code
-    MSG = $(shell printf '...%30s: %s' $(1) $($(1)))
-endef
-
-ifeq ($(VF),1)
-  $(call print_var,prefix)
-  $(call print_var,bindir)
-  $(call print_var,libdir)
-  $(call print_var,sysconfdir)
-  $(call print_var,LIBUNWIND_DIR)
-  $(call print_var,LIBDW_DIR)
-
-  ifeq ($(dwarf-post-unwind),1)
-    $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
-  endif
-  $(info )
-endif
-
-$(call detected_var,bindir_SQ)
-$(call detected_var,PYTHON_WORD)
-ifneq ($(OUTPUT),)
-$(call detected_var,OUTPUT)
-endif
-$(call detected_var,htmldir_SQ)
-$(call detected_var,infodir_SQ)
-$(call detected_var,mandir_SQ)
-$(call detected_var,ETC_PERFCONFIG_SQ)
-$(call detected_var,STRACE_GROUPS_DIR_SQ)
-$(call detected_var,prefix_SQ)
-$(call detected_var,perfexecdir_SQ)
-$(call detected_var,tipdir_SQ)
-$(call detected_var,srcdir_SQ)
-$(call detected_var,LIBDIR)
-$(call detected_var,GTK_CFLAGS)
-$(call detected_var,PERL_EMBED_CCOPTS)
-$(call detected_var,PYTHON_EMBED_CCOPTS)
index a7e0f14..cb0f135 100644 (file)
@@ -52,6 +52,7 @@ struct record_opts {
        bool         sample_weight;
        bool         sample_time;
        bool         sample_time_set;
+       bool         sample_cpu;
        bool         period;
        bool         running_time;
        bool         full_auxtrace;
index 928e110..34faecf 100644 (file)
@@ -1,3 +1,5 @@
 libperf-y += Context.o
 
-CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default
+CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes
+CFLAGS_Context.o += -Wno-unused-parameter -Wno-nested-externs -Wno-undef
+CFLAGS_Context.o += -Wno-switch-default -Wno-shadow
index cb20ae1..dc51bc5 100644 (file)
@@ -41,6 +41,7 @@ perf-y += event-times.o
 perf-y += backward-ring-buffer.o
 perf-y += sdt.o
 perf-y += is_printable_array.o
+perf-y += bitmap.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
        $(call rule_mkdir)
diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c
new file mode 100644 (file)
index 0000000..9abe6c1
--- /dev/null
@@ -0,0 +1,53 @@
+#include <linux/compiler.h>
+#include <linux/bitmap.h>
+#include "tests.h"
+#include "cpumap.h"
+#include "debug.h"
+
+#define NBITS 100
+
+static unsigned long *get_bitmap(const char *str, int nbits)
+{
+       struct cpu_map *map = cpu_map__new(str);
+       unsigned long *bm = NULL;
+       int i;
+
+       bm = bitmap_alloc(nbits);
+
+       if (map && bm) {
+               bitmap_zero(bm, nbits);
+
+               for (i = 0; i < map->nr; i++)
+                       set_bit(map->map[i], bm);
+       }
+
+       if (map)
+               cpu_map__put(map);
+       return bm;
+}
+
+static int test_bitmap(const char *str)
+{
+       unsigned long *bm = get_bitmap(str, NBITS);
+       char buf[100];
+       int ret;
+
+       bitmap_scnprintf(bm, NBITS, buf, sizeof(buf));
+       pr_debug("bitmap: %s\n", buf);
+
+       ret = !strcmp(buf, str);
+       free(bm);
+       return ret;
+}
+
+int test__bitmap_print(int subtest __maybe_unused)
+{
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1,5"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1,3,5,7,9,11,13,15,17,19,21-40"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("2-5"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1,3-6,8-10,24,35-37"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1,3-6,8-10,24,35-37"));
+       TEST_ASSERT_VAL("failed to convert map", test_bitmap("1-10,12-20,22-30,32-40"));
+       return 0;
+}
index e53bc91..268e5f8 100644 (file)
@@ -31,8 +31,8 @@ struct bpf_map_def SEC("maps") flip_table = {
        .max_entries = 1,
 };
 
-SEC("func=sys_epoll_wait")
-int bpf_func__sys_epoll_wait(void *ctx)
+SEC("func=SyS_epoll_wait")
+int bpf_func__SyS_epoll_wait(void *ctx)
 {
        int ind =0;
        int *flag = bpf_map_lookup_elem(&flip_table, &ind);
index 10eb306..778668a 100644 (file)
@@ -225,6 +225,10 @@ static struct test generic_tests[] = {
                .desc = "Test is_printable_array function",
                .func = test__is_printable_array,
        },
+       {
+               .desc = "Test bitmap print",
+               .func = test__bitmap_print,
+       },
        {
                .func = NULL,
        },
index 68a69a1..2af156a 100644 (file)
@@ -33,44 +33,86 @@ static unsigned int hex(char c)
        return c - 'A' + 10;
 }
 
-static size_t read_objdump_line(const char *line, size_t line_len, void *buf,
-                             size_t len)
+static size_t read_objdump_chunk(const char **line, unsigned char **buf,
+                                size_t *buf_len)
 {
-       const char *p;
-       size_t i, j = 0;
-
-       /* Skip to a colon */
-       p = strchr(line, ':');
-       if (!p)
-               return 0;
-       i = p + 1 - line;
+       size_t bytes_read = 0;
+       unsigned char *chunk_start = *buf;
 
        /* Read bytes */
-       while (j < len) {
+       while (*buf_len > 0) {
                char c1, c2;
 
-               /* Skip spaces */
-               for (; i < line_len; i++) {
-                       if (!isspace(line[i]))
-                               break;
-               }
                /* Get 2 hex digits */
-               if (i >= line_len || !isxdigit(line[i]))
+               c1 = *(*line)++;
+               if (!isxdigit(c1))
                        break;
-               c1 = line[i++];
-               if (i >= line_len || !isxdigit(line[i]))
+               c2 = *(*line)++;
+               if (!isxdigit(c2))
                        break;
-               c2 = line[i++];
-               /* Followed by a space */
-               if (i < line_len && line[i] && !isspace(line[i]))
+
+               /* Store byte and advance buf */
+               **buf = (hex(c1) << 4) | hex(c2);
+               (*buf)++;
+               (*buf_len)--;
+               bytes_read++;
+
+               /* End of chunk? */
+               if (isspace(**line))
                        break;
-               /* Store byte */
-               *(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
-               buf += 1;
-               j++;
        }
+
+       /*
+        * objdump will display raw insn as LE if code endian
+        * is LE and bytes_per_chunk > 1. In that case reverse
+        * the chunk we just read.
+        *
+        * see disassemble_bytes() at binutils/objdump.c for details
+        * how objdump chooses display endian)
+        */
+       if (bytes_read > 1 && !bigendian()) {
+               unsigned char *chunk_end = chunk_start + bytes_read - 1;
+               unsigned char tmp;
+
+               while (chunk_start < chunk_end) {
+                       tmp = *chunk_start;
+                       *chunk_start = *chunk_end;
+                       *chunk_end = tmp;
+                       chunk_start++;
+                       chunk_end--;
+               }
+       }
+
+       return bytes_read;
+}
+
+static size_t read_objdump_line(const char *line, unsigned char *buf,
+                               size_t buf_len)
+{
+       const char *p;
+       size_t ret, bytes_read = 0;
+
+       /* Skip to a colon */
+       p = strchr(line, ':');
+       if (!p)
+               return 0;
+       p++;
+
+       /* Skip initial spaces */
+       while (*p) {
+               if (!isspace(*p))
+                       break;
+               p++;
+       }
+
+       do {
+               ret = read_objdump_chunk(&p, &buf, &buf_len);
+               bytes_read += ret;
+               p++;
+       } while (ret > 0);
+
        /* return number of successfully read bytes */
-       return j;
+       return bytes_read;
 }
 
 static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
@@ -95,7 +137,7 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
                }
 
                /* read objdump data into temporary buffer */
-               read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp));
+               read_bytes = read_objdump_line(line, tmp, sizeof(tmp));
                if (!read_bytes)
                        continue;
 
@@ -152,7 +194,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
 
        ret = read_objdump_output(f, buf, &len, addr);
        if (len) {
-               pr_debug("objdump read too few bytes\n");
+               pr_debug("objdump read too few bytes: %zd\n", len);
                if (!ret)
                        ret = len;
        }
index 9bfc0e0..7c196c5 100644 (file)
@@ -90,6 +90,7 @@ int test__backward_ring_buffer(int subtest);
 int test__cpu_map_print(int subtest);
 int test__sdt_event(int subtest);
 int test__is_printable_array(int subtest);
+int test__bitmap_print(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
index 29dc6d2..2e2d100 100644 (file)
@@ -1026,7 +1026,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
                        .use_navkeypressed = true,
                },
        };
-       int ret = -1;
+       int ret = -1, err;
        int nr_pcnt = 1;
        size_t sizeof_bdl = sizeof(struct browser_disasm_line);
 
@@ -1050,8 +1050,11 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
                  (nr_pcnt - 1);
        }
 
-       if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
-               ui__error("%s", ui_helpline__last_msg);
+       err = symbol__disassemble(sym, map, sizeof_bdl);
+       if (err) {
+               char msg[BUFSIZ];
+               symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
+               ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
                goto out_free_offsets;
        }
 
index 9c7ff8d..42d3199 100644 (file)
@@ -162,12 +162,16 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
        GtkWidget *notebook;
        GtkWidget *scrolled_window;
        GtkWidget *tab_label;
+       int err;
 
        if (map->dso->annotate_warned)
                return -1;
 
-       if (symbol__annotate(sym, map, 0) < 0) {
-               ui__error("%s", ui_helpline__current);
+       err = symbol__disassemble(sym, map, 0);
+       if (err) {
+               char msg[BUFSIZ];
+               symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
+               ui__error("Couldn't annotate %s: %s\n", sym->name, msg);
                return -1;
        }
 
index e9825fe..4024d30 100644 (file)
@@ -1123,7 +1123,46 @@ static void delete_last_nop(struct symbol *sym)
        }
 }
 
-int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
+int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
+                             int errnum, char *buf, size_t buflen)
+{
+       struct dso *dso = map->dso;
+
+       BUG_ON(buflen == 0);
+
+       if (errnum >= 0) {
+               str_error_r(errnum, buf, buflen);
+               return 0;
+       }
+
+       switch (errnum) {
+       case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
+               char bf[SBUILD_ID_SIZE + 15] = " with build id ";
+               char *build_id_msg = NULL;
+
+               if (dso->has_build_id) {
+                       build_id__sprintf(dso->build_id,
+                                         sizeof(dso->build_id), bf + 15);
+                       build_id_msg = bf;
+               }
+               scnprintf(buf, buflen,
+                         "No vmlinux file%s\nwas found in the path.\n\n"
+                         "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
+                         "Please use:\n\n"
+                         "  perf buildid-cache -vu vmlinux\n\n"
+                         "or:\n\n"
+                         "  --vmlinux vmlinux\n", build_id_msg ?: "");
+       }
+               break;
+       default:
+               scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
+               break;
+       }
+
+       return 0;
+}
+
+int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
 {
        struct dso *dso = map->dso;
        char *filename = dso__build_id_filename(dso, NULL, 0);
@@ -1134,22 +1173,20 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
        char symfs_filename[PATH_MAX];
        struct kcore_extract kce;
        bool delete_extract = false;
+       int stdout_fd[2];
        int lineno = 0;
        int nline;
+       pid_t pid;
 
        if (filename)
                symbol__join_symfs(symfs_filename, filename);
 
        if (filename == NULL) {
-               if (dso->has_build_id) {
-                       pr_err("Can't annotate %s: not enough memory\n",
-                              sym->name);
-                       return -ENOMEM;
-               }
+               if (dso->has_build_id)
+                       return ENOMEM;
                goto fallback;
-       } else if (dso__is_kcore(dso)) {
-               goto fallback;
-       } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
+       } else if (dso__is_kcore(dso) ||
+                  readlink(symfs_filename, command, sizeof(command)) < 0 ||
                   strstr(command, DSO__NAME_KALLSYMS) ||
                   access(symfs_filename, R_OK)) {
                free(filename);
@@ -1166,27 +1203,7 @@ fallback:
 
        if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
            !dso__is_kcore(dso)) {
-               char bf[SBUILD_ID_SIZE + 15] = " with build id ";
-               char *build_id_msg = NULL;
-
-               if (dso->annotate_warned)
-                       goto out_free_filename;
-
-               if (dso->has_build_id) {
-                       build_id__sprintf(dso->build_id,
-                                         sizeof(dso->build_id), bf + 15);
-                       build_id_msg = bf;
-               }
-               err = -ENOENT;
-               dso->annotate_warned = 1;
-               pr_err("Can't annotate %s:\n\n"
-                      "No vmlinux file%s\nwas found in the path.\n\n"
-                      "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
-                      "Please use:\n\n"
-                      "  perf buildid-cache -vu vmlinux\n\n"
-                      "or:\n\n"
-                      "  --vmlinux vmlinux\n",
-                      sym->name, build_id_msg ?: "");
+               err = SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
                goto out_free_filename;
        }
 
@@ -1258,9 +1275,32 @@ fallback:
 
        pr_debug("Executing: %s\n", command);
 
-       file = popen(command, "r");
+       err = -1;
+       if (pipe(stdout_fd) < 0) {
+               pr_err("Failure creating the pipe to run %s\n", command);
+               goto out_remove_tmp;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               pr_err("Failure forking to run %s\n", command);
+               goto out_close_stdout;
+       }
+
+       if (pid == 0) {
+               close(stdout_fd[0]);
+               dup2(stdout_fd[1], 1);
+               close(stdout_fd[1]);
+               execl("/bin/sh", "sh", "-c", command, NULL);
+               perror(command);
+               exit(-1);
+       }
+
+       close(stdout_fd[1]);
+
+       file = fdopen(stdout_fd[0], "r");
        if (!file) {
-               pr_err("Failure running %s\n", command);
+               pr_err("Failure creating FILE stream for %s\n", command);
                /*
                 * If we were using debug info should retry with
                 * original binary.
@@ -1286,9 +1326,11 @@ fallback:
        if (dso__is_kcore(dso))
                delete_last_nop(sym);
 
-       pclose(file);
-
+       fclose(file);
+       err = 0;
 out_remove_tmp:
+       close(stdout_fd[0]);
+
        if (dso__needs_decompress(dso))
                unlink(symfs_filename);
 out_free_filename:
@@ -1297,6 +1339,10 @@ out_free_filename:
        if (free_filename)
                free(filename);
        return err;
+
+out_close_stdout:
+       close(stdout_fd[1]);
+       goto out_remove_tmp;
 }
 
 static void insert_source_line(struct rb_root *root, struct source_line *src_line)
@@ -1663,7 +1709,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
        struct rb_root source_line = RB_ROOT;
        u64 len;
 
-       if (symbol__annotate(sym, map, 0) < 0)
+       if (symbol__disassemble(sym, map, 0) < 0)
                return -1;
 
        len = symbol__size(sym);
index a23084f..f67ccb0 100644 (file)
@@ -155,7 +155,27 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
 int symbol__alloc_hist(struct symbol *sym);
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
-int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
+int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize);
+
+enum symbol_disassemble_errno {
+       SYMBOL_ANNOTATE_ERRNO__SUCCESS          = 0,
+
+       /*
+        * Choose an arbitrary negative big number not to clash with standard
+        * errno since SUS requires the errno has distinct positive values.
+        * See 'Issue 6' in the link below.
+        *
+        * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+        */
+       __SYMBOL_ANNOTATE_ERRNO__START          = -10000,
+
+       SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX       = __SYMBOL_ANNOTATE_ERRNO__START,
+
+       __SYMBOL_ANNOTATE_ERRNO__END,
+};
+
+int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
+                                int errnum, char *buf, size_t buflen);
 
 int symbol__annotate_init(struct map *map, struct symbol *sym);
 int symbol__annotate_printf(struct symbol *sym, struct map *map,
index 2a40b8e..097b3ed 100644 (file)
@@ -239,31 +239,13 @@ void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr)
 
 int perf_evlist__add_default(struct perf_evlist *evlist)
 {
-       struct perf_event_attr attr = {
-               .type = PERF_TYPE_HARDWARE,
-               .config = PERF_COUNT_HW_CPU_CYCLES,
-       };
-       struct perf_evsel *evsel;
-
-       event_attr_init(&attr);
+       struct perf_evsel *evsel = perf_evsel__new_cycles();
 
-       perf_event_attr__set_max_precise_ip(&attr);
-
-       evsel = perf_evsel__new(&attr);
        if (evsel == NULL)
-               goto error;
-
-       /* use asprintf() because free(evsel) assumes name is allocated */
-       if (asprintf(&evsel->name, "cycles%.*s",
-                    attr.precise_ip ? attr.precise_ip + 1 : 0, ":ppp") < 0)
-               goto error_free;
+               return -ENOMEM;
 
        perf_evlist__add(evlist, evsel);
        return 0;
-error_free:
-       perf_evsel__delete(evsel);
-error:
-       return -ENOMEM;
 }
 
 int perf_evlist__add_dummy(struct perf_evlist *evlist)
index 8c54df6..d9b80ef 100644 (file)
@@ -253,6 +253,34 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
        return evsel;
 }
 
+struct perf_evsel *perf_evsel__new_cycles(void)
+{
+       struct perf_event_attr attr = {
+               .type   = PERF_TYPE_HARDWARE,
+               .config = PERF_COUNT_HW_CPU_CYCLES,
+       };
+       struct perf_evsel *evsel;
+
+       event_attr_init(&attr);
+
+       perf_event_attr__set_max_precise_ip(&attr);
+
+       evsel = perf_evsel__new(&attr);
+       if (evsel == NULL)
+               goto out;
+
+       /* use asprintf() because free(evsel) assumes name is allocated */
+       if (asprintf(&evsel->name, "cycles%.*s",
+                    attr.precise_ip ? attr.precise_ip + 1 : 0, ":ppp") < 0)
+               goto error_free;
+out:
+       return evsel;
+error_free:
+       perf_evsel__delete(evsel);
+       evsel = NULL;
+       goto out;
+}
+
 /*
  * Returns pointer with encoded error via <linux/err.h> interface.
  */
@@ -854,7 +882,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
                perf_evsel__set_sample_bit(evsel, REGS_INTR);
        }
 
-       if (target__has_cpu(&opts->target))
+       if (target__has_cpu(&opts->target) || opts->sample_cpu)
                perf_evsel__set_sample_bit(evsel, CPU);
 
        if (opts->period)
index 8a4a6c9..4d44129 100644 (file)
@@ -175,6 +175,8 @@ static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *
        return perf_evsel__newtp_idx(sys, name, 0);
 }
 
+struct perf_evsel *perf_evsel__new_cycles(void);
+
 struct event_format *event_format__new(const char *sys, const char *name);
 
 void perf_evsel__init(struct perf_evsel *evsel,
index a18d142..de15dbc 100644 (file)
@@ -1672,7 +1672,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
 }
 
 static void output_resort(struct hists *hists, struct ui_progress *prog,
-                         bool use_callchain)
+                         bool use_callchain, hists__resort_cb_t cb)
 {
        struct rb_root *root;
        struct rb_node *next;
@@ -1711,6 +1711,9 @@ static void output_resort(struct hists *hists, struct ui_progress *prog,
                n = rb_entry(next, struct hist_entry, rb_node_in);
                next = rb_next(&n->rb_node_in);
 
+               if (cb && cb(n))
+                       continue;
+
                __hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
                hists__inc_stats(hists, n);
 
@@ -1731,12 +1734,18 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro
        else
                use_callchain = symbol_conf.use_callchain;
 
-       output_resort(evsel__hists(evsel), prog, use_callchain);
+       output_resort(evsel__hists(evsel), prog, use_callchain, NULL);
 }
 
 void hists__output_resort(struct hists *hists, struct ui_progress *prog)
 {
-       output_resort(hists, prog, symbol_conf.use_callchain);
+       output_resort(hists, prog, symbol_conf.use_callchain, NULL);
+}
+
+void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
+                            hists__resort_cb_t cb)
+{
+       output_resort(hists, prog, symbol_conf.use_callchain, cb);
 }
 
 static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
index 49aa4fa..0a1edf1 100644 (file)
@@ -153,8 +153,12 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
                                   struct perf_hpp_fmt *fmt, int printed);
 void hist_entry__delete(struct hist_entry *he);
 
+typedef int (*hists__resort_cb_t)(struct hist_entry *he);
+
 void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
 void hists__output_resort(struct hists *hists, struct ui_progress *prog);
+void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
+                            hists__resort_cb_t cb);
 int hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
index 8cdcf46..21c4d9b 100644 (file)
@@ -122,11 +122,7 @@ int target__strerror(struct target *target, int errnum,
        BUG_ON(buflen == 0);
 
        if (errnum >= 0) {
-               const char *err = str_error_r(errnum, buf, buflen);
-
-               if (err != buf)
-                       scnprintf(buf, buflen, "%s", err);
-
+               str_error_r(errnum, buf, buflen);
                return 0;
        }
 
index 0e37f7a..5201b91 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _GFP_H
 #define _GFP_H
 
-#define __GFP_BITS_SHIFT 22
+#define __GFP_BITS_SHIFT 26
 #define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 #define __GFP_WAIT 1
 #define __GFP_ACCOUNT 0
diff --git a/tools/testing/selftests/ntb/ntb_test.sh b/tools/testing/selftests/ntb/ntb_test.sh
new file mode 100755 (executable)
index 0000000..a676d3e
--- /dev/null
@@ -0,0 +1,422 @@
+#!/bin/bash
+# Copyright (c) 2016 Microsemi. 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.
+#
+# 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.  See the
+# GNU General Public License for more details.
+#
+# Author: Logan Gunthorpe <logang@deltatee.com>
+
+REMOTE_HOST=
+LIST_DEVS=FALSE
+
+DEBUGFS=${DEBUGFS-/sys/kernel/debug}
+
+PERF_RUN_ORDER=32
+MAX_MW_SIZE=0
+RUN_DMA_TESTS=
+DONT_CLEANUP=
+MW_SIZE=65536
+
+function show_help()
+{
+       echo "Usage: $0 [OPTIONS] LOCAL_DEV REMOTE_DEV"
+       echo "Run tests on a pair of NTB endpoints."
+       echo
+       echo "If the NTB device loops back to the same host then,"
+       echo "just specifying the two PCI ids on the command line is"
+       echo "sufficient. Otherwise, if the NTB link spans two hosts"
+       echo "use the -r option to specify the hostname for the remote"
+       echo "device. SSH will then be used to test the remote side."
+       echo "An SSH key between the root users of the host would then"
+       echo "be highly recommended."
+       echo
+       echo "Options:"
+       echo "  -C              don't cleanup ntb modules on exit"
+       echo "  -d              run dma tests"
+       echo "  -h              show this help message"
+       echo "  -l              list available local and remote PCI ids"
+       echo "  -r REMOTE_HOST  specify the remote's hostname to connect"
+        echo "                  to for the test (using ssh)"
+       echo "  -p NUM          ntb_perf run order (default: $PERF_RUN_ORDER)"
+       echo "  -w max_mw_size  maxmium memory window size"
+       echo
+}
+
+function parse_args()
+{
+       OPTIND=0
+       while getopts "Cdhlm:r:p:w:" opt; do
+               case "$opt" in
+               C)  DONT_CLEANUP=1 ;;
+               d)  RUN_DMA_TESTS=1 ;;
+               h)  show_help; exit 0 ;;
+               l)  LIST_DEVS=TRUE ;;
+               m)  MW_SIZE=${OPTARG} ;;
+               r)  REMOTE_HOST=${OPTARG} ;;
+               p)  PERF_RUN_ORDER=${OPTARG} ;;
+               w)  MAX_MW_SIZE=${OPTARG} ;;
+               \?)
+                   echo "Invalid option: -$OPTARG" >&2
+                   exit 1
+                   ;;
+               esac
+       done
+}
+
+parse_args "$@"
+shift $((OPTIND-1))
+LOCAL_DEV=$1
+shift
+parse_args "$@"
+shift $((OPTIND-1))
+REMOTE_DEV=$1
+shift
+parse_args "$@"
+
+set -e
+
+function _modprobe()
+{
+        modprobe "$@"
+}
+
+function split_remote()
+{
+       VPATH=$1
+       REMOTE=
+
+       if [[ "$VPATH" == *":/"* ]]; then
+               REMOTE=${VPATH%%:*}
+               VPATH=${VPATH#*:}
+       fi
+}
+
+function read_file()
+{
+       split_remote $1
+       if [[ "$REMOTE" != "" ]]; then
+               ssh "$REMOTE" cat "$VPATH"
+       else
+               cat "$VPATH"
+       fi
+}
+
+function write_file()
+{
+       split_remote $2
+       VALUE=$1
+
+       if [[ "$REMOTE" != "" ]]; then
+               ssh "$REMOTE" "echo \"$VALUE\" > \"$VPATH\""
+       else
+               echo "$VALUE" > "$VPATH"
+       fi
+}
+
+function link_test()
+{
+       LOC=$1
+       REM=$2
+       EXP=0
+
+       echo "Running link tests on: $(basename $LOC) / $(basename $REM)"
+
+       if ! write_file "N" "$LOC/link" 2> /dev/null; then
+               echo "  Unsupported"
+               return
+       fi
+
+       write_file "N" "$LOC/link_event"
+
+       if [[ $(read_file "$REM/link") != "N" ]]; then
+               echo "Expected remote link to be down in $REM/link" >&2
+               exit -1
+       fi
+
+       write_file "Y" "$LOC/link"
+       write_file "Y" "$LOC/link_event"
+
+       echo "  Passed"
+}
+
+function doorbell_test()
+{
+       LOC=$1
+       REM=$2
+       EXP=0
+
+       echo "Running db tests on: $(basename $LOC) / $(basename $REM)"
+
+       write_file "c 0xFFFFFFFF" "$REM/db"
+
+       for ((i=1; i <= 8; i++)); do
+               let DB=$(read_file "$REM/db") || true
+               if [[ "$DB" != "$EXP" ]]; then
+                       echo "Doorbell doesn't match expected value $EXP " \
+                            "in $REM/db" >&2
+                       exit -1
+               fi
+
+               let "MASK=1 << ($i-1)" || true
+               let "EXP=$EXP | $MASK" || true
+               write_file "s $MASK" "$LOC/peer_db"
+       done
+
+       echo "  Passed"
+}
+
+function read_spad()
+{
+       VPATH=$1
+       IDX=$2
+
+       ROW=($(read_file "$VPATH" | grep -e "^$IDX"))
+       let VAL=${ROW[1]} || true
+       echo $VAL
+}
+
+function scratchpad_test()
+{
+       LOC=$1
+       REM=$2
+       CNT=$(read_file "$LOC/spad" | wc -l)
+
+       echo "Running spad tests on: $(basename $LOC) / $(basename $REM)"
+
+       for ((i = 0; i < $CNT; i++)); do
+               VAL=$RANDOM
+               write_file "$i $VAL" "$LOC/peer_spad"
+               RVAL=$(read_spad "$REM/spad" $i)
+
+               if [[ "$VAL" != "$RVAL" ]]; then
+                       echo "Scratchpad doesn't match expected value $VAL " \
+                            "in $REM/spad, got $RVAL" >&2
+                       exit -1
+               fi
+
+       done
+
+       echo "  Passed"
+}
+
+function write_mw()
+{
+       split_remote $2
+
+       if [[ "$REMOTE" != "" ]]; then
+               ssh "$REMOTE" \
+                       dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
+       else
+               dd if=/dev/urandom "of=$VPATH" 2> /dev/null || true
+       fi
+}
+
+function mw_test()
+{
+       IDX=$1
+       LOC=$2
+       REM=$3
+
+       echo "Running $IDX tests on: $(basename $LOC) / $(basename $REM)"
+
+       write_mw "$LOC/$IDX"
+
+       split_remote "$LOC/$IDX"
+       if [[ "$REMOTE" == "" ]]; then
+               A=$VPATH
+       else
+               A=/tmp/ntb_test.$$.A
+               ssh "$REMOTE" cat "$VPATH" > "$A"
+       fi
+
+       split_remote "$REM/peer_$IDX"
+       if [[ "$REMOTE" == "" ]]; then
+               B=$VPATH
+       else
+               B=/tmp/ntb_test.$$.B
+               ssh "$REMOTE" cat "$VPATH" > "$B"
+       fi
+
+       cmp -n $MW_SIZE "$A" "$B"
+       if [[ $? != 0 ]]; then
+               echo "Memory window $MW did not match!" >&2
+       fi
+
+       if [[ "$A" == "/tmp/*" ]]; then
+               rm "$A"
+       fi
+
+       if [[ "$B" == "/tmp/*" ]]; then
+               rm "$B"
+       fi
+
+       echo "  Passed"
+}
+
+function pingpong_test()
+{
+       LOC=$1
+       REM=$2
+
+       echo "Running ping pong tests on: $(basename $LOC) / $(basename $REM)"
+
+       LOC_START=$(read_file $LOC/count)
+       REM_START=$(read_file $REM/count)
+
+       sleep 7
+
+       LOC_END=$(read_file $LOC/count)
+       REM_END=$(read_file $REM/count)
+
+       if [[ $LOC_START == $LOC_END ]] || [[ $REM_START == $REM_END ]]; then
+               echo "Ping pong counter not incrementing!" >&2
+               exit 1
+       fi
+
+       echo "  Passed"
+}
+
+function perf_test()
+{
+       USE_DMA=$1
+
+       if [[ $USE_DMA == "1" ]]; then
+               WITH="with"
+       else
+               WITH="without"
+       fi
+
+       _modprobe ntb_perf run_order=$PERF_RUN_ORDER \
+               max_mw_size=$MAX_MW_SIZE use_dma=$USE_DMA
+
+       echo "Running local perf test $WITH DMA"
+       write_file "" $LOCAL_PERF/run
+       echo -n "  "
+       read_file $LOCAL_PERF/run
+       echo "  Passed"
+
+       echo "Running remote perf test $WITH DMA"
+       write_file "" $REMOTE_PERF/run
+       echo -n "  "
+       read_file $LOCAL_PERF/run
+       echo "  Passed"
+
+       _modprobe -r ntb_perf
+}
+
+function ntb_tool_tests()
+{
+       LOCAL_TOOL=$DEBUGFS/ntb_tool/$LOCAL_DEV
+       REMOTE_TOOL=$REMOTE_HOST:$DEBUGFS/ntb_tool/$REMOTE_DEV
+
+       echo "Starting ntb_tool tests..."
+
+       _modprobe ntb_tool
+
+       write_file Y $LOCAL_TOOL/link_event
+       write_file Y $REMOTE_TOOL/link_event
+
+       link_test $LOCAL_TOOL $REMOTE_TOOL
+       link_test $REMOTE_TOOL $LOCAL_TOOL
+
+       for PEER_TRANS in $(ls $LOCAL_TOOL/peer_trans*); do
+               PT=$(basename $PEER_TRANS)
+               write_file $MW_SIZE $LOCAL_TOOL/$PT
+               write_file $MW_SIZE $REMOTE_TOOL/$PT
+       done
+
+       doorbell_test $LOCAL_TOOL $REMOTE_TOOL
+       doorbell_test $REMOTE_TOOL $LOCAL_TOOL
+       scratchpad_test $LOCAL_TOOL $REMOTE_TOOL
+       scratchpad_test $REMOTE_TOOL $LOCAL_TOOL
+
+       for MW in $(ls $LOCAL_TOOL/mw*); do
+               MW=$(basename $MW)
+
+               mw_test $MW $LOCAL_TOOL $REMOTE_TOOL
+               mw_test $MW $REMOTE_TOOL $LOCAL_TOOL
+       done
+
+       _modprobe -r ntb_tool
+}
+
+function ntb_pingpong_tests()
+{
+       LOCAL_PP=$DEBUGFS/ntb_pingpong/$LOCAL_DEV
+       REMOTE_PP=$REMOTE_HOST:$DEBUGFS/ntb_pingpong/$REMOTE_DEV
+
+       echo "Starting ntb_pingpong tests..."
+
+       _modprobe ntb_pingpong
+
+       pingpong_test $LOCAL_PP $REMOTE_PP
+
+       _modprobe -r ntb_pingpong
+}
+
+function ntb_perf_tests()
+{
+       LOCAL_PERF=$DEBUGFS/ntb_perf/$LOCAL_DEV
+       REMOTE_PERF=$REMOTE_HOST:$DEBUGFS/ntb_perf/$REMOTE_DEV
+
+       echo "Starting ntb_perf tests..."
+
+       perf_test 0
+
+       if [[ $RUN_DMA_TESTS ]]; then
+               perf_test 1
+       fi
+}
+
+function cleanup()
+{
+       set +e
+       _modprobe -r ntb_tool 2> /dev/null
+       _modprobe -r ntb_perf 2> /dev/null
+       _modprobe -r ntb_pingpong 2> /dev/null
+       _modprobe -r ntb_transport 2> /dev/null
+       set -e
+}
+
+cleanup
+
+if ! [[ $$DONT_CLEANUP ]]; then
+       trap cleanup EXIT
+fi
+
+if [ "$(id -u)" != "0" ]; then
+       echo "This script must be run as root" 1>&2
+       exit 1
+fi
+
+if [[ "$LIST_DEVS" == TRUE ]]; then
+       echo "Local Devices:"
+       ls -1 /sys/bus/ntb/devices
+       echo
+
+       if [[ "$REMOTE_HOST" != "" ]]; then
+               echo "Remote Devices:"
+               ssh $REMOTE_HOST ls -1 /sys/bus/ntb/devices
+       fi
+
+       exit 0
+fi
+
+if [[ "$LOCAL_DEV" == $"" ]] || [[ "$REMOTE_DEV" == $"" ]]; then
+       show_help
+       exit 1
+fi
+
+ntb_tool_tests
+echo
+ntb_pingpong_tests
+echo
+ntb_perf_tests
+echo
index 624bce5..4230d30 100644 (file)
@@ -144,11 +144,12 @@ test_READ:
 
        retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
        if (retval == -1) {
-               if (errno == ENOTTY) {
+               if (errno == EINVAL) {
                        fprintf(stderr,
                                "\n...Alarm IRQs not supported.\n");
                        goto test_PIE;
                }
+
                perror("RTC_ALM_SET ioctl");
                exit(errno);
        }
@@ -166,6 +167,12 @@ test_READ:
        /* Enable alarm interrupts */
        retval = ioctl(fd, RTC_AIE_ON, 0);
        if (retval == -1) {
+               if (errno == EINVAL) {
+                       fprintf(stderr,
+                               "\n...Alarm IRQs not supported.\n");
+                       goto test_PIE;
+               }
+
                perror("RTC_AIE_ON ioctl");
                exit(errno);
        }
@@ -193,7 +200,7 @@ test_PIE:
        retval = ioctl(fd, RTC_IRQP_READ, &tmp);
        if (retval == -1) {
                /* not all RTCs support periodic IRQs */
-               if (errno == ENOTTY) {
+               if (errno == EINVAL) {
                        fprintf(stderr, "\nNo periodic IRQ support\n");
                        goto done;
                }
@@ -211,7 +218,7 @@ test_PIE:
                retval = ioctl(fd, RTC_IRQP_SET, tmp);
                if (retval == -1) {
                        /* not all RTCs can change their periodic IRQ rate */
-                       if (errno == ENOTTY) {
+                       if (errno == EINVAL) {
                                fprintf(stderr,
                                        "\n...Periodic IRQ rate is fixed\n");
                                goto done;
index e5d6108..b0cc1a3 100644 (file)
@@ -16,9 +16,6 @@ config HAVE_KVM_EVENTFD
        bool
        select EVENTFD
 
-config KVM_APIC_ARCHITECTURE
-       bool
-
 config KVM_MMIO
        bool
 
index 3a3a699..7cffd93 100644 (file)
 
 #include <asm/kvm_hyp.h>
 
-#ifdef CONFIG_KVM_NEW_VGIC
-extern struct vgic_global kvm_vgic_global_state;
-#define vgic_v2_params kvm_vgic_global_state
-#else
-extern struct vgic_params vgic_v2_params;
-#endif
-
 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
                                            void __iomem *base)
 {
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+       int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
        u32 eisr0, eisr1;
        int i;
        bool expect_mi;
@@ -74,7 +67,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 {
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+       int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
        u32 elrsr0, elrsr1;
 
        elrsr0 = readl_relaxed(base + GICH_ELRSR0);
@@ -93,7 +86,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
 {
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-       int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+       int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
        int i;
 
        for (i = 0; i < nr_lr; i++) {
@@ -147,7 +140,7 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
        struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
        struct vgic_dist *vgic = &kvm->arch.vgic;
        void __iomem *base = kern_hyp_va(vgic->vctrl_base);
-       int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+       int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
        int i;
        u64 live_lrs = 0;
 
diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
deleted file mode 100644 (file)
index 1b0bee0..0000000
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Contains GICv2 specific emulation code, was in vgic.c before.
- *
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/cpu.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include <linux/irqchip/arm-gic.h>
-
-#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-
-#include "vgic.h"
-
-#define GICC_ARCH_VERSION_V2           0x2
-
-static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg);
-static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi)
-{
-       return dist->irq_sgi_sources + vcpu_id * VGIC_NR_SGIS + sgi;
-}
-
-static bool handle_mmio_misc(struct kvm_vcpu *vcpu,
-                            struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg;
-       u32 word_offset = offset & 3;
-
-       switch (offset & ~3) {
-       case 0:                 /* GICD_CTLR */
-               reg = vcpu->kvm->arch.vgic.enabled;
-               vgic_reg_access(mmio, &reg, word_offset,
-                               ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-               if (mmio->is_write) {
-                       vcpu->kvm->arch.vgic.enabled = reg & 1;
-                       vgic_update_state(vcpu->kvm);
-                       return true;
-               }
-               break;
-
-       case 4:                 /* GICD_TYPER */
-               reg  = (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
-               reg |= (vcpu->kvm->arch.vgic.nr_irqs >> 5) - 1;
-               vgic_reg_access(mmio, &reg, word_offset,
-                               ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-               break;
-
-       case 8:                 /* GICD_IIDR */
-               reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
-               vgic_reg_access(mmio, &reg, word_offset,
-                               ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-               break;
-       }
-
-       return false;
-}
-
-static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu,
-                                      struct kvm_exit_mmio *mmio,
-                                      phys_addr_t offset)
-{
-       return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                     vcpu->vcpu_id, ACCESS_WRITE_SETBIT);
-}
-
-static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu,
-                                        struct kvm_exit_mmio *mmio,
-                                        phys_addr_t offset)
-{
-       return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                     vcpu->vcpu_id, ACCESS_WRITE_CLEARBIT);
-}
-
-static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu,
-                                       struct kvm_exit_mmio *mmio,
-                                       phys_addr_t offset)
-{
-       return vgic_handle_set_pending_reg(vcpu->kvm, mmio, offset,
-                                          vcpu->vcpu_id);
-}
-
-static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu,
-                                         struct kvm_exit_mmio *mmio,
-                                         phys_addr_t offset)
-{
-       return vgic_handle_clear_pending_reg(vcpu->kvm, mmio, offset,
-                                            vcpu->vcpu_id);
-}
-
-static bool handle_mmio_set_active_reg(struct kvm_vcpu *vcpu,
-                                      struct kvm_exit_mmio *mmio,
-                                      phys_addr_t offset)
-{
-       return vgic_handle_set_active_reg(vcpu->kvm, mmio, offset,
-                                         vcpu->vcpu_id);
-}
-
-static bool handle_mmio_clear_active_reg(struct kvm_vcpu *vcpu,
-                                        struct kvm_exit_mmio *mmio,
-                                        phys_addr_t offset)
-{
-       return vgic_handle_clear_active_reg(vcpu->kvm, mmio, offset,
-                                           vcpu->vcpu_id);
-}
-
-static bool handle_mmio_priority_reg(struct kvm_vcpu *vcpu,
-                                    struct kvm_exit_mmio *mmio,
-                                    phys_addr_t offset)
-{
-       u32 *reg = vgic_bytemap_get_reg(&vcpu->kvm->arch.vgic.irq_priority,
-                                       vcpu->vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       return false;
-}
-
-#define GICD_ITARGETSR_SIZE    32
-#define GICD_CPUTARGETS_BITS   8
-#define GICD_IRQS_PER_ITARGETSR        (GICD_ITARGETSR_SIZE / GICD_CPUTARGETS_BITS)
-static u32 vgic_get_target_reg(struct kvm *kvm, int irq)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       int i;
-       u32 val = 0;
-
-       irq -= VGIC_NR_PRIVATE_IRQS;
-
-       for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++)
-               val |= 1 << (dist->irq_spi_cpu[irq + i] + i * 8);
-
-       return val;
-}
-
-static void vgic_set_target_reg(struct kvm *kvm, u32 val, int irq)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct kvm_vcpu *vcpu;
-       int i, c;
-       unsigned long *bmap;
-       u32 target;
-
-       irq -= VGIC_NR_PRIVATE_IRQS;
-
-       /*
-        * Pick the LSB in each byte. This ensures we target exactly
-        * one vcpu per IRQ. If the byte is null, assume we target
-        * CPU0.
-        */
-       for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++) {
-               int shift = i * GICD_CPUTARGETS_BITS;
-
-               target = ffs((val >> shift) & 0xffU);
-               target = target ? (target - 1) : 0;
-               dist->irq_spi_cpu[irq + i] = target;
-               kvm_for_each_vcpu(c, vcpu, kvm) {
-                       bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[c]);
-                       if (c == target)
-                               set_bit(irq + i, bmap);
-                       else
-                               clear_bit(irq + i, bmap);
-               }
-       }
-}
-
-static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu,
-                                  struct kvm_exit_mmio *mmio,
-                                  phys_addr_t offset)
-{
-       u32 reg;
-
-       /* We treat the banked interrupts targets as read-only */
-       if (offset < 32) {
-               u32 roreg;
-
-               roreg = 1 << vcpu->vcpu_id;
-               roreg |= roreg << 8;
-               roreg |= roreg << 16;
-
-               vgic_reg_access(mmio, &roreg, offset,
-                               ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-               return false;
-       }
-
-       reg = vgic_get_target_reg(vcpu->kvm, offset & ~3U);
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       if (mmio->is_write) {
-               vgic_set_target_reg(vcpu->kvm, reg, offset & ~3U);
-               vgic_update_state(vcpu->kvm);
-               return true;
-       }
-
-       return false;
-}
-
-static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu,
-                               struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 *reg;
-
-       reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
-                                 vcpu->vcpu_id, offset >> 1);
-
-       return vgic_handle_cfg_reg(reg, mmio, offset);
-}
-
-static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu,
-                               struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg;
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_VALUE);
-       if (mmio->is_write) {
-               vgic_dispatch_sgi(vcpu, reg);
-               vgic_update_state(vcpu->kvm);
-               return true;
-       }
-
-       return false;
-}
-
-/* Handle reads of GICD_CPENDSGIRn and GICD_SPENDSGIRn */
-static bool read_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu,
-                                       struct kvm_exit_mmio *mmio,
-                                       phys_addr_t offset)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       int sgi;
-       int min_sgi = (offset & ~0x3);
-       int max_sgi = min_sgi + 3;
-       int vcpu_id = vcpu->vcpu_id;
-       u32 reg = 0;
-
-       /* Copy source SGIs from distributor side */
-       for (sgi = min_sgi; sgi <= max_sgi; sgi++) {
-               u8 sources = *vgic_get_sgi_sources(dist, vcpu_id, sgi);
-
-               reg |= ((u32)sources) << (8 * (sgi - min_sgi));
-       }
-
-       mmio_data_write(mmio, ~0, reg);
-       return false;
-}
-
-static bool write_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu,
-                                        struct kvm_exit_mmio *mmio,
-                                        phys_addr_t offset, bool set)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       int sgi;
-       int min_sgi = (offset & ~0x3);
-       int max_sgi = min_sgi + 3;
-       int vcpu_id = vcpu->vcpu_id;
-       u32 reg;
-       bool updated = false;
-
-       reg = mmio_data_read(mmio, ~0);
-
-       /* Clear pending SGIs on the distributor */
-       for (sgi = min_sgi; sgi <= max_sgi; sgi++) {
-               u8 mask = reg >> (8 * (sgi - min_sgi));
-               u8 *src = vgic_get_sgi_sources(dist, vcpu_id, sgi);
-
-               if (set) {
-                       if ((*src & mask) != mask)
-                               updated = true;
-                       *src |= mask;
-               } else {
-                       if (*src & mask)
-                               updated = true;
-                       *src &= ~mask;
-               }
-       }
-
-       if (updated)
-               vgic_update_state(vcpu->kvm);
-
-       return updated;
-}
-
-static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu,
-                               struct kvm_exit_mmio *mmio,
-                               phys_addr_t offset)
-{
-       if (!mmio->is_write)
-               return read_set_clear_sgi_pend_reg(vcpu, mmio, offset);
-       else
-               return write_set_clear_sgi_pend_reg(vcpu, mmio, offset, true);
-}
-
-static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu,
-                                 struct kvm_exit_mmio *mmio,
-                                 phys_addr_t offset)
-{
-       if (!mmio->is_write)
-               return read_set_clear_sgi_pend_reg(vcpu, mmio, offset);
-       else
-               return write_set_clear_sgi_pend_reg(vcpu, mmio, offset, false);
-}
-
-static const struct vgic_io_range vgic_dist_ranges[] = {
-       {
-               .base           = GIC_DIST_SOFTINT,
-               .len            = 4,
-               .handle_mmio    = handle_mmio_sgi_reg,
-       },
-       {
-               .base           = GIC_DIST_CTRL,
-               .len            = 12,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_misc,
-       },
-       {
-               .base           = GIC_DIST_IGROUP,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GIC_DIST_ENABLE_SET,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_enable_reg,
-       },
-       {
-               .base           = GIC_DIST_ENABLE_CLEAR,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_enable_reg,
-       },
-       {
-               .base           = GIC_DIST_PENDING_SET,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_pending_reg,
-       },
-       {
-               .base           = GIC_DIST_PENDING_CLEAR,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_pending_reg,
-       },
-       {
-               .base           = GIC_DIST_ACTIVE_SET,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_active_reg,
-       },
-       {
-               .base           = GIC_DIST_ACTIVE_CLEAR,
-               .len            = VGIC_MAX_IRQS / 8,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_active_reg,
-       },
-       {
-               .base           = GIC_DIST_PRI,
-               .len            = VGIC_MAX_IRQS,
-               .bits_per_irq   = 8,
-               .handle_mmio    = handle_mmio_priority_reg,
-       },
-       {
-               .base           = GIC_DIST_TARGET,
-               .len            = VGIC_MAX_IRQS,
-               .bits_per_irq   = 8,
-               .handle_mmio    = handle_mmio_target_reg,
-       },
-       {
-               .base           = GIC_DIST_CONFIG,
-               .len            = VGIC_MAX_IRQS / 4,
-               .bits_per_irq   = 2,
-               .handle_mmio    = handle_mmio_cfg_reg,
-       },
-       {
-               .base           = GIC_DIST_SGI_PENDING_CLEAR,
-               .len            = VGIC_NR_SGIS,
-               .handle_mmio    = handle_mmio_sgi_clear,
-       },
-       {
-               .base           = GIC_DIST_SGI_PENDING_SET,
-               .len            = VGIC_NR_SGIS,
-               .handle_mmio    = handle_mmio_sgi_set,
-       },
-       {}
-};
-
-static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg)
-{
-       struct kvm *kvm = vcpu->kvm;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       int nrcpus = atomic_read(&kvm->online_vcpus);
-       u8 target_cpus;
-       int sgi, mode, c, vcpu_id;
-
-       vcpu_id = vcpu->vcpu_id;
-
-       sgi = reg & 0xf;
-       target_cpus = (reg >> 16) & 0xff;
-       mode = (reg >> 24) & 3;
-
-       switch (mode) {
-       case 0:
-               if (!target_cpus)
-                       return;
-               break;
-
-       case 1:
-               target_cpus = ((1 << nrcpus) - 1) & ~(1 << vcpu_id) & 0xff;
-               break;
-
-       case 2:
-               target_cpus = 1 << vcpu_id;
-               break;
-       }
-
-       kvm_for_each_vcpu(c, vcpu, kvm) {
-               if (target_cpus & 1) {
-                       /* Flag the SGI as pending */
-                       vgic_dist_irq_set_pending(vcpu, sgi);
-                       *vgic_get_sgi_sources(dist, c, sgi) |= 1 << vcpu_id;
-                       kvm_debug("SGI%d from CPU%d to CPU%d\n",
-                                 sgi, vcpu_id, c);
-               }
-
-               target_cpus >>= 1;
-       }
-}
-
-static bool vgic_v2_queue_sgi(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       unsigned long sources;
-       int vcpu_id = vcpu->vcpu_id;
-       int c;
-
-       sources = *vgic_get_sgi_sources(dist, vcpu_id, irq);
-
-       for_each_set_bit(c, &sources, dist->nr_cpus) {
-               if (vgic_queue_irq(vcpu, c, irq))
-                       clear_bit(c, &sources);
-       }
-
-       *vgic_get_sgi_sources(dist, vcpu_id, irq) = sources;
-
-       /*
-        * If the sources bitmap has been cleared it means that we
-        * could queue all the SGIs onto link registers (see the
-        * clear_bit above), and therefore we are done with them in
-        * our emulated gic and can get rid of them.
-        */
-       if (!sources) {
-               vgic_dist_irq_clear_pending(vcpu, irq);
-               vgic_cpu_irq_clear(vcpu, irq);
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * kvm_vgic_map_resources - Configure global VGIC state before running any VCPUs
- * @kvm: pointer to the kvm struct
- *
- * Map the virtual CPU interface into the VM before running any VCPUs.  We
- * can't do this at creation time, because user space must first set the
- * virtual CPU interface address in the guest physical address space.
- */
-static int vgic_v2_map_resources(struct kvm *kvm,
-                                const struct vgic_params *params)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       int ret = 0;
-
-       if (!irqchip_in_kernel(kvm))
-               return 0;
-
-       mutex_lock(&kvm->lock);
-
-       if (vgic_ready(kvm))
-               goto out;
-
-       if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
-           IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
-               kvm_err("Need to set vgic cpu and dist addresses first\n");
-               ret = -ENXIO;
-               goto out;
-       }
-
-       vgic_register_kvm_io_dev(kvm, dist->vgic_dist_base,
-                                KVM_VGIC_V2_DIST_SIZE,
-                                vgic_dist_ranges, -1, &dist->dist_iodev);
-
-       /*
-        * Initialize the vgic if this hasn't already been done on demand by
-        * accessing the vgic state from userspace.
-        */
-       ret = vgic_init(kvm);
-       if (ret) {
-               kvm_err("Unable to allocate maps\n");
-               goto out_unregister;
-       }
-
-       ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
-                                   params->vcpu_base, KVM_VGIC_V2_CPU_SIZE,
-                                   true);
-       if (ret) {
-               kvm_err("Unable to remap VGIC CPU to VCPU\n");
-               goto out_unregister;
-       }
-
-       dist->ready = true;
-       goto out;
-
-out_unregister:
-       kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &dist->dist_iodev.dev);
-
-out:
-       if (ret)
-               kvm_vgic_destroy(kvm);
-       mutex_unlock(&kvm->lock);
-       return ret;
-}
-
-static void vgic_v2_add_sgi_source(struct kvm_vcpu *vcpu, int irq, int source)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       *vgic_get_sgi_sources(dist, vcpu->vcpu_id, irq) |= 1 << source;
-}
-
-static int vgic_v2_init_model(struct kvm *kvm)
-{
-       int i;
-
-       for (i = VGIC_NR_PRIVATE_IRQS; i < kvm->arch.vgic.nr_irqs; i += 4)
-               vgic_set_target_reg(kvm, 0, i);
-
-       return 0;
-}
-
-void vgic_v2_init_emulation(struct kvm *kvm)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       dist->vm_ops.queue_sgi = vgic_v2_queue_sgi;
-       dist->vm_ops.add_sgi_source = vgic_v2_add_sgi_source;
-       dist->vm_ops.init_model = vgic_v2_init_model;
-       dist->vm_ops.map_resources = vgic_v2_map_resources;
-
-       kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
-}
-
-static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu,
-                                struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       bool updated = false;
-       struct vgic_vmcr vmcr;
-       u32 *vmcr_field;
-       u32 reg;
-
-       vgic_get_vmcr(vcpu, &vmcr);
-
-       switch (offset & ~0x3) {
-       case GIC_CPU_CTRL:
-               vmcr_field = &vmcr.ctlr;
-               break;
-       case GIC_CPU_PRIMASK:
-               vmcr_field = &vmcr.pmr;
-               break;
-       case GIC_CPU_BINPOINT:
-               vmcr_field = &vmcr.bpr;
-               break;
-       case GIC_CPU_ALIAS_BINPOINT:
-               vmcr_field = &vmcr.abpr;
-               break;
-       default:
-               BUG();
-       }
-
-       if (!mmio->is_write) {
-               reg = *vmcr_field;
-               mmio_data_write(mmio, ~0, reg);
-       } else {
-               reg = mmio_data_read(mmio, ~0);
-               if (reg != *vmcr_field) {
-                       *vmcr_field = reg;
-                       vgic_set_vmcr(vcpu, &vmcr);
-                       updated = true;
-               }
-       }
-       return updated;
-}
-
-static bool handle_mmio_abpr(struct kvm_vcpu *vcpu,
-                            struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       return handle_cpu_mmio_misc(vcpu, mmio, GIC_CPU_ALIAS_BINPOINT);
-}
-
-static bool handle_cpu_mmio_ident(struct kvm_vcpu *vcpu,
-                                 struct kvm_exit_mmio *mmio,
-                                 phys_addr_t offset)
-{
-       u32 reg;
-
-       if (mmio->is_write)
-               return false;
-
-       /* GICC_IIDR */
-       reg = (PRODUCT_ID_KVM << 20) |
-             (GICC_ARCH_VERSION_V2 << 16) |
-             (IMPLEMENTER_ARM << 0);
-       mmio_data_write(mmio, ~0, reg);
-       return false;
-}
-
-/*
- * CPU Interface Register accesses - these are not accessed by the VM, but by
- * user space for saving and restoring VGIC state.
- */
-static const struct vgic_io_range vgic_cpu_ranges[] = {
-       {
-               .base           = GIC_CPU_CTRL,
-               .len            = 12,
-               .handle_mmio    = handle_cpu_mmio_misc,
-       },
-       {
-               .base           = GIC_CPU_ALIAS_BINPOINT,
-               .len            = 4,
-               .handle_mmio    = handle_mmio_abpr,
-       },
-       {
-               .base           = GIC_CPU_ACTIVEPRIO,
-               .len            = 16,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GIC_CPU_IDENT,
-               .len            = 4,
-               .handle_mmio    = handle_cpu_mmio_ident,
-       },
-};
-
-static int vgic_attr_regs_access(struct kvm_device *dev,
-                                struct kvm_device_attr *attr,
-                                u32 *reg, bool is_write)
-{
-       const struct vgic_io_range *r = NULL, *ranges;
-       phys_addr_t offset;
-       int ret, cpuid, c;
-       struct kvm_vcpu *vcpu, *tmp_vcpu;
-       struct vgic_dist *vgic;
-       struct kvm_exit_mmio mmio;
-       u32 data;
-
-       offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
-       cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
-               KVM_DEV_ARM_VGIC_CPUID_SHIFT;
-
-       mutex_lock(&dev->kvm->lock);
-
-       ret = vgic_init(dev->kvm);
-       if (ret)
-               goto out;
-
-       if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       vcpu = kvm_get_vcpu(dev->kvm, cpuid);
-       vgic = &dev->kvm->arch.vgic;
-
-       mmio.len = 4;
-       mmio.is_write = is_write;
-       mmio.data = &data;
-       if (is_write)
-               mmio_data_write(&mmio, ~0, *reg);
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-               mmio.phys_addr = vgic->vgic_dist_base + offset;
-               ranges = vgic_dist_ranges;
-               break;
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               mmio.phys_addr = vgic->vgic_cpu_base + offset;
-               ranges = vgic_cpu_ranges;
-               break;
-       default:
-               BUG();
-       }
-       r = vgic_find_range(ranges, 4, offset);
-
-       if (unlikely(!r || !r->handle_mmio)) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-
-       spin_lock(&vgic->lock);
-
-       /*
-        * Ensure that no other VCPU is running by checking the vcpu->cpu
-        * field.  If no other VPCUs are running we can safely access the VGIC
-        * state, because even if another VPU is run after this point, that
-        * VCPU will not touch the vgic state, because it will block on
-        * getting the vgic->lock in kvm_vgic_sync_hwstate().
-        */
-       kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
-               if (unlikely(tmp_vcpu->cpu != -1)) {
-                       ret = -EBUSY;
-                       goto out_vgic_unlock;
-               }
-       }
-
-       /*
-        * Move all pending IRQs from the LRs on all VCPUs so the pending
-        * state can be properly represented in the register state accessible
-        * through this API.
-        */
-       kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm)
-               vgic_unqueue_irqs(tmp_vcpu);
-
-       offset -= r->base;
-       r->handle_mmio(vcpu, &mmio, offset);
-
-       if (!is_write)
-               *reg = mmio_data_read(&mmio, ~0);
-
-       ret = 0;
-out_vgic_unlock:
-       spin_unlock(&vgic->lock);
-out:
-       mutex_unlock(&dev->kvm->lock);
-       return ret;
-}
-
-static int vgic_v2_create(struct kvm_device *dev, u32 type)
-{
-       return kvm_vgic_create(dev->kvm, type);
-}
-
-static void vgic_v2_destroy(struct kvm_device *dev)
-{
-       kfree(dev);
-}
-
-static int vgic_v2_set_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       int ret;
-
-       ret = vgic_set_common_attr(dev, attr);
-       if (ret != -ENXIO)
-               return ret;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
-               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-               u32 reg;
-
-               if (get_user(reg, uaddr))
-                       return -EFAULT;
-
-               return vgic_attr_regs_access(dev, attr, &reg, true);
-       }
-
-       }
-
-       return -ENXIO;
-}
-
-static int vgic_v2_get_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       int ret;
-
-       ret = vgic_get_common_attr(dev, attr);
-       if (ret != -ENXIO)
-               return ret;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
-               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-               u32 reg = 0;
-
-               ret = vgic_attr_regs_access(dev, attr, &reg, false);
-               if (ret)
-                       return ret;
-               return put_user(reg, uaddr);
-       }
-
-       }
-
-       return -ENXIO;
-}
-
-static int vgic_v2_has_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       phys_addr_t offset;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_ADDR:
-               switch (attr->attr) {
-               case KVM_VGIC_V2_ADDR_TYPE_DIST:
-               case KVM_VGIC_V2_ADDR_TYPE_CPU:
-                       return 0;
-               }
-               break;
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-               offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
-               return vgic_has_attr_regs(vgic_dist_ranges, offset);
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
-               return vgic_has_attr_regs(vgic_cpu_ranges, offset);
-       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
-               return 0;
-       case KVM_DEV_ARM_VGIC_GRP_CTRL:
-               switch (attr->attr) {
-               case KVM_DEV_ARM_VGIC_CTRL_INIT:
-                       return 0;
-               }
-       }
-       return -ENXIO;
-}
-
-struct kvm_device_ops kvm_arm_vgic_v2_ops = {
-       .name = "kvm-arm-vgic-v2",
-       .create = vgic_v2_create,
-       .destroy = vgic_v2_destroy,
-       .set_attr = vgic_v2_set_attr,
-       .get_attr = vgic_v2_get_attr,
-       .has_attr = vgic_v2_has_attr,
-};
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
deleted file mode 100644 (file)
index 334cd7a..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2012,2013 ARM Limited, All Rights Reserved.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/cpu.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <linux/irqchip/arm-gic.h>
-
-#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-
-static struct vgic_lr vgic_v2_get_lr(const struct kvm_vcpu *vcpu, int lr)
-{
-       struct vgic_lr lr_desc;
-       u32 val = vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr];
-
-       lr_desc.irq     = val & GICH_LR_VIRTUALID;
-       if (lr_desc.irq <= 15)
-               lr_desc.source  = (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
-       else
-               lr_desc.source = 0;
-       lr_desc.state   = 0;
-
-       if (val & GICH_LR_PENDING_BIT)
-               lr_desc.state |= LR_STATE_PENDING;
-       if (val & GICH_LR_ACTIVE_BIT)
-               lr_desc.state |= LR_STATE_ACTIVE;
-       if (val & GICH_LR_EOI)
-               lr_desc.state |= LR_EOI_INT;
-       if (val & GICH_LR_HW) {
-               lr_desc.state |= LR_HW;
-               lr_desc.hwirq = (val & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT;
-       }
-
-       return lr_desc;
-}
-
-static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr,
-                          struct vgic_lr lr_desc)
-{
-       u32 lr_val;
-
-       lr_val = lr_desc.irq;
-
-       if (lr_desc.state & LR_STATE_PENDING)
-               lr_val |= GICH_LR_PENDING_BIT;
-       if (lr_desc.state & LR_STATE_ACTIVE)
-               lr_val |= GICH_LR_ACTIVE_BIT;
-       if (lr_desc.state & LR_EOI_INT)
-               lr_val |= GICH_LR_EOI;
-
-       if (lr_desc.state & LR_HW) {
-               lr_val |= GICH_LR_HW;
-               lr_val |= (u32)lr_desc.hwirq << GICH_LR_PHYSID_CPUID_SHIFT;
-       }
-
-       if (lr_desc.irq < VGIC_NR_SGIS)
-               lr_val |= (lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT);
-
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = lr_val;
-
-       if (!(lr_desc.state & LR_STATE_MASK))
-               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr |= (1ULL << lr);
-       else
-               vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr &= ~(1ULL << lr);
-}
-
-static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr;
-}
-
-static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
-}
-
-static void vgic_v2_clear_eisr(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr = 0;
-}
-
-static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
-{
-       u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
-       u32 ret = 0;
-
-       if (misr & GICH_MISR_EOI)
-               ret |= INT_STATUS_EOI;
-       if (misr & GICH_MISR_U)
-               ret |= INT_STATUS_UNDERFLOW;
-
-       return ret;
-}
-
-static void vgic_v2_enable_underflow(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |= GICH_HCR_UIE;
-}
-
-static void vgic_v2_disable_underflow(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
-}
-
-static void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
-{
-       u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
-
-       vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >> GICH_VMCR_CTRL_SHIFT;
-       vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >> GICH_VMCR_ALIAS_BINPOINT_SHIFT;
-       vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >> GICH_VMCR_BINPOINT_SHIFT;
-       vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >> GICH_VMCR_PRIMASK_SHIFT;
-}
-
-static void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
-{
-       u32 vmcr;
-
-       vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
-       vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) & GICH_VMCR_ALIAS_BINPOINT_MASK;
-       vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) & GICH_VMCR_BINPOINT_MASK;
-       vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) & GICH_VMCR_PRIMASK_MASK;
-
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
-}
-
-static void vgic_v2_enable(struct kvm_vcpu *vcpu)
-{
-       /*
-        * By forcing VMCR to zero, the GIC will restore the binary
-        * points to their reset values. Anything else resets to zero
-        * anyway.
-        */
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
-
-       /* Get the show on the road... */
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
-}
-
-static const struct vgic_ops vgic_v2_ops = {
-       .get_lr                 = vgic_v2_get_lr,
-       .set_lr                 = vgic_v2_set_lr,
-       .get_elrsr              = vgic_v2_get_elrsr,
-       .get_eisr               = vgic_v2_get_eisr,
-       .clear_eisr             = vgic_v2_clear_eisr,
-       .get_interrupt_status   = vgic_v2_get_interrupt_status,
-       .enable_underflow       = vgic_v2_enable_underflow,
-       .disable_underflow      = vgic_v2_disable_underflow,
-       .get_vmcr               = vgic_v2_get_vmcr,
-       .set_vmcr               = vgic_v2_set_vmcr,
-       .enable                 = vgic_v2_enable,
-};
-
-struct vgic_params __section(.hyp.text) vgic_v2_params;
-
-static void vgic_cpu_init_lrs(void *params)
-{
-       struct vgic_params *vgic = params;
-       int i;
-
-       for (i = 0; i < vgic->nr_lr; i++)
-               writel_relaxed(0, vgic->vctrl_base + GICH_LR0 + (i * 4));
-}
-
-/**
- * vgic_v2_probe - probe for a GICv2 compatible interrupt controller
- * @gic_kvm_info:      pointer to the GIC description
- * @ops:               address of a pointer to the GICv2 operations
- * @params:            address of a pointer to HW-specific parameters
- *
- * Returns 0 if a GICv2 has been found, with the low level operations
- * in *ops and the HW parameters in *params. Returns an error code
- * otherwise.
- */
-int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info,
-                  const struct vgic_ops **ops,
-                  const struct vgic_params **params)
-{
-       int ret;
-       struct vgic_params *vgic = &vgic_v2_params;
-       const struct resource *vctrl_res = &gic_kvm_info->vctrl;
-       const struct resource *vcpu_res = &gic_kvm_info->vcpu;
-
-       memset(vgic, 0, sizeof(*vgic));
-
-       if (!gic_kvm_info->maint_irq) {
-               kvm_err("error getting vgic maintenance irq\n");
-               ret = -ENXIO;
-               goto out;
-       }
-       vgic->maint_irq = gic_kvm_info->maint_irq;
-
-       if (!gic_kvm_info->vctrl.start) {
-               kvm_err("GICH not present in the firmware table\n");
-               ret = -ENXIO;
-               goto out;
-       }
-
-       vgic->vctrl_base = ioremap(gic_kvm_info->vctrl.start,
-                                  resource_size(&gic_kvm_info->vctrl));
-       if (!vgic->vctrl_base) {
-               kvm_err("Cannot ioremap GICH\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       vgic->nr_lr = readl_relaxed(vgic->vctrl_base + GICH_VTR);
-       vgic->nr_lr = (vgic->nr_lr & 0x3f) + 1;
-
-       ret = create_hyp_io_mappings(vgic->vctrl_base,
-                                    vgic->vctrl_base + resource_size(vctrl_res),
-                                    vctrl_res->start);
-       if (ret) {
-               kvm_err("Cannot map VCTRL into hyp\n");
-               goto out_unmap;
-       }
-
-       if (!PAGE_ALIGNED(vcpu_res->start)) {
-               kvm_err("GICV physical address 0x%llx not page aligned\n",
-                       (unsigned long long)vcpu_res->start);
-               ret = -ENXIO;
-               goto out_unmap;
-       }
-
-       if (!PAGE_ALIGNED(resource_size(vcpu_res))) {
-               kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
-                       (unsigned long long)resource_size(vcpu_res),
-                       PAGE_SIZE);
-               ret = -ENXIO;
-               goto out_unmap;
-       }
-
-       vgic->can_emulate_gicv2 = true;
-       kvm_register_device_ops(&kvm_arm_vgic_v2_ops, KVM_DEV_TYPE_ARM_VGIC_V2);
-
-       vgic->vcpu_base = vcpu_res->start;
-
-       kvm_info("GICH base=0x%llx, GICV base=0x%llx, IRQ=%d\n",
-                gic_kvm_info->vctrl.start, vgic->vcpu_base, vgic->maint_irq);
-
-       vgic->type = VGIC_V2;
-       vgic->max_gic_vcpus = VGIC_V2_MAX_CPUS;
-
-       on_each_cpu(vgic_cpu_init_lrs, vgic, 1);
-
-       *ops = &vgic_v2_ops;
-       *params = vgic;
-       goto out;
-
-out_unmap:
-       iounmap(vgic->vctrl_base);
-out:
-       return ret;
-}
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
deleted file mode 100644 (file)
index e661e7f..0000000
+++ /dev/null
@@ -1,1074 +0,0 @@
-/*
- * GICv3 distributor and redistributor emulation
- *
- * GICv3 emulation is currently only supported on a GICv3 host (because
- * we rely on the hardware's CPU interface virtualization support), but
- * supports both hardware with or without the optional GICv2 backwards
- * compatibility features.
- *
- * Limitations of the emulation:
- * (RAZ/WI: read as zero, write ignore, RAO/WI: read as one, write ignore)
- * - We do not support LPIs (yet). TYPER.LPIS is reported as 0 and is RAZ/WI.
- * - We do not support the message based interrupts (MBIs) triggered by
- *   writes to the GICD_{SET,CLR}SPI_* registers. TYPER.MBIS is reported as 0.
- * - We do not support the (optional) backwards compatibility feature.
- *   GICD_CTLR.ARE resets to 1 and is RAO/WI. If the _host_ GIC supports
- *   the compatiblity feature, you can use a GICv2 in the guest, though.
- * - We only support a single security state. GICD_CTLR.DS is 1 and is RAO/WI.
- * - Priorities are not emulated (same as the GICv2 emulation). Linux
- *   as a guest is fine with this, because it does not use priorities.
- * - We only support Group1 interrupts. Again Linux uses only those.
- *
- * Copyright (C) 2014 ARM Ltd.
- * Author: Andre Przywara <andre.przywara@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/cpu.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/interrupt.h>
-
-#include <linux/irqchip/arm-gic-v3.h>
-#include <kvm/arm_vgic.h>
-
-#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-
-#include "vgic.h"
-
-static bool handle_mmio_rao_wi(struct kvm_vcpu *vcpu,
-                              struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg = 0xffffffff;
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-
-       return false;
-}
-
-static bool handle_mmio_ctlr(struct kvm_vcpu *vcpu,
-                            struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg = 0;
-
-       /*
-        * Force ARE and DS to 1, the guest cannot change this.
-        * For the time being we only support Group1 interrupts.
-        */
-       if (vcpu->kvm->arch.vgic.enabled)
-               reg = GICD_CTLR_ENABLE_SS_G1;
-       reg |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       if (mmio->is_write) {
-               vcpu->kvm->arch.vgic.enabled = !!(reg & GICD_CTLR_ENABLE_SS_G1);
-               vgic_update_state(vcpu->kvm);
-               return true;
-       }
-       return false;
-}
-
-/*
- * As this implementation does not provide compatibility
- * with GICv2 (ARE==1), we report zero CPUs in bits [5..7].
- * Also LPIs and MBIs are not supported, so we set the respective bits to 0.
- * Also we report at most 2**10=1024 interrupt IDs (to match 1024 SPIs).
- */
-#define INTERRUPT_ID_BITS 10
-static bool handle_mmio_typer(struct kvm_vcpu *vcpu,
-                             struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg;
-
-       reg = (min(vcpu->kvm->arch.vgic.nr_irqs, 1024) >> 5) - 1;
-
-       reg |= (INTERRUPT_ID_BITS - 1) << 19;
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-
-       return false;
-}
-
-static bool handle_mmio_iidr(struct kvm_vcpu *vcpu,
-                            struct kvm_exit_mmio *mmio, phys_addr_t offset)
-{
-       u32 reg;
-
-       reg = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-
-       return false;
-}
-
-static bool handle_mmio_set_enable_reg_dist(struct kvm_vcpu *vcpu,
-                                           struct kvm_exit_mmio *mmio,
-                                           phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                             vcpu->vcpu_id,
-                                             ACCESS_WRITE_SETBIT);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_clear_enable_reg_dist(struct kvm_vcpu *vcpu,
-                                             struct kvm_exit_mmio *mmio,
-                                             phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                             vcpu->vcpu_id,
-                                             ACCESS_WRITE_CLEARBIT);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_set_pending_reg_dist(struct kvm_vcpu *vcpu,
-                                            struct kvm_exit_mmio *mmio,
-                                            phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_set_pending_reg(vcpu->kvm, mmio, offset,
-                                                  vcpu->vcpu_id);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_clear_pending_reg_dist(struct kvm_vcpu *vcpu,
-                                              struct kvm_exit_mmio *mmio,
-                                              phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_clear_pending_reg(vcpu->kvm, mmio, offset,
-                                                    vcpu->vcpu_id);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_set_active_reg_dist(struct kvm_vcpu *vcpu,
-                                           struct kvm_exit_mmio *mmio,
-                                           phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_set_active_reg(vcpu->kvm, mmio, offset,
-                                                  vcpu->vcpu_id);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_clear_active_reg_dist(struct kvm_vcpu *vcpu,
-                                             struct kvm_exit_mmio *mmio,
-                                             phys_addr_t offset)
-{
-       if (likely(offset >= VGIC_NR_PRIVATE_IRQS / 8))
-               return vgic_handle_clear_active_reg(vcpu->kvm, mmio, offset,
-                                                   vcpu->vcpu_id);
-
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_priority_reg_dist(struct kvm_vcpu *vcpu,
-                                         struct kvm_exit_mmio *mmio,
-                                         phys_addr_t offset)
-{
-       u32 *reg;
-
-       if (unlikely(offset < VGIC_NR_PRIVATE_IRQS)) {
-               vgic_reg_access(mmio, NULL, offset,
-                               ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-               return false;
-       }
-
-       reg = vgic_bytemap_get_reg(&vcpu->kvm->arch.vgic.irq_priority,
-                                  vcpu->vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset,
-               ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       return false;
-}
-
-static bool handle_mmio_cfg_reg_dist(struct kvm_vcpu *vcpu,
-                                    struct kvm_exit_mmio *mmio,
-                                    phys_addr_t offset)
-{
-       u32 *reg;
-
-       if (unlikely(offset < VGIC_NR_PRIVATE_IRQS / 4)) {
-               vgic_reg_access(mmio, NULL, offset,
-                               ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-               return false;
-       }
-
-       reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
-                                 vcpu->vcpu_id, offset >> 1);
-
-       return vgic_handle_cfg_reg(reg, mmio, offset);
-}
-
-/*
- * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
- * when we store the target MPIDR written by the guest.
- */
-static u32 compress_mpidr(unsigned long mpidr)
-{
-       u32 ret;
-
-       ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-       ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
-       ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
-       ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
-
-       return ret;
-}
-
-static unsigned long uncompress_mpidr(u32 value)
-{
-       unsigned long mpidr;
-
-       mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
-       mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
-       mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
-       mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
-
-       return mpidr;
-}
-
-/*
- * Lookup the given MPIDR value to get the vcpu_id (if there is one)
- * and store that in the irq_spi_cpu[] array.
- * This limits the number of VCPUs to 255 for now, extending the data
- * type (or storing kvm_vcpu pointers) should lift the limit.
- * Store the original MPIDR value in an extra array to support read-as-written.
- * Unallocated MPIDRs are translated to a special value and caught
- * before any array accesses.
- */
-static bool handle_mmio_route_reg(struct kvm_vcpu *vcpu,
-                                 struct kvm_exit_mmio *mmio,
-                                 phys_addr_t offset)
-{
-       struct kvm *kvm = vcpu->kvm;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       int spi;
-       u32 reg;
-       int vcpu_id;
-       unsigned long *bmap, mpidr;
-
-       /*
-        * The upper 32 bits of each 64 bit register are zero,
-        * as we don't support Aff3.
-        */
-       if ((offset & 4)) {
-               vgic_reg_access(mmio, NULL, offset,
-                               ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-               return false;
-       }
-
-       /* This region only covers SPIs, so no handling of private IRQs here. */
-       spi = offset / 8;
-
-       /* get the stored MPIDR for this IRQ */
-       mpidr = uncompress_mpidr(dist->irq_spi_mpidr[spi]);
-       reg = mpidr;
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-
-       if (!mmio->is_write)
-               return false;
-
-       /*
-        * Now clear the currently assigned vCPU from the map, making room
-        * for the new one to be written below
-        */
-       vcpu = kvm_mpidr_to_vcpu(kvm, mpidr);
-       if (likely(vcpu)) {
-               vcpu_id = vcpu->vcpu_id;
-               bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]);
-               __clear_bit(spi, bmap);
-       }
-
-       dist->irq_spi_mpidr[spi] = compress_mpidr(reg);
-       vcpu = kvm_mpidr_to_vcpu(kvm, reg & MPIDR_HWID_BITMASK);
-
-       /*
-        * The spec says that non-existent MPIDR values should not be
-        * forwarded to any existent (v)CPU, but should be able to become
-        * pending anyway. We simply keep the irq_spi_target[] array empty, so
-        * the interrupt will never be injected.
-        * irq_spi_cpu[irq] gets a magic value in this case.
-        */
-       if (likely(vcpu)) {
-               vcpu_id = vcpu->vcpu_id;
-               dist->irq_spi_cpu[spi] = vcpu_id;
-               bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]);
-               __set_bit(spi, bmap);
-       } else {
-               dist->irq_spi_cpu[spi] = VCPU_NOT_ALLOCATED;
-       }
-
-       vgic_update_state(kvm);
-
-       return true;
-}
-
-/*
- * We should be careful about promising too much when a guest reads
- * this register. Don't claim to be like any hardware implementation,
- * but just report the GIC as version 3 - which is what a Linux guest
- * would check.
- */
-static bool handle_mmio_idregs(struct kvm_vcpu *vcpu,
-                              struct kvm_exit_mmio *mmio,
-                              phys_addr_t offset)
-{
-       u32 reg = 0;
-
-       switch (offset + GICD_IDREGS) {
-       case GICD_PIDR2:
-               reg = 0x3b;
-               break;
-       }
-
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-
-       return false;
-}
-
-static const struct vgic_io_range vgic_v3_dist_ranges[] = {
-       {
-               .base           = GICD_CTLR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_ctlr,
-       },
-       {
-               .base           = GICD_TYPER,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_typer,
-       },
-       {
-               .base           = GICD_IIDR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_iidr,
-       },
-       {
-               /* this register is optional, it is RAZ/WI if not implemented */
-               .base           = GICD_STATUSR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this write only register is WI when TYPER.MBIS=0 */
-               .base           = GICD_SETSPI_NSR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this write only register is WI when TYPER.MBIS=0 */
-               .base           = GICD_CLRSPI_NSR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when DS=1 */
-               .base           = GICD_SETSPI_SR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when DS=1 */
-               .base           = GICD_CLRSPI_SR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GICD_IGROUPR,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_rao_wi,
-       },
-       {
-               .base           = GICD_ISENABLER,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_enable_reg_dist,
-       },
-       {
-               .base           = GICD_ICENABLER,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_enable_reg_dist,
-       },
-       {
-               .base           = GICD_ISPENDR,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_pending_reg_dist,
-       },
-       {
-               .base           = GICD_ICPENDR,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_pending_reg_dist,
-       },
-       {
-               .base           = GICD_ISACTIVER,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_active_reg_dist,
-       },
-       {
-               .base           = GICD_ICACTIVER,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_active_reg_dist,
-       },
-       {
-               .base           = GICD_IPRIORITYR,
-               .len            = 0x400,
-               .bits_per_irq   = 8,
-               .handle_mmio    = handle_mmio_priority_reg_dist,
-       },
-       {
-               /* TARGETSRn is RES0 when ARE=1 */
-               .base           = GICD_ITARGETSR,
-               .len            = 0x400,
-               .bits_per_irq   = 8,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GICD_ICFGR,
-               .len            = 0x100,
-               .bits_per_irq   = 2,
-               .handle_mmio    = handle_mmio_cfg_reg_dist,
-       },
-       {
-               /* this is RAZ/WI when DS=1 */
-               .base           = GICD_IGRPMODR,
-               .len            = 0x80,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when DS=1 */
-               .base           = GICD_NSACR,
-               .len            = 0x100,
-               .bits_per_irq   = 2,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when ARE=1 */
-               .base           = GICD_SGIR,
-               .len            = 0x04,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when ARE=1 */
-               .base           = GICD_CPENDSGIR,
-               .len            = 0x10,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               /* this is RAZ/WI when ARE=1 */
-               .base           = GICD_SPENDSGIR,
-               .len            = 0x10,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GICD_IROUTER + 0x100,
-               .len            = 0x1ee0,
-               .bits_per_irq   = 64,
-               .handle_mmio    = handle_mmio_route_reg,
-       },
-       {
-               .base           = GICD_IDREGS,
-               .len            = 0x30,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_idregs,
-       },
-       {},
-};
-
-static bool handle_mmio_ctlr_redist(struct kvm_vcpu *vcpu,
-                                   struct kvm_exit_mmio *mmio,
-                                   phys_addr_t offset)
-{
-       /* since we don't support LPIs, this register is zero for now */
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_typer_redist(struct kvm_vcpu *vcpu,
-                                    struct kvm_exit_mmio *mmio,
-                                    phys_addr_t offset)
-{
-       u32 reg;
-       u64 mpidr;
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-       int target_vcpu_id = redist_vcpu->vcpu_id;
-
-       /* the upper 32 bits contain the affinity value */
-       if ((offset & ~3) == 4) {
-               mpidr = kvm_vcpu_get_mpidr_aff(redist_vcpu);
-               reg = compress_mpidr(mpidr);
-
-               vgic_reg_access(mmio, &reg, offset,
-                               ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-               return false;
-       }
-
-       reg = redist_vcpu->vcpu_id << 8;
-       if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
-               reg |= GICR_TYPER_LAST;
-       vgic_reg_access(mmio, &reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-static bool handle_mmio_set_enable_reg_redist(struct kvm_vcpu *vcpu,
-                                             struct kvm_exit_mmio *mmio,
-                                             phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                     redist_vcpu->vcpu_id,
-                                     ACCESS_WRITE_SETBIT);
-}
-
-static bool handle_mmio_clear_enable_reg_redist(struct kvm_vcpu *vcpu,
-                                               struct kvm_exit_mmio *mmio,
-                                               phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_enable_reg(vcpu->kvm, mmio, offset,
-                                     redist_vcpu->vcpu_id,
-                                     ACCESS_WRITE_CLEARBIT);
-}
-
-static bool handle_mmio_set_active_reg_redist(struct kvm_vcpu *vcpu,
-                                             struct kvm_exit_mmio *mmio,
-                                             phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_set_active_reg(vcpu->kvm, mmio, offset,
-                                         redist_vcpu->vcpu_id);
-}
-
-static bool handle_mmio_clear_active_reg_redist(struct kvm_vcpu *vcpu,
-                                               struct kvm_exit_mmio *mmio,
-                                               phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_clear_active_reg(vcpu->kvm, mmio, offset,
-                                            redist_vcpu->vcpu_id);
-}
-
-static bool handle_mmio_set_pending_reg_redist(struct kvm_vcpu *vcpu,
-                                              struct kvm_exit_mmio *mmio,
-                                              phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_set_pending_reg(vcpu->kvm, mmio, offset,
-                                          redist_vcpu->vcpu_id);
-}
-
-static bool handle_mmio_clear_pending_reg_redist(struct kvm_vcpu *vcpu,
-                                                struct kvm_exit_mmio *mmio,
-                                                phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       return vgic_handle_clear_pending_reg(vcpu->kvm, mmio, offset,
-                                            redist_vcpu->vcpu_id);
-}
-
-static bool handle_mmio_priority_reg_redist(struct kvm_vcpu *vcpu,
-                                           struct kvm_exit_mmio *mmio,
-                                           phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-       u32 *reg;
-
-       reg = vgic_bytemap_get_reg(&vcpu->kvm->arch.vgic.irq_priority,
-                                  redist_vcpu->vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       return false;
-}
-
-static bool handle_mmio_cfg_reg_redist(struct kvm_vcpu *vcpu,
-                                      struct kvm_exit_mmio *mmio,
-                                      phys_addr_t offset)
-{
-       struct kvm_vcpu *redist_vcpu = mmio->private;
-
-       u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
-                                      redist_vcpu->vcpu_id, offset >> 1);
-
-       return vgic_handle_cfg_reg(reg, mmio, offset);
-}
-
-#define SGI_base(x) ((x) + SZ_64K)
-
-static const struct vgic_io_range vgic_redist_ranges[] = {
-       {
-               .base           = GICR_CTLR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_ctlr_redist,
-       },
-       {
-               .base           = GICR_TYPER,
-               .len            = 0x08,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_typer_redist,
-       },
-       {
-               .base           = GICR_IIDR,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_iidr,
-       },
-       {
-               .base           = GICR_WAKER,
-               .len            = 0x04,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = GICR_IDREGS,
-               .len            = 0x30,
-               .bits_per_irq   = 0,
-               .handle_mmio    = handle_mmio_idregs,
-       },
-       {
-               .base           = SGI_base(GICR_IGROUPR0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_rao_wi,
-       },
-       {
-               .base           = SGI_base(GICR_ISENABLER0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_enable_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ICENABLER0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_enable_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ISPENDR0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_pending_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ICPENDR0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_pending_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ISACTIVER0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_set_active_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ICACTIVER0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_clear_active_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_IPRIORITYR0),
-               .len            = 0x20,
-               .bits_per_irq   = 8,
-               .handle_mmio    = handle_mmio_priority_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_ICFGR0),
-               .len            = 0x08,
-               .bits_per_irq   = 2,
-               .handle_mmio    = handle_mmio_cfg_reg_redist,
-       },
-       {
-               .base           = SGI_base(GICR_IGRPMODR0),
-               .len            = 0x04,
-               .bits_per_irq   = 1,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {
-               .base           = SGI_base(GICR_NSACR),
-               .len            = 0x04,
-               .handle_mmio    = handle_mmio_raz_wi,
-       },
-       {},
-};
-
-static bool vgic_v3_queue_sgi(struct kvm_vcpu *vcpu, int irq)
-{
-       if (vgic_queue_irq(vcpu, 0, irq)) {
-               vgic_dist_irq_clear_pending(vcpu, irq);
-               vgic_cpu_irq_clear(vcpu, irq);
-               return true;
-       }
-
-       return false;
-}
-
-static int vgic_v3_map_resources(struct kvm *kvm,
-                                const struct vgic_params *params)
-{
-       int ret = 0;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       gpa_t rdbase = dist->vgic_redist_base;
-       struct vgic_io_device *iodevs = NULL;
-       int i;
-
-       if (!irqchip_in_kernel(kvm))
-               return 0;
-
-       mutex_lock(&kvm->lock);
-
-       if (vgic_ready(kvm))
-               goto out;
-
-       if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
-           IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
-               kvm_err("Need to set vgic distributor addresses first\n");
-               ret = -ENXIO;
-               goto out;
-       }
-
-       /*
-        * For a VGICv3 we require the userland to explicitly initialize
-        * the VGIC before we need to use it.
-        */
-       if (!vgic_initialized(kvm)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = vgic_register_kvm_io_dev(kvm, dist->vgic_dist_base,
-                                      GIC_V3_DIST_SIZE, vgic_v3_dist_ranges,
-                                      -1, &dist->dist_iodev);
-       if (ret)
-               goto out;
-
-       iodevs = kcalloc(dist->nr_cpus, sizeof(iodevs[0]), GFP_KERNEL);
-       if (!iodevs) {
-               ret = -ENOMEM;
-               goto out_unregister;
-       }
-
-       for (i = 0; i < dist->nr_cpus; i++) {
-               ret = vgic_register_kvm_io_dev(kvm, rdbase,
-                                              SZ_128K, vgic_redist_ranges,
-                                              i, &iodevs[i]);
-               if (ret)
-                       goto out_unregister;
-               rdbase += GIC_V3_REDIST_SIZE;
-       }
-
-       dist->redist_iodevs = iodevs;
-       dist->ready = true;
-       goto out;
-
-out_unregister:
-       kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &dist->dist_iodev.dev);
-       if (iodevs) {
-               for (i = 0; i < dist->nr_cpus; i++) {
-                       if (iodevs[i].dev.ops)
-                               kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
-                                                         &iodevs[i].dev);
-               }
-       }
-
-out:
-       if (ret)
-               kvm_vgic_destroy(kvm);
-       mutex_unlock(&kvm->lock);
-       return ret;
-}
-
-static int vgic_v3_init_model(struct kvm *kvm)
-{
-       int i;
-       u32 mpidr;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       int nr_spis = dist->nr_irqs - VGIC_NR_PRIVATE_IRQS;
-
-       dist->irq_spi_mpidr = kcalloc(nr_spis, sizeof(dist->irq_spi_mpidr[0]),
-                                     GFP_KERNEL);
-
-       if (!dist->irq_spi_mpidr)
-               return -ENOMEM;
-
-       /* Initialize the target VCPUs for each IRQ to VCPU 0 */
-       mpidr = compress_mpidr(kvm_vcpu_get_mpidr_aff(kvm_get_vcpu(kvm, 0)));
-       for (i = VGIC_NR_PRIVATE_IRQS; i < dist->nr_irqs; i++) {
-               dist->irq_spi_cpu[i - VGIC_NR_PRIVATE_IRQS] = 0;
-               dist->irq_spi_mpidr[i - VGIC_NR_PRIVATE_IRQS] = mpidr;
-               vgic_bitmap_set_irq_val(dist->irq_spi_target, 0, i, 1);
-       }
-
-       return 0;
-}
-
-/* GICv3 does not keep track of SGI sources anymore. */
-static void vgic_v3_add_sgi_source(struct kvm_vcpu *vcpu, int irq, int source)
-{
-}
-
-void vgic_v3_init_emulation(struct kvm *kvm)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       dist->vm_ops.queue_sgi = vgic_v3_queue_sgi;
-       dist->vm_ops.add_sgi_source = vgic_v3_add_sgi_source;
-       dist->vm_ops.init_model = vgic_v3_init_model;
-       dist->vm_ops.map_resources = vgic_v3_map_resources;
-
-       kvm->arch.max_vcpus = KVM_MAX_VCPUS;
-}
-
-/*
- * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
- * generation register ICC_SGI1R_EL1) with a given VCPU.
- * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
- * return -1.
- */
-static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
-{
-       unsigned long affinity;
-       int level0;
-
-       /*
-        * Split the current VCPU's MPIDR into affinity level 0 and the
-        * rest as this is what we have to compare against.
-        */
-       affinity = kvm_vcpu_get_mpidr_aff(vcpu);
-       level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
-       affinity &= ~MPIDR_LEVEL_MASK;
-
-       /* bail out if the upper three levels don't match */
-       if (sgi_aff != affinity)
-               return -1;
-
-       /* Is this VCPU's bit set in the mask ? */
-       if (!(sgi_cpu_mask & BIT(level0)))
-               return -1;
-
-       return level0;
-}
-
-#define SGI_AFFINITY_LEVEL(reg, level) \
-       ((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
-       >> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
-
-/**
- * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
- * @vcpu: The VCPU requesting a SGI
- * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
- *
- * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
- * This will trap in sys_regs.c and call this function.
- * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
- * target processors as well as a bitmask of 16 Aff0 CPUs.
- * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
- * check for matching ones. If this bit is set, we signal all, but not the
- * calling VCPU.
- */
-void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
-{
-       struct kvm *kvm = vcpu->kvm;
-       struct kvm_vcpu *c_vcpu;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       u16 target_cpus;
-       u64 mpidr;
-       int sgi, c;
-       int vcpu_id = vcpu->vcpu_id;
-       bool broadcast;
-       int updated = 0;
-
-       sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
-       broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
-       target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
-       mpidr = SGI_AFFINITY_LEVEL(reg, 3);
-       mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
-       mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
-
-       /*
-        * We take the dist lock here, because we come from the sysregs
-        * code path and not from the MMIO one (which already takes the lock).
-        */
-       spin_lock(&dist->lock);
-
-       /*
-        * We iterate over all VCPUs to find the MPIDRs matching the request.
-        * If we have handled one CPU, we clear it's bit to detect early
-        * if we are already finished. This avoids iterating through all
-        * VCPUs when most of the times we just signal a single VCPU.
-        */
-       kvm_for_each_vcpu(c, c_vcpu, kvm) {
-
-               /* Exit early if we have dealt with all requested CPUs */
-               if (!broadcast && target_cpus == 0)
-                       break;
-
-                /* Don't signal the calling VCPU */
-               if (broadcast && c == vcpu_id)
-                       continue;
-
-               if (!broadcast) {
-                       int level0;
-
-                       level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
-                       if (level0 == -1)
-                               continue;
-
-                       /* remove this matching VCPU from the mask */
-                       target_cpus &= ~BIT(level0);
-               }
-
-               /* Flag the SGI as pending */
-               vgic_dist_irq_set_pending(c_vcpu, sgi);
-               updated = 1;
-               kvm_debug("SGI%d from CPU%d to CPU%d\n", sgi, vcpu_id, c);
-       }
-       if (updated)
-               vgic_update_state(vcpu->kvm);
-       spin_unlock(&dist->lock);
-       if (updated)
-               vgic_kick_vcpus(vcpu->kvm);
-}
-
-static int vgic_v3_create(struct kvm_device *dev, u32 type)
-{
-       return kvm_vgic_create(dev->kvm, type);
-}
-
-static void vgic_v3_destroy(struct kvm_device *dev)
-{
-       kfree(dev);
-}
-
-static int vgic_v3_set_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       int ret;
-
-       ret = vgic_set_common_attr(dev, attr);
-       if (ret != -ENXIO)
-               return ret;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               return -ENXIO;
-       }
-
-       return -ENXIO;
-}
-
-static int vgic_v3_get_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       int ret;
-
-       ret = vgic_get_common_attr(dev, attr);
-       if (ret != -ENXIO)
-               return ret;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               return -ENXIO;
-       }
-
-       return -ENXIO;
-}
-
-static int vgic_v3_has_attr(struct kvm_device *dev,
-                           struct kvm_device_attr *attr)
-{
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_ADDR:
-               switch (attr->attr) {
-               case KVM_VGIC_V2_ADDR_TYPE_DIST:
-               case KVM_VGIC_V2_ADDR_TYPE_CPU:
-                       return -ENXIO;
-               case KVM_VGIC_V3_ADDR_TYPE_DIST:
-               case KVM_VGIC_V3_ADDR_TYPE_REDIST:
-                       return 0;
-               }
-               break;
-       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
-       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-               return -ENXIO;
-       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
-               return 0;
-       case KVM_DEV_ARM_VGIC_GRP_CTRL:
-               switch (attr->attr) {
-               case KVM_DEV_ARM_VGIC_CTRL_INIT:
-                       return 0;
-               }
-       }
-       return -ENXIO;
-}
-
-struct kvm_device_ops kvm_arm_vgic_v3_ops = {
-       .name = "kvm-arm-vgic-v3",
-       .create = vgic_v3_create,
-       .destroy = vgic_v3_destroy,
-       .set_attr = vgic_v3_set_attr,
-       .get_attr = vgic_v3_get_attr,
-       .has_attr = vgic_v3_has_attr,
-};
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
deleted file mode 100644 (file)
index 75b02fa..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2013 ARM Limited, All Rights Reserved.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/cpu.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <linux/irqchip/arm-gic-v3.h>
-#include <linux/irqchip/arm-gic-common.h>
-
-#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_mmu.h>
-
-static u32 ich_vtr_el2;
-
-static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
-{
-       struct vgic_lr lr_desc;
-       u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
-
-       if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-               lr_desc.irq = val & ICH_LR_VIRTUAL_ID_MASK;
-       else
-               lr_desc.irq = val & GICH_LR_VIRTUALID;
-
-       lr_desc.source = 0;
-       if (lr_desc.irq <= 15 &&
-           vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
-               lr_desc.source = (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
-
-       lr_desc.state = 0;
-
-       if (val & ICH_LR_PENDING_BIT)
-               lr_desc.state |= LR_STATE_PENDING;
-       if (val & ICH_LR_ACTIVE_BIT)
-               lr_desc.state |= LR_STATE_ACTIVE;
-       if (val & ICH_LR_EOI)
-               lr_desc.state |= LR_EOI_INT;
-       if (val & ICH_LR_HW) {
-               lr_desc.state |= LR_HW;
-               lr_desc.hwirq = (val >> ICH_LR_PHYS_ID_SHIFT) & GENMASK(9, 0);
-       }
-
-       return lr_desc;
-}
-
-static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
-                          struct vgic_lr lr_desc)
-{
-       u64 lr_val;
-
-       lr_val = lr_desc.irq;
-
-       /*
-        * Currently all guest IRQs are Group1, as Group0 would result
-        * in a FIQ in the guest, which it wouldn't expect.
-        * Eventually we want to make this configurable, so we may revisit
-        * this in the future.
-        */
-       switch (vcpu->kvm->arch.vgic.vgic_model) {
-       case KVM_DEV_TYPE_ARM_VGIC_V3:
-               lr_val |= ICH_LR_GROUP;
-               break;
-       case  KVM_DEV_TYPE_ARM_VGIC_V2:
-               if (lr_desc.irq < VGIC_NR_SGIS)
-                       lr_val |= (u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT;
-               break;
-       default:
-               BUG();
-       }
-
-       if (lr_desc.state & LR_STATE_PENDING)
-               lr_val |= ICH_LR_PENDING_BIT;
-       if (lr_desc.state & LR_STATE_ACTIVE)
-               lr_val |= ICH_LR_ACTIVE_BIT;
-       if (lr_desc.state & LR_EOI_INT)
-               lr_val |= ICH_LR_EOI;
-       if (lr_desc.state & LR_HW) {
-               lr_val |= ICH_LR_HW;
-               lr_val |= ((u64)lr_desc.hwirq) << ICH_LR_PHYS_ID_SHIFT;
-       }
-
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = lr_val;
-
-       if (!(lr_desc.state & LR_STATE_MASK))
-               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
-       else
-               vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr &= ~(1U << lr);
-}
-
-static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr;
-}
-
-static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
-}
-
-static void vgic_v3_clear_eisr(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr = 0;
-}
-
-static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
-{
-       u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
-       u32 ret = 0;
-
-       if (misr & ICH_MISR_EOI)
-               ret |= INT_STATUS_EOI;
-       if (misr & ICH_MISR_U)
-               ret |= INT_STATUS_UNDERFLOW;
-
-       return ret;
-}
-
-static void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
-{
-       u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
-
-       vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
-       vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
-       vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
-       vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
-}
-
-static void vgic_v3_enable_underflow(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr |= ICH_HCR_UIE;
-}
-
-static void vgic_v3_disable_underflow(struct kvm_vcpu *vcpu)
-{
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &= ~ICH_HCR_UIE;
-}
-
-static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
-{
-       u32 vmcr;
-
-       vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
-       vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
-       vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
-       vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
-
-       vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
-}
-
-static void vgic_v3_enable(struct kvm_vcpu *vcpu)
-{
-       struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
-
-       /*
-        * By forcing VMCR to zero, the GIC will restore the binary
-        * points to their reset values. Anything else resets to zero
-        * anyway.
-        */
-       vgic_v3->vgic_vmcr = 0;
-       vgic_v3->vgic_elrsr = ~0;
-
-       /*
-        * If we are emulating a GICv3, we do it in an non-GICv2-compatible
-        * way, so we force SRE to 1 to demonstrate this to the guest.
-        * This goes with the spec allowing the value to be RAO/WI.
-        */
-       if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-               vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
-       else
-               vgic_v3->vgic_sre = 0;
-
-       /* Get the show on the road... */
-       vgic_v3->vgic_hcr = ICH_HCR_EN;
-}
-
-static const struct vgic_ops vgic_v3_ops = {
-       .get_lr                 = vgic_v3_get_lr,
-       .set_lr                 = vgic_v3_set_lr,
-       .get_elrsr              = vgic_v3_get_elrsr,
-       .get_eisr               = vgic_v3_get_eisr,
-       .clear_eisr             = vgic_v3_clear_eisr,
-       .get_interrupt_status   = vgic_v3_get_interrupt_status,
-       .enable_underflow       = vgic_v3_enable_underflow,
-       .disable_underflow      = vgic_v3_disable_underflow,
-       .get_vmcr               = vgic_v3_get_vmcr,
-       .set_vmcr               = vgic_v3_set_vmcr,
-       .enable                 = vgic_v3_enable,
-};
-
-static struct vgic_params vgic_v3_params;
-
-static void vgic_cpu_init_lrs(void *params)
-{
-       kvm_call_hyp(__vgic_v3_init_lrs);
-}
-
-/**
- * vgic_v3_probe - probe for a GICv3 compatible interrupt controller
- * @gic_kvm_info:      pointer to the GIC description
- * @ops:               address of a pointer to the GICv3 operations
- * @params:            address of a pointer to HW-specific parameters
- *
- * Returns 0 if a GICv3 has been found, with the low level operations
- * in *ops and the HW parameters in *params. Returns an error code
- * otherwise.
- */
-int vgic_v3_probe(const struct gic_kvm_info *gic_kvm_info,
-                 const struct vgic_ops **ops,
-                 const struct vgic_params **params)
-{
-       int ret = 0;
-       struct vgic_params *vgic = &vgic_v3_params;
-       const struct resource *vcpu_res = &gic_kvm_info->vcpu;
-
-       vgic->maint_irq = gic_kvm_info->maint_irq;
-
-       ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
-
-       /*
-        * The ListRegs field is 5 bits, but there is a architectural
-        * maximum of 16 list registers. Just ignore bit 4...
-        */
-       vgic->nr_lr = (ich_vtr_el2 & 0xf) + 1;
-       vgic->can_emulate_gicv2 = false;
-
-       if (!vcpu_res->start) {
-               kvm_info("GICv3: no GICV resource entry\n");
-               vgic->vcpu_base = 0;
-       } else if (!PAGE_ALIGNED(vcpu_res->start)) {
-               pr_warn("GICV physical address 0x%llx not page aligned\n",
-                       (unsigned long long)vcpu_res->start);
-               vgic->vcpu_base = 0;
-       } else if (!PAGE_ALIGNED(resource_size(vcpu_res))) {
-               pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
-                       (unsigned long long)resource_size(vcpu_res),
-                       PAGE_SIZE);
-       } else {
-               vgic->vcpu_base = vcpu_res->start;
-               vgic->can_emulate_gicv2 = true;
-               kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
-                                       KVM_DEV_TYPE_ARM_VGIC_V2);
-       }
-       if (vgic->vcpu_base == 0)
-               kvm_info("disabling GICv2 emulation\n");
-       kvm_register_device_ops(&kvm_arm_vgic_v3_ops, KVM_DEV_TYPE_ARM_VGIC_V3);
-
-       vgic->vctrl_base = NULL;
-       vgic->type = VGIC_V3;
-       vgic->max_gic_vcpus = VGIC_V3_MAX_CPUS;
-
-       kvm_info("GICV base=0x%llx, IRQ=%d\n",
-                vgic->vcpu_base, vgic->maint_irq);
-
-       on_each_cpu(vgic_cpu_init_lrs, vgic, 1);
-
-       *ops = &vgic_v3_ops;
-       *params = vgic;
-
-       return ret;
-}
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
deleted file mode 100644 (file)
index 67cb5e9..0000000
+++ /dev/null
@@ -1,2417 +0,0 @@
-/*
- * Copyright (C) 2012 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/cpu.h>
-#include <linux/kvm.h>
-#include <linux/kvm_host.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/rculist.h>
-#include <linux/uaccess.h>
-
-#include <asm/kvm_emulate.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-#include <trace/events/kvm.h>
-#include <asm/kvm.h>
-#include <kvm/iodev.h>
-#include <linux/irqchip/arm-gic-common.h>
-
-#define CREATE_TRACE_POINTS
-#include "trace.h"
-
-/*
- * How the whole thing works (courtesy of Christoffer Dall):
- *
- * - At any time, the dist->irq_pending_on_cpu is the oracle that knows if
- *   something is pending on the CPU interface.
- * - Interrupts that are pending on the distributor are stored on the
- *   vgic.irq_pending vgic bitmap (this bitmap is updated by both user land
- *   ioctls and guest mmio ops, and other in-kernel peripherals such as the
- *   arch. timers).
- * - Every time the bitmap changes, the irq_pending_on_cpu oracle is
- *   recalculated
- * - To calculate the oracle, we need info for each cpu from
- *   compute_pending_for_cpu, which considers:
- *   - PPI: dist->irq_pending & dist->irq_enable
- *   - SPI: dist->irq_pending & dist->irq_enable & dist->irq_spi_target
- *   - irq_spi_target is a 'formatted' version of the GICD_ITARGETSRn
- *     registers, stored on each vcpu. We only keep one bit of
- *     information per interrupt, making sure that only one vcpu can
- *     accept the interrupt.
- * - If any of the above state changes, we must recalculate the oracle.
- * - The same is true when injecting an interrupt, except that we only
- *   consider a single interrupt at a time. The irq_spi_cpu array
- *   contains the target CPU for each SPI.
- *
- * The handling of level interrupts adds some extra complexity. We
- * need to track when the interrupt has been EOIed, so we can sample
- * the 'line' again. This is achieved as such:
- *
- * - When a level interrupt is moved onto a vcpu, the corresponding
- *   bit in irq_queued is set. As long as this bit is set, the line
- *   will be ignored for further interrupts. The interrupt is injected
- *   into the vcpu with the GICH_LR_EOI bit set (generate a
- *   maintenance interrupt on EOI).
- * - When the interrupt is EOIed, the maintenance interrupt fires,
- *   and clears the corresponding bit in irq_queued. This allows the
- *   interrupt line to be sampled again.
- * - Note that level-triggered interrupts can also be set to pending from
- *   writes to GICD_ISPENDRn and lowering the external input line does not
- *   cause the interrupt to become inactive in such a situation.
- *   Conversely, writes to GICD_ICPENDRn do not cause the interrupt to become
- *   inactive as long as the external input line is held high.
- *
- *
- * Initialization rules: there are multiple stages to the vgic
- * initialization, both for the distributor and the CPU interfaces.
- *
- * Distributor:
- *
- * - kvm_vgic_early_init(): initialization of static data that doesn't
- *   depend on any sizing information or emulation type. No allocation
- *   is allowed there.
- *
- * - vgic_init(): allocation and initialization of the generic data
- *   structures that depend on sizing information (number of CPUs,
- *   number of interrupts). Also initializes the vcpu specific data
- *   structures. Can be executed lazily for GICv2.
- *   [to be renamed to kvm_vgic_init??]
- *
- * CPU Interface:
- *
- * - kvm_vgic_cpu_early_init(): initialization of static data that
- *   doesn't depend on any sizing information or emulation type. No
- *   allocation is allowed there.
- */
-
-#include "vgic.h"
-
-static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu);
-static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu);
-static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr);
-static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, struct vgic_lr lr_desc);
-static u64 vgic_get_elrsr(struct kvm_vcpu *vcpu);
-static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
-                                               int virt_irq);
-static int compute_pending_for_cpu(struct kvm_vcpu *vcpu);
-
-static const struct vgic_ops *vgic_ops;
-static const struct vgic_params *vgic;
-
-static void add_sgi_source(struct kvm_vcpu *vcpu, int irq, int source)
-{
-       vcpu->kvm->arch.vgic.vm_ops.add_sgi_source(vcpu, irq, source);
-}
-
-static bool queue_sgi(struct kvm_vcpu *vcpu, int irq)
-{
-       return vcpu->kvm->arch.vgic.vm_ops.queue_sgi(vcpu, irq);
-}
-
-int kvm_vgic_map_resources(struct kvm *kvm)
-{
-       return kvm->arch.vgic.vm_ops.map_resources(kvm, vgic);
-}
-
-/*
- * struct vgic_bitmap contains a bitmap made of unsigned longs, but
- * extracts u32s out of them.
- *
- * This does not work on 64-bit BE systems, because the bitmap access
- * will store two consecutive 32-bit words with the higher-addressed
- * register's bits at the lower index and the lower-addressed register's
- * bits at the higher index.
- *
- * Therefore, swizzle the register index when accessing the 32-bit word
- * registers to access the right register's value.
- */
-#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 64
-#define REG_OFFSET_SWIZZLE     1
-#else
-#define REG_OFFSET_SWIZZLE     0
-#endif
-
-static int vgic_init_bitmap(struct vgic_bitmap *b, int nr_cpus, int nr_irqs)
-{
-       int nr_longs;
-
-       nr_longs = nr_cpus + BITS_TO_LONGS(nr_irqs - VGIC_NR_PRIVATE_IRQS);
-
-       b->private = kzalloc(sizeof(unsigned long) * nr_longs, GFP_KERNEL);
-       if (!b->private)
-               return -ENOMEM;
-
-       b->shared = b->private + nr_cpus;
-
-       return 0;
-}
-
-static void vgic_free_bitmap(struct vgic_bitmap *b)
-{
-       kfree(b->private);
-       b->private = NULL;
-       b->shared = NULL;
-}
-
-/*
- * Call this function to convert a u64 value to an unsigned long * bitmask
- * in a way that works on both 32-bit and 64-bit LE and BE platforms.
- *
- * Warning: Calling this function may modify *val.
- */
-static unsigned long *u64_to_bitmask(u64 *val)
-{
-#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
-       *val = (*val >> 32) | (*val << 32);
-#endif
-       return (unsigned long *)val;
-}
-
-u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x, int cpuid, u32 offset)
-{
-       offset >>= 2;
-       if (!offset)
-               return (u32 *)(x->private + cpuid) + REG_OFFSET_SWIZZLE;
-       else
-               return (u32 *)(x->shared) + ((offset - 1) ^ REG_OFFSET_SWIZZLE);
-}
-
-static int vgic_bitmap_get_irq_val(struct vgic_bitmap *x,
-                                  int cpuid, int irq)
-{
-       if (irq < VGIC_NR_PRIVATE_IRQS)
-               return test_bit(irq, x->private + cpuid);
-
-       return test_bit(irq - VGIC_NR_PRIVATE_IRQS, x->shared);
-}
-
-void vgic_bitmap_set_irq_val(struct vgic_bitmap *x, int cpuid,
-                            int irq, int val)
-{
-       unsigned long *reg;
-
-       if (irq < VGIC_NR_PRIVATE_IRQS) {
-               reg = x->private + cpuid;
-       } else {
-               reg = x->shared;
-               irq -= VGIC_NR_PRIVATE_IRQS;
-       }
-
-       if (val)
-               set_bit(irq, reg);
-       else
-               clear_bit(irq, reg);
-}
-
-static unsigned long *vgic_bitmap_get_cpu_map(struct vgic_bitmap *x, int cpuid)
-{
-       return x->private + cpuid;
-}
-
-unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x)
-{
-       return x->shared;
-}
-
-static int vgic_init_bytemap(struct vgic_bytemap *x, int nr_cpus, int nr_irqs)
-{
-       int size;
-
-       size  = nr_cpus * VGIC_NR_PRIVATE_IRQS;
-       size += nr_irqs - VGIC_NR_PRIVATE_IRQS;
-
-       x->private = kzalloc(size, GFP_KERNEL);
-       if (!x->private)
-               return -ENOMEM;
-
-       x->shared = x->private + nr_cpus * VGIC_NR_PRIVATE_IRQS / sizeof(u32);
-       return 0;
-}
-
-static void vgic_free_bytemap(struct vgic_bytemap *b)
-{
-       kfree(b->private);
-       b->private = NULL;
-       b->shared = NULL;
-}
-
-u32 *vgic_bytemap_get_reg(struct vgic_bytemap *x, int cpuid, u32 offset)
-{
-       u32 *reg;
-
-       if (offset < VGIC_NR_PRIVATE_IRQS) {
-               reg = x->private;
-               offset += cpuid * VGIC_NR_PRIVATE_IRQS;
-       } else {
-               reg = x->shared;
-               offset -= VGIC_NR_PRIVATE_IRQS;
-       }
-
-       return reg + (offset / sizeof(u32));
-}
-
-#define VGIC_CFG_LEVEL 0
-#define VGIC_CFG_EDGE  1
-
-static bool vgic_irq_is_edge(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       int irq_val;
-
-       irq_val = vgic_bitmap_get_irq_val(&dist->irq_cfg, vcpu->vcpu_id, irq);
-       return irq_val == VGIC_CFG_EDGE;
-}
-
-static int vgic_irq_is_enabled(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_enabled, vcpu->vcpu_id, irq);
-}
-
-static int vgic_irq_is_queued(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_queued, vcpu->vcpu_id, irq);
-}
-
-static int vgic_irq_is_active(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_active, vcpu->vcpu_id, irq);
-}
-
-static void vgic_irq_set_queued(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_queued, vcpu->vcpu_id, irq, 1);
-}
-
-static void vgic_irq_clear_queued(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_queued, vcpu->vcpu_id, irq, 0);
-}
-
-static void vgic_irq_set_active(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 1);
-}
-
-static void vgic_irq_clear_active(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_active, vcpu->vcpu_id, irq, 0);
-}
-
-static int vgic_dist_irq_get_level(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_level, vcpu->vcpu_id, irq);
-}
-
-static void vgic_dist_irq_set_level(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_level, vcpu->vcpu_id, irq, 1);
-}
-
-static void vgic_dist_irq_clear_level(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_level, vcpu->vcpu_id, irq, 0);
-}
-
-static int vgic_dist_irq_soft_pend(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_soft_pend, vcpu->vcpu_id, irq);
-}
-
-static void vgic_dist_irq_clear_soft_pend(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_soft_pend, vcpu->vcpu_id, irq, 0);
-       if (!vgic_dist_irq_get_level(vcpu, irq)) {
-               vgic_dist_irq_clear_pending(vcpu, irq);
-               if (!compute_pending_for_cpu(vcpu))
-                       clear_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
-       }
-}
-
-static int vgic_dist_irq_is_pending(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return vgic_bitmap_get_irq_val(&dist->irq_pending, vcpu->vcpu_id, irq);
-}
-
-void vgic_dist_irq_set_pending(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_pending, vcpu->vcpu_id, irq, 1);
-}
-
-void vgic_dist_irq_clear_pending(struct kvm_vcpu *vcpu, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       vgic_bitmap_set_irq_val(&dist->irq_pending, vcpu->vcpu_id, irq, 0);
-}
-
-static void vgic_cpu_irq_set(struct kvm_vcpu *vcpu, int irq)
-{
-       if (irq < VGIC_NR_PRIVATE_IRQS)
-               set_bit(irq, vcpu->arch.vgic_cpu.pending_percpu);
-       else
-               set_bit(irq - VGIC_NR_PRIVATE_IRQS,
-                       vcpu->arch.vgic_cpu.pending_shared);
-}
-
-void vgic_cpu_irq_clear(struct kvm_vcpu *vcpu, int irq)
-{
-       if (irq < VGIC_NR_PRIVATE_IRQS)
-               clear_bit(irq, vcpu->arch.vgic_cpu.pending_percpu);
-       else
-               clear_bit(irq - VGIC_NR_PRIVATE_IRQS,
-                         vcpu->arch.vgic_cpu.pending_shared);
-}
-
-static bool vgic_can_sample_irq(struct kvm_vcpu *vcpu, int irq)
-{
-       return !vgic_irq_is_queued(vcpu, irq);
-}
-
-/**
- * vgic_reg_access - access vgic register
- * @mmio:   pointer to the data describing the mmio access
- * @reg:    pointer to the virtual backing of vgic distributor data
- * @offset: least significant 2 bits used for word offset
- * @mode:   ACCESS_ mode (see defines above)
- *
- * Helper to make vgic register access easier using one of the access
- * modes defined for vgic register access
- * (read,raz,write-ignored,setbit,clearbit,write)
- */
-void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
-                    phys_addr_t offset, int mode)
-{
-       int word_offset = (offset & 3) * 8;
-       u32 mask = (1UL << (mmio->len * 8)) - 1;
-       u32 regval;
-
-       /*
-        * Any alignment fault should have been delivered to the guest
-        * directly (ARM ARM B3.12.7 "Prioritization of aborts").
-        */
-
-       if (reg) {
-               regval = *reg;
-       } else {
-               BUG_ON(mode != (ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED));
-               regval = 0;
-       }
-
-       if (mmio->is_write) {
-               u32 data = mmio_data_read(mmio, mask) << word_offset;
-               switch (ACCESS_WRITE_MASK(mode)) {
-               case ACCESS_WRITE_IGNORED:
-                       return;
-
-               case ACCESS_WRITE_SETBIT:
-                       regval |= data;
-                       break;
-
-               case ACCESS_WRITE_CLEARBIT:
-                       regval &= ~data;
-                       break;
-
-               case ACCESS_WRITE_VALUE:
-                       regval = (regval & ~(mask << word_offset)) | data;
-                       break;
-               }
-               *reg = regval;
-       } else {
-               switch (ACCESS_READ_MASK(mode)) {
-               case ACCESS_READ_RAZ:
-                       regval = 0;
-                       /* fall through */
-
-               case ACCESS_READ_VALUE:
-                       mmio_data_write(mmio, mask, regval >> word_offset);
-               }
-       }
-}
-
-bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
-                       phys_addr_t offset)
-{
-       vgic_reg_access(mmio, NULL, offset,
-                       ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED);
-       return false;
-}
-
-bool vgic_handle_enable_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio,
-                           phys_addr_t offset, int vcpu_id, int access)
-{
-       u32 *reg;
-       int mode = ACCESS_READ_VALUE | access;
-       struct kvm_vcpu *target_vcpu = kvm_get_vcpu(kvm, vcpu_id);
-
-       reg = vgic_bitmap_get_reg(&kvm->arch.vgic.irq_enabled, vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset, mode);
-       if (mmio->is_write) {
-               if (access & ACCESS_WRITE_CLEARBIT) {
-                       if (offset < 4) /* Force SGI enabled */
-                               *reg |= 0xffff;
-                       vgic_retire_disabled_irqs(target_vcpu);
-               }
-               vgic_update_state(kvm);
-               return true;
-       }
-
-       return false;
-}
-
-bool vgic_handle_set_pending_reg(struct kvm *kvm,
-                                struct kvm_exit_mmio *mmio,
-                                phys_addr_t offset, int vcpu_id)
-{
-       u32 *reg, orig;
-       u32 level_mask;
-       int mode = ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       reg = vgic_bitmap_get_reg(&dist->irq_cfg, vcpu_id, offset);
-       level_mask = (~(*reg));
-
-       /* Mark both level and edge triggered irqs as pending */
-       reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu_id, offset);
-       orig = *reg;
-       vgic_reg_access(mmio, reg, offset, mode);
-
-       if (mmio->is_write) {
-               /* Set the soft-pending flag only for level-triggered irqs */
-               reg = vgic_bitmap_get_reg(&dist->irq_soft_pend,
-                                         vcpu_id, offset);
-               vgic_reg_access(mmio, reg, offset, mode);
-               *reg &= level_mask;
-
-               /* Ignore writes to SGIs */
-               if (offset < 2) {
-                       *reg &= ~0xffff;
-                       *reg |= orig & 0xffff;
-               }
-
-               vgic_update_state(kvm);
-               return true;
-       }
-
-       return false;
-}
-
-bool vgic_handle_clear_pending_reg(struct kvm *kvm,
-                                  struct kvm_exit_mmio *mmio,
-                                  phys_addr_t offset, int vcpu_id)
-{
-       u32 *level_active;
-       u32 *reg, orig;
-       int mode = ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu_id, offset);
-       orig = *reg;
-       vgic_reg_access(mmio, reg, offset, mode);
-       if (mmio->is_write) {
-               /* Re-set level triggered level-active interrupts */
-               level_active = vgic_bitmap_get_reg(&dist->irq_level,
-                                         vcpu_id, offset);
-               reg = vgic_bitmap_get_reg(&dist->irq_pending, vcpu_id, offset);
-               *reg |= *level_active;
-
-               /* Ignore writes to SGIs */
-               if (offset < 2) {
-                       *reg &= ~0xffff;
-                       *reg |= orig & 0xffff;
-               }
-
-               /* Clear soft-pending flags */
-               reg = vgic_bitmap_get_reg(&dist->irq_soft_pend,
-                                         vcpu_id, offset);
-               vgic_reg_access(mmio, reg, offset, mode);
-
-               vgic_update_state(kvm);
-               return true;
-       }
-       return false;
-}
-
-bool vgic_handle_set_active_reg(struct kvm *kvm,
-                               struct kvm_exit_mmio *mmio,
-                               phys_addr_t offset, int vcpu_id)
-{
-       u32 *reg;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       reg = vgic_bitmap_get_reg(&dist->irq_active, vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT);
-
-       if (mmio->is_write) {
-               vgic_update_state(kvm);
-               return true;
-       }
-
-       return false;
-}
-
-bool vgic_handle_clear_active_reg(struct kvm *kvm,
-                                 struct kvm_exit_mmio *mmio,
-                                 phys_addr_t offset, int vcpu_id)
-{
-       u32 *reg;
-       struct vgic_dist *dist = &kvm->arch.vgic;
-
-       reg = vgic_bitmap_get_reg(&dist->irq_active, vcpu_id, offset);
-       vgic_reg_access(mmio, reg, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT);
-
-       if (mmio->is_write) {
-               vgic_update_state(kvm);
-               return true;
-       }
-
-       return false;
-}
-
-static u32 vgic_cfg_expand(u16 val)
-{
-       u32 res = 0;
-       int i;
-
-       /*
-        * Turn a 16bit value like abcd...mnop into a 32bit word
-        * a0b0c0d0...m0n0o0p0, which is what the HW cfg register is.
-        */
-       for (i = 0; i < 16; i++)
-               res |= ((val >> i) & VGIC_CFG_EDGE) << (2 * i + 1);
-
-       return res;
-}
-
-static u16 vgic_cfg_compress(u32 val)
-{
-       u16 res = 0;
-       int i;
-
-       /*
-        * Turn a 32bit word a0b0c0d0...m0n0o0p0 into 16bit value like
-        * abcd...mnop which is what we really care about.
-        */
-       for (i = 0; i < 16; i++)
-               res |= ((val >> (i * 2 + 1)) & VGIC_CFG_EDGE) << i;
-
-       return res;
-}
-
-/*
- * The distributor uses 2 bits per IRQ for the CFG register, but the
- * LSB is always 0. As such, we only keep the upper bit, and use the
- * two above functions to compress/expand the bits
- */
-bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
-                        phys_addr_t offset)
-{
-       u32 val;
-
-       if (offset & 4)
-               val = *reg >> 16;
-       else
-               val = *reg & 0xffff;
-
-       val = vgic_cfg_expand(val);
-       vgic_reg_access(mmio, &val, offset,
-                       ACCESS_READ_VALUE | ACCESS_WRITE_VALUE);
-       if (mmio->is_write) {
-               /* Ignore writes to read-only SGI and PPI bits */
-               if (offset < 8)
-                       return false;
-
-               val = vgic_cfg_compress(val);
-               if (offset & 4) {
-                       *reg &= 0xffff;
-                       *reg |= val << 16;
-               } else {
-                       *reg &= 0xffff << 16;
-                       *reg |= val;
-               }
-       }
-
-       return false;
-}
-
-/**
- * vgic_unqueue_irqs - move pending/active IRQs from LRs to the distributor
- * @vgic_cpu: Pointer to the vgic_cpu struct holding the LRs
- *
- * Move any IRQs that have already been assigned to LRs back to the
- * emulated distributor state so that the complete emulated state can be read
- * from the main emulation structures without investigating the LRs.
- */
-void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
-{
-       u64 elrsr = vgic_get_elrsr(vcpu);
-       unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
-       int i;
-
-       for_each_clear_bit(i, elrsr_ptr, vgic->nr_lr) {
-               struct vgic_lr lr = vgic_get_lr(vcpu, i);
-
-               /*
-                * There are three options for the state bits:
-                *
-                * 01: pending
-                * 10: active
-                * 11: pending and active
-                */
-               BUG_ON(!(lr.state & LR_STATE_MASK));
-
-               /* Reestablish SGI source for pending and active IRQs */
-               if (lr.irq < VGIC_NR_SGIS)
-                       add_sgi_source(vcpu, lr.irq, lr.source);
-
-               /*
-                * If the LR holds an active (10) or a pending and active (11)
-                * interrupt then move the active state to the
-                * distributor tracking bit.
-                */
-               if (lr.state & LR_STATE_ACTIVE)
-                       vgic_irq_set_active(vcpu, lr.irq);
-
-               /*
-                * Reestablish the pending state on the distributor and the
-                * CPU interface and mark the LR as free for other use.
-                */
-               vgic_retire_lr(i, vcpu);
-
-               /* Finally update the VGIC state. */
-               vgic_update_state(vcpu->kvm);
-       }
-}
-
-const
-struct vgic_io_range *vgic_find_range(const struct vgic_io_range *ranges,
-                                     int len, gpa_t offset)
-{
-       while (ranges->len) {
-               if (offset >= ranges->base &&
-                   (offset + len) <= (ranges->base + ranges->len))
-                       return ranges;
-               ranges++;
-       }
-
-       return NULL;
-}
-
-static bool vgic_validate_access(const struct vgic_dist *dist,
-                                const struct vgic_io_range *range,
-                                unsigned long offset)
-{
-       int irq;
-
-       if (!range->bits_per_irq)
-               return true;    /* Not an irq-based access */
-
-       irq = offset * 8 / range->bits_per_irq;
-       if (irq >= dist->nr_irqs)
-               return false;
-
-       return true;
-}
-
-/*
- * Call the respective handler function for the given range.
- * We split up any 64 bit accesses into two consecutive 32 bit
- * handler calls and merge the result afterwards.
- * We do this in a little endian fashion regardless of the host's
- * or guest's endianness, because the GIC is always LE and the rest of
- * the code (vgic_reg_access) also puts it in a LE fashion already.
- * At this point we have already identified the handle function, so
- * range points to that one entry and offset is relative to this.
- */
-static bool call_range_handler(struct kvm_vcpu *vcpu,
-                              struct kvm_exit_mmio *mmio,
-                              unsigned long offset,
-                              const struct vgic_io_range *range)
-{
-       struct kvm_exit_mmio mmio32;
-       bool ret;
-
-       if (likely(mmio->len <= 4))
-               return range->handle_mmio(vcpu, mmio, offset);
-
-       /*
-        * Any access bigger than 4 bytes (that we currently handle in KVM)
-        * is actually 8 bytes long, caused by a 64-bit access
-        */
-
-       mmio32.len = 4;
-       mmio32.is_write = mmio->is_write;
-       mmio32.private = mmio->private;
-
-       mmio32.phys_addr = mmio->phys_addr + 4;
-       mmio32.data = &((u32 *)mmio->data)[1];
-       ret = range->handle_mmio(vcpu, &mmio32, offset + 4);
-
-       mmio32.phys_addr = mmio->phys_addr;
-       mmio32.data = &((u32 *)mmio->data)[0];
-       ret |= range->handle_mmio(vcpu, &mmio32, offset);
-
-       return ret;
-}
-
-/**
- * vgic_handle_mmio_access - handle an in-kernel MMIO access
- * This is called by the read/write KVM IO device wrappers below.
- * @vcpu:      pointer to the vcpu performing the access
- * @this:      pointer to the KVM IO device in charge
- * @addr:      guest physical address of the access
- * @len:       size of the access
- * @val:       pointer to the data region
- * @is_write:  read or write access
- *
- * returns true if the MMIO access could be performed
- */
-static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
-                                  struct kvm_io_device *this, gpa_t addr,
-                                  int len, void *val, bool is_write)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       struct vgic_io_device *iodev = container_of(this,
-                                                   struct vgic_io_device, dev);
-       const struct vgic_io_range *range;
-       struct kvm_exit_mmio mmio;
-       bool updated_state;
-       gpa_t offset;
-
-       offset = addr - iodev->addr;
-       range = vgic_find_range(iodev->reg_ranges, len, offset);
-       if (unlikely(!range || !range->handle_mmio)) {
-               pr_warn("Unhandled access %d %08llx %d\n", is_write, addr, len);
-               return -ENXIO;
-       }
-
-       mmio.phys_addr = addr;
-       mmio.len = len;
-       mmio.is_write = is_write;
-       mmio.data = val;
-       mmio.private = iodev->redist_vcpu;
-
-       spin_lock(&dist->lock);
-       offset -= range->base;
-       if (vgic_validate_access(dist, range, offset)) {
-               updated_state = call_range_handler(vcpu, &mmio, offset, range);
-       } else {
-               if (!is_write)
-                       memset(val, 0, len);
-               updated_state = false;
-       }
-       spin_unlock(&dist->lock);
-
-       if (updated_state)
-               vgic_kick_vcpus(vcpu->kvm);
-
-       return 0;
-}
-
-static int vgic_handle_mmio_read(struct kvm_vcpu *vcpu,
-                                struct kvm_io_device *this,
-                                gpa_t addr, int len, void *val)
-{
-       return vgic_handle_mmio_access(vcpu, this, addr, len, val, false);
-}
-
-static int vgic_handle_mmio_write(struct kvm_vcpu *vcpu,
-                                 struct kvm_io_device *this,
-                                 gpa_t addr, int len, const void *val)
-{
-       return vgic_handle_mmio_access(vcpu, this, addr, len, (void *)val,
-                                      true);
-}
-
-static struct kvm_io_device_ops vgic_io_ops = {
-       .read   = vgic_handle_mmio_read,
-       .write  = vgic_handle_mmio_write,
-};
-
-/**
- * vgic_register_kvm_io_dev - register VGIC register frame on the KVM I/O bus
- * @kvm:            The VM structure pointer
- * @base:           The (guest) base address for the register frame
- * @len:            Length of the register frame window
- * @ranges:         Describing the handler functions for each register
- * @redist_vcpu_id: The VCPU ID to pass on to the handlers on call
- * @iodev:          Points to memory to be passed on to the handler
- *
- * @iodev stores the parameters of this function to be usable by the handler
- * respectively the dispatcher function (since the KVM I/O bus framework lacks
- * an opaque parameter). Initialization is done in this function, but the
- * reference should be valid and unique for the whole VGIC lifetime.
- * If the register frame is not mapped for a specific VCPU, pass -1 to
- * @redist_vcpu_id.
- */
-int vgic_register_kvm_io_dev(struct kvm *kvm, gpa_t base, int len,
-                            const struct vgic_io_range *ranges,
-                            int redist_vcpu_id,
-                            struct vgic_io_device *iodev)
-{
-       struct kvm_vcpu *vcpu = NULL;
-       int ret;
-
-       if (redist_vcpu_id >= 0)
-               vcpu = kvm_get_vcpu(kvm, redist_vcpu_id);
-
-       iodev->addr             = base;
-       iodev->len              = len;
-       iodev->reg_ranges       = ranges;
-       iodev->redist_vcpu      = vcpu;
-
-       kvm_iodevice_init(&iodev->dev, &vgic_io_ops);
-
-       mutex_lock(&kvm->slots_lock);
-
-       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, base, len,
-                                     &iodev->dev);
-       mutex_unlock(&kvm->slots_lock);
-
-       /* Mark the iodev as invalid if registration fails. */
-       if (ret)
-               iodev->dev.ops = NULL;
-
-       return ret;
-}
-
-static int vgic_nr_shared_irqs(struct vgic_dist *dist)
-{
-       return dist->nr_irqs - VGIC_NR_PRIVATE_IRQS;
-}
-
-static int compute_active_for_cpu(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       unsigned long *active, *enabled, *act_percpu, *act_shared;
-       unsigned long active_private, active_shared;
-       int nr_shared = vgic_nr_shared_irqs(dist);
-       int vcpu_id;
-
-       vcpu_id = vcpu->vcpu_id;
-       act_percpu = vcpu->arch.vgic_cpu.active_percpu;
-       act_shared = vcpu->arch.vgic_cpu.active_shared;
-
-       active = vgic_bitmap_get_cpu_map(&dist->irq_active, vcpu_id);
-       enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
-       bitmap_and(act_percpu, active, enabled, VGIC_NR_PRIVATE_IRQS);
-
-       active = vgic_bitmap_get_shared_map(&dist->irq_active);
-       enabled = vgic_bitmap_get_shared_map(&dist->irq_enabled);
-       bitmap_and(act_shared, active, enabled, nr_shared);
-       bitmap_and(act_shared, act_shared,
-                  vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]),
-                  nr_shared);
-
-       active_private = find_first_bit(act_percpu, VGIC_NR_PRIVATE_IRQS);
-       active_shared = find_first_bit(act_shared, nr_shared);
-
-       return (active_private < VGIC_NR_PRIVATE_IRQS ||
-               active_shared < nr_shared);
-}
-
-static int compute_pending_for_cpu(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       unsigned long *pending, *enabled, *pend_percpu, *pend_shared;
-       unsigned long pending_private, pending_shared;
-       int nr_shared = vgic_nr_shared_irqs(dist);
-       int vcpu_id;
-
-       vcpu_id = vcpu->vcpu_id;
-       pend_percpu = vcpu->arch.vgic_cpu.pending_percpu;
-       pend_shared = vcpu->arch.vgic_cpu.pending_shared;
-
-       if (!dist->enabled) {
-               bitmap_zero(pend_percpu, VGIC_NR_PRIVATE_IRQS);
-               bitmap_zero(pend_shared, nr_shared);
-               return 0;
-       }
-
-       pending = vgic_bitmap_get_cpu_map(&dist->irq_pending, vcpu_id);
-       enabled = vgic_bitmap_get_cpu_map(&dist->irq_enabled, vcpu_id);
-       bitmap_and(pend_percpu, pending, enabled, VGIC_NR_PRIVATE_IRQS);
-
-       pending = vgic_bitmap_get_shared_map(&dist->irq_pending);
-       enabled = vgic_bitmap_get_shared_map(&dist->irq_enabled);
-       bitmap_and(pend_shared, pending, enabled, nr_shared);
-       bitmap_and(pend_shared, pend_shared,
-                  vgic_bitmap_get_shared_map(&dist->irq_spi_target[vcpu_id]),
-                  nr_shared);
-
-       pending_private = find_first_bit(pend_percpu, VGIC_NR_PRIVATE_IRQS);
-       pending_shared = find_first_bit(pend_shared, nr_shared);
-       return (pending_private < VGIC_NR_PRIVATE_IRQS ||
-               pending_shared < vgic_nr_shared_irqs(dist));
-}
-
-/*
- * Update the interrupt state and determine which CPUs have pending
- * or active interrupts. Must be called with distributor lock held.
- */
-void vgic_update_state(struct kvm *kvm)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct kvm_vcpu *vcpu;
-       int c;
-
-       kvm_for_each_vcpu(c, vcpu, kvm) {
-               if (compute_pending_for_cpu(vcpu))
-                       set_bit(c, dist->irq_pending_on_cpu);
-
-               if (compute_active_for_cpu(vcpu))
-                       set_bit(c, dist->irq_active_on_cpu);
-               else
-                       clear_bit(c, dist->irq_active_on_cpu);
-       }
-}
-
-static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
-{
-       return vgic_ops->get_lr(vcpu, lr);
-}
-
-static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
-                              struct vgic_lr vlr)
-{
-       vgic_ops->set_lr(vcpu, lr, vlr);
-}
-
-static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
-{
-       return vgic_ops->get_elrsr(vcpu);
-}
-
-static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
-{
-       return vgic_ops->get_eisr(vcpu);
-}
-
-static inline void vgic_clear_eisr(struct kvm_vcpu *vcpu)
-{
-       vgic_ops->clear_eisr(vcpu);
-}
-
-static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
-{
-       return vgic_ops->get_interrupt_status(vcpu);
-}
-
-static inline void vgic_enable_underflow(struct kvm_vcpu *vcpu)
-{
-       vgic_ops->enable_underflow(vcpu);
-}
-
-static inline void vgic_disable_underflow(struct kvm_vcpu *vcpu)
-{
-       vgic_ops->disable_underflow(vcpu);
-}
-
-void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-       vgic_ops->get_vmcr(vcpu, vmcr);
-}
-
-void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-       vgic_ops->set_vmcr(vcpu, vmcr);
-}
-
-static inline void vgic_enable(struct kvm_vcpu *vcpu)
-{
-       vgic_ops->enable(vcpu);
-}
-
-static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu)
-{
-       struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
-
-       vgic_irq_clear_queued(vcpu, vlr.irq);
-
-       /*
-        * We must transfer the pending state back to the distributor before
-        * retiring the LR, otherwise we may loose edge-triggered interrupts.
-        */
-       if (vlr.state & LR_STATE_PENDING) {
-               vgic_dist_irq_set_pending(vcpu, vlr.irq);
-               vlr.hwirq = 0;
-       }
-
-       vlr.state = 0;
-       vgic_set_lr(vcpu, lr_nr, vlr);
-}
-
-static bool dist_active_irq(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
-}
-
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
-{
-       int i;
-
-       for (i = 0; i < vgic->nr_lr; i++) {
-               struct vgic_lr vlr = vgic_get_lr(vcpu, i);
-
-               if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
-                       return true;
-       }
-
-       return vgic_irq_is_active(vcpu, virt_irq);
-}
-
-/*
- * An interrupt may have been disabled after being made pending on the
- * CPU interface (the classic case is a timer running while we're
- * rebooting the guest - the interrupt would kick as soon as the CPU
- * interface gets enabled, with deadly consequences).
- *
- * The solution is to examine already active LRs, and check the
- * interrupt is still enabled. If not, just retire it.
- */
-static void vgic_retire_disabled_irqs(struct kvm_vcpu *vcpu)
-{
-       u64 elrsr = vgic_get_elrsr(vcpu);
-       unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
-       int lr;
-
-       for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
-               struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
-
-               if (!vgic_irq_is_enabled(vcpu, vlr.irq))
-                       vgic_retire_lr(lr, vcpu);
-       }
-}
-
-static void vgic_queue_irq_to_lr(struct kvm_vcpu *vcpu, int irq,
-                                int lr_nr, struct vgic_lr vlr)
-{
-       if (vgic_irq_is_active(vcpu, irq)) {
-               vlr.state |= LR_STATE_ACTIVE;
-               kvm_debug("Set active, clear distributor: 0x%x\n", vlr.state);
-               vgic_irq_clear_active(vcpu, irq);
-               vgic_update_state(vcpu->kvm);
-       } else {
-               WARN_ON(!vgic_dist_irq_is_pending(vcpu, irq));
-               vlr.state |= LR_STATE_PENDING;
-               kvm_debug("Set pending: 0x%x\n", vlr.state);
-       }
-
-       if (!vgic_irq_is_edge(vcpu, irq))
-               vlr.state |= LR_EOI_INT;
-
-       if (vlr.irq >= VGIC_NR_SGIS) {
-               struct irq_phys_map *map;
-               map = vgic_irq_map_search(vcpu, irq);
-
-               if (map) {
-                       vlr.hwirq = map->phys_irq;
-                       vlr.state |= LR_HW;
-                       vlr.state &= ~LR_EOI_INT;
-
-                       /*
-                        * Make sure we're not going to sample this
-                        * again, as a HW-backed interrupt cannot be
-                        * in the PENDING_ACTIVE stage.
-                        */
-                       vgic_irq_set_queued(vcpu, irq);
-               }
-       }
-
-       vgic_set_lr(vcpu, lr_nr, vlr);
-}
-
-/*
- * Queue an interrupt to a CPU virtual interface. Return true on success,
- * or false if it wasn't possible to queue it.
- * sgi_source must be zero for any non-SGI interrupts.
- */
-bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       u64 elrsr = vgic_get_elrsr(vcpu);
-       unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
-       struct vgic_lr vlr;
-       int lr;
-
-       /* Sanitize the input... */
-       BUG_ON(sgi_source_id & ~7);
-       BUG_ON(sgi_source_id && irq >= VGIC_NR_SGIS);
-       BUG_ON(irq >= dist->nr_irqs);
-
-       kvm_debug("Queue IRQ%d\n", irq);
-
-       /* Do we have an active interrupt for the same CPUID? */
-       for_each_clear_bit(lr, elrsr_ptr, vgic->nr_lr) {
-               vlr = vgic_get_lr(vcpu, lr);
-               if (vlr.irq == irq && vlr.source == sgi_source_id) {
-                       kvm_debug("LR%d piggyback for IRQ%d\n", lr, vlr.irq);
-                       vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
-                       return true;
-               }
-       }
-
-       /* Try to use another LR for this interrupt */
-       lr = find_first_bit(elrsr_ptr, vgic->nr_lr);
-       if (lr >= vgic->nr_lr)
-               return false;
-
-       kvm_debug("LR%d allocated for IRQ%d %x\n", lr, irq, sgi_source_id);
-
-       vlr.irq = irq;
-       vlr.source = sgi_source_id;
-       vlr.state = 0;
-       vgic_queue_irq_to_lr(vcpu, irq, lr, vlr);
-
-       return true;
-}
-
-static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
-{
-       if (!vgic_can_sample_irq(vcpu, irq))
-               return true; /* level interrupt, already queued */
-
-       if (vgic_queue_irq(vcpu, 0, irq)) {
-               if (vgic_irq_is_edge(vcpu, irq)) {
-                       vgic_dist_irq_clear_pending(vcpu, irq);
-                       vgic_cpu_irq_clear(vcpu, irq);
-               } else {
-                       vgic_irq_set_queued(vcpu, irq);
-               }
-
-               return true;
-       }
-
-       return false;
-}
-
-/*
- * Fill the list registers with pending interrupts before running the
- * guest.
- */
-static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
-{
-       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       unsigned long *pa_percpu, *pa_shared;
-       int i, vcpu_id;
-       int overflow = 0;
-       int nr_shared = vgic_nr_shared_irqs(dist);
-
-       vcpu_id = vcpu->vcpu_id;
-
-       pa_percpu = vcpu->arch.vgic_cpu.pend_act_percpu;
-       pa_shared = vcpu->arch.vgic_cpu.pend_act_shared;
-
-       bitmap_or(pa_percpu, vgic_cpu->pending_percpu, vgic_cpu->active_percpu,
-                 VGIC_NR_PRIVATE_IRQS);
-       bitmap_or(pa_shared, vgic_cpu->pending_shared, vgic_cpu->active_shared,
-                 nr_shared);
-       /*
-        * We may not have any pending interrupt, or the interrupts
-        * may have been serviced from another vcpu. In all cases,
-        * move along.
-        */
-       if (!kvm_vgic_vcpu_pending_irq(vcpu) && !dist_active_irq(vcpu))
-               goto epilog;
-
-       /* SGIs */
-       for_each_set_bit(i, pa_percpu, VGIC_NR_SGIS) {
-               if (!queue_sgi(vcpu, i))
-                       overflow = 1;
-       }
-
-       /* PPIs */
-       for_each_set_bit_from(i, pa_percpu, VGIC_NR_PRIVATE_IRQS) {
-               if (!vgic_queue_hwirq(vcpu, i))
-                       overflow = 1;
-       }
-
-       /* SPIs */
-       for_each_set_bit(i, pa_shared, nr_shared) {
-               if (!vgic_queue_hwirq(vcpu, i + VGIC_NR_PRIVATE_IRQS))
-                       overflow = 1;
-       }
-
-
-
-
-epilog:
-       if (overflow) {
-               vgic_enable_underflow(vcpu);
-       } else {
-               vgic_disable_underflow(vcpu);
-               /*
-                * We're about to run this VCPU, and we've consumed
-                * everything the distributor had in store for
-                * us. Claim we don't have anything pending. We'll
-                * adjust that if needed while exiting.
-                */
-               clear_bit(vcpu_id, dist->irq_pending_on_cpu);
-       }
-}
-
-static int process_queued_irq(struct kvm_vcpu *vcpu,
-                                  int lr, struct vgic_lr vlr)
-{
-       int pending = 0;
-
-       /*
-        * If the IRQ was EOIed (called from vgic_process_maintenance) or it
-        * went from active to non-active (called from vgic_sync_hwirq) it was
-        * also ACKed and we we therefore assume we can clear the soft pending
-        * state (should it had been set) for this interrupt.
-        *
-        * Note: if the IRQ soft pending state was set after the IRQ was
-        * acked, it actually shouldn't be cleared, but we have no way of
-        * knowing that unless we start trapping ACKs when the soft-pending
-        * state is set.
-        */
-       vgic_dist_irq_clear_soft_pend(vcpu, vlr.irq);
-
-       /*
-        * Tell the gic to start sampling this interrupt again.
-        */
-       vgic_irq_clear_queued(vcpu, vlr.irq);
-
-       /* Any additional pending interrupt? */
-       if (vgic_irq_is_edge(vcpu, vlr.irq)) {
-               BUG_ON(!(vlr.state & LR_HW));
-               pending = vgic_dist_irq_is_pending(vcpu, vlr.irq);
-       } else {
-               if (vgic_dist_irq_get_level(vcpu, vlr.irq)) {
-                       vgic_cpu_irq_set(vcpu, vlr.irq);
-                       pending = 1;
-               } else {
-                       vgic_dist_irq_clear_pending(vcpu, vlr.irq);
-                       vgic_cpu_irq_clear(vcpu, vlr.irq);
-               }
-       }
-
-       /*
-        * Despite being EOIed, the LR may not have
-        * been marked as empty.
-        */
-       vlr.state = 0;
-       vlr.hwirq = 0;
-       vgic_set_lr(vcpu, lr, vlr);
-
-       return pending;
-}
-
-static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
-{
-       u32 status = vgic_get_interrupt_status(vcpu);
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       struct kvm *kvm = vcpu->kvm;
-       int level_pending = 0;
-
-       kvm_debug("STATUS = %08x\n", status);
-
-       if (status & INT_STATUS_EOI) {
-               /*
-                * Some level interrupts have been EOIed. Clear their
-                * active bit.
-                */
-               u64 eisr = vgic_get_eisr(vcpu);
-               unsigned long *eisr_ptr = u64_to_bitmask(&eisr);
-               int lr;
-
-               for_each_set_bit(lr, eisr_ptr, vgic->nr_lr) {
-                       struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
-
-                       WARN_ON(vgic_irq_is_edge(vcpu, vlr.irq));
-                       WARN_ON(vlr.state & LR_STATE_MASK);
-
-
-                       /*
-                        * kvm_notify_acked_irq calls kvm_set_irq()
-                        * to reset the IRQ level, which grabs the dist->lock
-                        * so we call this before taking the dist->lock.
-                        */
-                       kvm_notify_acked_irq(kvm, 0,
-                                            vlr.irq - VGIC_NR_PRIVATE_IRQS);
-
-                       spin_lock(&dist->lock);
-                       level_pending |= process_queued_irq(vcpu, lr, vlr);
-                       spin_unlock(&dist->lock);
-               }
-       }
-
-       if (status & INT_STATUS_UNDERFLOW)
-               vgic_disable_underflow(vcpu);
-
-       /*
-        * In the next iterations of the vcpu loop, if we sync the vgic state
-        * after flushing it, but before entering the guest (this happens for
-        * pending signals and vmid rollovers), then make sure we don't pick
-        * up any old maintenance interrupts here.
-        */
-       vgic_clear_eisr(vcpu);
-
-       return level_pending;
-}
-
-/*
- * Save the physical active state, and reset it to inactive.
- *
- * Return true if there's a pending forwarded interrupt to queue.
- */
-static bool vgic_sync_hwirq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       bool level_pending;
-
-       if (!(vlr.state & LR_HW))
-               return false;
-
-       if (vlr.state & LR_STATE_ACTIVE)
-               return false;
-
-       spin_lock(&dist->lock);
-       level_pending = process_queued_irq(vcpu, lr, vlr);
-       spin_unlock(&dist->lock);
-       return level_pending;
-}
-
-/* Sync back the VGIC state after a guest run */
-static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       u64 elrsr;
-       unsigned long *elrsr_ptr;
-       int lr, pending;
-       bool level_pending;
-
-       level_pending = vgic_process_maintenance(vcpu);
-
-       /* Deal with HW interrupts, and clear mappings for empty LRs */
-       for (lr = 0; lr < vgic->nr_lr; lr++) {
-               struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
-
-               level_pending |= vgic_sync_hwirq(vcpu, lr, vlr);
-               BUG_ON(vlr.irq >= dist->nr_irqs);
-       }
-
-       /* Check if we still have something up our sleeve... */
-       elrsr = vgic_get_elrsr(vcpu);
-       elrsr_ptr = u64_to_bitmask(&elrsr);
-       pending = find_first_zero_bit(elrsr_ptr, vgic->nr_lr);
-       if (level_pending || pending < vgic->nr_lr)
-               set_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
-}
-
-void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       if (!irqchip_in_kernel(vcpu->kvm))
-               return;
-
-       spin_lock(&dist->lock);
-       __kvm_vgic_flush_hwstate(vcpu);
-       spin_unlock(&dist->lock);
-}
-
-void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
-{
-       if (!irqchip_in_kernel(vcpu->kvm))
-               return;
-
-       __kvm_vgic_sync_hwstate(vcpu);
-}
-
-int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
-       if (!irqchip_in_kernel(vcpu->kvm))
-               return 0;
-
-       return test_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
-}
-
-void vgic_kick_vcpus(struct kvm *kvm)
-{
-       struct kvm_vcpu *vcpu;
-       int c;
-
-       /*
-        * We've injected an interrupt, time to find out who deserves
-        * a good kick...
-        */
-       kvm_for_each_vcpu(c, vcpu, kvm) {
-               if (kvm_vgic_vcpu_pending_irq(vcpu))
-                       kvm_vcpu_kick(vcpu);
-       }
-}
-
-static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
-{
-       int edge_triggered = vgic_irq_is_edge(vcpu, irq);
-
-       /*
-        * Only inject an interrupt if:
-        * - edge triggered and we have a rising edge
-        * - level triggered and we change level
-        */
-       if (edge_triggered) {
-               int state = vgic_dist_irq_is_pending(vcpu, irq);
-               return level > state;
-       } else {
-               int state = vgic_dist_irq_get_level(vcpu, irq);
-               return level != state;
-       }
-}
-
-static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
-                                  unsigned int irq_num, bool level)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct kvm_vcpu *vcpu;
-       int edge_triggered, level_triggered;
-       int enabled;
-       bool ret = true, can_inject = true;
-
-       trace_vgic_update_irq_pending(cpuid, irq_num, level);
-
-       if (irq_num >= min(kvm->arch.vgic.nr_irqs, 1020))
-               return -EINVAL;
-
-       spin_lock(&dist->lock);
-
-       vcpu = kvm_get_vcpu(kvm, cpuid);
-       edge_triggered = vgic_irq_is_edge(vcpu, irq_num);
-       level_triggered = !edge_triggered;
-
-       if (!vgic_validate_injection(vcpu, irq_num, level)) {
-               ret = false;
-               goto out;
-       }
-
-       if (irq_num >= VGIC_NR_PRIVATE_IRQS) {
-               cpuid = dist->irq_spi_cpu[irq_num - VGIC_NR_PRIVATE_IRQS];
-               if (cpuid == VCPU_NOT_ALLOCATED) {
-                       /* Pretend we use CPU0, and prevent injection */
-                       cpuid = 0;
-                       can_inject = false;
-               }
-               vcpu = kvm_get_vcpu(kvm, cpuid);
-       }
-
-       kvm_debug("Inject IRQ%d level %d CPU%d\n", irq_num, level, cpuid);
-
-       if (level) {
-               if (level_triggered)
-                       vgic_dist_irq_set_level(vcpu, irq_num);
-               vgic_dist_irq_set_pending(vcpu, irq_num);
-       } else {
-               if (level_triggered) {
-                       vgic_dist_irq_clear_level(vcpu, irq_num);
-                       if (!vgic_dist_irq_soft_pend(vcpu, irq_num)) {
-                               vgic_dist_irq_clear_pending(vcpu, irq_num);
-                               vgic_cpu_irq_clear(vcpu, irq_num);
-                               if (!compute_pending_for_cpu(vcpu))
-                                       clear_bit(cpuid, dist->irq_pending_on_cpu);
-                       }
-               }
-
-               ret = false;
-               goto out;
-       }
-
-       enabled = vgic_irq_is_enabled(vcpu, irq_num);
-
-       if (!enabled || !can_inject) {
-               ret = false;
-               goto out;
-       }
-
-       if (!vgic_can_sample_irq(vcpu, irq_num)) {
-               /*
-                * Level interrupt in progress, will be picked up
-                * when EOId.
-                */
-               ret = false;
-               goto out;
-       }
-
-       if (level) {
-               vgic_cpu_irq_set(vcpu, irq_num);
-               set_bit(cpuid, dist->irq_pending_on_cpu);
-       }
-
-out:
-       spin_unlock(&dist->lock);
-
-       if (ret) {
-               /* kick the specified vcpu */
-               kvm_vcpu_kick(kvm_get_vcpu(kvm, cpuid));
-       }
-
-       return 0;
-}
-
-static int vgic_lazy_init(struct kvm *kvm)
-{
-       int ret = 0;
-
-       if (unlikely(!vgic_initialized(kvm))) {
-               /*
-                * We only provide the automatic initialization of the VGIC
-                * for the legacy case of a GICv2. Any other type must
-                * be explicitly initialized once setup with the respective
-                * KVM device call.
-                */
-               if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
-                       return -EBUSY;
-
-               mutex_lock(&kvm->lock);
-               ret = vgic_init(kvm);
-               mutex_unlock(&kvm->lock);
-       }
-
-       return ret;
-}
-
-/**
- * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
- * @kvm:     The VM structure pointer
- * @cpuid:   The CPU for PPIs
- * @irq_num: The IRQ number that is assigned to the device. This IRQ
- *           must not be mapped to a HW interrupt.
- * @level:   Edge-triggered:  true:  to trigger the interrupt
- *                           false: to ignore the call
- *          Level-sensitive  true:  raise the input signal
- *                           false: lower the input signal
- *
- * The GIC is not concerned with devices being active-LOW or active-HIGH for
- * level-sensitive interrupts.  You can think of the level parameter as 1
- * being HIGH and 0 being LOW and all devices being active-HIGH.
- */
-int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
-                       bool level)
-{
-       struct irq_phys_map *map;
-       int ret;
-
-       ret = vgic_lazy_init(kvm);
-       if (ret)
-               return ret;
-
-       map = vgic_irq_map_search(kvm_get_vcpu(kvm, cpuid), irq_num);
-       if (map)
-               return -EINVAL;
-
-       return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
-}
-
-/**
- * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
- * @kvm:     The VM structure pointer
- * @cpuid:   The CPU for PPIs
- * @virt_irq: The virtual IRQ to be injected
- * @level:   Edge-triggered:  true:  to trigger the interrupt
- *                           false: to ignore the call
- *          Level-sensitive  true:  raise the input signal
- *                           false: lower the input signal
- *
- * The GIC is not concerned with devices being active-LOW or active-HIGH for
- * level-sensitive interrupts.  You can think of the level parameter as 1
- * being HIGH and 0 being LOW and all devices being active-HIGH.
- */
-int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-                              unsigned int virt_irq, bool level)
-{
-       int ret;
-
-       ret = vgic_lazy_init(kvm);
-       if (ret)
-               return ret;
-
-       return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
-}
-
-static irqreturn_t vgic_maintenance_handler(int irq, void *data)
-{
-       /*
-        * We cannot rely on the vgic maintenance interrupt to be
-        * delivered synchronously. This means we can only use it to
-        * exit the VM, and we perform the handling of EOIed
-        * interrupts on the exit path (see vgic_process_maintenance).
-        */
-       return IRQ_HANDLED;
-}
-
-static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
-                                                   int virt_irq)
-{
-       if (virt_irq < VGIC_NR_PRIVATE_IRQS)
-               return &vcpu->arch.vgic_cpu.irq_phys_map_list;
-       else
-               return &vcpu->kvm->arch.vgic.irq_phys_map_list;
-}
-
-/**
- * kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ
- * @vcpu: The VCPU pointer
- * @virt_irq: The virtual IRQ number for the guest
- * @phys_irq: The hardware IRQ number of the host
- *
- * Establish a mapping between a guest visible irq (@virt_irq) and a
- * hardware irq (@phys_irq). On injection, @virt_irq will be associated with
- * the physical interrupt represented by @phys_irq. This mapping can be
- * established multiple times as long as the parameters are the same.
- *
- * Returns 0 on success or an error value otherwise.
- */
-int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
-       struct irq_phys_map *map;
-       struct irq_phys_map_entry *entry;
-       int ret = 0;
-
-       /* Create a new mapping */
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry)
-               return -ENOMEM;
-
-       spin_lock(&dist->irq_phys_map_lock);
-
-       /* Try to match an existing mapping */
-       map = vgic_irq_map_search(vcpu, virt_irq);
-       if (map) {
-               /* Make sure this mapping matches */
-               if (map->phys_irq != phys_irq)
-                       ret = -EINVAL;
-
-               /* Found an existing, valid mapping */
-               goto out;
-       }
-
-       map           = &entry->map;
-       map->virt_irq = virt_irq;
-       map->phys_irq = phys_irq;
-
-       list_add_tail_rcu(&entry->entry, root);
-
-out:
-       spin_unlock(&dist->irq_phys_map_lock);
-       /* If we've found a hit in the existing list, free the useless
-        * entry */
-       if (ret || map != &entry->map)
-               kfree(entry);
-       return ret;
-}
-
-static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
-                                               int virt_irq)
-{
-       struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
-       struct irq_phys_map_entry *entry;
-       struct irq_phys_map *map;
-
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(entry, root, entry) {
-               map = &entry->map;
-               if (map->virt_irq == virt_irq) {
-                       rcu_read_unlock();
-                       return map;
-               }
-       }
-
-       rcu_read_unlock();
-
-       return NULL;
-}
-
-static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
-{
-       struct irq_phys_map_entry *entry;
-
-       entry = container_of(rcu, struct irq_phys_map_entry, rcu);
-       kfree(entry);
-}
-
-/**
- * kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping
- * @vcpu: The VCPU pointer
- * @virt_irq: The virtual IRQ number to be unmapped
- *
- * Remove an existing mapping between virtual and physical interrupts.
- */
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
-{
-       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       struct irq_phys_map_entry *entry;
-       struct list_head *root;
-
-       root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
-
-       spin_lock(&dist->irq_phys_map_lock);
-
-       list_for_each_entry(entry, root, entry) {
-               if (entry->map.virt_irq == virt_irq) {
-                       list_del_rcu(&entry->entry);
-                       call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
-                       break;
-               }
-       }
-
-       spin_unlock(&dist->irq_phys_map_lock);
-
-       return 0;
-}
-
-static void vgic_destroy_irq_phys_map(struct kvm *kvm, struct list_head *root)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct irq_phys_map_entry *entry;
-
-       spin_lock(&dist->irq_phys_map_lock);
-
-       list_for_each_entry(entry, root, entry) {
-               list_del_rcu(&entry->entry);
-               call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
-       }
-
-       spin_unlock(&dist->irq_phys_map_lock);
-}
-
-void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
-{
-       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-
-       kfree(vgic_cpu->pending_shared);
-       kfree(vgic_cpu->active_shared);
-       kfree(vgic_cpu->pend_act_shared);
-       vgic_destroy_irq_phys_map(vcpu->kvm, &vgic_cpu->irq_phys_map_list);
-       vgic_cpu->pending_shared = NULL;
-       vgic_cpu->active_shared = NULL;
-       vgic_cpu->pend_act_shared = NULL;
-}
-
-static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
-{
-       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-       int nr_longs = BITS_TO_LONGS(nr_irqs - VGIC_NR_PRIVATE_IRQS);
-       int sz = nr_longs * sizeof(unsigned long);
-       vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL);
-       vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL);
-       vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL);
-
-       if (!vgic_cpu->pending_shared
-               || !vgic_cpu->active_shared
-               || !vgic_cpu->pend_act_shared) {
-               kvm_vgic_vcpu_destroy(vcpu);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/**
- * kvm_vgic_vcpu_early_init - Earliest possible per-vcpu vgic init stage
- *
- * No memory allocation should be performed here, only static init.
- */
-void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
-{
-       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-       INIT_LIST_HEAD(&vgic_cpu->irq_phys_map_list);
-}
-
-/**
- * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
- *
- * The host's GIC naturally limits the maximum amount of VCPUs a guest
- * can use.
- */
-int kvm_vgic_get_max_vcpus(void)
-{
-       return vgic->max_gic_vcpus;
-}
-
-void kvm_vgic_destroy(struct kvm *kvm)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct kvm_vcpu *vcpu;
-       int i;
-
-       kvm_for_each_vcpu(i, vcpu, kvm)
-               kvm_vgic_vcpu_destroy(vcpu);
-
-       vgic_free_bitmap(&dist->irq_enabled);
-       vgic_free_bitmap(&dist->irq_level);
-       vgic_free_bitmap(&dist->irq_pending);
-       vgic_free_bitmap(&dist->irq_soft_pend);
-       vgic_free_bitmap(&dist->irq_queued);
-       vgic_free_bitmap(&dist->irq_cfg);
-       vgic_free_bytemap(&dist->irq_priority);
-       if (dist->irq_spi_target) {
-               for (i = 0; i < dist->nr_cpus; i++)
-                       vgic_free_bitmap(&dist->irq_spi_target[i]);
-       }
-       kfree(dist->irq_sgi_sources);
-       kfree(dist->irq_spi_cpu);
-       kfree(dist->irq_spi_mpidr);
-       kfree(dist->irq_spi_target);
-       kfree(dist->irq_pending_on_cpu);
-       kfree(dist->irq_active_on_cpu);
-       vgic_destroy_irq_phys_map(kvm, &dist->irq_phys_map_list);
-       dist->irq_sgi_sources = NULL;
-       dist->irq_spi_cpu = NULL;
-       dist->irq_spi_target = NULL;
-       dist->irq_pending_on_cpu = NULL;
-       dist->irq_active_on_cpu = NULL;
-       dist->nr_cpus = 0;
-}
-
-/*
- * Allocate and initialize the various data structures. Must be called
- * with kvm->lock held!
- */
-int vgic_init(struct kvm *kvm)
-{
-       struct vgic_dist *dist = &kvm->arch.vgic;
-       struct kvm_vcpu *vcpu;
-       int nr_cpus, nr_irqs;
-       int ret, i, vcpu_id;
-
-       if (vgic_initialized(kvm))
-               return 0;
-
-       nr_cpus = dist->nr_cpus = atomic_read(&kvm->online_vcpus);
-       if (!nr_cpus)           /* No vcpus? Can't be good... */
-               return -ENODEV;
-
-       /*
-        * If nobody configured the number of interrupts, use the
-        * legacy one.
-        */
-       if (!dist->nr_irqs)
-               dist->nr_irqs = VGIC_NR_IRQS_LEGACY;
-
-       nr_irqs = dist->nr_irqs;
-
-       ret  = vgic_init_bitmap(&dist->irq_enabled, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_level, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_pending, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_soft_pend, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_queued, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_active, nr_cpus, nr_irqs);
-       ret |= vgic_init_bitmap(&dist->irq_cfg, nr_cpus, nr_irqs);
-       ret |= vgic_init_bytemap(&dist->irq_priority, nr_cpus, nr_irqs);
-
-       if (ret)
-               goto out;
-
-       dist->irq_sgi_sources = kzalloc(nr_cpus * VGIC_NR_SGIS, GFP_KERNEL);
-       dist->irq_spi_cpu = kzalloc(nr_irqs - VGIC_NR_PRIVATE_IRQS, GFP_KERNEL);
-       dist->irq_spi_target = kzalloc(sizeof(*dist->irq_spi_target) * nr_cpus,
-                                      GFP_KERNEL);
-       dist->irq_pending_on_cpu = kzalloc(BITS_TO_LONGS(nr_cpus) * sizeof(long),
-                                          GFP_KERNEL);
-       dist->irq_active_on_cpu = kzalloc(BITS_TO_LONGS(nr_cpus) * sizeof(long),
-                                          GFP_KERNEL);
-       if (!dist->irq_sgi_sources ||
-           !dist->irq_spi_cpu ||
-           !dist->irq_spi_target ||
-           !dist->irq_pending_on_cpu ||
-           !dist->irq_active_on_cpu) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (i = 0; i < nr_cpus; i++)
-               ret |= vgic_init_bitmap(&dist->irq_spi_target[i],
-                                       nr_cpus, nr_irqs);
-
-       if (ret)
-               goto out;
-
-       ret = kvm->arch.vgic.vm_ops.init_model(kvm);
-       if (ret)
-               goto out;
-
-       kvm_for_each_vcpu(vcpu_id, vcpu, kvm) {
-               ret = vgic_vcpu_init_maps(vcpu, nr_irqs);
-               if (ret) {
-                       kvm_err("VGIC: Failed to allocate vcpu memory\n");
-                       break;
-               }
-
-               /*
-                * Enable and configure all SGIs to be edge-triggere and
-                * configure all PPIs as level-triggered.
-                */
-               for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
-                       if (i < VGIC_NR_SGIS) {
-                               /* SGIs */
-                               vgic_bitmap_set_irq_val(&dist->irq_enabled,
-                                                       vcpu->vcpu_id, i, 1);
-                               vgic_bitmap_set_irq_val(&dist->irq_cfg,
-                                                       vcpu->vcpu_id, i,
-                                                       VGIC_CFG_EDGE);
-                       } else if (i < VGIC_NR_PRIVATE_IRQS) {
-                               /* PPIs */
-                               vgic_bitmap_set_irq_val(&dist->irq_cfg,
-                                                       vcpu->vcpu_id, i,
-                                                       VGIC_CFG_LEVEL);
-                       }
-               }
-
-               vgic_enable(vcpu);
-       }
-
-out:
-       if (ret)
-               kvm_vgic_destroy(kvm);
-
-       return ret;
-}
-
-static int init_vgic_model(struct kvm *kvm, int type)
-{
-       switch (type) {
-       case KVM_DEV_TYPE_ARM_VGIC_V2:
-               vgic_v2_init_emulation(kvm);
-               break;
-#ifdef CONFIG_KVM_ARM_VGIC_V3
-       case KVM_DEV_TYPE_ARM_VGIC_V3:
-               vgic_v3_init_emulation(kvm);
-               break;
-#endif
-       default:
-               return -ENODEV;
-       }
-
-       if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus)
-               return -E2BIG;
-
-       return 0;
-}
-
-/**
- * kvm_vgic_early_init - Earliest possible vgic initialization stage
- *
- * No memory allocation should be performed here, only static init.
- */
-void kvm_vgic_early_init(struct kvm *kvm)
-{
-       spin_lock_init(&kvm->arch.vgic.lock);
-       spin_lock_init(&kvm->arch.vgic.irq_phys_map_lock);
-       INIT_LIST_HEAD(&kvm->arch.vgic.irq_phys_map_list);
-}
-
-int kvm_vgic_create(struct kvm *kvm, u32 type)
-{
-       int i, vcpu_lock_idx = -1, ret;
-       struct kvm_vcpu *vcpu;
-
-       mutex_lock(&kvm->lock);
-
-       if (irqchip_in_kernel(kvm)) {
-               ret = -EEXIST;
-               goto out;
-       }
-
-       /*
-        * This function is also called by the KVM_CREATE_IRQCHIP handler,
-        * which had no chance yet to check the availability of the GICv2
-        * emulation. So check this here again. KVM_CREATE_DEVICE does
-        * the proper checks already.
-        */
-       if (type == KVM_DEV_TYPE_ARM_VGIC_V2 && !vgic->can_emulate_gicv2) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       /*
-        * Any time a vcpu is run, vcpu_load is called which tries to grab the
-        * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
-        * that no other VCPUs are run while we create the vgic.
-        */
-       ret = -EBUSY;
-       kvm_for_each_vcpu(i, vcpu, kvm) {
-               if (!mutex_trylock(&vcpu->mutex))
-                       goto out_unlock;
-               vcpu_lock_idx = i;
-       }
-
-       kvm_for_each_vcpu(i, vcpu, kvm) {
-               if (vcpu->arch.has_run_once)
-                       goto out_unlock;
-       }
-       ret = 0;
-
-       ret = init_vgic_model(kvm, type);
-       if (ret)
-               goto out_unlock;
-
-       kvm->arch.vgic.in_kernel = true;
-       kvm->arch.vgic.vgic_model = type;
-       kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
-       kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
-       kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
-       kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
-
-out_unlock:
-       for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
-               vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
-               mutex_unlock(&vcpu->mutex);
-       }
-
-out:
-       mutex_unlock(&kvm->lock);
-       return ret;
-}
-
-static int vgic_ioaddr_overlap(struct kvm *kvm)
-{
-       phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
-       phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
-
-       if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
-               return 0;
-       if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
-           (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
-               return -EBUSY;
-       return 0;
-}
-
-static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
-                             phys_addr_t addr, phys_addr_t size)
-{
-       int ret;
-
-       if (addr & ~KVM_PHYS_MASK)
-               return -E2BIG;
-
-       if (addr & (SZ_4K - 1))
-               return -EINVAL;
-
-       if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
-               return -EEXIST;
-       if (addr + size < addr)
-               return -EINVAL;
-
-       *ioaddr = addr;
-       ret = vgic_ioaddr_overlap(kvm);
-       if (ret)
-               *ioaddr = VGIC_ADDR_UNDEF;
-
-       return ret;
-}
-
-/**
- * kvm_vgic_addr - set or get vgic VM base addresses
- * @kvm:   pointer to the vm struct
- * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
- * @addr:  pointer to address value
- * @write: if true set the address in the VM address space, if false read the
- *          address
- *
- * Set or get the vgic base addresses for the distributor and the virtual CPU
- * interface in the VM physical address space.  These addresses are properties
- * of the emulated core/SoC and therefore user space initially knows this
- * information.
- */
-int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
-{
-       int r = 0;
-       struct vgic_dist *vgic = &kvm->arch.vgic;
-       int type_needed;
-       phys_addr_t *addr_ptr, block_size;
-       phys_addr_t alignment;
-
-       mutex_lock(&kvm->lock);
-       switch (type) {
-       case KVM_VGIC_V2_ADDR_TYPE_DIST:
-               type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
-               addr_ptr = &vgic->vgic_dist_base;
-               block_size = KVM_VGIC_V2_DIST_SIZE;
-               alignment = SZ_4K;
-               break;
-       case KVM_VGIC_V2_ADDR_TYPE_CPU:
-               type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
-               addr_ptr = &vgic->vgic_cpu_base;
-               block_size = KVM_VGIC_V2_CPU_SIZE;
-               alignment = SZ_4K;
-               break;
-#ifdef CONFIG_KVM_ARM_VGIC_V3
-       case KVM_VGIC_V3_ADDR_TYPE_DIST:
-               type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
-               addr_ptr = &vgic->vgic_dist_base;
-               block_size = KVM_VGIC_V3_DIST_SIZE;
-               alignment = SZ_64K;
-               break;
-       case KVM_VGIC_V3_ADDR_TYPE_REDIST:
-               type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
-               addr_ptr = &vgic->vgic_redist_base;
-               block_size = KVM_VGIC_V3_REDIST_SIZE;
-               alignment = SZ_64K;
-               break;
-#endif
-       default:
-               r = -ENODEV;
-               goto out;
-       }
-
-       if (vgic->vgic_model != type_needed) {
-               r = -ENODEV;
-               goto out;
-       }
-
-       if (write) {
-               if (!IS_ALIGNED(*addr, alignment))
-                       r = -EINVAL;
-               else
-                       r = vgic_ioaddr_assign(kvm, addr_ptr, *addr,
-                                              block_size);
-       } else {
-               *addr = *addr_ptr;
-       }
-
-out:
-       mutex_unlock(&kvm->lock);
-       return r;
-}
-
-int vgic_set_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
-{
-       int r;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_ADDR: {
-               u64 __user *uaddr = (u64 __user *)(long)attr->addr;
-               u64 addr;
-               unsigned long type = (unsigned long)attr->attr;
-
-               if (copy_from_user(&addr, uaddr, sizeof(addr)))
-                       return -EFAULT;
-
-               r = kvm_vgic_addr(dev->kvm, type, &addr, true);
-               return (r == -ENODEV) ? -ENXIO : r;
-       }
-       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
-               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-               u32 val;
-               int ret = 0;
-
-               if (get_user(val, uaddr))
-                       return -EFAULT;
-
-               /*
-                * We require:
-                * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
-                * - at most 1024 interrupts
-                * - a multiple of 32 interrupts
-                */
-               if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
-                   val > VGIC_MAX_IRQS ||
-                   (val & 31))
-                       return -EINVAL;
-
-               mutex_lock(&dev->kvm->lock);
-
-               if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_irqs)
-                       ret = -EBUSY;
-               else
-                       dev->kvm->arch.vgic.nr_irqs = val;
-
-               mutex_unlock(&dev->kvm->lock);
-
-               return ret;
-       }
-       case KVM_DEV_ARM_VGIC_GRP_CTRL: {
-               switch (attr->attr) {
-               case KVM_DEV_ARM_VGIC_CTRL_INIT:
-                       r = vgic_init(dev->kvm);
-                       return r;
-               }
-               break;
-       }
-       }
-
-       return -ENXIO;
-}
-
-int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
-{
-       int r = -ENXIO;
-
-       switch (attr->group) {
-       case KVM_DEV_ARM_VGIC_GRP_ADDR: {
-               u64 __user *uaddr = (u64 __user *)(long)attr->addr;
-               u64 addr;
-               unsigned long type = (unsigned long)attr->attr;
-
-               r = kvm_vgic_addr(dev->kvm, type, &addr, false);
-               if (r)
-                       return (r == -ENODEV) ? -ENXIO : r;
-
-               if (copy_to_user(uaddr, &addr, sizeof(addr)))
-                       return -EFAULT;
-               break;
-       }
-       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
-               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-
-               r = put_user(dev->kvm->arch.vgic.nr_irqs, uaddr);
-               break;
-       }
-
-       }
-
-       return r;
-}
-
-int vgic_has_attr_regs(const struct vgic_io_range *ranges, phys_addr_t offset)
-{
-       if (vgic_find_range(ranges, 4, offset))
-               return 0;
-       else
-               return -ENXIO;
-}
-
-static int vgic_starting_cpu(unsigned int cpu)
-{
-       enable_percpu_irq(vgic->maint_irq, 0);
-       return 0;
-}
-
-static int vgic_dying_cpu(unsigned int cpu)
-{
-       disable_percpu_irq(vgic->maint_irq);
-       return 0;
-}
-
-static int kvm_vgic_probe(void)
-{
-       const struct gic_kvm_info *gic_kvm_info;
-       int ret;
-
-       gic_kvm_info = gic_get_kvm_info();
-       if (!gic_kvm_info)
-               return -ENODEV;
-
-       switch (gic_kvm_info->type) {
-       case GIC_V2:
-               ret = vgic_v2_probe(gic_kvm_info, &vgic_ops, &vgic);
-               break;
-       case GIC_V3:
-               ret = vgic_v3_probe(gic_kvm_info, &vgic_ops, &vgic);
-               break;
-       default:
-               ret = -ENODEV;
-       }
-
-       return ret;
-}
-
-int kvm_vgic_hyp_init(void)
-{
-       int ret;
-
-       ret = kvm_vgic_probe();
-       if (ret) {
-               kvm_err("error: KVM vGIC probing failed\n");
-               return ret;
-       }
-
-       ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
-                                "vgic", kvm_get_running_vcpus());
-       if (ret) {
-               kvm_err("Cannot register interrupt %d\n", vgic->maint_irq);
-               return ret;
-       }
-
-       cpuhp_setup_state(CPUHP_AP_KVM_ARM_VGIC_STARTING,
-                         "AP_KVM_ARM_VGIC_STARTING", vgic_starting_cpu,
-                         vgic_dying_cpu);
-       return 0;
-}
-
-int kvm_irq_map_gsi(struct kvm *kvm,
-                   struct kvm_kernel_irq_routing_entry *entries,
-                   int gsi)
-{
-       return 0;
-}
-
-int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
-{
-       return pin;
-}
-
-int kvm_set_irq(struct kvm *kvm, int irq_source_id,
-               u32 irq, int level, bool line_status)
-{
-       unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
-
-       trace_kvm_set_irq(irq, level, irq_source_id);
-
-       BUG_ON(!vgic_initialized(kvm));
-
-       return kvm_vgic_inject_irq(kvm, 0, spi, level);
-}
-
-/* MSI not implemented yet */
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-               struct kvm *kvm, int irq_source_id,
-               int level, bool line_status)
-{
-       return 0;
-}
diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
deleted file mode 100644 (file)
index 0df74cb..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2012-2014 ARM Ltd.
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * Derived from virt/kvm/arm/vgic.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __KVM_VGIC_H__
-#define __KVM_VGIC_H__
-
-#include <kvm/iodev.h>
-
-#define VGIC_ADDR_UNDEF                (-1)
-#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
-
-#define PRODUCT_ID_KVM         0x4b    /* ASCII code K */
-#define IMPLEMENTER_ARM                0x43b
-
-#define ACCESS_READ_VALUE      (1 << 0)
-#define ACCESS_READ_RAZ                (0 << 0)
-#define ACCESS_READ_MASK(x)    ((x) & (1 << 0))
-#define ACCESS_WRITE_IGNORED   (0 << 1)
-#define ACCESS_WRITE_SETBIT    (1 << 1)
-#define ACCESS_WRITE_CLEARBIT  (2 << 1)
-#define ACCESS_WRITE_VALUE     (3 << 1)
-#define ACCESS_WRITE_MASK(x)   ((x) & (3 << 1))
-
-#define VCPU_NOT_ALLOCATED     ((u8)-1)
-
-unsigned long *vgic_bitmap_get_shared_map(struct vgic_bitmap *x);
-
-void vgic_update_state(struct kvm *kvm);
-int vgic_init_common_maps(struct kvm *kvm);
-
-u32 *vgic_bitmap_get_reg(struct vgic_bitmap *x, int cpuid, u32 offset);
-u32 *vgic_bytemap_get_reg(struct vgic_bytemap *x, int cpuid, u32 offset);
-
-void vgic_dist_irq_set_pending(struct kvm_vcpu *vcpu, int irq);
-void vgic_dist_irq_clear_pending(struct kvm_vcpu *vcpu, int irq);
-void vgic_cpu_irq_clear(struct kvm_vcpu *vcpu, int irq);
-void vgic_bitmap_set_irq_val(struct vgic_bitmap *x, int cpuid,
-                            int irq, int val);
-
-void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-
-bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq);
-void vgic_unqueue_irqs(struct kvm_vcpu *vcpu);
-
-struct kvm_exit_mmio {
-       phys_addr_t     phys_addr;
-       void            *data;
-       u32             len;
-       bool            is_write;
-       void            *private;
-};
-
-void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
-                    phys_addr_t offset, int mode);
-bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
-                       phys_addr_t offset);
-
-static inline
-u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
-{
-       return le32_to_cpu(*((u32 *)mmio->data)) & mask;
-}
-
-static inline
-void mmio_data_write(struct kvm_exit_mmio *mmio, u32 mask, u32 value)
-{
-       *((u32 *)mmio->data) = cpu_to_le32(value) & mask;
-}
-
-struct vgic_io_range {
-       phys_addr_t base;
-       unsigned long len;
-       int bits_per_irq;
-       bool (*handle_mmio)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
-                           phys_addr_t offset);
-};
-
-int vgic_register_kvm_io_dev(struct kvm *kvm, gpa_t base, int len,
-                            const struct vgic_io_range *ranges,
-                            int redist_id,
-                            struct vgic_io_device *iodev);
-
-static inline bool is_in_range(phys_addr_t addr, unsigned long len,
-                              phys_addr_t baseaddr, unsigned long size)
-{
-       return (addr >= baseaddr) && (addr + len <= baseaddr + size);
-}
-
-const
-struct vgic_io_range *vgic_find_range(const struct vgic_io_range *ranges,
-                                     int len, gpa_t offset);
-
-bool vgic_handle_enable_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio,
-                           phys_addr_t offset, int vcpu_id, int access);
-
-bool vgic_handle_set_pending_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio,
-                                phys_addr_t offset, int vcpu_id);
-
-bool vgic_handle_clear_pending_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio,
-                                  phys_addr_t offset, int vcpu_id);
-
-bool vgic_handle_set_active_reg(struct kvm *kvm,
-                               struct kvm_exit_mmio *mmio,
-                               phys_addr_t offset, int vcpu_id);
-
-bool vgic_handle_clear_active_reg(struct kvm *kvm,
-                                 struct kvm_exit_mmio *mmio,
-                                 phys_addr_t offset, int vcpu_id);
-
-bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
-                        phys_addr_t offset);
-
-void vgic_kick_vcpus(struct kvm *kvm);
-
-int vgic_has_attr_regs(const struct vgic_io_range *ranges, phys_addr_t offset);
-int vgic_set_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
-int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
-
-int vgic_init(struct kvm *kvm);
-void vgic_v2_init_emulation(struct kvm *kvm);
-void vgic_v3_init_emulation(struct kvm *kvm);
-
-#endif
index 2c7f0d5..fb4b0a7 100644 (file)
@@ -157,6 +157,9 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
        struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
        int i;
 
+       INIT_LIST_HEAD(&dist->lpi_list_head);
+       spin_lock_init(&dist->lpi_list_lock);
+
        dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
        if (!dist->spis)
                return  -ENOMEM;
@@ -177,6 +180,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
                spin_lock_init(&irq->irq_lock);
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu0;
+               kref_init(&irq->refcount);
                if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
                        irq->targets = 0;
                else
@@ -211,6 +215,7 @@ static void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
                irq->vcpu = NULL;
                irq->target_vcpu = vcpu;
                irq->targets = 1U << vcpu->vcpu_id;
+               kref_init(&irq->refcount);
                if (vgic_irq_is_sgi(i)) {
                        /* SGIs */
                        irq->enabled = 1;
@@ -253,9 +258,16 @@ int vgic_init(struct kvm *kvm)
        if (ret)
                goto out;
 
+       if (vgic_has_its(kvm))
+               dist->msis_require_devid = true;
+
        kvm_for_each_vcpu(i, vcpu, kvm)
                kvm_vgic_vcpu_init(vcpu);
 
+       ret = kvm_vgic_setup_default_irq_routing(kvm);
+       if (ret)
+               goto out;
+
        dist->initialized = true;
 out:
        return ret;
@@ -271,7 +283,6 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
        dist->initialized = false;
 
        kfree(dist->spis);
-       kfree(dist->redist_iodevs);
        dist->nr_spis = 0;
 
        mutex_unlock(&kvm->lock);
index c675513..b31a51a 100644 (file)
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <trace/events/kvm.h>
+#include <kvm/arm_vgic.h>
+#include "vgic.h"
 
-int kvm_irq_map_gsi(struct kvm *kvm,
-                   struct kvm_kernel_irq_routing_entry *entries,
-                   int gsi)
+/**
+ * vgic_irqfd_set_irq: inject the IRQ corresponding to the
+ * irqchip routing entry
+ *
+ * This is the entry point for irqfd IRQ injection
+ */
+static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                       struct kvm *kvm, int irq_source_id,
+                       int level, bool line_status)
 {
-       return 0;
+       unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
+
+       if (!vgic_valid_spi(kvm, spi_id))
+               return -EINVAL;
+       return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
 }
 
-int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
-                        unsigned int pin)
+/**
+ * kvm_set_routing_entry: populate a kvm routing entry
+ * from a user routing entry
+ *
+ * @kvm: the VM this entry is applied to
+ * @e: kvm kernel routing entry handle
+ * @ue: user api routing entry handle
+ * return 0 on success, -EINVAL on errors.
+ */
+#ifdef KVM_CAP_X2APIC_API
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+#else
+/* Remove this version and the ifdefery once merged into 4.8 */
+int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+#endif
 {
-       return pin;
+       int r = -EINVAL;
+
+       switch (ue->type) {
+       case KVM_IRQ_ROUTING_IRQCHIP:
+               e->set = vgic_irqfd_set_irq;
+               e->irqchip.irqchip = ue->u.irqchip.irqchip;
+               e->irqchip.pin = ue->u.irqchip.pin;
+               if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
+                   (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
+                       goto out;
+               break;
+       case KVM_IRQ_ROUTING_MSI:
+               e->set = kvm_set_msi;
+               e->msi.address_lo = ue->u.msi.address_lo;
+               e->msi.address_hi = ue->u.msi.address_hi;
+               e->msi.data = ue->u.msi.data;
+               e->msi.flags = ue->flags;
+               e->msi.devid = ue->u.msi.devid;
+               break;
+       default:
+               goto out;
+       }
+       r = 0;
+out:
+       return r;
 }
 
-int kvm_set_irq(struct kvm *kvm, int irq_source_id,
-               u32 irq, int level, bool line_status)
+/**
+ * kvm_set_msi: inject the MSI corresponding to the
+ * MSI routing entry
+ *
+ * This is the entry point for irqfd MSI injection
+ * and userspace MSI injection.
+ */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+               struct kvm *kvm, int irq_source_id,
+               int level, bool line_status)
 {
-       unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+       struct kvm_msi msi;
 
-       trace_kvm_set_irq(irq, level, irq_source_id);
+       msi.address_lo = e->msi.address_lo;
+       msi.address_hi = e->msi.address_hi;
+       msi.data = e->msi.data;
+       msi.flags = e->msi.flags;
+       msi.devid = e->msi.devid;
 
-       BUG_ON(!vgic_initialized(kvm));
+       if (!vgic_has_its(kvm))
+               return -ENODEV;
 
-       return kvm_vgic_inject_irq(kvm, 0, spi, level);
+       return vgic_its_inject_msi(kvm, &msi);
 }
 
-/* MSI not implemented yet */
-int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
-               struct kvm *kvm, int irq_source_id,
-               int level, bool line_status)
+int kvm_vgic_setup_default_irq_routing(struct kvm *kvm)
 {
-       return 0;
+       struct kvm_irq_routing_entry *entries;
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       u32 nr = dist->nr_spis;
+       int i, ret;
+
+       entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry),
+                         GFP_KERNEL);
+       if (!entries)
+               return -ENOMEM;
+
+       for (i = 0; i < nr; i++) {
+               entries[i].gsi = i;
+               entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
+               entries[i].u.irqchip.irqchip = 0;
+               entries[i].u.irqchip.pin = i;
+       }
+       ret = kvm_set_irq_routing(kvm, entries, nr, 0);
+       kfree(entries);
+       return ret;
 }
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
new file mode 100644 (file)
index 0000000..07411cf
--- /dev/null
@@ -0,0 +1,1500 @@
+/*
+ * GICv3 ITS emulation
+ *
+ * Copyright (C) 2015,2016 ARM Ltd.
+ * Author: Andre Przywara <andre.przywara@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/*
+ * Creates a new (reference to a) struct vgic_irq for a given LPI.
+ * If this LPI is already mapped on another ITS, we increase its refcount
+ * and return a pointer to the existing structure.
+ * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
+ * This function returns a pointer to the _unlocked_ structure.
+ */
+static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
+
+       /* In this case there is no put, since we keep the reference. */
+       if (irq)
+               return irq;
+
+       irq = kzalloc(sizeof(struct vgic_irq), GFP_KERNEL);
+       if (!irq)
+               return NULL;
+
+       INIT_LIST_HEAD(&irq->lpi_list);
+       INIT_LIST_HEAD(&irq->ap_list);
+       spin_lock_init(&irq->irq_lock);
+
+       irq->config = VGIC_CONFIG_EDGE;
+       kref_init(&irq->refcount);
+       irq->intid = intid;
+
+       spin_lock(&dist->lpi_list_lock);
+
+       /*
+        * There could be a race with another vgic_add_lpi(), so we need to
+        * check that we don't add a second list entry with the same LPI.
+        */
+       list_for_each_entry(oldirq, &dist->lpi_list_head, lpi_list) {
+               if (oldirq->intid != intid)
+                       continue;
+
+               /* Someone was faster with adding this LPI, lets use that. */
+               kfree(irq);
+               irq = oldirq;
+
+               /*
+                * This increases the refcount, the caller is expected to
+                * call vgic_put_irq() on the returned pointer once it's
+                * finished with the IRQ.
+                */
+               vgic_get_irq_kref(irq);
+
+               goto out_unlock;
+       }
+
+       list_add_tail(&irq->lpi_list, &dist->lpi_list_head);
+       dist->lpi_list_count++;
+
+out_unlock:
+       spin_unlock(&dist->lpi_list_lock);
+
+       return irq;
+}
+
+struct its_device {
+       struct list_head dev_list;
+
+       /* the head for the list of ITTEs */
+       struct list_head itt_head;
+       u32 device_id;
+};
+
+#define COLLECTION_NOT_MAPPED ((u32)~0)
+
+struct its_collection {
+       struct list_head coll_list;
+
+       u32 collection_id;
+       u32 target_addr;
+};
+
+#define its_is_collection_mapped(coll) ((coll) && \
+                               ((coll)->target_addr != COLLECTION_NOT_MAPPED))
+
+struct its_itte {
+       struct list_head itte_list;
+
+       struct vgic_irq *irq;
+       struct its_collection *collection;
+       u32 lpi;
+       u32 event_id;
+};
+
+/*
+ * Find and returns a device in the device table for an ITS.
+ * Must be called with the its_lock mutex held.
+ */
+static struct its_device *find_its_device(struct vgic_its *its, u32 device_id)
+{
+       struct its_device *device;
+
+       list_for_each_entry(device, &its->device_list, dev_list)
+               if (device_id == device->device_id)
+                       return device;
+
+       return NULL;
+}
+
+/*
+ * Find and returns an interrupt translation table entry (ITTE) for a given
+ * Device ID/Event ID pair on an ITS.
+ * Must be called with the its_lock mutex held.
+ */
+static struct its_itte *find_itte(struct vgic_its *its, u32 device_id,
+                                 u32 event_id)
+{
+       struct its_device *device;
+       struct its_itte *itte;
+
+       device = find_its_device(its, device_id);
+       if (device == NULL)
+               return NULL;
+
+       list_for_each_entry(itte, &device->itt_head, itte_list)
+               if (itte->event_id == event_id)
+                       return itte;
+
+       return NULL;
+}
+
+/* To be used as an iterator this macro misses the enclosing parentheses */
+#define for_each_lpi_its(dev, itte, its) \
+       list_for_each_entry(dev, &(its)->device_list, dev_list) \
+               list_for_each_entry(itte, &(dev)->itt_head, itte_list)
+
+/*
+ * We only implement 48 bits of PA at the moment, although the ITS
+ * supports more. Let's be restrictive here.
+ */
+#define BASER_ADDRESS(x)       ((x) & GENMASK_ULL(47, 16))
+#define CBASER_ADDRESS(x)      ((x) & GENMASK_ULL(47, 12))
+#define PENDBASER_ADDRESS(x)   ((x) & GENMASK_ULL(47, 16))
+#define PROPBASER_ADDRESS(x)   ((x) & GENMASK_ULL(47, 12))
+
+#define GIC_LPI_OFFSET 8192
+
+/*
+ * Finds and returns a collection in the ITS collection table.
+ * Must be called with the its_lock mutex held.
+ */
+static struct its_collection *find_collection(struct vgic_its *its, int coll_id)
+{
+       struct its_collection *collection;
+
+       list_for_each_entry(collection, &its->collection_list, coll_list) {
+               if (coll_id == collection->collection_id)
+                       return collection;
+       }
+
+       return NULL;
+}
+
+#define LPI_PROP_ENABLE_BIT(p) ((p) & LPI_PROP_ENABLED)
+#define LPI_PROP_PRIORITY(p)   ((p) & 0xfc)
+
+/*
+ * Reads the configuration data for a given LPI from guest memory and
+ * updates the fields in struct vgic_irq.
+ * If filter_vcpu is not NULL, applies only if the IRQ is targeting this
+ * VCPU. Unconditionally applies if filter_vcpu is NULL.
+ */
+static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
+                            struct kvm_vcpu *filter_vcpu)
+{
+       u64 propbase = PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
+       u8 prop;
+       int ret;
+
+       ret = kvm_read_guest(kvm, propbase + irq->intid - GIC_LPI_OFFSET,
+                            &prop, 1);
+
+       if (ret)
+               return ret;
+
+       spin_lock(&irq->irq_lock);
+
+       if (!filter_vcpu || filter_vcpu == irq->target_vcpu) {
+               irq->priority = LPI_PROP_PRIORITY(prop);
+               irq->enabled = LPI_PROP_ENABLE_BIT(prop);
+
+               vgic_queue_irq_unlock(kvm, irq);
+       } else {
+               spin_unlock(&irq->irq_lock);
+       }
+
+       return 0;
+}
+
+/*
+ * Create a snapshot of the current LPI list, so that we can enumerate all
+ * LPIs without holding any lock.
+ * Returns the array length and puts the kmalloc'ed array into intid_ptr.
+ */
+static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       struct vgic_irq *irq;
+       u32 *intids;
+       int irq_count = dist->lpi_list_count, i = 0;
+
+       /*
+        * We use the current value of the list length, which may change
+        * after the kmalloc. We don't care, because the guest shouldn't
+        * change anything while the command handling is still running,
+        * and in the worst case we would miss a new IRQ, which one wouldn't
+        * expect to be covered by this command anyway.
+        */
+       intids = kmalloc_array(irq_count, sizeof(intids[0]), GFP_KERNEL);
+       if (!intids)
+               return -ENOMEM;
+
+       spin_lock(&dist->lpi_list_lock);
+       list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
+               /* We don't need to "get" the IRQ, as we hold the list lock. */
+               intids[i] = irq->intid;
+               if (++i == irq_count)
+                       break;
+       }
+       spin_unlock(&dist->lpi_list_lock);
+
+       *intid_ptr = intids;
+       return irq_count;
+}
+
+/*
+ * Promotes the ITS view of affinity of an ITTE (which redistributor this LPI
+ * is targeting) to the VGIC's view, which deals with target VCPUs.
+ * Needs to be called whenever either the collection for a LPIs has
+ * changed or the collection itself got retargeted.
+ */
+static void update_affinity_itte(struct kvm *kvm, struct its_itte *itte)
+{
+       struct kvm_vcpu *vcpu;
+
+       if (!its_is_collection_mapped(itte->collection))
+               return;
+
+       vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+
+       spin_lock(&itte->irq->irq_lock);
+       itte->irq->target_vcpu = vcpu;
+       spin_unlock(&itte->irq->irq_lock);
+}
+
+/*
+ * Updates the target VCPU for every LPI targeting this collection.
+ * Must be called with the its_lock mutex held.
+ */
+static void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
+                                      struct its_collection *coll)
+{
+       struct its_device *device;
+       struct its_itte *itte;
+
+       for_each_lpi_its(device, itte, its) {
+               if (!itte->collection || coll != itte->collection)
+                       continue;
+
+               update_affinity_itte(kvm, itte);
+       }
+}
+
+static u32 max_lpis_propbaser(u64 propbaser)
+{
+       int nr_idbits = (propbaser & 0x1f) + 1;
+
+       return 1U << min(nr_idbits, INTERRUPT_ID_BITS_ITS);
+}
+
+/*
+ * Scan the whole LPI pending table and sync the pending bit in there
+ * with our own data structures. This relies on the LPI being
+ * mapped before.
+ */
+static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
+{
+       gpa_t pendbase = PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+       struct vgic_irq *irq;
+       int last_byte_offset = -1;
+       int ret = 0;
+       u32 *intids;
+       int nr_irqs, i;
+
+       nr_irqs = vgic_copy_lpi_list(vcpu->kvm, &intids);
+       if (nr_irqs < 0)
+               return nr_irqs;
+
+       for (i = 0; i < nr_irqs; i++) {
+               int byte_offset, bit_nr;
+               u8 pendmask;
+
+               byte_offset = intids[i] / BITS_PER_BYTE;
+               bit_nr = intids[i] % BITS_PER_BYTE;
+
+               /*
+                * For contiguously allocated LPIs chances are we just read
+                * this very same byte in the last iteration. Reuse that.
+                */
+               if (byte_offset != last_byte_offset) {
+                       ret = kvm_read_guest(vcpu->kvm, pendbase + byte_offset,
+                                            &pendmask, 1);
+                       if (ret) {
+                               kfree(intids);
+                               return ret;
+                       }
+                       last_byte_offset = byte_offset;
+               }
+
+               irq = vgic_get_irq(vcpu->kvm, NULL, intids[i]);
+               spin_lock(&irq->irq_lock);
+               irq->pending = pendmask & (1U << bit_nr);
+               vgic_queue_irq_unlock(vcpu->kvm, irq);
+               vgic_put_irq(vcpu->kvm, irq);
+       }
+
+       kfree(intids);
+
+       return ret;
+}
+
+static unsigned long vgic_mmio_read_its_ctlr(struct kvm *vcpu,
+                                            struct vgic_its *its,
+                                            gpa_t addr, unsigned int len)
+{
+       u32 reg = 0;
+
+       mutex_lock(&its->cmd_lock);
+       if (its->creadr == its->cwriter)
+               reg |= GITS_CTLR_QUIESCENT;
+       if (its->enabled)
+               reg |= GITS_CTLR_ENABLE;
+       mutex_unlock(&its->cmd_lock);
+
+       return reg;
+}
+
+static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
+                                    gpa_t addr, unsigned int len,
+                                    unsigned long val)
+{
+       its->enabled = !!(val & GITS_CTLR_ENABLE);
+}
+
+static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
+                                             struct vgic_its *its,
+                                             gpa_t addr, unsigned int len)
+{
+       u64 reg = GITS_TYPER_PLPIS;
+
+       /*
+        * We use linear CPU numbers for redistributor addressing,
+        * so GITS_TYPER.PTA is 0.
+        * Also we force all PROPBASER registers to be the same, so
+        * CommonLPIAff is 0 as well.
+        * To avoid memory waste in the guest, we keep the number of IDBits and
+        * DevBits low - as least for the time being.
+        */
+       reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
+       reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+
+       return extract_bytes(reg, addr & 7, len);
+}
+
+static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
+                                            struct vgic_its *its,
+                                            gpa_t addr, unsigned int len)
+{
+       return (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+}
+
+static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
+                                              struct vgic_its *its,
+                                              gpa_t addr, unsigned int len)
+{
+       switch (addr & 0xffff) {
+       case GITS_PIDR0:
+               return 0x92;    /* part number, bits[7:0] */
+       case GITS_PIDR1:
+               return 0xb4;    /* part number, bits[11:8] */
+       case GITS_PIDR2:
+               return GIC_PIDR2_ARCH_GICv3 | 0x0b;
+       case GITS_PIDR4:
+               return 0x40;    /* This is a 64K software visible page */
+       /* The following are the ID registers for (any) GIC. */
+       case GITS_CIDR0:
+               return 0x0d;
+       case GITS_CIDR1:
+               return 0xf0;
+       case GITS_CIDR2:
+               return 0x05;
+       case GITS_CIDR3:
+               return 0xb1;
+       }
+
+       return 0;
+}
+
+/*
+ * Find the target VCPU and the LPI number for a given devid/eventid pair
+ * and make this IRQ pending, possibly injecting it.
+ * Must be called with the its_lock mutex held.
+ */
+static void vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
+                                u32 devid, u32 eventid)
+{
+       struct its_itte *itte;
+
+       if (!its->enabled)
+               return;
+
+       itte = find_itte(its, devid, eventid);
+       /* Triggering an unmapped IRQ gets silently dropped. */
+       if (itte && its_is_collection_mapped(itte->collection)) {
+               struct kvm_vcpu *vcpu;
+
+               vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+               if (vcpu && vcpu->arch.vgic_cpu.lpis_enabled) {
+                       spin_lock(&itte->irq->irq_lock);
+                       itte->irq->pending = true;
+                       vgic_queue_irq_unlock(kvm, itte->irq);
+               }
+       }
+}
+
+/*
+ * Queries the KVM IO bus framework to get the ITS pointer from the given
+ * doorbell address.
+ * We then call vgic_its_trigger_msi() with the decoded data.
+ */
+int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+       u64 address;
+       struct kvm_io_device *kvm_io_dev;
+       struct vgic_io_device *iodev;
+
+       if (!vgic_has_its(kvm))
+               return -ENODEV;
+
+       if (!(msi->flags & KVM_MSI_VALID_DEVID))
+               return -EINVAL;
+
+       address = (u64)msi->address_hi << 32 | msi->address_lo;
+
+       kvm_io_dev = kvm_io_bus_get_dev(kvm, KVM_MMIO_BUS, address);
+       if (!kvm_io_dev)
+               return -ENODEV;
+
+       iodev = container_of(kvm_io_dev, struct vgic_io_device, dev);
+
+       mutex_lock(&iodev->its->its_lock);
+       vgic_its_trigger_msi(kvm, iodev->its, msi->devid, msi->data);
+       mutex_unlock(&iodev->its->its_lock);
+
+       return 0;
+}
+
+/* Requires the its_lock to be held. */
+static void its_free_itte(struct kvm *kvm, struct its_itte *itte)
+{
+       list_del(&itte->itte_list);
+
+       /* This put matches the get in vgic_add_lpi. */
+       vgic_put_irq(kvm, itte->irq);
+
+       kfree(itte);
+}
+
+static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
+{
+       return (le64_to_cpu(its_cmd[word]) >> shift) & (BIT_ULL(size) - 1);
+}
+
+#define its_cmd_get_command(cmd)       its_cmd_mask_field(cmd, 0,  0,  8)
+#define its_cmd_get_deviceid(cmd)      its_cmd_mask_field(cmd, 0, 32, 32)
+#define its_cmd_get_id(cmd)            its_cmd_mask_field(cmd, 1,  0, 32)
+#define its_cmd_get_physical_id(cmd)   its_cmd_mask_field(cmd, 1, 32, 32)
+#define its_cmd_get_collection(cmd)    its_cmd_mask_field(cmd, 2,  0, 16)
+#define its_cmd_get_target_addr(cmd)   its_cmd_mask_field(cmd, 2, 16, 32)
+#define its_cmd_get_validbit(cmd)      its_cmd_mask_field(cmd, 2, 63,  1)
+
+/*
+ * The DISCARD command frees an Interrupt Translation Table Entry (ITTE).
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
+                                      u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       u32 event_id = its_cmd_get_id(its_cmd);
+       struct its_itte *itte;
+
+
+       itte = find_itte(its, device_id, event_id);
+       if (itte && itte->collection) {
+               /*
+                * Though the spec talks about removing the pending state, we
+                * don't bother here since we clear the ITTE anyway and the
+                * pending state is a property of the ITTE struct.
+                */
+               its_free_itte(kvm, itte);
+               return 0;
+       }
+
+       return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
+}
+
+/*
+ * The MOVI command moves an ITTE to a different collection.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
+                                   u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       u32 event_id = its_cmd_get_id(its_cmd);
+       u32 coll_id = its_cmd_get_collection(its_cmd);
+       struct kvm_vcpu *vcpu;
+       struct its_itte *itte;
+       struct its_collection *collection;
+
+       itte = find_itte(its, device_id, event_id);
+       if (!itte)
+               return E_ITS_MOVI_UNMAPPED_INTERRUPT;
+
+       if (!its_is_collection_mapped(itte->collection))
+               return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+       collection = find_collection(its, coll_id);
+       if (!its_is_collection_mapped(collection))
+               return E_ITS_MOVI_UNMAPPED_COLLECTION;
+
+       itte->collection = collection;
+       vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+       spin_lock(&itte->irq->irq_lock);
+       itte->irq->target_vcpu = vcpu;
+       spin_unlock(&itte->irq->irq_lock);
+
+       return 0;
+}
+
+/*
+ * Check whether an ID can be stored into the corresponding guest table.
+ * For a direct table this is pretty easy, but gets a bit nasty for
+ * indirect tables. We check whether the resulting guest physical address
+ * is actually valid (covered by a memslot and guest accessbible).
+ * For this we have to read the respective first level entry.
+ */
+static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id)
+{
+       int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
+       int index;
+       u64 indirect_ptr;
+       gfn_t gfn;
+
+       if (!(baser & GITS_BASER_INDIRECT)) {
+               phys_addr_t addr;
+
+               if (id >= (l1_tbl_size / GITS_BASER_ENTRY_SIZE(baser)))
+                       return false;
+
+               addr = BASER_ADDRESS(baser) + id * GITS_BASER_ENTRY_SIZE(baser);
+               gfn = addr >> PAGE_SHIFT;
+
+               return kvm_is_visible_gfn(its->dev->kvm, gfn);
+       }
+
+       /* calculate and check the index into the 1st level */
+       index = id / (SZ_64K / GITS_BASER_ENTRY_SIZE(baser));
+       if (index >= (l1_tbl_size / sizeof(u64)))
+               return false;
+
+       /* Each 1st level entry is represented by a 64-bit value. */
+       if (kvm_read_guest(its->dev->kvm,
+                          BASER_ADDRESS(baser) + index * sizeof(indirect_ptr),
+                          &indirect_ptr, sizeof(indirect_ptr)))
+               return false;
+
+       indirect_ptr = le64_to_cpu(indirect_ptr);
+
+       /* check the valid bit of the first level entry */
+       if (!(indirect_ptr & BIT_ULL(63)))
+               return false;
+
+       /*
+        * Mask the guest physical address and calculate the frame number.
+        * Any address beyond our supported 48 bits of PA will be caught
+        * by the actual check in the final step.
+        */
+       indirect_ptr &= GENMASK_ULL(51, 16);
+
+       /* Find the address of the actual entry */
+       index = id % (SZ_64K / GITS_BASER_ENTRY_SIZE(baser));
+       indirect_ptr += index * GITS_BASER_ENTRY_SIZE(baser);
+       gfn = indirect_ptr >> PAGE_SHIFT;
+
+       return kvm_is_visible_gfn(its->dev->kvm, gfn);
+}
+
+static int vgic_its_alloc_collection(struct vgic_its *its,
+                                    struct its_collection **colp,
+                                    u32 coll_id)
+{
+       struct its_collection *collection;
+
+       if (!vgic_its_check_id(its, its->baser_coll_table, coll_id))
+               return E_ITS_MAPC_COLLECTION_OOR;
+
+       collection = kzalloc(sizeof(*collection), GFP_KERNEL);
+
+       collection->collection_id = coll_id;
+       collection->target_addr = COLLECTION_NOT_MAPPED;
+
+       list_add_tail(&collection->coll_list, &its->collection_list);
+       *colp = collection;
+
+       return 0;
+}
+
+static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
+{
+       struct its_collection *collection;
+       struct its_device *device;
+       struct its_itte *itte;
+
+       /*
+        * Clearing the mapping for that collection ID removes the
+        * entry from the list. If there wasn't any before, we can
+        * go home early.
+        */
+       collection = find_collection(its, coll_id);
+       if (!collection)
+               return;
+
+       for_each_lpi_its(device, itte, its)
+               if (itte->collection &&
+                   itte->collection->collection_id == coll_id)
+                       itte->collection = NULL;
+
+       list_del(&collection->coll_list);
+       kfree(collection);
+}
+
+/*
+ * The MAPTI and MAPI commands map LPIs to ITTEs.
+ * Must be called with its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
+                                   u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       u32 event_id = its_cmd_get_id(its_cmd);
+       u32 coll_id = its_cmd_get_collection(its_cmd);
+       struct its_itte *itte;
+       struct its_device *device;
+       struct its_collection *collection, *new_coll = NULL;
+       int lpi_nr;
+
+       device = find_its_device(its, device_id);
+       if (!device)
+               return E_ITS_MAPTI_UNMAPPED_DEVICE;
+
+       if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
+               lpi_nr = its_cmd_get_physical_id(its_cmd);
+       else
+               lpi_nr = event_id;
+       if (lpi_nr < GIC_LPI_OFFSET ||
+           lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser))
+               return E_ITS_MAPTI_PHYSICALID_OOR;
+
+       collection = find_collection(its, coll_id);
+       if (!collection) {
+               int ret = vgic_its_alloc_collection(its, &collection, coll_id);
+               if (ret)
+                       return ret;
+               new_coll = collection;
+       }
+
+       itte = find_itte(its, device_id, event_id);
+       if (!itte) {
+               itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
+               if (!itte) {
+                       if (new_coll)
+                               vgic_its_free_collection(its, coll_id);
+                       return -ENOMEM;
+               }
+
+               itte->event_id  = event_id;
+               list_add_tail(&itte->itte_list, &device->itt_head);
+       }
+
+       itte->collection = collection;
+       itte->lpi = lpi_nr;
+       itte->irq = vgic_add_lpi(kvm, lpi_nr);
+       update_affinity_itte(kvm, itte);
+
+       /*
+        * We "cache" the configuration table entries in out struct vgic_irq's.
+        * However we only have those structs for mapped IRQs, so we read in
+        * the respective config data from memory here upon mapping the LPI.
+        */
+       update_lpi_config(kvm, itte->irq, NULL);
+
+       return 0;
+}
+
+/* Requires the its_lock to be held. */
+static void vgic_its_unmap_device(struct kvm *kvm, struct its_device *device)
+{
+       struct its_itte *itte, *temp;
+
+       /*
+        * The spec says that unmapping a device with still valid
+        * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
+        * since we cannot leave the memory unreferenced.
+        */
+       list_for_each_entry_safe(itte, temp, &device->itt_head, itte_list)
+               its_free_itte(kvm, itte);
+
+       list_del(&device->dev_list);
+       kfree(device);
+}
+
+/*
+ * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
+                                   u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       bool valid = its_cmd_get_validbit(its_cmd);
+       struct its_device *device;
+
+       if (!vgic_its_check_id(its, its->baser_device_table, device_id))
+               return E_ITS_MAPD_DEVICE_OOR;
+
+       device = find_its_device(its, device_id);
+
+       /*
+        * The spec says that calling MAPD on an already mapped device
+        * invalidates all cached data for this device. We implement this
+        * by removing the mapping and re-establishing it.
+        */
+       if (device)
+               vgic_its_unmap_device(kvm, device);
+
+       /*
+        * The spec does not say whether unmapping a not-mapped device
+        * is an error, so we are done in any case.
+        */
+       if (!valid)
+               return 0;
+
+       device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       device->device_id = device_id;
+       INIT_LIST_HEAD(&device->itt_head);
+
+       list_add_tail(&device->dev_list, &its->device_list);
+
+       return 0;
+}
+
+/*
+ * The MAPC command maps collection IDs to redistributors.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
+                                   u64 *its_cmd)
+{
+       u16 coll_id;
+       u32 target_addr;
+       struct its_collection *collection;
+       bool valid;
+
+       valid = its_cmd_get_validbit(its_cmd);
+       coll_id = its_cmd_get_collection(its_cmd);
+       target_addr = its_cmd_get_target_addr(its_cmd);
+
+       if (target_addr >= atomic_read(&kvm->online_vcpus))
+               return E_ITS_MAPC_PROCNUM_OOR;
+
+       if (!valid) {
+               vgic_its_free_collection(its, coll_id);
+       } else {
+               collection = find_collection(its, coll_id);
+
+               if (!collection) {
+                       int ret;
+
+                       ret = vgic_its_alloc_collection(its, &collection,
+                                                       coll_id);
+                       if (ret)
+                               return ret;
+                       collection->target_addr = target_addr;
+               } else {
+                       collection->target_addr = target_addr;
+                       update_affinity_collection(kvm, its, collection);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * The CLEAR command removes the pending state for a particular LPI.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_clear(struct kvm *kvm, struct vgic_its *its,
+                                    u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       u32 event_id = its_cmd_get_id(its_cmd);
+       struct its_itte *itte;
+
+
+       itte = find_itte(its, device_id, event_id);
+       if (!itte)
+               return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
+
+       itte->irq->pending = false;
+
+       return 0;
+}
+
+/*
+ * The INV command syncs the configuration bits from the memory table.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its,
+                                  u64 *its_cmd)
+{
+       u32 device_id = its_cmd_get_deviceid(its_cmd);
+       u32 event_id = its_cmd_get_id(its_cmd);
+       struct its_itte *itte;
+
+
+       itte = find_itte(its, device_id, event_id);
+       if (!itte)
+               return E_ITS_INV_UNMAPPED_INTERRUPT;
+
+       return update_lpi_config(kvm, itte->irq, NULL);
+}
+
+/*
+ * The INVALL command requests flushing of all IRQ data in this collection.
+ * Find the VCPU mapped to that collection, then iterate over the VM's list
+ * of mapped LPIs and update the configuration for each IRQ which targets
+ * the specified vcpu. The configuration will be read from the in-memory
+ * configuration table.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
+                                     u64 *its_cmd)
+{
+       u32 coll_id = its_cmd_get_collection(its_cmd);
+       struct its_collection *collection;
+       struct kvm_vcpu *vcpu;
+       struct vgic_irq *irq;
+       u32 *intids;
+       int irq_count, i;
+
+       collection = find_collection(its, coll_id);
+       if (!its_is_collection_mapped(collection))
+               return E_ITS_INVALL_UNMAPPED_COLLECTION;
+
+       vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+       irq_count = vgic_copy_lpi_list(kvm, &intids);
+       if (irq_count < 0)
+               return irq_count;
+
+       for (i = 0; i < irq_count; i++) {
+               irq = vgic_get_irq(kvm, NULL, intids[i]);
+               if (!irq)
+                       continue;
+               update_lpi_config(kvm, irq, vcpu);
+               vgic_put_irq(kvm, irq);
+       }
+
+       kfree(intids);
+
+       return 0;
+}
+
+/*
+ * The MOVALL command moves the pending state of all IRQs targeting one
+ * redistributor to another. We don't hold the pending state in the VCPUs,
+ * but in the IRQs instead, so there is really not much to do for us here.
+ * However the spec says that no IRQ must target the old redistributor
+ * afterwards, so we make sure that no LPI is using the associated target_vcpu.
+ * This command affects all LPIs in the system that target that redistributor.
+ */
+static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
+                                     u64 *its_cmd)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       u32 target1_addr = its_cmd_get_target_addr(its_cmd);
+       u32 target2_addr = its_cmd_mask_field(its_cmd, 3, 16, 32);
+       struct kvm_vcpu *vcpu1, *vcpu2;
+       struct vgic_irq *irq;
+
+       if (target1_addr >= atomic_read(&kvm->online_vcpus) ||
+           target2_addr >= atomic_read(&kvm->online_vcpus))
+               return E_ITS_MOVALL_PROCNUM_OOR;
+
+       if (target1_addr == target2_addr)
+               return 0;
+
+       vcpu1 = kvm_get_vcpu(kvm, target1_addr);
+       vcpu2 = kvm_get_vcpu(kvm, target2_addr);
+
+       spin_lock(&dist->lpi_list_lock);
+
+       list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
+               spin_lock(&irq->irq_lock);
+
+               if (irq->target_vcpu == vcpu1)
+                       irq->target_vcpu = vcpu2;
+
+               spin_unlock(&irq->irq_lock);
+       }
+
+       spin_unlock(&dist->lpi_list_lock);
+
+       return 0;
+}
+
+/*
+ * The INT command injects the LPI associated with that DevID/EvID pair.
+ * Must be called with the its_lock mutex held.
+ */
+static int vgic_its_cmd_handle_int(struct kvm *kvm, struct vgic_its *its,
+                                  u64 *its_cmd)
+{
+       u32 msi_data = its_cmd_get_id(its_cmd);
+       u64 msi_devid = its_cmd_get_deviceid(its_cmd);
+
+       vgic_its_trigger_msi(kvm, its, msi_devid, msi_data);
+
+       return 0;
+}
+
+/*
+ * This function is called with the its_cmd lock held, but the ITS data
+ * structure lock dropped.
+ */
+static int vgic_its_handle_command(struct kvm *kvm, struct vgic_its *its,
+                                  u64 *its_cmd)
+{
+       int ret = -ENODEV;
+
+       mutex_lock(&its->its_lock);
+       switch (its_cmd_get_command(its_cmd)) {
+       case GITS_CMD_MAPD:
+               ret = vgic_its_cmd_handle_mapd(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_MAPC:
+               ret = vgic_its_cmd_handle_mapc(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_MAPI:
+               ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_MAPTI:
+               ret = vgic_its_cmd_handle_mapi(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_MOVI:
+               ret = vgic_its_cmd_handle_movi(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_DISCARD:
+               ret = vgic_its_cmd_handle_discard(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_CLEAR:
+               ret = vgic_its_cmd_handle_clear(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_MOVALL:
+               ret = vgic_its_cmd_handle_movall(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_INT:
+               ret = vgic_its_cmd_handle_int(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_INV:
+               ret = vgic_its_cmd_handle_inv(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_INVALL:
+               ret = vgic_its_cmd_handle_invall(kvm, its, its_cmd);
+               break;
+       case GITS_CMD_SYNC:
+               /* we ignore this command: we are in sync all of the time */
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&its->its_lock);
+
+       return ret;
+}
+
+static u64 vgic_sanitise_its_baser(u64 reg)
+{
+       reg = vgic_sanitise_field(reg, GITS_BASER_SHAREABILITY_MASK,
+                                 GITS_BASER_SHAREABILITY_SHIFT,
+                                 vgic_sanitise_shareability);
+       reg = vgic_sanitise_field(reg, GITS_BASER_INNER_CACHEABILITY_MASK,
+                                 GITS_BASER_INNER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_inner_cacheability);
+       reg = vgic_sanitise_field(reg, GITS_BASER_OUTER_CACHEABILITY_MASK,
+                                 GITS_BASER_OUTER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_outer_cacheability);
+
+       /* Bits 15:12 contain bits 51:48 of the PA, which we don't support. */
+       reg &= ~GENMASK_ULL(15, 12);
+
+       /* We support only one (ITS) page size: 64K */
+       reg = (reg & ~GITS_BASER_PAGE_SIZE_MASK) | GITS_BASER_PAGE_SIZE_64K;
+
+       return reg;
+}
+
+static u64 vgic_sanitise_its_cbaser(u64 reg)
+{
+       reg = vgic_sanitise_field(reg, GITS_CBASER_SHAREABILITY_MASK,
+                                 GITS_CBASER_SHAREABILITY_SHIFT,
+                                 vgic_sanitise_shareability);
+       reg = vgic_sanitise_field(reg, GITS_CBASER_INNER_CACHEABILITY_MASK,
+                                 GITS_CBASER_INNER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_inner_cacheability);
+       reg = vgic_sanitise_field(reg, GITS_CBASER_OUTER_CACHEABILITY_MASK,
+                                 GITS_CBASER_OUTER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_outer_cacheability);
+
+       /*
+        * Sanitise the physical address to be 64k aligned.
+        * Also limit the physical addresses to 48 bits.
+        */
+       reg &= ~(GENMASK_ULL(51, 48) | GENMASK_ULL(15, 12));
+
+       return reg;
+}
+
+static unsigned long vgic_mmio_read_its_cbaser(struct kvm *kvm,
+                                              struct vgic_its *its,
+                                              gpa_t addr, unsigned int len)
+{
+       return extract_bytes(its->cbaser, addr & 7, len);
+}
+
+static void vgic_mmio_write_its_cbaser(struct kvm *kvm, struct vgic_its *its,
+                                      gpa_t addr, unsigned int len,
+                                      unsigned long val)
+{
+       /* When GITS_CTLR.Enable is 1, this register is RO. */
+       if (its->enabled)
+               return;
+
+       mutex_lock(&its->cmd_lock);
+       its->cbaser = update_64bit_reg(its->cbaser, addr & 7, len, val);
+       its->cbaser = vgic_sanitise_its_cbaser(its->cbaser);
+       its->creadr = 0;
+       /*
+        * CWRITER is architecturally UNKNOWN on reset, but we need to reset
+        * it to CREADR to make sure we start with an empty command buffer.
+        */
+       its->cwriter = its->creadr;
+       mutex_unlock(&its->cmd_lock);
+}
+
+#define ITS_CMD_BUFFER_SIZE(baser)     ((((baser) & 0xff) + 1) << 12)
+#define ITS_CMD_SIZE                   32
+#define ITS_CMD_OFFSET(reg)            ((reg) & GENMASK(19, 5))
+
+/*
+ * By writing to CWRITER the guest announces new commands to be processed.
+ * To avoid any races in the first place, we take the its_cmd lock, which
+ * protects our ring buffer variables, so that there is only one user
+ * per ITS handling commands at a given time.
+ */
+static void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
+                                       gpa_t addr, unsigned int len,
+                                       unsigned long val)
+{
+       gpa_t cbaser;
+       u64 cmd_buf[4];
+       u32 reg;
+
+       if (!its)
+               return;
+
+       mutex_lock(&its->cmd_lock);
+
+       reg = update_64bit_reg(its->cwriter, addr & 7, len, val);
+       reg = ITS_CMD_OFFSET(reg);
+       if (reg >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
+               mutex_unlock(&its->cmd_lock);
+               return;
+       }
+
+       its->cwriter = reg;
+       cbaser = CBASER_ADDRESS(its->cbaser);
+
+       while (its->cwriter != its->creadr) {
+               int ret = kvm_read_guest(kvm, cbaser + its->creadr,
+                                        cmd_buf, ITS_CMD_SIZE);
+               /*
+                * If kvm_read_guest() fails, this could be due to the guest
+                * programming a bogus value in CBASER or something else going
+                * wrong from which we cannot easily recover.
+                * According to section 6.3.2 in the GICv3 spec we can just
+                * ignore that command then.
+                */
+               if (!ret)
+                       vgic_its_handle_command(kvm, its, cmd_buf);
+
+               its->creadr += ITS_CMD_SIZE;
+               if (its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser))
+                       its->creadr = 0;
+       }
+
+       mutex_unlock(&its->cmd_lock);
+}
+
+static unsigned long vgic_mmio_read_its_cwriter(struct kvm *kvm,
+                                               struct vgic_its *its,
+                                               gpa_t addr, unsigned int len)
+{
+       return extract_bytes(its->cwriter, addr & 0x7, len);
+}
+
+static unsigned long vgic_mmio_read_its_creadr(struct kvm *kvm,
+                                              struct vgic_its *its,
+                                              gpa_t addr, unsigned int len)
+{
+       return extract_bytes(its->creadr, addr & 0x7, len);
+}
+
+#define BASER_INDEX(addr) (((addr) / sizeof(u64)) & 0x7)
+static unsigned long vgic_mmio_read_its_baser(struct kvm *kvm,
+                                             struct vgic_its *its,
+                                             gpa_t addr, unsigned int len)
+{
+       u64 reg;
+
+       switch (BASER_INDEX(addr)) {
+       case 0:
+               reg = its->baser_device_table;
+               break;
+       case 1:
+               reg = its->baser_coll_table;
+               break;
+       default:
+               reg = 0;
+               break;
+       }
+
+       return extract_bytes(reg, addr & 7, len);
+}
+
+#define GITS_BASER_RO_MASK     (GENMASK_ULL(52, 48) | GENMASK_ULL(58, 56))
+static void vgic_mmio_write_its_baser(struct kvm *kvm,
+                                     struct vgic_its *its,
+                                     gpa_t addr, unsigned int len,
+                                     unsigned long val)
+{
+       u64 entry_size, device_type;
+       u64 reg, *regptr, clearbits = 0;
+
+       /* When GITS_CTLR.Enable is 1, we ignore write accesses. */
+       if (its->enabled)
+               return;
+
+       switch (BASER_INDEX(addr)) {
+       case 0:
+               regptr = &its->baser_device_table;
+               entry_size = 8;
+               device_type = GITS_BASER_TYPE_DEVICE;
+               break;
+       case 1:
+               regptr = &its->baser_coll_table;
+               entry_size = 8;
+               device_type = GITS_BASER_TYPE_COLLECTION;
+               clearbits = GITS_BASER_INDIRECT;
+               break;
+       default:
+               return;
+       }
+
+       reg = update_64bit_reg(*regptr, addr & 7, len, val);
+       reg &= ~GITS_BASER_RO_MASK;
+       reg &= ~clearbits;
+
+       reg |= (entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT;
+       reg |= device_type << GITS_BASER_TYPE_SHIFT;
+       reg = vgic_sanitise_its_baser(reg);
+
+       *regptr = reg;
+}
+
+#define REGISTER_ITS_DESC(off, rd, wr, length, acc)            \
+{                                                              \
+       .reg_offset = off,                                      \
+       .len = length,                                          \
+       .access_flags = acc,                                    \
+       .its_read = rd,                                         \
+       .its_write = wr,                                        \
+}
+
+static void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
+                             gpa_t addr, unsigned int len, unsigned long val)
+{
+       /* Ignore */
+}
+
+static struct vgic_register_region its_registers[] = {
+       REGISTER_ITS_DESC(GITS_CTLR,
+               vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_IIDR,
+               vgic_mmio_read_its_iidr, its_mmio_write_wi, 4,
+               VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_TYPER,
+               vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
+               VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_CBASER,
+               vgic_mmio_read_its_cbaser, vgic_mmio_write_its_cbaser, 8,
+               VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_CWRITER,
+               vgic_mmio_read_its_cwriter, vgic_mmio_write_its_cwriter, 8,
+               VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_CREADR,
+               vgic_mmio_read_its_creadr, its_mmio_write_wi, 8,
+               VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_BASER,
+               vgic_mmio_read_its_baser, vgic_mmio_write_its_baser, 0x40,
+               VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+       REGISTER_ITS_DESC(GITS_IDREGS_BASE,
+               vgic_mmio_read_its_idregs, its_mmio_write_wi, 0x30,
+               VGIC_ACCESS_32bit),
+};
+
+/* This is called on setting the LPI enable bit in the redistributor. */
+void vgic_enable_lpis(struct kvm_vcpu *vcpu)
+{
+       if (!(vcpu->arch.vgic_cpu.pendbaser & GICR_PENDBASER_PTZ))
+               its_sync_lpi_pending_table(vcpu);
+}
+
+static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
+{
+       struct vgic_io_device *iodev = &its->iodev;
+       int ret;
+
+       if (its->initialized)
+               return 0;
+
+       if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base))
+               return -ENXIO;
+
+       iodev->regions = its_registers;
+       iodev->nr_regions = ARRAY_SIZE(its_registers);
+       kvm_iodevice_init(&iodev->dev, &kvm_io_gic_ops);
+
+       iodev->base_addr = its->vgic_its_base;
+       iodev->iodev_type = IODEV_ITS;
+       iodev->its = its;
+       mutex_lock(&kvm->slots_lock);
+       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, iodev->base_addr,
+                                     KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
+       mutex_unlock(&kvm->slots_lock);
+
+       if (!ret)
+               its->initialized = true;
+
+       return ret;
+}
+
+#define INITIAL_BASER_VALUE                                              \
+       (GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb)                | \
+        GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner)         | \
+        GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)             | \
+        ((8ULL - 1) << GITS_BASER_ENTRY_SIZE_SHIFT)                    | \
+        GITS_BASER_PAGE_SIZE_64K)
+
+#define INITIAL_PROPBASER_VALUE                                                  \
+       (GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWb)            | \
+        GIC_BASER_CACHEABILITY(GICR_PROPBASER, OUTER, SameAsInner)     | \
+        GIC_BASER_SHAREABILITY(GICR_PROPBASER, InnerShareable))
+
+static int vgic_its_create(struct kvm_device *dev, u32 type)
+{
+       struct vgic_its *its;
+
+       if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
+               return -ENODEV;
+
+       its = kzalloc(sizeof(struct vgic_its), GFP_KERNEL);
+       if (!its)
+               return -ENOMEM;
+
+       mutex_init(&its->its_lock);
+       mutex_init(&its->cmd_lock);
+
+       its->vgic_its_base = VGIC_ADDR_UNDEF;
+
+       INIT_LIST_HEAD(&its->device_list);
+       INIT_LIST_HEAD(&its->collection_list);
+
+       dev->kvm->arch.vgic.has_its = true;
+       its->initialized = false;
+       its->enabled = false;
+       its->dev = dev;
+
+       its->baser_device_table = INITIAL_BASER_VALUE                   |
+               ((u64)GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT);
+       its->baser_coll_table = INITIAL_BASER_VALUE |
+               ((u64)GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT);
+       dev->kvm->arch.vgic.propbaser = INITIAL_PROPBASER_VALUE;
+
+       dev->private = its;
+
+       return 0;
+}
+
+static void vgic_its_destroy(struct kvm_device *kvm_dev)
+{
+       struct kvm *kvm = kvm_dev->kvm;
+       struct vgic_its *its = kvm_dev->private;
+       struct its_device *dev;
+       struct its_itte *itte;
+       struct list_head *dev_cur, *dev_temp;
+       struct list_head *cur, *temp;
+
+       /*
+        * We may end up here without the lists ever having been initialized.
+        * Check this and bail out early to avoid dereferencing a NULL pointer.
+        */
+       if (!its->device_list.next)
+               return;
+
+       mutex_lock(&its->its_lock);
+       list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
+               dev = container_of(dev_cur, struct its_device, dev_list);
+               list_for_each_safe(cur, temp, &dev->itt_head) {
+                       itte = (container_of(cur, struct its_itte, itte_list));
+                       its_free_itte(kvm, itte);
+               }
+               list_del(dev_cur);
+               kfree(dev);
+       }
+
+       list_for_each_safe(cur, temp, &its->collection_list) {
+               list_del(cur);
+               kfree(container_of(cur, struct its_collection, coll_list));
+       }
+       mutex_unlock(&its->its_lock);
+
+       kfree(its);
+}
+
+static int vgic_its_has_attr(struct kvm_device *dev,
+                            struct kvm_device_attr *attr)
+{
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_ADDR:
+               switch (attr->attr) {
+               case KVM_VGIC_ITS_ADDR_TYPE:
+                       return 0;
+               }
+               break;
+       case KVM_DEV_ARM_VGIC_GRP_CTRL:
+               switch (attr->attr) {
+               case KVM_DEV_ARM_VGIC_CTRL_INIT:
+                       return 0;
+               }
+               break;
+       }
+       return -ENXIO;
+}
+
+static int vgic_its_set_attr(struct kvm_device *dev,
+                            struct kvm_device_attr *attr)
+{
+       struct vgic_its *its = dev->private;
+       int ret;
+
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+               u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+               unsigned long type = (unsigned long)attr->attr;
+               u64 addr;
+
+               if (type != KVM_VGIC_ITS_ADDR_TYPE)
+                       return -ENODEV;
+
+               if (its->initialized)
+                       return -EBUSY;
+
+               if (copy_from_user(&addr, uaddr, sizeof(addr)))
+                       return -EFAULT;
+
+               ret = vgic_check_ioaddr(dev->kvm, &its->vgic_its_base,
+                                       addr, SZ_64K);
+               if (ret)
+                       return ret;
+
+               its->vgic_its_base = addr;
+
+               return 0;
+       }
+       case KVM_DEV_ARM_VGIC_GRP_CTRL:
+               switch (attr->attr) {
+               case KVM_DEV_ARM_VGIC_CTRL_INIT:
+                       return vgic_its_init_its(dev->kvm, its);
+               }
+               break;
+       }
+       return -ENXIO;
+}
+
+static int vgic_its_get_attr(struct kvm_device *dev,
+                            struct kvm_device_attr *attr)
+{
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+               struct vgic_its *its = dev->private;
+               u64 addr = its->vgic_its_base;
+               u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+               unsigned long type = (unsigned long)attr->attr;
+
+               if (type != KVM_VGIC_ITS_ADDR_TYPE)
+                       return -ENODEV;
+
+               if (copy_to_user(uaddr, &addr, sizeof(addr)))
+                       return -EFAULT;
+               break;
+       default:
+               return -ENXIO;
+       }
+       }
+
+       return 0;
+}
+
+static struct kvm_device_ops kvm_arm_vgic_its_ops = {
+       .name = "kvm-arm-vgic-its",
+       .create = vgic_its_create,
+       .destroy = vgic_its_destroy,
+       .set_attr = vgic_its_set_attr,
+       .get_attr = vgic_its_get_attr,
+       .has_attr = vgic_its_has_attr,
+};
+
+int kvm_vgic_register_its_device(void)
+{
+       return kvm_register_device_ops(&kvm_arm_vgic_its_ops,
+                                      KVM_DEV_TYPE_ARM_VGIC_ITS);
+}
index 0130c4b..1813f93 100644 (file)
@@ -21,8 +21,8 @@
 
 /* common helpers */
 
-static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
-                            phys_addr_t addr, phys_addr_t alignment)
+int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
+                     phys_addr_t addr, phys_addr_t alignment)
 {
        if (addr & ~KVM_PHYS_MASK)
                return -E2BIG;
@@ -210,20 +210,27 @@ static void vgic_destroy(struct kvm_device *dev)
        kfree(dev);
 }
 
-void kvm_register_vgic_device(unsigned long type)
+int kvm_register_vgic_device(unsigned long type)
 {
+       int ret = -ENODEV;
+
        switch (type) {
        case KVM_DEV_TYPE_ARM_VGIC_V2:
-               kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
-                                       KVM_DEV_TYPE_ARM_VGIC_V2);
+               ret = kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+                                             KVM_DEV_TYPE_ARM_VGIC_V2);
                break;
 #ifdef CONFIG_KVM_ARM_VGIC_V3
        case KVM_DEV_TYPE_ARM_VGIC_V3:
-               kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
-                                       KVM_DEV_TYPE_ARM_VGIC_V3);
+               ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+                                             KVM_DEV_TYPE_ARM_VGIC_V3);
+               if (ret)
+                       break;
+               ret = kvm_vgic_register_its_device();
                break;
 #endif
        }
+
+       return ret;
 }
 
 /** vgic_attr_regs_access: allows user space to read/write VGIC registers
@@ -428,4 +435,3 @@ struct kvm_device_ops kvm_arm_vgic_v3_ops = {
 };
 
 #endif /* CONFIG_KVM_ARM_VGIC_V3 */
-
index a213936..b44b359 100644 (file)
@@ -102,6 +102,7 @@ static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
                irq->source |= 1U << source_vcpu->vcpu_id;
 
                vgic_queue_irq_unlock(source_vcpu->kvm, irq);
+               vgic_put_irq(source_vcpu->kvm, irq);
        }
 }
 
@@ -116,6 +117,8 @@ static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
                val |= (u64)irq->targets << (i * 8);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return val;
@@ -143,6 +146,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
                irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -157,6 +161,8 @@ static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
                val |= (u64)irq->source << (i * 8);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
        return val;
 }
@@ -178,6 +184,7 @@ static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
                        irq->pending = false;
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -201,6 +208,7 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
                } else {
                        spin_unlock(&irq->irq_lock);
                }
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -429,6 +437,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
        struct vgic_io_device dev = {
                .regions = vgic_v2_cpu_registers,
                .nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+               .iodev_type = IODEV_CPUIF,
        };
 
        return vgic_uaccess(vcpu, &dev, is_write, offset, val);
@@ -440,6 +449,7 @@ int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
        struct vgic_io_device dev = {
                .regions = vgic_v2_dist_registers,
                .nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+               .iodev_type = IODEV_DIST,
        };
 
        return vgic_uaccess(vcpu, &dev, is_write, offset, val);
index a0c515a..ff668e0 100644 (file)
 #include "vgic-mmio.h"
 
 /* extract @num bytes at @offset bytes offset in data */
-static unsigned long extract_bytes(unsigned long data, unsigned int offset,
-                                  unsigned int num)
+unsigned long extract_bytes(unsigned long data, unsigned int offset,
+                           unsigned int num)
 {
        return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
 }
 
+/* allows updates of any half of a 64-bit register (or the whole thing) */
+u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
+                    unsigned long val)
+{
+       int lower = (offset & 4) * 8;
+       int upper = lower + 8 * len - 1;
+
+       reg &= ~GENMASK_ULL(upper, lower);
+       val &= GENMASK_ULL(len * 8 - 1, 0);
+
+       return reg | ((u64)val << lower);
+}
+
+bool vgic_has_its(struct kvm *kvm)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+
+       if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+               return false;
+
+       return dist->has_its;
+}
+
 static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
                                            gpa_t addr, unsigned int len)
 {
@@ -43,7 +66,12 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
        case GICD_TYPER:
                value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
                value = (value >> 5) - 1;
-               value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+               if (vgic_has_its(vcpu->kvm)) {
+                       value |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
+                       value |= GICD_TYPER_LPIS;
+               } else {
+                       value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+               }
                break;
        case GICD_IIDR:
                value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
@@ -80,15 +108,17 @@ static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
 {
        int intid = VGIC_ADDR_TO_INTID(addr, 64);
        struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+       unsigned long ret = 0;
 
        if (!irq)
                return 0;
 
        /* The upper word is RAZ for us. */
-       if (addr & 4)
-               return 0;
+       if (!(addr & 4))
+               ret = extract_bytes(READ_ONCE(irq->mpidr), addr & 7, len);
 
-       return extract_bytes(READ_ONCE(irq->mpidr), addr & 7, len);
+       vgic_put_irq(vcpu->kvm, irq);
+       return ret;
 }
 
 static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
@@ -96,15 +126,17 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
                                    unsigned long val)
 {
        int intid = VGIC_ADDR_TO_INTID(addr, 64);
-       struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
-
-       if (!irq)
-               return;
+       struct vgic_irq *irq;
 
        /* The upper word is WI for us since we don't implement Aff3. */
        if (addr & 4)
                return;
 
+       irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+
+       if (!irq)
+               return;
+
        spin_lock(&irq->irq_lock);
 
        /* We only care about and preserve Aff0, Aff1 and Aff2. */
@@ -112,6 +144,32 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
        irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, irq->mpidr);
 
        spin_unlock(&irq->irq_lock);
+       vgic_put_irq(vcpu->kvm, irq);
+}
+
+static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
+                                            gpa_t addr, unsigned int len)
+{
+       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+       return vgic_cpu->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
+}
+
+
+static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
+                                    gpa_t addr, unsigned int len,
+                                    unsigned long val)
+{
+       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+       bool was_enabled = vgic_cpu->lpis_enabled;
+
+       if (!vgic_has_its(vcpu->kvm))
+               return;
+
+       vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS;
+
+       if (!was_enabled && vgic_cpu->lpis_enabled)
+               vgic_enable_lpis(vcpu);
 }
 
 static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
@@ -125,6 +183,8 @@ static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
        value |= ((target_vcpu_id & 0xffff) << 8);
        if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
                value |= GICR_TYPER_LAST;
+       if (vgic_has_its(vcpu->kvm))
+               value |= GICR_TYPER_PLPIS;
 
        return extract_bytes(value, addr & 7, len);
 }
@@ -147,6 +207,142 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+/* We want to avoid outer shareable. */
+u64 vgic_sanitise_shareability(u64 field)
+{
+       switch (field) {
+       case GIC_BASER_OuterShareable:
+               return GIC_BASER_InnerShareable;
+       default:
+               return field;
+       }
+}
+
+/* Avoid any inner non-cacheable mapping. */
+u64 vgic_sanitise_inner_cacheability(u64 field)
+{
+       switch (field) {
+       case GIC_BASER_CACHE_nCnB:
+       case GIC_BASER_CACHE_nC:
+               return GIC_BASER_CACHE_RaWb;
+       default:
+               return field;
+       }
+}
+
+/* Non-cacheable or same-as-inner are OK. */
+u64 vgic_sanitise_outer_cacheability(u64 field)
+{
+       switch (field) {
+       case GIC_BASER_CACHE_SameAsInner:
+       case GIC_BASER_CACHE_nC:
+               return field;
+       default:
+               return GIC_BASER_CACHE_nC;
+       }
+}
+
+u64 vgic_sanitise_field(u64 reg, u64 field_mask, int field_shift,
+                       u64 (*sanitise_fn)(u64))
+{
+       u64 field = (reg & field_mask) >> field_shift;
+
+       field = sanitise_fn(field) << field_shift;
+       return (reg & ~field_mask) | field;
+}
+
+#define PROPBASER_RES0_MASK                                            \
+       (GENMASK_ULL(63, 59) | GENMASK_ULL(55, 52) | GENMASK_ULL(6, 5))
+#define PENDBASER_RES0_MASK                                            \
+       (BIT_ULL(63) | GENMASK_ULL(61, 59) | GENMASK_ULL(55, 52) |      \
+        GENMASK_ULL(15, 12) | GENMASK_ULL(6, 0))
+
+static u64 vgic_sanitise_pendbaser(u64 reg)
+{
+       reg = vgic_sanitise_field(reg, GICR_PENDBASER_SHAREABILITY_MASK,
+                                 GICR_PENDBASER_SHAREABILITY_SHIFT,
+                                 vgic_sanitise_shareability);
+       reg = vgic_sanitise_field(reg, GICR_PENDBASER_INNER_CACHEABILITY_MASK,
+                                 GICR_PENDBASER_INNER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_inner_cacheability);
+       reg = vgic_sanitise_field(reg, GICR_PENDBASER_OUTER_CACHEABILITY_MASK,
+                                 GICR_PENDBASER_OUTER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_outer_cacheability);
+
+       reg &= ~PENDBASER_RES0_MASK;
+       reg &= ~GENMASK_ULL(51, 48);
+
+       return reg;
+}
+
+static u64 vgic_sanitise_propbaser(u64 reg)
+{
+       reg = vgic_sanitise_field(reg, GICR_PROPBASER_SHAREABILITY_MASK,
+                                 GICR_PROPBASER_SHAREABILITY_SHIFT,
+                                 vgic_sanitise_shareability);
+       reg = vgic_sanitise_field(reg, GICR_PROPBASER_INNER_CACHEABILITY_MASK,
+                                 GICR_PROPBASER_INNER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_inner_cacheability);
+       reg = vgic_sanitise_field(reg, GICR_PROPBASER_OUTER_CACHEABILITY_MASK,
+                                 GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT,
+                                 vgic_sanitise_outer_cacheability);
+
+       reg &= ~PROPBASER_RES0_MASK;
+       reg &= ~GENMASK_ULL(51, 48);
+       return reg;
+}
+
+static unsigned long vgic_mmio_read_propbase(struct kvm_vcpu *vcpu,
+                                            gpa_t addr, unsigned int len)
+{
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+       return extract_bytes(dist->propbaser, addr & 7, len);
+}
+
+static void vgic_mmio_write_propbase(struct kvm_vcpu *vcpu,
+                                    gpa_t addr, unsigned int len,
+                                    unsigned long val)
+{
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+       u64 propbaser = dist->propbaser;
+
+       /* Storing a value with LPIs already enabled is undefined */
+       if (vgic_cpu->lpis_enabled)
+               return;
+
+       propbaser = update_64bit_reg(propbaser, addr & 4, len, val);
+       propbaser = vgic_sanitise_propbaser(propbaser);
+
+       dist->propbaser = propbaser;
+}
+
+static unsigned long vgic_mmio_read_pendbase(struct kvm_vcpu *vcpu,
+                                            gpa_t addr, unsigned int len)
+{
+       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+       return extract_bytes(vgic_cpu->pendbaser, addr & 7, len);
+}
+
+static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
+                                    gpa_t addr, unsigned int len,
+                                    unsigned long val)
+{
+       struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+       u64 pendbaser = vgic_cpu->pendbaser;
+
+       /* Storing a value with LPIs already enabled is undefined */
+       if (vgic_cpu->lpis_enabled)
+               return;
+
+       pendbaser = update_64bit_reg(pendbaser, addr & 4, len, val);
+       pendbaser = vgic_sanitise_pendbaser(pendbaser);
+
+       vgic_cpu->pendbaser = pendbaser;
+}
+
 /*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
@@ -218,7 +414,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
 
 static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
        REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+               vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
                VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
                vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
@@ -227,10 +423,10 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
                vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
                VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+               vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
                VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+               vgic_mmio_read_pendbase, vgic_mmio_write_pendbase, 8,
                VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
                vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
@@ -285,24 +481,18 @@ unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
 
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 {
-       int nr_vcpus = atomic_read(&kvm->online_vcpus);
        struct kvm_vcpu *vcpu;
-       struct vgic_io_device *devices;
        int c, ret = 0;
 
-       devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
-                         GFP_KERNEL);
-       if (!devices)
-               return -ENOMEM;
-
        kvm_for_each_vcpu(c, vcpu, kvm) {
                gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
                gpa_t sgi_base = rd_base + SZ_64K;
-               struct vgic_io_device *rd_dev = &devices[c * 2];
-               struct vgic_io_device *sgi_dev = &devices[c * 2 + 1];
+               struct vgic_io_device *rd_dev = &vcpu->arch.vgic_cpu.rd_iodev;
+               struct vgic_io_device *sgi_dev = &vcpu->arch.vgic_cpu.sgi_iodev;
 
                kvm_iodevice_init(&rd_dev->dev, &kvm_io_gic_ops);
                rd_dev->base_addr = rd_base;
+               rd_dev->iodev_type = IODEV_REDIST;
                rd_dev->regions = vgic_v3_rdbase_registers;
                rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
                rd_dev->redist_vcpu = vcpu;
@@ -317,6 +507,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 
                kvm_iodevice_init(&sgi_dev->dev, &kvm_io_gic_ops);
                sgi_dev->base_addr = sgi_base;
+               sgi_dev->iodev_type = IODEV_REDIST;
                sgi_dev->regions = vgic_v3_sgibase_registers;
                sgi_dev->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
                sgi_dev->redist_vcpu = vcpu;
@@ -335,14 +526,15 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
        if (ret) {
                /* The current c failed, so we start with the previous one. */
                for (c--; c >= 0; c--) {
+                       struct vgic_cpu *vgic_cpu;
+
+                       vcpu = kvm_get_vcpu(kvm, c);
+                       vgic_cpu = &vcpu->arch.vgic_cpu;
                        kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
-                                                 &devices[c * 2].dev);
+                                                 &vgic_cpu->rd_iodev.dev);
                        kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
-                                                 &devices[c * 2 + 1].dev);
+                                                 &vgic_cpu->sgi_iodev.dev);
                }
-               kfree(devices);
-       } else {
-               kvm->arch.vgic.redist_iodevs = devices;
        }
 
        return ret;
@@ -451,5 +643,6 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
                irq->pending = true;
 
                vgic_queue_irq_unlock(vcpu->kvm, irq);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
index 9f6fab7..3bad3c5 100644 (file)
@@ -56,6 +56,8 @@ unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
 
                if (irq->enabled)
                        value |= (1U << i);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return value;
@@ -74,6 +76,8 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
                spin_lock(&irq->irq_lock);
                irq->enabled = true;
                vgic_queue_irq_unlock(vcpu->kvm, irq);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -92,6 +96,7 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
                irq->enabled = false;
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -108,6 +113,8 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
 
                if (irq->pending)
                        value |= (1U << i);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return value;
@@ -129,6 +136,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
                        irq->soft_pending = true;
 
                vgic_queue_irq_unlock(vcpu->kvm, irq);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -152,6 +160,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
                }
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -168,6 +177,8 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
 
                if (irq->active)
                        value |= (1U << i);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return value;
@@ -242,6 +253,7 @@ void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
        for_each_set_bit(i, &val, len * 8) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
                vgic_mmio_change_active(vcpu, irq, false);
+               vgic_put_irq(vcpu->kvm, irq);
        }
        vgic_change_active_finish(vcpu, intid);
 }
@@ -257,6 +269,7 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
        for_each_set_bit(i, &val, len * 8) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
                vgic_mmio_change_active(vcpu, irq, true);
+               vgic_put_irq(vcpu->kvm, irq);
        }
        vgic_change_active_finish(vcpu, intid);
 }
@@ -272,6 +285,8 @@ unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
                val |= (u64)irq->priority << (i * 8);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return val;
@@ -298,6 +313,8 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
                /* Narrow the priority range to what we actually support */
                irq->priority = (val >> (i * 8)) & GENMASK(7, 8 - VGIC_PRI_BITS);
                spin_unlock(&irq->irq_lock);
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -313,6 +330,8 @@ unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
 
                if (irq->config == VGIC_CONFIG_EDGE)
                        value |= (2U << (i * 2));
+
+               vgic_put_irq(vcpu->kvm, irq);
        }
 
        return value;
@@ -326,7 +345,7 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
        int i;
 
        for (i = 0; i < len * 4; i++) {
-               struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+               struct vgic_irq *irq;
 
                /*
                 * The configuration cannot be changed for SGIs in general,
@@ -337,14 +356,18 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
                if (intid + i < VGIC_NR_PRIVATE_IRQS)
                        continue;
 
+               irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
                spin_lock(&irq->irq_lock);
+
                if (test_bit(i * 2 + 1, &val)) {
                        irq->config = VGIC_CONFIG_EDGE;
                } else {
                        irq->config = VGIC_CONFIG_LEVEL;
                        irq->pending = irq->line_level | irq->soft_pending;
                }
+
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -450,8 +473,7 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 {
        struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
        const struct vgic_register_region *region;
-       struct kvm_vcpu *r_vcpu;
-       unsigned long data;
+       unsigned long data = 0;
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
                                       addr - iodev->base_addr);
@@ -460,8 +482,21 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
                return 0;
        }
 
-       r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
-       data = region->read(r_vcpu, addr, len);
+       switch (iodev->iodev_type) {
+       case IODEV_CPUIF:
+               data = region->read(vcpu, addr, len);
+               break;
+       case IODEV_DIST:
+               data = region->read(vcpu, addr, len);
+               break;
+       case IODEV_REDIST:
+               data = region->read(iodev->redist_vcpu, addr, len);
+               break;
+       case IODEV_ITS:
+               data = region->its_read(vcpu->kvm, iodev->its, addr, len);
+               break;
+       }
+
        vgic_data_host_to_mmio_bus(val, len, data);
        return 0;
 }
@@ -471,7 +506,6 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 {
        struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
        const struct vgic_register_region *region;
-       struct kvm_vcpu *r_vcpu;
        unsigned long data = vgic_data_mmio_bus_to_host(val, len);
 
        region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
@@ -482,8 +516,21 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
        if (!check_region(region, addr, len))
                return 0;
 
-       r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
-       region->write(r_vcpu, addr, len, data);
+       switch (iodev->iodev_type) {
+       case IODEV_CPUIF:
+               region->write(vcpu, addr, len, data);
+               break;
+       case IODEV_DIST:
+               region->write(vcpu, addr, len, data);
+               break;
+       case IODEV_REDIST:
+               region->write(iodev->redist_vcpu, addr, len, data);
+               break;
+       case IODEV_ITS:
+               region->its_write(vcpu->kvm, iodev->its, addr, len, data);
+               break;
+       }
+
        return 0;
 }
 
@@ -513,6 +560,7 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
        }
 
        io_device->base_addr = dist_base_address;
+       io_device->iodev_type = IODEV_DIST;
        io_device->redist_vcpu = NULL;
 
        mutex_lock(&kvm->slots_lock);
index 8509014..0b3ecf9 100644 (file)
@@ -21,10 +21,19 @@ struct vgic_register_region {
        unsigned int len;
        unsigned int bits_per_irq;
        unsigned int access_flags;
-       unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
-                             unsigned int len);
-       void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
-                     unsigned long val);
+       union {
+               unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
+                                     unsigned int len);
+               unsigned long (*its_read)(struct kvm *kvm, struct vgic_its *its,
+                                         gpa_t addr, unsigned int len);
+       };
+       union {
+               void (*write)(struct kvm_vcpu *vcpu, gpa_t addr,
+                             unsigned int len, unsigned long val);
+               void (*its_write)(struct kvm *kvm, struct vgic_its *its,
+                                 gpa_t addr, unsigned int len,
+                                 unsigned long val);
+       };
 };
 
 extern struct kvm_io_device_ops kvm_io_gic_ops;
@@ -87,6 +96,12 @@ unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
 void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
                                unsigned long data);
 
+unsigned long extract_bytes(unsigned long data, unsigned int offset,
+                           unsigned int num);
+
+u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
+                    unsigned long val);
+
 unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
                                 gpa_t addr, unsigned int len);
 
@@ -147,4 +162,12 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+u64 vgic_sanitise_outer_cacheability(u64 reg);
+u64 vgic_sanitise_inner_cacheability(u64 reg);
+u64 vgic_sanitise_shareability(u64 reg);
+u64 vgic_sanitise_field(u64 reg, u64 field_mask, int field_shift,
+                       u64 (*sanitise_fn)(u64));
+#endif
+
 #endif
index e31405e..0bf6709 100644 (file)
@@ -124,6 +124,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
                }
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -332,20 +333,25 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
        vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
        kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1;
 
+       ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+       if (ret) {
+               kvm_err("Cannot register GICv2 KVM device\n");
+               iounmap(kvm_vgic_global_state.vctrl_base);
+               return ret;
+       }
+
        ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
                                     kvm_vgic_global_state.vctrl_base +
                                         resource_size(&info->vctrl),
                                     info->vctrl.start);
-
        if (ret) {
                kvm_err("Cannot map VCTRL into hyp\n");
+               kvm_unregister_device_ops(KVM_DEV_TYPE_ARM_VGIC_V2);
                iounmap(kvm_vgic_global_state.vctrl_base);
                return ret;
        }
 
        kvm_vgic_global_state.can_emulate_gicv2 = true;
-       kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
-
        kvm_vgic_global_state.vcpu_base = info->vcpu.start;
        kvm_vgic_global_state.type = VGIC_V2;
        kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
index 346b4ad..0506543 100644 (file)
@@ -81,6 +81,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
                else
                        intid = val & GICH_LR_VIRTUALID;
                irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+               if (!irq)       /* An LPI could have been unmapped. */
+                       continue;
 
                spin_lock(&irq->irq_lock);
 
@@ -113,6 +115,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
                }
 
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(vcpu->kvm, irq);
        }
 }
 
@@ -190,6 +193,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
        vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
+#define INITIAL_PENDBASER_VALUE                                                  \
+       (GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWb)            | \
+       GIC_BASER_CACHEABILITY(GICR_PENDBASER, OUTER, SameAsInner)      | \
+       GIC_BASER_SHAREABILITY(GICR_PENDBASER, InnerShareable))
+
 void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
        struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -207,10 +215,12 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
         * way, so we force SRE to 1 to demonstrate this to the guest.
         * This goes with the spec allowing the value to be RAO/WI.
         */
-       if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+       if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
                vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
-       else
+               vcpu->arch.vgic_cpu.pendbaser = INITIAL_PENDBASER_VALUE;
+       } else {
                vgic_v3->vgic_sre = 0;
+       }
 
        /* Get the show on the road... */
        vgic_v3->vgic_hcr = ICH_HCR_EN;
@@ -296,6 +306,7 @@ out:
 int vgic_v3_probe(const struct gic_kvm_info *info)
 {
        u32 ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+       int ret;
 
        /*
         * The ListRegs field is 5 bits, but there is a architectural
@@ -319,12 +330,22 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
        } else {
                kvm_vgic_global_state.vcpu_base = info->vcpu.start;
                kvm_vgic_global_state.can_emulate_gicv2 = true;
-               kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+               ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+               if (ret) {
+                       kvm_err("Cannot register GICv2 KVM device.\n");
+                       return ret;
+               }
                kvm_info("vgic-v2@%llx\n", info->vcpu.start);
        }
+       ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+       if (ret) {
+               kvm_err("Cannot register GICv3 KVM device.\n");
+               kvm_unregister_device_ops(KVM_DEV_TYPE_ARM_VGIC_V2);
+               return ret;
+       }
+
        if (kvm_vgic_global_state.vcpu_base == 0)
                kvm_info("disabling GICv2 emulation\n");
-       kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
 
        kvm_vgic_global_state.vctrl_base = NULL;
        kvm_vgic_global_state.type = VGIC_V3;
index 69b61ab..e7aeac7 100644 (file)
@@ -33,10 +33,17 @@ struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
 
 /*
  * Locking order is always:
- *   vgic_cpu->ap_list_lock
- *     vgic_irq->irq_lock
+ * its->cmd_lock (mutex)
+ *   its->its_lock (mutex)
+ *     vgic_cpu->ap_list_lock
+ *       kvm->lpi_list_lock
+ *         vgic_irq->irq_lock
  *
- * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ * If you need to take multiple locks, always take the upper lock first,
+ * then the lower ones, e.g. first take the its_lock, then the irq_lock.
+ * If you are already holding a lock and need to take a higher one, you
+ * have to drop the lower ranking lock first and re-aquire it after having
+ * taken the upper one.
  *
  * When taking more than one ap_list_lock at the same time, always take the
  * lowest numbered VCPU's ap_list_lock first, so:
@@ -45,6 +52,41 @@ struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
  *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
  */
 
+/*
+ * Iterate over the VM's list of mapped LPIs to find the one with a
+ * matching interrupt ID and return a reference to the IRQ structure.
+ */
+static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       struct vgic_irq *irq = NULL;
+
+       spin_lock(&dist->lpi_list_lock);
+
+       list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
+               if (irq->intid != intid)
+                       continue;
+
+               /*
+                * This increases the refcount, the caller is expected to
+                * call vgic_put_irq() later once it's finished with the IRQ.
+                */
+               vgic_get_irq_kref(irq);
+               goto out_unlock;
+       }
+       irq = NULL;
+
+out_unlock:
+       spin_unlock(&dist->lpi_list_lock);
+
+       return irq;
+}
+
+/*
+ * This looks up the virtual interrupt ID to get the corresponding
+ * struct vgic_irq. It also increases the refcount, so any caller is expected
+ * to call vgic_put_irq() once it's finished with this IRQ.
+ */
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
                              u32 intid)
 {
@@ -56,14 +98,43 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
        if (intid <= VGIC_MAX_SPI)
                return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
 
-       /* LPIs are not yet covered */
+       /* LPIs */
        if (intid >= VGIC_MIN_LPI)
-               return NULL;
+               return vgic_get_lpi(kvm, intid);
 
        WARN(1, "Looking up struct vgic_irq for reserved INTID");
        return NULL;
 }
 
+/*
+ * We can't do anything in here, because we lack the kvm pointer to
+ * lock and remove the item from the lpi_list. So we keep this function
+ * empty and use the return value of kref_put() to trigger the freeing.
+ */
+static void vgic_irq_release(struct kref *ref)
+{
+}
+
+void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
+{
+       struct vgic_dist *dist;
+
+       if (irq->intid < VGIC_MIN_LPI)
+               return;
+
+       if (!kref_put(&irq->refcount, vgic_irq_release))
+               return;
+
+       dist = &kvm->arch.vgic;
+
+       spin_lock(&dist->lpi_list_lock);
+       list_del(&irq->lpi_list);
+       dist->lpi_list_count--;
+       spin_unlock(&dist->lpi_list_lock);
+
+       kfree(irq);
+}
+
 /**
  * kvm_vgic_target_oracle - compute the target vcpu for an irq
  *
@@ -236,6 +307,11 @@ retry:
                goto retry;
        }
 
+       /*
+        * Grab a reference to the irq to reflect the fact that it is
+        * now in the ap_list.
+        */
+       vgic_get_irq_kref(irq);
        list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
        irq->vcpu = vcpu;
 
@@ -269,14 +345,17 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
        if (!irq)
                return -EINVAL;
 
-       if (irq->hw != mapped_irq)
+       if (irq->hw != mapped_irq) {
+               vgic_put_irq(kvm, irq);
                return -EINVAL;
+       }
 
        spin_lock(&irq->irq_lock);
 
        if (!vgic_validate_injection(irq, level)) {
                /* Nothing to see here, move along... */
                spin_unlock(&irq->irq_lock);
+               vgic_put_irq(kvm, irq);
                return 0;
        }
 
@@ -288,6 +367,7 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
        }
 
        vgic_queue_irq_unlock(kvm, irq);
+       vgic_put_irq(kvm, irq);
 
        return 0;
 }
@@ -330,25 +410,28 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
        irq->hwintid = phys_irq;
 
        spin_unlock(&irq->irq_lock);
+       vgic_put_irq(vcpu->kvm, irq);
 
        return 0;
 }
 
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
-       struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
-
-       BUG_ON(!irq);
+       struct vgic_irq *irq;
 
        if (!vgic_initialized(vcpu->kvm))
                return -EAGAIN;
 
+       irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+       BUG_ON(!irq);
+
        spin_lock(&irq->irq_lock);
 
        irq->hw = false;
        irq->hwintid = 0;
 
        spin_unlock(&irq->irq_lock);
+       vgic_put_irq(vcpu->kvm, irq);
 
        return 0;
 }
@@ -386,6 +469,15 @@ retry:
                        list_del(&irq->ap_list);
                        irq->vcpu = NULL;
                        spin_unlock(&irq->irq_lock);
+
+                       /*
+                        * This vgic_put_irq call matches the
+                        * vgic_get_irq_kref in vgic_queue_irq_unlock,
+                        * where we added the LPI to the ap_list. As
+                        * we remove the irq from the list, we drop
+                        * also drop the refcount.
+                        */
+                       vgic_put_irq(vcpu->kvm, irq);
                        continue;
                }
 
@@ -614,6 +706,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
        spin_lock(&irq->irq_lock);
        map_is_active = irq->hw && irq->active;
        spin_unlock(&irq->irq_lock);
+       vgic_put_irq(vcpu->kvm, irq);
 
        return map_is_active;
 }
+
index 7b300ca..1d8e21d 100644 (file)
@@ -25,6 +25,7 @@
 #define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
 
 #define INTERRUPT_ID_BITS_SPIS 10
+#define INTERRUPT_ID_BITS_ITS  16
 #define VGIC_PRI_BITS          5
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
@@ -38,9 +39,13 @@ struct vgic_vmcr {
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
                              u32 intid);
+void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 void vgic_kick_vcpus(struct kvm *kvm);
 
+int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
+                     phys_addr_t addr, phys_addr_t alignment);
+
 void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
@@ -59,6 +64,14 @@ int vgic_v2_map_resources(struct kvm *kvm);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
                             enum vgic_type);
 
+static inline void vgic_get_irq_kref(struct vgic_irq *irq)
+{
+       if (irq->intid < VGIC_MIN_LPI)
+               return;
+
+       kref_get(&irq->refcount);
+}
+
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
@@ -71,6 +84,10 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
+bool vgic_has_its(struct kvm *kvm);
+int kvm_vgic_register_its_device(void);
+void vgic_enable_lpis(struct kvm_vcpu *vcpu);
+int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
@@ -122,9 +139,28 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 {
        return -ENODEV;
 }
+
+static inline bool vgic_has_its(struct kvm *kvm)
+{
+       return false;
+}
+
+static inline int kvm_vgic_register_its_device(void)
+{
+       return -ENODEV;
+}
+
+static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+       return -ENODEV;
+}
 #endif
 
-void kvm_register_vgic_device(unsigned long type);
+int kvm_register_vgic_device(unsigned long type);
 int vgic_lazy_init(struct kvm *kvm);
 int vgic_init(struct kvm *kvm);
 
index 8db197b..3bcc999 100644 (file)
@@ -62,12 +62,14 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
 {
        struct kvm_kernel_irq_routing_entry route;
 
-       if (!irqchip_in_kernel(kvm) || msi->flags != 0)
+       if (!irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID))
                return -EINVAL;
 
        route.msi.address_lo = msi->address_lo;
        route.msi.address_hi = msi->address_hi;
        route.msi.data = msi->data;
+       route.msi.flags = msi->flags;
+       route.msi.devid = msi->devid;
 
        return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false);
 }
@@ -135,7 +137,8 @@ void kvm_free_irq_routing(struct kvm *kvm)
        free_irq_routing_table(rt);
 }
 
-static int setup_routing_entry(struct kvm_irq_routing_table *rt,
+static int setup_routing_entry(struct kvm *kvm,
+                              struct kvm_irq_routing_table *rt,
                               struct kvm_kernel_irq_routing_entry *e,
                               const struct kvm_irq_routing_entry *ue)
 {
@@ -154,7 +157,7 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt,
 
        e->gsi = ue->gsi;
        e->type = ue->type;
-       r = kvm_set_routing_entry(e, ue);
+       r = kvm_set_routing_entry(kvm, e, ue);
        if (r)
                goto out;
        if (e->type == KVM_IRQ_ROUTING_IRQCHIP)
@@ -176,6 +179,7 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        unsigned flags)
 {
        struct kvm_irq_routing_table *new, *old;
+       struct kvm_kernel_irq_routing_entry *e;
        u32 i, j, nr_rt_entries = 0;
        int r;
 
@@ -199,23 +203,25 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        new->chip[i][j] = -1;
 
        for (i = 0; i < nr; ++i) {
-               struct kvm_kernel_irq_routing_entry *e;
-
                r = -ENOMEM;
                e = kzalloc(sizeof(*e), GFP_KERNEL);
                if (!e)
                        goto out;
 
                r = -EINVAL;
-               if (ue->flags) {
-                       kfree(e);
-                       goto out;
-               }
-               r = setup_routing_entry(new, e, ue);
-               if (r) {
-                       kfree(e);
-                       goto out;
+               switch (ue->type) {
+               case KVM_IRQ_ROUTING_MSI:
+                       if (ue->flags & ~KVM_MSI_VALID_DEVID)
+                               goto free_entry;
+                       break;
+               default:
+                       if (ue->flags)
+                               goto free_entry;
+                       break;
                }
+               r = setup_routing_entry(kvm, new, e, ue);
+               if (r)
+                       goto free_entry;
                ++ue;
        }
 
@@ -232,7 +238,10 @@ int kvm_set_irq_routing(struct kvm *kvm,
 
        new = old;
        r = 0;
+       goto out;
 
+free_entry:
+       kfree(e);
 out:
        free_irq_routing_table(new);
 
index 2e79136..cc081cc 100644 (file)
@@ -1444,6 +1444,52 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault)
        return true;
 }
 
+static int hva_to_pfn_remapped(struct vm_area_struct *vma,
+                              unsigned long addr, bool *async,
+                              bool write_fault, kvm_pfn_t *p_pfn)
+{
+       unsigned long pfn;
+       int r;
+
+       r = follow_pfn(vma, addr, &pfn);
+       if (r) {
+               /*
+                * get_user_pages fails for VM_IO and VM_PFNMAP vmas and does
+                * not call the fault handler, so do it here.
+                */
+               bool unlocked = false;
+               r = fixup_user_fault(current, current->mm, addr,
+                                    (write_fault ? FAULT_FLAG_WRITE : 0),
+                                    &unlocked);
+               if (unlocked)
+                       return -EAGAIN;
+               if (r)
+                       return r;
+
+               r = follow_pfn(vma, addr, &pfn);
+               if (r)
+                       return r;
+
+       }
+
+
+       /*
+        * Get a reference here because callers of *hva_to_pfn* and
+        * *gfn_to_pfn* ultimately call kvm_release_pfn_clean on the
+        * returned pfn.  This is only needed if the VMA has VM_MIXEDMAP
+        * set, but the kvm_get_pfn/kvm_release_pfn_clean pair will
+        * simply do nothing for reserved pfns.
+        *
+        * Whoever called remap_pfn_range is also going to call e.g.
+        * unmap_mapping_range before the underlying pages are freed,
+        * causing a call to our MMU notifier.
+        */ 
+       kvm_get_pfn(pfn);
+
+       *p_pfn = pfn;
+       return 0;
+}
+
 /*
  * Pin guest page in memory and return its pfn.
  * @addr: host virtual address which maps memory to the guest
@@ -1463,7 +1509,7 @@ static kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
 {
        struct vm_area_struct *vma;
        kvm_pfn_t pfn = 0;
-       int npages;
+       int npages, r;
 
        /* we can do it either atomically or asynchronously, not both */
        BUG_ON(atomic && async);
@@ -1485,14 +1531,17 @@ static kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
                goto exit;
        }
 
+retry:
        vma = find_vma_intersection(current->mm, addr, addr + 1);
 
        if (vma == NULL)
                pfn = KVM_PFN_ERR_FAULT;
-       else if ((vma->vm_flags & VM_PFNMAP)) {
-               pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) +
-                       vma->vm_pgoff;
-               BUG_ON(!kvm_is_reserved_pfn(pfn));
+       else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) {
+               r = hva_to_pfn_remapped(vma, addr, async, write_fault, &pfn);
+               if (r == -EAGAIN)
+                       goto retry;
+               if (r < 0)
+                       pfn = KVM_PFN_ERR_FAULT;
        } else {
                if (async && vma_is_valid(vma, write_fault))
                        *async = true;
@@ -2348,9 +2397,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
        if (id >= KVM_MAX_VCPU_ID)
                return -EINVAL;
 
+       mutex_lock(&kvm->lock);
+       if (kvm->created_vcpus == KVM_MAX_VCPUS) {
+               mutex_unlock(&kvm->lock);
+               return -EINVAL;
+       }
+
+       kvm->created_vcpus++;
+       mutex_unlock(&kvm->lock);
+
        vcpu = kvm_arch_vcpu_create(kvm, id);
-       if (IS_ERR(vcpu))
-               return PTR_ERR(vcpu);
+       if (IS_ERR(vcpu)) {
+               r = PTR_ERR(vcpu);
+               goto vcpu_decrement;
+       }
 
        preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
 
@@ -2359,14 +2419,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
                goto vcpu_destroy;
 
        mutex_lock(&kvm->lock);
-       if (!kvm_vcpu_compatible(vcpu)) {
-               r = -EINVAL;
-               goto unlock_vcpu_destroy;
-       }
-       if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
-               r = -EINVAL;
-               goto unlock_vcpu_destroy;
-       }
        if (kvm_get_vcpu_by_id(kvm, id)) {
                r = -EEXIST;
                goto unlock_vcpu_destroy;
@@ -2399,6 +2451,10 @@ unlock_vcpu_destroy:
        mutex_unlock(&kvm->lock);
 vcpu_destroy:
        kvm_arch_vcpu_destroy(vcpu);
+vcpu_decrement:
+       mutex_lock(&kvm->lock);
+       kvm->created_vcpus--;
+       mutex_unlock(&kvm->lock);
        return r;
 }
 
@@ -3487,6 +3543,30 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
        return r;
 }
 
+struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+                                        gpa_t addr)
+{
+       struct kvm_io_bus *bus;
+       int dev_idx, srcu_idx;
+       struct kvm_io_device *iodev = NULL;
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+
+       dev_idx = kvm_io_bus_get_first_dev(bus, addr, 1);
+       if (dev_idx < 0)
+               goto out_unlock;
+
+       iodev = bus->range[dev_idx].dev;
+
+out_unlock:
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+       return iodev;
+}
+EXPORT_SYMBOL_GPL(kvm_io_bus_get_dev);
+
 static int kvm_debugfs_open(struct inode *inode, struct file *file,
                           int (*get)(void *, u64 *), int (*set)(void *, u64),
                           const char *fmt)